@bnsights/bbsf-controls 1.0.180 → 1.0.182

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,1085 +1,711 @@
1
1
  import { Component, Input, Optional, ViewChild, Output, EventEmitter } from '@angular/core';
2
2
  import { FormControl, Validators } from '@angular/forms';
3
3
  import { FileUploader } from 'ng2-file-upload';
4
- import { FileUploadModel } from '../../Shared/Models/FileUploadModel';
5
- import { MultipleFileUploadModel } from '../../Shared/Models/MultipleFileUploadModel';
6
4
  import { HttpEventType } from '@angular/common/http';
7
- import { Subscription } from 'rxjs';
5
+ import { Subject } from 'rxjs';
6
+ import { takeUntil } from 'rxjs/operators';
7
+ import { FileUploadModel, MultipleFileUploadModel } from '../../Shared/Models';
8
8
  import * as i0 from "@angular/core";
9
9
  import * as i1 from "@angular/forms";
10
- import * as i2 from "../../Shared/services/ControlUtility";
10
+ import * as i2 from "../../Shared/services";
11
11
  import * as i3 from "@bnsights/bbsf-utilities";
12
- import * as i4 from "../../Shared/services/GlobalSettings.service";
13
- import * as i5 from "../../Shared/services/file-upload.service";
14
- import * as i6 from "@angular/common";
15
- import * as i7 from "ng2-file-upload";
12
+ import * as i4 from "@angular/common";
13
+ import * as i5 from "ng2-file-upload";
16
14
  export class FileUploadComponent {
17
15
  static { this.controlContainerStatic = null; }
18
- constructor(controlContainer, multipleFileUploadControlHost, controlUtility, utilityService, controlValidationService, globalSettings, fileUploadService) {
16
+ constructor(controlContainer, MultipleFileUploadControlHost, controlUtility, UtilityService, controlValidationService, globalSettings, fileUploadService) {
19
17
  this.controlContainer = controlContainer;
20
- this.multipleFileUploadControlHost = multipleFileUploadControlHost;
18
+ this.MultipleFileUploadControlHost = MultipleFileUploadControlHost;
21
19
  this.controlUtility = controlUtility;
22
- this.utilityService = utilityService;
20
+ this.UtilityService = UtilityService;
23
21
  this.controlValidationService = controlValidationService;
24
22
  this.globalSettings = globalSettings;
25
23
  this.fileUploadService = fileUploadService;
26
- this.BYTES_TO_MB = 1024 * 1024;
27
- this.PROGRESS_COMPLETE = 100;
28
- this.PROGRESS_NEAR_COMPLETE = 95;
29
- this.ERROR_DISPLAY_DURATION = 5000;
30
- this.MAX_MEMORY_USAGE = 100 * 1024 * 1024; // 100MB limit
31
- this.currentMemoryUsage = 0;
32
- this.isSubmitted = false;
33
24
  this.OnChange = new EventEmitter();
34
25
  this.isUploadComplete = new EventEmitter();
35
26
  this.validationMessage = '';
36
27
  this.validationCountMessage = '';
37
- this.hasAnotherDropZoneOver = false;
38
28
  this.acceptedType = '';
39
29
  this.acceptedTypeArray = [];
40
30
  this.toolTipTypeArray = [];
41
31
  this.markAllAsTouched = false;
42
32
  this.validationRules = [];
43
33
  this.validationRulesAsync = [];
44
- this.file = null;
45
34
  this.deletedFiles = [];
46
- this.subscriptions = new Subscription();
35
+ this.destroy$ = new Subject();
36
+ this.pendingValidationErrors = null;
47
37
  this.resetError = () => {
48
38
  this.controlValidationService.removeGlobalError();
49
39
  };
40
+ //External Method
50
41
  this.removeRequiredValidation = () => {
51
42
  this.controlUtility.removeRequiredValidation(this.fileUploadFormControl, this.validationRules, this.options);
52
43
  };
44
+ //External Method
53
45
  this.addRequiredValidation = () => {
54
46
  this.controlUtility.addRequiredValidation(this.fileUploadFormControl, this.validationRules, this.options);
55
47
  };
48
+ //External Method
56
49
  this.removeCustomValidation = (customValidation) => {
57
50
  this.controlUtility.removeCustomValidation(this.fileUploadFormControl, this.validationRules, customValidation);
58
51
  };
52
+ //External Method
59
53
  this.addCustomValidation = (customValidation) => {
60
54
  this.controlUtility.addCustomValidation(this.fileUploadFormControl, this.validationRules, customValidation);
61
55
  };
56
+ //External Method
62
57
  this.isValid = () => {
63
58
  this.controlUtility.isValid(this.fileUploadFormControl);
64
- return this.fileUploadFormControl.valid;
65
59
  };
66
60
  FileUploadComponent.controlContainerStatic = this.controlContainer;
67
- this.initializeUploader();
68
- }
69
- initializeUploader() {
61
+ // Initialize uploader with minimal options, URL will be set in ngOnInit only if needed
70
62
  this.uploader = new FileUploader({
71
- disableMultipart: false
63
+ url: '',
64
+ disableMultipart: false // 'DisableMultipart' must be 'true' for formatDataFunction to be called.
72
65
  });
66
+ this.hasAnotherDropZoneOver = false;
73
67
  }
74
68
  ngOnInit() {
75
- this.initializeModels();
76
- this.setViewType();
77
- this.processInitialValue();
78
- this.setupLabels();
79
- this.setupFileTypeValidation();
80
- this.setupFormControl();
81
- this.setupSubscriptions();
82
- }
83
- initializeModels() {
84
69
  this.fileUploadModel = new FileUploadModel();
85
70
  this.multipleFileUploadModel = new MultipleFileUploadModel();
86
- }
87
- setViewType() {
88
- if (!this.options.viewType) {
71
+ if (!this.options.viewType)
89
72
  this.options.viewType = this.globalSettings.viewType;
90
- }
91
- }
92
- processInitialValue() {
93
- if (this.options.value == null) {
94
- return;
95
- }
96
- if (this.options.isMultipleFile) {
97
- this.processMultipleFileValue();
98
- }
99
- else {
100
- this.processSingleFileValue();
101
- }
102
- this.uploader.queue.forEach((element) => {
103
- element.progress = this.PROGRESS_COMPLETE;
73
+ // Configure uploader options - no URL needed since we handle uploads via FileUploadService
74
+ // Note: allowedMimeType in ng2-file-upload doesn't work well with comma-separated enum values
75
+ // We handle MIME type validation manually in onFileChange
76
+ this.uploader.setOptions({
77
+ url: '',
78
+ disableMultipart: false,
79
+ autoUpload: false // We manually control uploads
80
+ // allowedMimeType removed - we handle validation manually for better control
104
81
  });
105
- }
106
- processMultipleFileValue() {
107
- const files = [];
108
- this.multipleFileUploadModel.existingFiles = this.options.value.existingFiles;
109
- this.multipleFileUploadModel.uploadedFiles = [];
110
- for (const element of this.options.value.existingFiles) {
111
- const fileLikeObject = this.createFileLikeObject(element);
112
- files.push(fileLikeObject);
113
- }
114
- this.uploader.addToQueue(files);
115
- }
116
- processSingleFileValue() {
117
- const element = this.options.value.file ?? this.options.value;
118
- const fileLikeObject = this.createFileLikeObject(element);
119
- this.file = element;
120
- this.uploader.addToQueue([fileLikeObject]);
121
- if (!this.options.value.file) {
122
- this.fileUploadModel = new FileUploadModel();
123
- this.fileUploadModel.file = this.options.value;
82
+ if (this.options.value == null) {
83
+ if (this.options.isMultipleFile == true) {
84
+ //this.options.Value=this.multipleFileUploadModel
85
+ }
86
+ else {
87
+ // this.options.Value=this.fileUploadModel
88
+ }
124
89
  }
125
90
  else {
126
- this.fileUploadModel = this.options.value;
127
- }
128
- this.options.value = this.fileUploadModel;
129
- }
130
- createFileLikeObject(element) {
131
- const bytes = new Uint8Array(element.bytes);
132
- const base64 = btoa(String.fromCharCode(...bytes));
133
- return {
134
- name: element.nameWithExtension || element.fileName,
135
- type: element.mimeType || element.fileType,
136
- rawFile: base64,
137
- size: element.fileSizeInMB ? element.fileSizeInMB * this.BYTES_TO_MB : 0,
138
- lastModifiedDate: new Date(),
139
- url: element.fullFileURL
140
- };
141
- }
142
- setupLabels() {
143
- if (this.options.labelKey) {
144
- this.options.labelValue = this.utilityService.getResourceValue(this.options.labelKey);
145
- }
146
- }
147
- setupFileTypeValidation() {
148
- if (!this.options.fileUploadAcceptsTypes?.length) {
149
- console.warn('FileUpload: No file types specified in fileUploadAcceptsTypes');
150
- return;
151
- }
152
- try {
153
- this.processAcceptedTypes();
154
- this.buildValidationMessage();
155
- // Log the processed types for debugging
156
- console.log('FileUpload: Processed file types:', {
157
- original: this.options.fileUploadAcceptsTypes,
158
- processed: this.acceptedTypeArray,
159
- acceptAttribute: this.acceptedType,
160
- displayTypes: this.toolTipTypeArray
161
- });
162
- }
163
- catch (error) {
164
- console.error('FileUpload: Error processing file types:', error);
165
- // Fallback to accepting all files if processing fails
166
- this.acceptedType = '';
167
- this.acceptedTypeArray = [];
168
- this.toolTipTypeArray = [];
169
- }
170
- }
171
- processAcceptedTypes() {
172
- // Process each file type and extract individual MIME types
173
- const allMimeTypes = [];
174
- for (const fileType of this.options.fileUploadAcceptsTypes) {
175
- if (fileType.includes(',')) {
176
- // Handle types like ImageTypes that contain multiple MIME types
177
- const mimeTypes = fileType.split(',').map(type => type.trim());
178
- allMimeTypes.push(...mimeTypes);
91
+ if (this.options.isMultipleFile == true) {
92
+ let files = [];
93
+ this.multipleFileUploadModel.existingFiles = this.options.value.existingFiles;
94
+ this.multipleFileUploadModel.uploadedFiles = [];
95
+ for (let index = 0; index < this.options.value.existingFiles.length; index++) {
96
+ const element = this.options.value.existingFiles[index];
97
+ var bytes = new Uint8Array(element.bytes);
98
+ var base64 = btoa(String.fromCharCode(...Array.from(bytes)));
99
+ this.fileLikeObject = {
100
+ name: element.nameWithExtension,
101
+ type: element.mimeType,
102
+ rawFile: base64
103
+ };
104
+ // let blob: any;
105
+ // blob = new Blob(['']) as any;
106
+ // blob.name = element.FileName;
107
+ // blob.lastModifiedDate = null;
108
+ // blob.webkitRelativePath = '';
109
+ let file = this.fileLikeObject;
110
+ file.url = element.fileURL;
111
+ files.push(file);
112
+ }
113
+ this.uploader.addToQueue(files);
114
+ console.log(this.uploader.queue);
179
115
  }
180
116
  else {
181
- // Single MIME type
182
- allMimeTypes.push(fileType);
117
+ const element = this.options.value.file ?? this.options.value;
118
+ var bytes = new Uint8Array(element.bytes);
119
+ var base64 = btoa(String.fromCharCode(...Array.from(bytes)));
120
+ this.fileLikeObject = {
121
+ name: element.nameWithExtension,
122
+ type: element.mimeType,
123
+ rawFile: base64
124
+ };
125
+ this.file = element;
126
+ let file = this.fileLikeObject;
127
+ file.url = element.fileURL;
128
+ this.uploader.addToQueue([file]);
129
+ if (!this.options.value.file) {
130
+ this.fileUploadModel = new FileUploadModel();
131
+ this.fileUploadModel.file = this.options.value;
132
+ }
133
+ else
134
+ this.fileUploadModel = this.options.value;
135
+ this.options.value = this.fileUploadModel;
183
136
  }
137
+ this.uploader.queue.forEach((element) => {
138
+ element.progress = 100;
139
+ });
184
140
  }
185
- // Filter out empty strings and normalize MIME types
186
- const normalizedMimeTypes = allMimeTypes
187
- .filter(type => type.trim())
188
- .map(type => type.trim().toLowerCase());
189
- // Create the accept attribute string for HTML input
190
- this.acceptedType = normalizedMimeTypes.join(',');
191
- // Store the processed array for validation (keep original case for display)
192
- this.acceptedTypeArray = allMimeTypes.filter(type => type.trim());
193
- const mimeTypeMap = this.getMimeTypeMap();
194
- for (const type of this.acceptedTypeArray) {
195
- const displayType = mimeTypeMap[type];
196
- if (displayType && !this.toolTipTypeArray.includes(displayType)) {
197
- this.toolTipTypeArray.push(displayType);
141
+ if (this.options.labelKey != null && this.options.labelKey != '')
142
+ this.options.labelValue = this.UtilityService.getResourceValue(this.options.labelKey);
143
+ if (this.options.fileUploadAcceptsTypes != null &&
144
+ this.options.fileUploadAcceptsTypes.length > 0) {
145
+ // Process FileType enum values which may contain comma-separated MIME types
146
+ for (let index = 0; index < this.options.fileUploadAcceptsTypes.length; index++) {
147
+ const Type = this.options.fileUploadAcceptsTypes[index];
148
+ this.acceptedType = this.acceptedType + Type + ',';
198
149
  }
199
- }
200
- }
201
- getMimeTypeMap() {
202
- return {
203
- 'application/pdf': 'PDF',
204
- 'application/msword': 'Word',
205
- 'application/vnd.openxmlformats-officedocument.wordprocessingml.document': 'Word',
206
- 'application/vnd.ms-excel': 'Excel',
207
- 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': 'Excel',
208
- 'application/vnd.ms-powerpoint': 'PowerPoint',
209
- 'application/vnd.openxmlformats-officedocument.presentationml.presentation': 'PowerPoint',
210
- 'image/png': 'PNG',
211
- 'image/bmp': 'BMP',
212
- 'image/jpeg': 'JPEG',
213
- 'image/svg+xml': 'SVG',
214
- 'application/zip': 'ZIP',
215
- 'application/x-rar-compressed': 'RAR',
216
- 'video/webm': 'WebM',
217
- 'video/ogg': 'OGG',
218
- 'video/mp4': 'MP4',
219
- 'video/quicktime': 'MOV',
220
- 'video/x-msvideo': 'AVI',
221
- 'video/x-ms-wmv': 'WMV',
222
- 'video/avi': 'AVI',
223
- 'video/mpeg': 'MPEG',
224
- 'video/x-flv': 'FLV',
225
- 'audio/mpeg': 'MP3',
226
- 'text/plain': 'Txt',
227
- 'text/xml': 'XML',
228
- 'application/json': 'JSON',
229
- 'application/octet-stream': 'Binary',
230
- 'application/BN': 'License'
231
- };
232
- }
233
- buildValidationMessage() {
234
- const messages = [];
235
- if (this.toolTipTypeArray.length) {
236
- messages.push(`${this.utilityService.getResourceValue('Extensions')} (${this.toolTipTypeArray.join(', ')})`);
150
+ this.acceptedTypeArray = this.acceptedType.split(',');
151
+ this.acceptedTypeArray = this.acceptedTypeArray.filter((value) => value.trim() != '');
152
+ // Rebuild acceptedType string for HTML accept attribute (properly formatted)
153
+ this.acceptedType = this.acceptedTypeArray.join(',');
154
+ // Process each accepted MIME type to build tooltip display names
155
+ for (let index = 0; index < this.acceptedTypeArray.length; index++) {
156
+ const element = this.acceptedTypeArray[index].trim();
157
+ switch (element) {
158
+ case 'application/pdf':
159
+ if (!this.toolTipTypeArray.includes('PDF'))
160
+ this.toolTipTypeArray.push('PDF');
161
+ break;
162
+ case 'application/msword':
163
+ if (!this.toolTipTypeArray.includes('Word'))
164
+ this.toolTipTypeArray.push('Word');
165
+ break;
166
+ case 'application/vnd.openxmlformats-officedocument.wordprocessingml.document':
167
+ if (!this.toolTipTypeArray.includes('Word'))
168
+ this.toolTipTypeArray.push('Word');
169
+ break;
170
+ case 'application/vnd.ms-excel':
171
+ if (!this.toolTipTypeArray.includes('Excel'))
172
+ this.toolTipTypeArray.push('Excel');
173
+ break;
174
+ case 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet':
175
+ if (!this.toolTipTypeArray.includes('Excel'))
176
+ this.toolTipTypeArray.push('Excel');
177
+ break;
178
+ case 'application/vnd.ms-powerpoint':
179
+ if (!this.toolTipTypeArray.includes('PowerPoint'))
180
+ this.toolTipTypeArray.push('PowerPoint');
181
+ break;
182
+ case 'application/vnd.openxmlformats-officedocument.presentationml.presentation':
183
+ if (!this.toolTipTypeArray.includes('PowerPoint'))
184
+ this.toolTipTypeArray.push('PowerPoint');
185
+ break;
186
+ case 'image/png':
187
+ if (!this.toolTipTypeArray.includes('PNG'))
188
+ this.toolTipTypeArray.push('PNG');
189
+ break;
190
+ case 'image/bmp':
191
+ if (!this.toolTipTypeArray.includes('BMP'))
192
+ this.toolTipTypeArray.push('BMP');
193
+ break;
194
+ case 'image/jpeg':
195
+ if (!this.toolTipTypeArray.includes('JPEG'))
196
+ this.toolTipTypeArray.push('JPEG');
197
+ break;
198
+ case 'application/zip':
199
+ if (!this.toolTipTypeArray.includes('ZIP'))
200
+ this.toolTipTypeArray.push('ZIP');
201
+ break;
202
+ case 'application/x-rar-compressed':
203
+ if (!this.toolTipTypeArray.includes('RAR'))
204
+ this.toolTipTypeArray.push('RAR');
205
+ break;
206
+ case 'video/mp4':
207
+ if (!this.toolTipTypeArray.includes('MP4'))
208
+ this.toolTipTypeArray.push('MP4');
209
+ break;
210
+ case 'video/avi':
211
+ if (!this.toolTipTypeArray.includes('AVI'))
212
+ this.toolTipTypeArray.push('AVI');
213
+ break;
214
+ case 'video/quicktime':
215
+ if (!this.toolTipTypeArray.includes('MOV'))
216
+ this.toolTipTypeArray.push('MOV');
217
+ break;
218
+ case 'video/mpeg':
219
+ if (!this.toolTipTypeArray.includes('MPEG'))
220
+ this.toolTipTypeArray.push('MPEG');
221
+ break;
222
+ case 'audio/mpeg':
223
+ if (!this.toolTipTypeArray.includes('MP3'))
224
+ this.toolTipTypeArray.push('MP3');
225
+ break;
226
+ case 'video/x-flv':
227
+ if (!this.toolTipTypeArray.includes('FLV'))
228
+ this.toolTipTypeArray.push('FLV');
229
+ break;
230
+ case 'video/x-ms-wmv':
231
+ if (!this.toolTipTypeArray.includes('WMV'))
232
+ this.toolTipTypeArray.push('WMV');
233
+ break;
234
+ case 'image/svg+xml':
235
+ if (!this.toolTipTypeArray.includes('SVG'))
236
+ this.toolTipTypeArray.push('SVG');
237
+ break;
238
+ case 'text/plain':
239
+ if (!this.toolTipTypeArray.includes('Txt'))
240
+ this.toolTipTypeArray.push('Txt');
241
+ break;
242
+ case 'application/BN':
243
+ if (!this.toolTipTypeArray.includes('License'))
244
+ this.toolTipTypeArray.push('License');
245
+ break;
246
+ default:
247
+ break;
248
+ }
249
+ }
250
+ this.validationMessage = this.validationMessage + `${this.UtilityService.getResourceValue('Extensions')} (${this.toolTipTypeArray}) `;
237
251
  }
238
252
  if (this.options.fileMaxSizeInMB > 0) {
239
- messages.push(`${this.utilityService.getResourceValue('FileMaxSizeInMB')}${this.options.fileMaxSizeInMB}`);
253
+ this.validationMessage = this.validationMessage + `<br /> ${this.UtilityService.getResourceValue('FileMaxSizeInMB') + this.options.fileMaxSizeInMB + ' ' + this.UtilityService.getResourceValue('MB')}`;
240
254
  }
241
255
  if (this.options.minNoOfFiles > 0) {
242
- messages.push(`${this.utilityService.getResourceValue('MinFileCountValidationKey')}${this.options.minNoOfFiles}`);
256
+ this.validationMessage = this.validationMessage + `<br /> ${this.UtilityService.getResourceValue('MinFileCountValidationKey') + this.options.minNoOfFiles}`;
243
257
  }
244
258
  if (this.options.maxNoOfFiles > 0) {
245
- messages.push(`${this.utilityService.getResourceValue('MaxFileCountValidationKey')}${this.options.maxNoOfFiles}`);
259
+ this.validationMessage = this.validationMessage + `<br /> ${this.UtilityService.getResourceValue('MaxFileCountValidationKey') + this.options.maxNoOfFiles}`;
246
260
  }
247
- this.validationMessage = messages.join(' <br/> ');
248
- }
249
- setupFormControl() {
250
261
  this.group.addControl(this.options.name, new FormControl(''));
251
262
  this.fileUploadFormControl = this.group.controls[this.options.name];
252
- this.setupValidators();
253
- this.setupCountMessage();
254
- this.applyValidatorsAndState();
255
- this.fileUploadFormControl.setValue(this.options.value, { emitEvent: false });
256
- }
257
- setupValidators() {
258
- if (this.options.customValidation?.length) {
259
- for (const validation of this.options.customValidation) {
260
- this.validationRules.push(validation.functionBody);
263
+ if (this.options.customValidation.length > 0) {
264
+ let Validations = this.options.customValidation;
265
+ for (let index = 0; index < Validations.length; index++) {
266
+ const Validation = Validations[index];
267
+ this.validationRules.push(Validation.functionBody);
261
268
  }
262
269
  }
270
+ if (this.options.isMultipleFile && this.options.maxNoOfFiles > 0) {
271
+ this.validationCountMessage = `${this.UtilityService.getResourceValue('MaxFilesCount')} : ${this.options.maxNoOfFiles}`;
272
+ }
263
273
  if (this.options.isRequired) {
264
274
  this.validationRules.push(Validators.required);
265
275
  }
266
- }
267
- setupCountMessage() {
268
- if (this.options.isMultipleFile && this.options.maxNoOfFiles > 0) {
269
- this.validationCountMessage = `${this.utilityService.getResourceValue('MaxFilesCount')} : ${this.options.maxNoOfFiles}`;
270
- }
271
- }
272
- applyValidatorsAndState() {
273
276
  this.fileUploadFormControl.setValidators(this.validationRules);
274
- if (this.validationRulesAsync.length > 0) {
275
- this.fileUploadFormControl.setAsyncValidators(this.validationRulesAsync);
276
- }
277
+ this.fileUploadFormControl.setAsyncValidators(this.validationRulesAsync);
277
278
  if (this.options.isDisabled) {
278
279
  this.fileUploadFormControl.disable();
279
280
  }
280
- }
281
- setupSubscriptions() {
282
- this.multipleFileUploadControlHost.ngSubmit.subscribe(() => {
281
+ this.MultipleFileUploadControlHost.ngSubmit
282
+ .pipe(takeUntil(this.destroy$))
283
+ .subscribe((value) => {
283
284
  this.group.markAllAsTouched();
284
285
  this.markAllAsTouched = true;
285
286
  });
287
+ this.fileUploadFormControl.setValue(this.options.value);
286
288
  }
287
289
  ngAfterViewInit() {
288
- this.applyAttributes();
289
- }
290
- applyAttributes() {
291
- if (!this.options.attributeList?.length) {
292
- return;
293
- }
294
- const element = document.getElementById(this.options.name);
295
- if (element) {
296
- for (const attribute of this.options.attributeList) {
297
- element.setAttribute(attribute.key, attribute.value);
290
+ if (this.options.attributeList != null) {
291
+ var element = document.getElementById(this.options.name);
292
+ for (let index = 0; index < this.options.attributeList.length; index++) {
293
+ element.setAttribute(this.options.attributeList[index].key, this.options.attributeList[index].value);
298
294
  }
299
295
  }
300
296
  }
301
297
  showGlobalError() {
302
298
  this.controlUtility.showGlobalError();
303
299
  }
304
- getErrorValidation(errorList) {
300
+ getErrorValidation(ErrorList) {
305
301
  if (this.markAllAsTouched && this.group.invalid) {
306
302
  this.showGlobalError();
307
303
  this.markAllAsTouched = false;
308
304
  }
309
- if (errorList && errorList.length > 0) {
310
- for (const error of errorList) {
311
- if (error.key === 'InvalidFiles') {
312
- return error.value;
313
- }
314
- }
315
- }
316
- return this.controlUtility.getErrorValidationMassage(errorList, this.group, this.options);
305
+ return this.controlUtility.getErrorValidationMassage(ErrorList, this.group, this.options);
317
306
  }
318
307
  fileOverAnother(event) {
319
- this.hasAnotherDropZoneOver = !!event;
308
+ this.hasAnotherDropZoneOver = event;
320
309
  }
321
310
  isHideInput() {
322
311
  if (this.options.isMultipleFile) {
323
- return this.options.maxNoOfFiles > 0 &&
324
- this.options.maxNoOfFiles === this.uploader.queue.length;
325
- }
326
- return this.uploader.queue.length > 0;
327
- }
328
- onFileChange() {
329
- this.validateFileConstraints();
330
- const fileProcessingResult = this.processNewlyAddedFiles();
331
- this.handleFileValidationResults(fileProcessingResult);
332
- this.processValidFilesForUpload();
333
- }
334
- processNewlyAddedFiles() {
335
- const addedQueue = this.getNewlyAddedFiles();
336
- const validationResult = this.validateFilesInQueue(addedQueue);
337
- return {
338
- validFiles: addedQueue.filter(file => !validationResult.invalidFiles.includes(file)),
339
- invalidFiles: validationResult.invalidFiles,
340
- errors: validationResult.errors
341
- };
342
- }
343
- getNewlyAddedFiles() {
344
- return this.uploader.queue.filter((obj) => obj['some']?.lastModified != null);
345
- }
346
- validateFilesInQueue(fileQueue) {
347
- const validationErrors = [];
348
- const invalidFiles = [];
349
- const processedDuplicateNames = new Set();
350
- for (const element of fileQueue) {
351
- const file = element.file;
352
- if (!file)
353
- continue;
354
- const fileValidation = this.validateSingleFile(file, element, processedDuplicateNames);
355
- if (!fileValidation.isValid) {
356
- invalidFiles.push(element);
357
- validationErrors.push(...fileValidation.errors);
358
- }
359
- }
360
- return {
361
- isValid: invalidFiles.length === 0,
362
- errors: validationErrors,
363
- invalidFiles
364
- };
365
- }
366
- validateSingleFile(file, element, processedDuplicateNames) {
367
- const errors = [];
368
- const sizeValid = this.validateIndividualFileSize(file);
369
- const typeValid = this.validateIndividualFileType(file);
370
- const nameValid = this.validateDuplicateFileName(file, element);
371
- if (!sizeValid) {
372
- errors.push(this.createFileSizeErrorMessage(file.name));
373
- }
374
- if (!typeValid) {
375
- errors.push(this.createFileTypeErrorMessage(file.name));
376
- }
377
- if (!nameValid) {
378
- const duplicateError = this.createDuplicateFileErrorMessage(file.name, processedDuplicateNames);
379
- if (duplicateError) {
380
- errors.push(duplicateError);
312
+ if (this.options.maxNoOfFiles != null &&
313
+ this.options.maxNoOfFiles > 0 &&
314
+ this.options.maxNoOfFiles == this.uploader.queue.length) {
315
+ return true;
381
316
  }
382
317
  }
383
- return {
384
- isValid: sizeValid && typeValid && nameValid,
385
- errors,
386
- invalidFiles: []
387
- };
388
- }
389
- createFileSizeErrorMessage(fileName) {
390
- return this.utilityService.getResourceValue('FileExceedsMaxSize')
391
- .replace('{fileName}', fileName)
392
- .replace('{maxSize}', this.options.fileMaxSizeInMB.toString());
393
- }
394
- createFileTypeErrorMessage(fileName) {
395
- return this.utilityService.getResourceValue('FileTypeNotAccepted')
396
- .replace('{fileName}', fileName);
397
- }
398
- createDuplicateFileErrorMessage(fileName, processedDuplicateNames) {
399
- const fileNameLower = fileName.toLowerCase();
400
- if (processedDuplicateNames.has(fileNameLower)) {
401
- return null;
402
- }
403
- processedDuplicateNames.add(fileNameLower);
404
- let duplicateErrorMsg = this.utilityService.getResourceValue('DuplicateFileName');
405
- if (!duplicateErrorMsg || duplicateErrorMsg === 'DuplicateFileName') {
406
- duplicateErrorMsg = `File '{fileName}' already exists. Please choose a different file or rename it.`;
407
- }
408
- return duplicateErrorMsg.replace('{fileName}', fileName);
409
- }
410
- handleFileValidationResults(result) {
411
- if (result.invalidFiles.length > 0) {
412
- this.removeInvalidFiles(result.invalidFiles);
413
- }
414
- if (result.errors.length > 0) {
415
- this.showValidationErrors(result.errors);
416
- }
417
- }
418
- processValidFilesForUpload() {
419
- const filesArray = [];
420
- const validQueue = this.getNewlyAddedFiles();
421
- for (const element of validQueue) {
422
- const file = element.file;
423
- if (!file)
424
- continue;
425
- if (this.shouldUseAsyncUpload(element)) {
426
- this.handleAsyncFileUpload(element, filesArray);
427
- }
428
- else {
429
- this.handleSyncFileUpload(file, filesArray);
318
+ else {
319
+ if (this.uploader.queue.length > 0) {
320
+ return true;
430
321
  }
431
322
  }
323
+ return false;
432
324
  }
433
- shouldUseAsyncUpload(element) {
434
- return this.options.isUploadFileAsync && !element._file['iD_GUID'];
435
- }
436
- validateFileConstraints() {
437
- if (this.options.isMultipleFile) {
438
- if (!this.validateMinFileCount() || !this.validateMaxFileCount() || !this.validateTotalFileSize()) {
439
- return false;
325
+ onFileChange() {
326
+ let FilesArray = [];
327
+ // Clear any previous validation errors at the start of file change
328
+ this.pendingValidationErrors = null;
329
+ // Check for duplicate file names in the queue
330
+ const duplicateFiles = this.findDuplicateFiles();
331
+ if (duplicateFiles.length > 0) {
332
+ // Remove only the newly added duplicate files from queue (keep existing files)
333
+ this.removeDuplicateFilesFromQueue(duplicateFiles);
334
+ // Set validation error for duplicate files
335
+ const duplicateFileNames = duplicateFiles.map(f => f.file?.name).join(', ');
336
+ const formControl = this.fileUploadFormControl;
337
+ const resourceValue = this.UtilityService.getResourceValue('DuplicateFileError');
338
+ // If resource value is the same as the key, it means the resource wasn't found
339
+ const errorMessage = (resourceValue && resourceValue !== 'DuplicateFileError') ? resourceValue : 'File(s) already exist';
340
+ const errorObj = {
341
+ DuplicateFileError: `${errorMessage}: ${duplicateFileNames}`
342
+ };
343
+ this.pendingValidationErrors = errorObj;
344
+ formControl.setErrors(errorObj);
345
+ formControl.markAsTouched();
346
+ // Auto-clear duplicate error after 5 seconds to allow form submission
347
+ setTimeout(() => {
348
+ // Only clear if the current error is still the duplicate error we set
349
+ const currentErrors = formControl.errors;
350
+ if (currentErrors && currentErrors.DuplicateFileError === errorObj.DuplicateFileError) {
351
+ formControl.setErrors(null);
352
+ this.pendingValidationErrors = null;
353
+ }
354
+ }, 5000);
355
+ // If all files were duplicates, return early
356
+ if (this.uploader.queue.filter(item => item['some'].lastModified != null).length === 0) {
357
+ return;
440
358
  }
441
359
  }
442
- return true;
443
- }
444
- validateMinFileCount() {
445
- if (this.options.minNoOfFiles > 0 && this.options.minNoOfFiles > this.uploader.queue.length) {
446
- const minFileMsg = this.utilityService.getResourceValue('MinimumFilesRequired')
447
- .replace('{count}', this.options.minNoOfFiles.toString());
448
- this.showFileCountError('MinFileCountValidationKey', minFileMsg);
449
- return false;
360
+ if (this.options.isMultipleFile && this.options.minNoOfFiles != null && this.options.minNoOfFiles > 0 && this.options.minNoOfFiles > this.uploader.queue.length) {
361
+ const formControl = this.fileUploadFormControl;
362
+ const existingErrors = formControl.errors || {};
363
+ const newErrors = {
364
+ ...existingErrors,
365
+ MinFileCountValidationKey: this.options.minNoOfFiles
366
+ };
367
+ formControl.setErrors(newErrors);
368
+ formControl.markAsTouched();
369
+ this.uploader.queue = [];
370
+ return;
450
371
  }
451
- return true;
452
- }
453
- validateMaxFileCount() {
454
- if (this.options.maxNoOfFiles > 0 && this.options.maxNoOfFiles < this.uploader.queue.length) {
455
- const maxFileMsg = this.utilityService.getResourceValue('MaximumFilesExceeded') ||
456
- `Maximum {maxCount} files allowed. You have selected {currentCount} files.`;
457
- const finalMsg = maxFileMsg
458
- .replace('{maxCount}', this.options.maxNoOfFiles.toString())
459
- .replace('{currentCount}', this.uploader.queue.length.toString());
460
- this.showFileCountError('MaxFileCountValidationKey', finalMsg);
461
- return false;
372
+ if (this.options.isMultipleFile && this.options.maxNoOfFiles != null && this.options.maxNoOfFiles > 0 && this.options.maxNoOfFiles < this.uploader.queue.length) {
373
+ const formControl = this.fileUploadFormControl;
374
+ const existingErrors = formControl.errors || {};
375
+ const newErrors = {
376
+ ...existingErrors,
377
+ MaxFileCountValidationKey: this.options.maxNoOfFiles
378
+ };
379
+ formControl.setErrors(newErrors);
380
+ formControl.markAsTouched();
381
+ this.uploader.queue = [];
382
+ return;
462
383
  }
463
- return true;
464
- }
465
- showFileCountError(errorKey, message) {
466
- const currentErrors = this.fileUploadFormControl.errors || {};
467
- currentErrors[errorKey] = message;
468
- this.fileUploadFormControl.setErrors(currentErrors);
469
- this.fileUploadFormControl.markAsTouched();
470
- }
471
- clearFileCountError(errorKey) {
472
- const currentErrors = this.fileUploadFormControl.errors;
473
- if (currentErrors && currentErrors[errorKey]) {
474
- delete currentErrors[errorKey];
475
- if (Object.keys(currentErrors).length === 0) {
476
- this.fileUploadFormControl.setErrors(null);
384
+ if (this.options.isMultipleFile && this.options.maxSizeForAllFilesInMB != null && this.options.maxSizeForAllFilesInMB > 0) {
385
+ let AllSizeFile = 0;
386
+ for (let index = 0; index < this.uploader.queue.length; index++) {
387
+ const element = this.uploader.queue[index];
388
+ const file = element.file;
389
+ AllSizeFile = AllSizeFile + file.size;
477
390
  }
478
- else {
479
- this.fileUploadFormControl.setErrors(currentErrors);
391
+ const MaxSizeForAllFiles = this.options.maxSizeForAllFilesInMB * 1000 * 1000;
392
+ if (AllSizeFile > MaxSizeForAllFiles) {
393
+ const formControl = this.fileUploadFormControl;
394
+ const existingErrors = formControl.errors || {};
395
+ const newErrors = {
396
+ ...existingErrors,
397
+ MaxSizeForAllFilesInMB: this.options.maxSizeForAllFilesInMB + ' ' + this.UtilityService.getResourceValue('MB')
398
+ };
399
+ formControl.setErrors(newErrors);
400
+ formControl.markAsTouched();
401
+ this.uploader.queue = [];
402
+ return;
480
403
  }
481
404
  }
482
- }
483
- validateTotalFileSize() {
484
- if (this.options.maxSizeForAllFilesInMB > 0) {
485
- const totalSize = this.uploader.queue.reduce((sum, element) => sum + element.file.size, 0);
486
- const maxSizeBytes = this.options.maxSizeForAllFilesInMB * this.BYTES_TO_MB;
487
- if (totalSize > maxSizeBytes) {
488
- this.showTotalSizeError();
489
- return false;
405
+ let AddedQueue = this.uploader.queue.filter((obj) => obj['some'].lastModified != null);
406
+ let hasValidationError = false;
407
+ let validationErrorType = '';
408
+ let validationErrorValue = '';
409
+ for (let index = 0; index < AddedQueue.length; index++) {
410
+ const element = AddedQueue[index];
411
+ const file = element.file;
412
+ const maxFileSize = this.options.fileMaxSizeInMB * 1000 * 1000;
413
+ if (file) {
414
+ const fileType = file.type;
415
+ if (file.size > maxFileSize) {
416
+ // Remove only the file that violates the size limit
417
+ this.uploader.queue = this.uploader.queue.filter(queueItem => queueItem.file.name !== file.name);
418
+ hasValidationError = true;
419
+ validationErrorType = 'FileMaxSizeInMB';
420
+ validationErrorValue = this.options.fileMaxSizeInMB + ' ' + this.UtilityService.getResourceValue('MB');
421
+ // Continue checking other files instead of returning immediately
422
+ }
423
+ if (this.options.fileUploadAcceptsTypes != null &&
424
+ this.options.fileUploadAcceptsTypes.length > 0 &&
425
+ !this.isFileTypeAccepted(fileType)) {
426
+ // Remove only the file that violates the file type restriction
427
+ this.uploader.queue = this.uploader.queue.filter(queueItem => queueItem.file.name !== file.name);
428
+ hasValidationError = true;
429
+ validationErrorType = 'ToolTipTypeError';
430
+ validationErrorValue = this.toolTipTypeArray;
431
+ // Continue checking other files instead of returning immediately
432
+ }
490
433
  }
491
434
  }
492
- return true;
493
- }
494
- showTotalSizeError() {
495
- const totalSizeMsg = this.utilityService.getResourceValue('TotalFileSizeExceeded')
496
- .replace('{maxSize}', this.options.maxSizeForAllFilesInMB.toString());
497
- const currentErrors = this.fileUploadFormControl.errors || {};
498
- currentErrors['MaxSizeForAllFilesInMB'] = totalSizeMsg;
499
- this.fileUploadFormControl.setErrors(currentErrors);
500
- this.fileUploadFormControl.markAsTouched();
501
- }
502
- validateFileSize(file) {
503
- const maxFileSize = this.options.fileMaxSizeInMB * this.BYTES_TO_MB;
504
- if (file.size > maxFileSize) {
505
- this.setFormControlError('FileMaxSizeInMB', `${this.options.fileMaxSizeInMB}MB`);
506
- return false;
507
- }
508
- return true;
509
- }
510
- validateFileType(file) {
511
- if (this.options.fileUploadAcceptsTypes?.length) {
512
- const fileType = file.type;
513
- const isAccepted = this.acceptedTypeArray.some(type => type.toLowerCase() === fileType.toLowerCase());
514
- if (!isAccepted) {
515
- this.setFormControlError('ToolTipTypeError', this.toolTipTypeArray);
516
- return false;
435
+ // Set validation error if any files were removed due to validation failures
436
+ this.pendingValidationErrors = null;
437
+ if (hasValidationError) {
438
+ const formControl = this.fileUploadFormControl;
439
+ const errorObj = {};
440
+ errorObj[validationErrorType] = validationErrorValue;
441
+ this.pendingValidationErrors = errorObj; // Store errors to reapply later
442
+ formControl.setErrors(errorObj);
443
+ formControl.markAsTouched();
444
+ // Don't return here, continue processing valid files
445
+ }
446
+ // Re-filter the queue to get only valid files for processing
447
+ AddedQueue = this.uploader.queue.filter((obj) => obj['some'].lastModified != null);
448
+ for (let index = 0; index < AddedQueue.length; index++) {
449
+ const element = AddedQueue[index];
450
+ const file = element.file;
451
+ if (file) {
452
+ if (this.options.isUploadFileAsync && !element._file['iD_GUID']) {
453
+ this.fileUploadService.uploadFile(element._file)
454
+ .pipe(takeUntil(this.destroy$))
455
+ .subscribe({
456
+ next: (event) => {
457
+ let queueIndex = this.uploader.queue.findIndex((file) => file == element);
458
+ if (event.type === HttpEventType.UploadProgress) {
459
+ let value = Math.round((100 * event.loaded) / event.total);
460
+ this.uploader.queue[queueIndex].progress = value >= 95 ? 95 : value;
461
+ }
462
+ else if (event.type === HttpEventType.Response) {
463
+ this.uploader.queue[queueIndex].progress = 100;
464
+ let fileID = event.body.val;
465
+ this.uploader.queue[queueIndex]._file['iD_GUID'] = fileID;
466
+ this.uploader.queue[queueIndex]._file['isNew'] = true;
467
+ let AddedFile = {
468
+ iD_GUID: fileID,
469
+ fileName: this.uploader.queue[queueIndex]._file['name'],
470
+ fileType: this.uploader.queue[queueIndex]._file['type'],
471
+ isNew: true
472
+ };
473
+ if (this.options.isMultipleFile == false) {
474
+ this.fileUploadModel = new FileUploadModel();
475
+ this.fileUploadModel.file = AddedFile;
476
+ this.setValuePreservingErrors(this.fileUploadModel, this.pendingValidationErrors);
477
+ }
478
+ else {
479
+ FilesArray.push(AddedFile);
480
+ this.multipleFileUploadModel.uploadedFiles = FilesArray;
481
+ if (this.options.value != null && this.options.value != undefined) {
482
+ if (this.options.value.correlationID_GUID == null) {
483
+ this.multipleFileUploadModel.removedFiles = [];
484
+ }
485
+ }
486
+ this.multipleFileUploadModel.correlationID_GUID =
487
+ this.options.value?.correlationID_GUID;
488
+ this.setValuePreservingErrors(this.multipleFileUploadModel, this.pendingValidationErrors);
489
+ this.isUploadComplete.emit(true);
490
+ }
491
+ }
492
+ }
493
+ });
494
+ }
495
+ else {
496
+ let reader = new FileReader();
497
+ let fileObject = file.rawFile;
498
+ reader.readAsDataURL(fileObject);
499
+ reader.onload = () => {
500
+ let existingID_GUID = null;
501
+ if (!this.options.isMultipleFile && this.file)
502
+ existingID_GUID = this.file.NameWithExtension == file.name ? this.file.iD_GUID : null;
503
+ let AddedFile = {
504
+ fileName: file.name,
505
+ fileType: file.type,
506
+ fileBase64: reader.result.toString().split(',')[1],
507
+ fileSizeInMB: file.size / 1000 / 1000,
508
+ nameWithExtension: file.name,
509
+ iD_GUID: existingID_GUID,
510
+ isNew: true
511
+ };
512
+ if (this.options.isMultipleFile == false) {
513
+ this.fileUploadModel = new FileUploadModel();
514
+ this.fileUploadModel.file = AddedFile;
515
+ this.setValuePreservingErrors(this.fileUploadModel, this.pendingValidationErrors);
516
+ }
517
+ else {
518
+ FilesArray.push(AddedFile);
519
+ this.multipleFileUploadModel.uploadedFiles = FilesArray;
520
+ if (this.options.value != null && this.options.value != undefined) {
521
+ if (this.options.value.correlationID_GUID == null) {
522
+ this.multipleFileUploadModel.removedFiles = [];
523
+ }
524
+ }
525
+ this.multipleFileUploadModel.correlationID_GUID =
526
+ this.options.value?.correlationID_GUID;
527
+ this.setValuePreservingErrors(this.multipleFileUploadModel, this.pendingValidationErrors);
528
+ }
529
+ };
530
+ let originalValue = this.group.get(this.options.name).value;
531
+ if (this.options.patchFunction &&
532
+ this.options.patchPath &&
533
+ this.group.get(this.options.name).valid) {
534
+ this.controlUtility.patchControlValue(originalValue, this.options.patchFunction, this.options.patchPath);
535
+ }
536
+ this.OnChange.emit(originalValue);
537
+ }
517
538
  }
518
539
  }
519
- return true;
520
- }
521
- validateIndividualFileSize(file) {
522
- const maxFileSize = this.options.fileMaxSizeInMB * this.BYTES_TO_MB;
523
- return file.size <= maxFileSize;
524
- }
525
- validateIndividualFileType(file) {
526
- if (!this.options.fileUploadAcceptsTypes?.length) {
527
- return true;
528
- }
529
- const fileType = file.type?.toLowerCase();
530
- if (!fileType) {
531
- return false;
532
- }
533
- return this.acceptedTypeArray.some(type => type.toLowerCase() === fileType);
534
540
  }
535
- validateDuplicateFileName(file, currentElement) {
536
- if (!file?.name) {
537
- return true;
538
- }
539
- const currentFileName = file.name.toLowerCase();
540
- const existingFiles = this.uploader.queue.filter(item => item !== currentElement);
541
- const duplicateExists = existingFiles.some(item => {
542
- const existingFileName = item.file?.name || item._file?.name;
543
- return existingFileName && existingFileName.toLowerCase() === currentFileName;
544
- });
545
- if (duplicateExists) {
546
- return false;
547
- }
548
- if (this.options.value) {
549
- const uploadedFiles = Array.isArray(this.options.value) ? this.options.value : [this.options.value];
550
- const duplicateInUploaded = uploadedFiles.some(uploadedFile => {
551
- const uploadedFileName = uploadedFile?.fileName || uploadedFile?.name;
552
- return uploadedFileName && uploadedFileName.toLowerCase() === currentFileName;
553
- });
554
- return !duplicateInUploaded;
555
- }
556
- return true;
557
- }
558
- removeInvalidFiles(invalidFiles) {
559
- invalidFiles.forEach(invalidFile => {
560
- const index = this.uploader.queue.indexOf(invalidFile);
561
- if (index > -1) {
562
- this.uploader.queue.splice(index, 1);
563
- }
564
- });
565
- }
566
- showValidationErrors(errors) {
567
- if (errors.length === 0)
568
- return;
569
- const errorMessage = errors.join('<br/>');
570
- this.setValidationError('InvalidFiles', errorMessage);
571
- setTimeout(() => {
572
- this.clearInvalidFilesError();
573
- }, this.ERROR_DISPLAY_DURATION);
574
- }
575
- setValidationError(errorKey, errorMessage) {
576
- const currentErrors = this.fileUploadFormControl.errors || {};
577
- currentErrors[errorKey] = errorMessage;
578
- this.fileUploadFormControl.setErrors(currentErrors);
579
- this.fileUploadFormControl.markAsTouched();
580
- }
581
- clearInvalidFilesError() {
582
- const currentErrors = this.fileUploadFormControl.errors;
583
- if (currentErrors && currentErrors['InvalidFiles']) {
584
- delete currentErrors['InvalidFiles'];
585
- if (Object.keys(currentErrors).length === 0) {
586
- this.fileUploadFormControl.setErrors(null);
587
- }
588
- else {
589
- this.fileUploadFormControl.setErrors(currentErrors);
541
+ removeFromControlValue(item) {
542
+ if (this.options.isUploadFileAsync && item.progress == 100 && item._file['isNew']) {
543
+ this.fileUploadService.deleteFile(item._file['iD_GUID'])
544
+ .pipe(takeUntil(this.destroy$))
545
+ .subscribe((res) => { });
546
+ }
547
+ if (this.options.isMultipleFile == false) {
548
+ this.fileUploadModel = null;
549
+ if (this.options.isRequired == true) {
550
+ this.fileUploadFormControl.markAsTouched();
551
+ this.fileUploadFormControl.updateValueAndValidity(); // Trigger validation check
590
552
  }
553
+ this.group.get(this.options.name).setValue(this.fileUploadModel);
554
+ this.options.value = this.fileUploadModel;
591
555
  }
592
- }
593
- setFormControlError(errorKey, errorValue) {
594
- this.fileUploadFormControl.setErrors({ [errorKey]: errorValue });
595
- this.fileUploadFormControl.markAsTouched();
596
- this.uploader.queue = [];
597
- }
598
- handleAsyncFileUpload(element, filesArray) {
599
- const uploadSubscription = this.fileUploadService.uploadFile(element._file).subscribe({
600
- next: (event) => {
601
- if (event.type === HttpEventType.UploadProgress) {
602
- this.handleUploadProgress(element, event);
556
+ else {
557
+ if (this.options.value != null && this.options.value != undefined) {
558
+ if (this.options.value.correlationID_GUID == null) {
559
+ this.deletedFiles = [];
560
+ this.multipleFileUploadModel.removedFiles = [];
603
561
  }
604
- else if (event.type === HttpEventType.Response) {
605
- this.handleUploadComplete(element, event, filesArray);
562
+ else {
563
+ if (this.multipleFileUploadModel.removedFiles.length == 0) {
564
+ let FileObject = item.file.rawFile;
565
+ let DeletedItem = this.multipleFileUploadModel.existingFiles.filter((obj) => obj.nameWithExtension == FileObject.name)[0];
566
+ this.multipleFileUploadModel.existingFiles =
567
+ this.multipleFileUploadModel.existingFiles.filter((obj) => obj.nameWithExtension != FileObject.name);
568
+ this.deletedFiles.push(DeletedItem);
569
+ this.multipleFileUploadModel.removedFiles.push(DeletedItem.iD_GUID);
570
+ }
571
+ else {
572
+ let FileObject = item.file.rawFile;
573
+ let deletedList = this.deletedFiles.filter((obj) => obj.nameWithExtension == FileObject.name);
574
+ if (deletedList.length == 0 || deletedList == undefined) {
575
+ let DeletedItem = this.multipleFileUploadModel.existingFiles.filter((obj) => obj.nameWithExtension == FileObject.name)[0];
576
+ this.multipleFileUploadModel.existingFiles =
577
+ this.multipleFileUploadModel.existingFiles.filter((obj) => obj.nameWithExtension != FileObject.name);
578
+ this.deletedFiles.push(DeletedItem);
579
+ this.multipleFileUploadModel.removedFiles.push(DeletedItem.iD_GUID);
580
+ }
581
+ }
606
582
  }
607
- },
608
- error: (error) => {
609
- console.error('Upload failed:', error);
610
- // Handle upload error - you can add custom error handling here
611
583
  }
612
- });
613
- // Store subscription for cleanup
614
- this.subscriptions.add(uploadSubscription);
615
- }
616
- handleUploadProgress(element, event) {
617
- const queueIndex = this.uploader.queue.findIndex((file) => file === element);
618
- if (queueIndex === -1)
619
- return;
620
- const progress = Math.round((100 * event.loaded) / event.total);
621
- this.uploader.queue[queueIndex].progress =
622
- progress >= this.PROGRESS_NEAR_COMPLETE ? this.PROGRESS_NEAR_COMPLETE : progress;
623
- }
624
- handleUploadComplete(element, event, filesArray) {
625
- const queueIndex = this.uploader.queue.findIndex((file) => file === element);
626
- if (queueIndex === -1)
627
- return;
628
- this.uploader.queue[queueIndex].progress = this.PROGRESS_COMPLETE;
629
- const fileID = event.body.val;
630
- this.updateElementWithFileInfo(element, fileID, event.body.downloadUrl);
631
- const addedFile = this.createFileDTO(element, fileID, event.body.downloadUrl);
632
- this.updateFormValue(addedFile, filesArray);
633
- }
634
- updateElementWithFileInfo(element, fileID, downloadUrl) {
635
- element._file['iD_GUID'] = fileID;
636
- element._file['isNew'] = true;
637
- if (downloadUrl) {
638
- element._file['url'] = downloadUrl;
639
- element.file.url = downloadUrl;
640
- }
641
- }
642
- createFileDTO(element, fileID, downloadUrl) {
643
- return {
644
- iD_GUID: fileID,
645
- fileName: element._file['name'],
646
- fileType: element._file['type'],
647
- isNew: true,
648
- fileBase64: '',
649
- fileSizeInMB: element._file.size / this.BYTES_TO_MB,
650
- nameWithExtension: element._file['name'],
651
- fullFileURL: downloadUrl || null
652
- };
653
- }
654
- handleSyncFileUpload(file, filesArray) {
655
- this.trackMemoryUsage(file.size);
656
- const reader = new FileReader();
657
- // Store reader reference for cleanup
658
- const readerRef = reader;
659
- reader.onload = () => {
660
- try {
661
- const existingGUID = this.getExistingFileGUID(file);
662
- this.updateQueueItemForSync(file);
663
- const addedFile = this.createSyncFileDTO(file, reader.result, existingGUID);
664
- this.updateFormValue(addedFile, filesArray);
665
- this.handlePatchAndEmit();
584
+ else {
585
+ this.deletedFiles = [];
586
+ this.multipleFileUploadModel.removedFiles = [];
666
587
  }
667
- finally {
668
- // Clean up reader
669
- readerRef.onload = null;
670
- readerRef.onerror = null;
671
- readerRef.onabort = null;
588
+ this.multipleFileUploadModel.uploadedFiles =
589
+ this.multipleFileUploadModel.uploadedFiles.filter((obj) => (obj.nameWithExtension && obj.nameWithExtension != item._file.name) ||
590
+ obj.iD_GUID != item._file['iD_GUID']);
591
+ if ((this.multipleFileUploadModel.uploadedFiles == null ||
592
+ this.multipleFileUploadModel.uploadedFiles.length == 0) &&
593
+ this.options.isRequired) {
594
+ const formControl = this.fileUploadFormControl;
595
+ formControl.setErrors({
596
+ MinFileCountValidationKey: this.options.minNoOfFiles
597
+ });
598
+ this.fileUploadFormControl.markAsTouched();
599
+ this.fileUploadFormControl.updateValueAndValidity(); // Trigger validation check
672
600
  }
673
- };
674
- reader.onerror = () => {
675
- console.error('File reading failed');
676
- readerRef.onload = null;
677
- readerRef.onerror = null;
678
- readerRef.onabort = null;
679
- };
680
- reader.readAsDataURL(file.rawFile);
681
- }
682
- updateQueueItemForSync(file) {
683
- const queueItem = this.findQueueItemByFile(file);
684
- if (queueItem) {
685
- this.preserveFileReference(queueItem, file);
686
- queueItem.progress = this.PROGRESS_COMPLETE;
687
- }
688
- }
689
- findQueueItemByFile(file) {
690
- return this.uploader.queue.find(item => item.file.name === file.name && item.file.size === file.size);
691
- }
692
- preserveFileReference(queueItem, file) {
693
- queueItem._file.rawFile = file.rawFile;
694
- queueItem.file.rawFile = file.rawFile;
695
- }
696
- createSyncFileDTO(file, readerResult, existingGUID) {
697
- return {
698
- fileName: file.name,
699
- fileType: file.type,
700
- fileBase64: readerResult.split(',')[1],
701
- fileSizeInMB: file.size / this.BYTES_TO_MB,
702
- nameWithExtension: file.name,
703
- iD_GUID: existingGUID,
704
- isNew: true,
705
- fullFileURL: null
706
- };
707
- }
708
- getExistingFileGUID(file) {
709
- if (!this.options.isMultipleFile && this.file) {
710
- return this.file.nameWithExtension === file.name ? this.file.iD_GUID : null;
711
- }
712
- return null;
713
- }
714
- updateFormValue(addedFile, filesArray) {
715
- if (!this.options.isMultipleFile) {
716
- this.fileUploadModel = new FileUploadModel();
717
- this.fileUploadModel.file = addedFile;
718
- this.updateFormControl(this.fileUploadModel);
719
- }
720
- else {
721
- filesArray.push(addedFile);
722
- this.multipleFileUploadModel.uploadedFiles = filesArray;
723
- this.setupMultipleFileModel();
724
- this.updateFormControl(this.multipleFileUploadModel);
725
- this.isUploadComplete.emit(true);
726
- }
727
- }
728
- setupMultipleFileModel() {
729
- if (this.options.value?.correlationID_GUID == null) {
730
- this.multipleFileUploadModel.removedFiles = [];
731
- }
732
- this.multipleFileUploadModel.correlationID_GUID = this.options.value?.correlationID_GUID;
733
- }
734
- updateFormControl(value) {
735
- this.preserveErrorsAndUpdateValue(value);
736
- this.options.value = value;
737
- }
738
- preserveErrorsAndUpdateValue(value) {
739
- const currentErrors = this.fileUploadFormControl.errors;
740
- this.fileUploadFormControl.setValue(value, { emitEvent: false });
741
- this.group.get(this.options.name)?.setValue(value, { emitEvent: false });
742
- if (currentErrors) {
743
- this.fileUploadFormControl.setErrors(currentErrors);
744
- }
745
- }
746
- handlePatchAndEmit() {
747
- const originalValue = this.group.get(this.options.name)?.value;
748
- if (this.options.patchFunction && this.options.patchPath && this.group.get(this.options.name)?.valid) {
749
- this.controlUtility.patchControlValue(originalValue, this.options.patchFunction, this.options.patchPath);
750
- }
751
- this.OnChange.emit(originalValue);
752
- }
753
- removeFromControlValue(item) {
754
- // Clean up blob URL before removing
755
- const downloadUrl = this.getFileDownloadUrl(item);
756
- if (downloadUrl && downloadUrl.startsWith('blob:')) {
757
- this.cleanupBlobUrl(downloadUrl);
758
- }
759
- this.handleAsyncFileDeletion(item);
760
- if (!this.options.isMultipleFile) {
761
- this.handleSingleFileRemoval();
762
- }
763
- else {
764
- this.handleMultipleFileRemoval(item);
765
- }
766
- this.checkAndClearMaxFileCountValidation();
767
- }
768
- handleAsyncFileDeletion(item) {
769
- if (this.options.isUploadFileAsync &&
770
- item.progress === this.PROGRESS_COMPLETE &&
771
- item._file['isNew']) {
772
- const deleteSubscription = this.fileUploadService.deleteFile(item._file['iD_GUID']).subscribe({
773
- error: (error) => console.error('Delete failed:', error)
774
- });
775
- this.subscriptions.add(deleteSubscription);
776
- }
777
- }
778
- handleSingleFileRemoval() {
779
- this.uploader.queue = [];
780
- this.fileUploadModel = null;
781
- if (this.options.isRequired) {
782
- this.fileUploadFormControl.markAsTouched();
783
- }
784
- const currentErrors = this.fileUploadFormControl.errors;
785
- this.group.get(this.options.name)?.setValue(this.fileUploadModel, { emitEvent: false });
786
- if (currentErrors) {
787
- this.fileUploadFormControl.setErrors(currentErrors);
788
- }
789
- this.options.value = this.fileUploadModel;
790
- }
791
- handleMultipleFileRemoval(item) {
792
- // Clean up blob URL
793
- const downloadUrl = this.getFileDownloadUrl(item);
794
- if (downloadUrl && downloadUrl.startsWith('blob:')) {
795
- this.cleanupBlobUrl(downloadUrl);
796
- }
797
- const queueIndex = this.uploader.queue.indexOf(item);
798
- if (queueIndex > -1) {
799
- this.uploader.queue.splice(queueIndex, 1);
800
- }
801
- this.processFileRemovalFromExisting(item);
802
- this.removeFromUploadedFiles(item);
803
- this.validateRemainingFiles();
804
- this.updateMultipleFileModel();
805
- }
806
- processFileRemovalFromExisting(item) {
807
- if (!this.options.value) {
808
- this.resetDeletedFiles();
809
- return;
810
- }
811
- if (!this.options.value.correlationID_GUID) {
812
- this.resetDeletedFiles();
813
- }
814
- else {
815
- this.handleExistingFileRemoval(item);
816
- }
817
- }
818
- resetDeletedFiles() {
819
- this.deletedFiles = [];
820
- this.multipleFileUploadModel.removedFiles = [];
821
- }
822
- handleExistingFileRemoval(item) {
823
- const fileName = item.file.rawFile.name;
824
- const existingFile = this.multipleFileUploadModel.existingFiles
825
- .find(obj => obj.nameWithExtension === fileName);
826
- if (existingFile && !this.deletedFiles.some(obj => obj.nameWithExtension === fileName)) {
827
- this.multipleFileUploadModel.existingFiles =
828
- this.multipleFileUploadModel.existingFiles.filter(obj => obj.nameWithExtension !== fileName);
829
- this.deletedFiles.push(existingFile);
830
- this.multipleFileUploadModel.removedFiles.push(existingFile.iD_GUID);
831
- }
832
- }
833
- removeFromUploadedFiles(item) {
834
- const itemFileName = item._file.name || item.file.name;
835
- const itemFileSize = item._file.size || item.file.size;
836
- const itemGUID = item._file['iD_GUID'];
837
- this.multipleFileUploadModel.uploadedFiles =
838
- this.multipleFileUploadModel.uploadedFiles.filter(obj => {
839
- if (itemGUID && obj.iD_GUID) {
840
- return obj.iD_GUID !== itemGUID;
841
- }
842
- const objFileName = obj.nameWithExtension || obj.fileName;
843
- const objFileSize = obj.fileSizeInMB ? obj.fileSizeInMB * this.BYTES_TO_MB : 0;
844
- return !(objFileName === itemFileName && Math.abs(objFileSize - itemFileSize) < 1000);
845
- });
846
- }
847
- validateRemainingFiles() {
848
- if ((!this.multipleFileUploadModel.uploadedFiles ||
849
- this.multipleFileUploadModel.uploadedFiles.length === 0) &&
850
- this.options.isRequired) {
851
- this.fileUploadFormControl.setErrors({
852
- MinFileCountValidationKey: this.options.minNoOfFiles
853
- });
854
- this.fileUploadFormControl.markAsTouched();
855
- }
856
- }
857
- updateMultipleFileModel() {
858
- this.multipleFileUploadModel.correlationID_GUID = this.options.value?.correlationID_GUID;
859
- const currentErrors = this.fileUploadFormControl.errors;
860
- this.fileUploadFormControl.setValue(this.multipleFileUploadModel, { emitEvent: false });
861
- this.group.get(this.options.name)?.setValue(this.multipleFileUploadModel, { emitEvent: false });
862
- this.options.value = this.multipleFileUploadModel;
863
- if (currentErrors) {
864
- this.fileUploadFormControl.setErrors(currentErrors);
601
+ this.multipleFileUploadModel.correlationID_GUID = this.options.value?.correlationID_GUID;
602
+ this.fileUploadFormControl.setValue(this.multipleFileUploadModel);
603
+ this.group.get(this.options.name).setValue(this.multipleFileUploadModel);
604
+ this.fileUploadFormControl.updateValueAndValidity();
605
+ //Use this line to enable two way binding.
606
+ this.options.value = this.multipleFileUploadModel;
865
607
  }
866
608
  }
867
609
  convertSizeToMB(size) {
868
610
  if (size === 0) {
869
611
  return 0;
870
612
  }
871
- const BYTES_TO_MB_ACCURATE = 1024 * 1024;
872
- const megabytes = size / BYTES_TO_MB_ACCURATE;
873
- return Math.round(megabytes * 100) / 100;
874
- }
875
- trackByFunction(index, item) {
876
- return item._file ? item._file.name + item._file.size : index;
877
- }
878
- shouldShowFileList() {
879
- return this.uploader?.queue && this.uploader.queue.length > 0;
880
- }
881
- isDownloadEnabled() {
882
- return true;
883
- }
884
- isRemoveEnabled() {
885
- return !this.options.isReadonly && !this.options.isDisabled;
886
- }
887
- getFileDownloadUrl(item) {
888
- const existingUrl = this.getExistingFileUrl(item);
889
- if (existingUrl) {
890
- return existingUrl;
891
- }
892
- return this.createFileUrl(item);
893
- }
894
- getExistingFileUrl(item) {
895
- return item?.file?.url ||
896
- item?._file?.url ||
897
- item?.url ||
898
- item?.file?.rawFile?.url ||
899
- item?._file?.rawFile?.url ||
900
- null;
901
- }
902
- createFileUrl(item) {
903
- const fileName = this.getFileName(item);
904
- const fileType = item?.file?.type || item?._file?.type;
905
- const originalFile = item?._file?.rawFile || item?.file?.rawFile;
906
- if (originalFile && originalFile instanceof File) {
907
- return URL.createObjectURL(originalFile);
908
- }
909
- const base64Data = typeof originalFile === 'string' ? originalFile : null;
910
- if (base64Data && fileName) {
911
- return this.createBlobUrlWithFilename(base64Data, fileType, fileName);
912
- }
913
- const fileId = item?._file?.['iD_GUID'];
914
- if (fileId && this.options.isUploadFileAsync) {
915
- return this.constructDownloadUrl(fileId, fileName);
916
- }
917
- return null;
613
+ // Convert size to megabytes
614
+ const megabytes = size / (1024 * 1024);
615
+ // Round to two decimal places
616
+ const roundedMegabytes = Math.round(megabytes * 100) / 100;
617
+ return roundedMegabytes;
918
618
  }
919
- createBlobUrlWithFilename(base64Data, fileType, fileName) {
920
- try {
921
- const byteCharacters = atob(base64Data);
922
- const byteNumbers = new Array(byteCharacters.length);
923
- for (let i = 0; i < byteCharacters.length; i++) {
924
- byteNumbers[i] = byteCharacters.charCodeAt(i);
619
+ ngOnDestroy() {
620
+ // Complete all subscriptions to prevent memory leaks
621
+ this.destroy$.next();
622
+ this.destroy$.complete();
623
+ // Clear uploader queue to free memory
624
+ if (this.uploader) {
625
+ this.uploader.clearQueue();
626
+ }
627
+ }
628
+ sanitizeFileName(fileName) {
629
+ // Remove potentially dangerous characters from file names
630
+ return fileName.replace(/[<>:"/\\|?*]/g, '_').trim();
631
+ }
632
+ /**
633
+ * Find duplicate files in the current upload queue
634
+ * @returns Array of newly added duplicate FileItem objects that should be rejected
635
+ */
636
+ findDuplicateFiles() {
637
+ const duplicateFiles = [];
638
+ const existingFileNames = new Set();
639
+ // First pass: collect names of existing files (already in queue before this upload)
640
+ const existingFiles = this.uploader.queue.filter(item => item['some'].lastModified == null);
641
+ for (const item of existingFiles) {
642
+ const fileName = item.file.name.toLowerCase().trim();
643
+ existingFileNames.add(fileName);
644
+ }
645
+ // Second pass: check newly added files against existing file names
646
+ const newlyAddedFiles = this.uploader.queue.filter(item => item['some'].lastModified != null);
647
+ for (const item of newlyAddedFiles) {
648
+ const fileName = item.file.name.toLowerCase().trim();
649
+ // If this new file name already exists in the queue, it's a duplicate
650
+ if (existingFileNames.has(fileName)) {
651
+ duplicateFiles.push(item);
925
652
  }
926
- const byteArray = new Uint8Array(byteNumbers);
927
- const blob = new Blob([byteArray], { type: fileType || 'application/octet-stream' });
928
- return URL.createObjectURL(blob);
929
- }
930
- catch (error) {
931
- const errorMsg = this.utilityService.getResourceValue('ErrorCreatingBlobUrl');
932
- console.error(errorMsg, error);
933
- return `data:${fileType || 'application/octet-stream'};base64,${base64Data}`;
934
- }
935
- }
936
- constructDownloadUrl(fileId, fileName) {
937
- const downloadBaseUrl = this.options.downloadBaseUrl;
938
- let url;
939
- if (downloadBaseUrl) {
940
- url = `${downloadBaseUrl}/${fileId}`;
941
- }
942
- else {
943
- url = `/api/files/download/${fileId}`;
944
- }
945
- if (fileName) {
946
- const separator = url.includes('?') ? '&' : '?';
947
- url += `${separator}filename=${encodeURIComponent(fileName)}`;
948
- }
949
- return url;
950
- }
951
- getFileName(item) {
952
- return item?.file?.name || item?._file?.name || 'file';
953
- }
954
- downloadFile(item) {
955
- const downloadInfo = this.prepareFileDownload(item);
956
- if (!downloadInfo.url) {
957
- this.handleDownloadError(downloadInfo.fileName);
958
- return;
959
- }
960
- this.executeFileDownload(downloadInfo.url, downloadInfo.fileName);
961
- }
962
- prepareFileDownload(item) {
963
- return {
964
- url: this.getFileDownloadUrl(item),
965
- fileName: this.getFileName(item)
966
- };
967
- }
968
- handleDownloadError(fileName) {
969
- const errorMsg = this.utilityService.getResourceValue('NoDownloadUrlAvailable')
970
- .replace('{fileName}', fileName);
971
- console.error(errorMsg);
972
- }
973
- executeFileDownload(url, fileName) {
974
- const link = this.createDownloadLink(url, fileName);
975
- this.triggerDownload(link);
976
- this.cleanupBlobUrl(url);
977
- }
978
- createDownloadLink(url, fileName) {
979
- const link = document.createElement('a');
980
- link.href = url;
981
- link.download = fileName;
982
- link.style.display = 'none';
983
- return link;
984
- }
985
- triggerDownload(link) {
986
- document.body.appendChild(link);
987
- link.click();
988
- document.body.removeChild(link);
989
- }
990
- cleanupBlobUrl(url) {
991
- if (url.startsWith('blob:')) {
992
- setTimeout(() => {
993
- URL.revokeObjectURL(url);
994
- }, 100);
995
- }
996
- }
997
- trackMemoryUsage(fileSize) {
998
- this.currentMemoryUsage += fileSize;
999
- // If memory usage exceeds limit, clean up old files
1000
- if (this.currentMemoryUsage > this.MAX_MEMORY_USAGE) {
1001
- this.cleanupOldFiles();
1002
- }
1003
- }
1004
- cleanupOldFiles() {
1005
- if (this.uploader?.queue && this.uploader.queue.length > 0) {
1006
- // Remove oldest files to free memory
1007
- const oldestFile = this.uploader.queue.shift();
1008
- if (oldestFile) {
1009
- const url = this.getFileDownloadUrl(oldestFile);
1010
- if (url && url.startsWith('blob:')) {
1011
- this.cleanupBlobUrl(url);
1012
- }
1013
- this.currentMemoryUsage -= (oldestFile.file?.size || 0);
653
+ else {
654
+ // Add this new file name to the set so subsequent files with same name are also flagged
655
+ existingFileNames.add(fileName);
1014
656
  }
1015
657
  }
658
+ return duplicateFiles;
1016
659
  }
1017
- cleanupEventListeners() {
1018
- // Clear file input references
1019
- if (this.fileInput?.nativeElement) {
1020
- this.fileInput.nativeElement.value = '';
1021
- }
1022
- // Clear uploader queue to prevent memory leaks
1023
- if (this.uploader?.queue) {
1024
- this.uploader.queue = [];
1025
- }
1026
- }
1027
- cleanupUploaderQueue() {
1028
- if (this.uploader?.queue) {
1029
- // Clear all items and their associated resources
1030
- this.uploader.queue.forEach(item => {
1031
- // Clean up blob URLs
1032
- const url = this.getFileDownloadUrl(item);
1033
- if (url && url.startsWith('blob:')) {
1034
- this.cleanupBlobUrl(url);
1035
- }
1036
- // Clear file references
1037
- if (item._file) {
1038
- item._file = null;
1039
- }
1040
- if (item.file) {
1041
- item.file = null;
1042
- }
1043
- });
1044
- // Clear the queue
1045
- this.uploader.queue = [];
660
+ /**
661
+ * Remove duplicate files from the uploader queue
662
+ * @param duplicateFiles Array of duplicate FileItem objects to remove
663
+ */
664
+ removeDuplicateFilesFromQueue(duplicateFiles) {
665
+ for (const duplicateFile of duplicateFiles) {
666
+ const index = this.uploader.queue.indexOf(duplicateFile);
667
+ if (index > -1) {
668
+ this.uploader.queue.splice(index, 1);
669
+ }
1046
670
  }
1047
671
  }
1048
- ngOnDestroy() {
1049
- // Clean up subscriptions
1050
- this.subscriptions.unsubscribe();
1051
- // Clean up uploader queue
1052
- this.cleanupUploaderQueue();
1053
- // Clean up event listeners
1054
- this.cleanupEventListeners();
1055
- // Clean up blob URLs
1056
- if (this.uploader?.queue) {
1057
- this.uploader.queue.forEach(item => {
1058
- const url = this.getFileDownloadUrl(item);
1059
- if (url && url.startsWith('blob:')) {
1060
- URL.revokeObjectURL(url);
1061
- }
1062
- });
672
+ isFileTypeAccepted(fileType) {
673
+ if (!this.acceptedTypeArray || this.acceptedTypeArray.length === 0) {
674
+ return true; // No restrictions
1063
675
  }
676
+ // Normalize the file type for comparison
677
+ const normalizedFileType = fileType.toLowerCase().trim();
678
+ // Check against all accepted types (case-insensitive and trimmed)
679
+ return this.acceptedTypeArray.some(acceptedType => {
680
+ const normalizedAcceptedType = acceptedType.toLowerCase().trim();
681
+ return normalizedAcceptedType === normalizedFileType;
682
+ });
1064
683
  }
1065
- checkAndClearMaxFileCountValidation() {
1066
- if (!this.options.maxNoOfFiles || this.options.maxNoOfFiles <= 0) {
1067
- return;
1068
- }
1069
- const currentQueueLength = this.uploader.queue.length;
1070
- if (currentQueueLength <= this.options.maxNoOfFiles) {
1071
- this.clearFileCountError('MaxFileCountValidationKey');
684
+ setValuePreservingErrors(value, preserveErrors) {
685
+ // Capture current duplicate errors before setValue clears them
686
+ const currentErrors = this.fileUploadFormControl.errors;
687
+ const duplicateError = currentErrors?.DuplicateFileError ? { DuplicateFileError: currentErrors.DuplicateFileError } : null;
688
+ // Set the form control value
689
+ this.fileUploadFormControl.setValue(value);
690
+ this.group.get(this.options.name).setValue(value);
691
+ // Apply errors in priority order: preserveErrors > duplicateError > pendingValidationErrors
692
+ const errorsToApply = preserveErrors || duplicateError || this.pendingValidationErrors;
693
+ if (errorsToApply) {
694
+ this.fileUploadFormControl.setErrors(errorsToApply);
695
+ this.fileUploadFormControl.markAsTouched();
1072
696
  }
697
+ // Update the options value for two-way binding
698
+ this.options.value = value;
1073
699
  }
1074
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: FileUploadComponent, deps: [{ token: i1.ControlContainer, optional: true }, { token: i1.FormGroupDirective }, { token: i2.ControlUtility }, { token: i3.UtilityService }, { token: i3.ControlValidationService }, { token: i4.GlobalSettings }, { token: i5.FileUploadService }], target: i0.ɵɵFactoryTarget.Component }); }
1075
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: FileUploadComponent, selector: "BBSF-FileUpload", inputs: { group: "group", options: "options" }, outputs: { OnChange: "OnChange", isUploadComplete: "isUploadComplete" }, viewQueries: [{ propertyName: "fileInput", first: true, predicate: ["fileInput"], descendants: true }], ngImport: i0, template: "<div class=\"form-group bbsf-control bbsf-file-upload\" [formGroup]=\"group\">\r\n <div [ngClass]=\"options.viewType === 1 ? 'bbsf-vertical' : 'bbsf-horizontal'\">\r\n <!-- Label -->\r\n <label [hidden]=\"options.hideLabel\" class=\"bbsf-label {{ options.labelExtraClasses }}\">\r\n {{ options.labelValue }}\r\n <!-- Required asterisk -->\r\n <span *ngIf=\"options.isRequired && !options.isReadonly && (options.showAsterisk || true)\"\r\n class=\"text-danger\">*</span>\r\n </label>\r\n <!-- Drop zone enabled -->\r\n <div ng2FileDrop class=\"bbsf-input-container {{ options.extraClasses }}\"\r\n *ngIf=\"options.isDropZone && !isHideInput() && !options.isReadonly\"\r\n [ngClass]=\"{ 'another-file-over-class': hasAnotherDropZoneOver }\" (onFileDrop)=\"onFileChange()\"\r\n (fileOver)=\"fileOverAnother($event)\" [uploader]=\"uploader\" [accept]=\"acceptedType\" [id]=\"options.name\"\r\n [attr.multiple]=\"options.isMultipleFile ? 'multiple' : null\"\r\n [class.is-invalid]=\"fileUploadFormControl.invalid && fileUploadFormControl.touched\"\r\n (click)=\"fileInputControl.click()\">\r\n\r\n <div class=\"dropzone-label\">\r\n <div class=\"svg-and-validation\">\r\n <!-- Upload icon -->\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"70\" height=\"70\" viewBox=\"0 0 70 70\" fill=\"none\">\r\n <path opacity=\"0.4\"\r\n d=\"M58.333 48.8332C61.8957 45.8908 64.1663 41.4397 64.1663 36.4583C64.1663 27.5988 56.9843 20.4167 48.1247 20.4167C47.4874 20.4167 46.8912 20.0842 46.5675 19.5351C42.7641 13.0808 35.7417 8.75 27.708 8.75C15.6268 8.75 5.83301 18.5438 5.83301 30.625C5.83301 36.6511 8.26974 42.1082 12.2116 46.0644\"\r\n stroke=\"#4B5489\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\r\n <path d=\"M23.333 46.6667L34.9997 35M34.9997 35L46.6663 46.6667M34.9997 35V61.25\" stroke=\"#4B5489\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\r\n </svg>\r\n\r\n <!-- Instruction text -->\r\n <div class=\"bbsf-validation-msg validation-msg-header text-center\">\r\n {{ utilityService.getResourceValue('DragAndDropHere') }}\r\n </div>\r\n\r\n <!-- Validation messages -->\r\n <div class=\"bbsf-validation-msg text-center\" *ngIf=\"validationMessage\" [innerHTML]=\"validationMessage\">\r\n </div>\r\n\r\n <div class=\"bbsf-validation-msg text-center text-danger\"\r\n *ngIf=\"validationCountMessage && options.isMultipleFile && options.maxNoOfFiles > 0\"\r\n [innerHTML]=\"validationCountMessage\">\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Hidden file input -->\r\n <input ng2FileSelect [uploader]=\"uploader\" [accept]=\"acceptedType\"\r\n class=\"fileSelector customFileUploadPlacment hidden v-required-multiplefiles d-none\"\r\n [attr.multiple]=\"options.isMultipleFile ? 'multiple' : null\" name=\"file\" type=\"file\" autocomplete=\"off\"\r\n (change)=\"onFileChange()\" [ngClass]=\"options.viewType === 1 ? '' : 'col-md-9'\" [id]=\"options.name\"\r\n #fileInputControl [class.is-invalid]=\"fileUploadFormControl.invalid && fileUploadFormControl.touched\" />\r\n </div>\r\n <!-- Click to upload (no drop zone) -->\r\n <div class=\"bbsf-input-container\" *ngIf=\"!options.isDropZone && !isHideInput() && !options.isReadonly\"\r\n (click)=\"fileInput.click()\">\r\n\r\n <div class=\"dropzone-label\">\r\n <div class=\"svg-and-validation\">\r\n <!-- Upload icon -->\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"70\" height=\"70\" viewBox=\"0 0 70 70\" fill=\"none\">\r\n <path opacity=\"0.4\"\r\n d=\"M58.333 48.8332C61.8957 45.8908 64.1663 41.4397 64.1663 36.4583C64.1663 27.5988 56.9843 20.4167 48.1247 20.4167C47.4874 20.4167 46.8912 20.0842 46.5675 19.5351C42.7641 13.0808 35.7417 8.75 27.708 8.75C15.6268 8.75 5.83301 18.5438 5.83301 30.625C5.83301 36.6511 8.26974 42.1082 12.2116 46.0644\"\r\n stroke=\"#4B5489\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\r\n <path d=\"M23.333 46.6667L34.9997 35M34.9997 35L46.6663 46.6667M34.9997 35V61.25\" stroke=\"#4B5489\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\r\n </svg>\r\n\r\n <!-- Upload text -->\r\n <div class=\"bbsf-validation-msg text-center\">\r\n {{ utilityService.getResourceValue('Upload') }}\r\n </div>\r\n\r\n <!-- Validation messages -->\r\n <div class=\"bbsf-validation-msg text-center\" *ngIf=\"validationMessage\" [innerHTML]=\"validationMessage\">\r\n </div>\r\n\r\n <div class=\"bbsf-validation-msg text-center text-danger\"\r\n *ngIf=\"validationCountMessage && options.isMultipleFile && options.maxNoOfFiles > 0\"\r\n [innerHTML]=\"validationCountMessage\">\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Hidden file input -->\r\n <input ng2FileSelect [uploader]=\"uploader\" [accept]=\"acceptedType\"\r\n class=\"fileSelector customFileUploadPlacment hidden v-required-multiplefiles d-none\"\r\n [attr.multiple]=\"options.isMultipleFile ? 'multiple' : null\" name=\"file\" type=\"file\" autocomplete=\"off\"\r\n (change)=\"onFileChange()\" [ngClass]=\"options.viewType === 1 ? '' : 'col-md-9'\" [id]=\"options.name\" #fileInput\r\n [class.is-invalid]=\"fileUploadFormControl.invalid && fileUploadFormControl.touched\" />\r\n </div>\r\n <!-- Read-only state with no files -->\r\n <div *ngIf=\"options.isReadonly && (!options.value || (uploader.queue && uploader.queue.length === 0))\">\r\n <span class=\"readonly-view\">{{ utilityService.getResourceValue('NA') }}</span>\r\n </div>\r\n </div>\r\n <!-- Uploaded files list -->\r\n <div class=\"uploaded-items\" *ngIf=\"shouldShowFileList()\">\r\n <div class=\"btn-group\" *ngFor=\"let item of uploader.queue; trackBy: trackByFunction\">\r\n\r\n <!-- Async upload completed files -->\r\n <ng-container *ngIf=\"item?.progress === 100 && options.isUploadFileAsync\">\r\n <!-- Download link - always visible -->\r\n <button *ngIf=\"getFileDownloadUrl(item); else noUrlTemplate\" type=\"button\"\r\n class=\"btn-download-file btn-sm btn-progress-upload\" (click)=\"downloadFile(item)\"\r\n [title]=\"'Download ' + getFileName(item)\">\r\n <span class=\"file-name\">{{ getFileName(item) }}</span>\r\n </button>\r\n\r\n <!-- File name display when no URL available -->\r\n <ng-template #noUrlTemplate>\r\n <span class=\"btn-download-file btn-sm btn-progress-upload\" [title]=\"getFileName(item)\">\r\n <span class=\"file-name\">{{ getFileName(item) }}</span>\r\n </span>\r\n </ng-template>\r\n\r\n <!-- Remove button - only show when not readonly and not disabled -->\r\n <button *ngIf=\"isRemoveEnabled()\" class=\"btn btn-download-file btn-sm\" type=\"button\"\r\n (click)=\"item.remove(); removeFromControlValue(item)\" [attr.aria-label]=\"'Remove ' + getFileName(item)\"\r\n [title]=\"'Remove ' + getFileName(item)\">\r\n <!-- Delete icon -->\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\">\r\n <path opacity=\"0.4\"\r\n d=\"M9.33301 3.70584V3.26663C9.33301 2.65166 9.33301 2.34419 9.20587 2.1093C9.09405 1.9027 8.91555 1.73471 8.69604 1.62944C8.44647 1.50977 8.11977 1.50977 7.46638 1.50977H6.53305C5.87965 1.50977 5.55296 1.50977 5.30339 1.62944C5.08387 1.73471 4.90539 1.9027 4.79354 2.1093C4.66638 2.34419 4.66638 2.65166 4.66638 3.26663V3.70584\"\r\n stroke=\"#D83731\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\r\n <path\r\n d=\"M1.75 3.70605H12.25M11.0834 3.70605V9.8551C11.0834 10.7775 11.0834 11.2387 10.8926 11.591C10.7248 11.901 10.4571 12.1529 10.1278 12.3109C9.75345 12.4904 9.26345 12.4904 8.28334 12.4904H5.71666C4.73658 12.4904 4.24653 12.4904 3.87218 12.3109C3.5429 12.1529 3.27519 11.901 3.10741 11.591C2.91666 11.2387 2.91666 10.7775 2.91666 9.8551V3.70605\"\r\n stroke=\"#D83731\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\r\n </svg>\r\n </button>\r\n </ng-container>\r\n\r\n <!-- Sync upload files -->\r\n <ng-container *ngIf=\"!options.isUploadFileAsync\">\r\n <!-- Download link - always visible -->\r\n <button type=\"button\" class=\"btn btn-download-file btn-sm\" (click)=\"downloadFile(item)\"\r\n [title]=\"'Download ' + getFileName(item)\">\r\n <!-- Download icon -->\r\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path\r\n d=\"M21 22H3C2.4 22 2 21.6 2 21C2 20.4 2.4 20 3 20H21C21.6 20 22 20.4 22 21C22 21.6 21.6 22 21 22ZM13 13.4V3C13 2.4 12.6 2 12 2C11.4 2 11 2.4 11 3V13.4H13Z\"\r\n fill=\"currentColor\"></path>\r\n <path opacity=\"0.3\" d=\"M7 13.4H17L12.7 17.7C12.3 18.1 11.7 18.1 11.3 17.7L7 13.4Z\" fill=\"currentColor\">\r\n </path>\r\n </svg>\r\n <span class=\"file-name\">{{ getFileName(item) }}</span>\r\n </button>\r\n\r\n <!-- Remove button - only show when not readonly and not disabled -->\r\n <button *ngIf=\"isRemoveEnabled()\" class=\"btn btn-download-file btn-sm btn-danger\" type=\"button\"\r\n (click)=\"item.remove(); removeFromControlValue(item)\" [attr.aria-label]=\"'Remove ' + getFileName(item)\"\r\n [title]=\"'Remove ' + getFileName(item)\">\r\n <i class=\"fa fa-times px-0\" aria-hidden=\"true\"></i>\r\n </button>\r\n </ng-container>\r\n </div>\r\n </div>\r\n <!-- File upload progress indicators -->\r\n <div *ngFor=\"let item of uploader.queue; trackBy: trackByFunction\">\r\n <div class=\"upload-items\" [ngClass]=\"{ 'mt-4': options.isMultipleFile }\"\r\n *ngIf=\"item?.progress < 100 && options.isUploadFileAsync && !options.isReadonly\">\r\n\r\n <div class=\"upload-items-toolbar\">\r\n <h4>{{ getFileName(item) }}</h4>\r\n <button *ngIf=\"isRemoveEnabled()\" type=\"button\" class=\"btn-cancel-upload\"\r\n (click)=\"item.remove(); removeFromControlValue(item)\"\r\n [attr.aria-label]=\"'Cancel upload for ' + getFileName(item)\">\r\n <!-- Cancel icon -->\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 18 18\" fill=\"none\">\r\n <g clip-path=\"url(#clip0_1324_13216)\">\r\n <path opacity=\"0.4\"\r\n d=\"M9 16.5C13.1421 16.5 16.5 13.1421 16.5 9C16.5 4.85786 13.1421 1.5 9 1.5C4.85786 1.5 1.5 4.85786 1.5 9C1.5 13.1421 4.85786 16.5 9 16.5Z\"\r\n stroke=\"#DBE1F0\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\r\n <path d=\"M11.25 6.75L6.75 11.25M6.75 6.75L11.25 11.25\" stroke=\"#DBE1F0\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\" />\r\n </g>\r\n <defs>\r\n <clipPath id=\"clip0_1324_13216\">\r\n <rect width=\"18\" height=\"18\" fill=\"white\" />\r\n </clipPath>\r\n </defs>\r\n </svg>\r\n </button>\r\n </div>\r\n\r\n <div class=\"progress\">\r\n <div class=\"progress-bar\" role=\"progressbar\" [attr.aria-valuenow]=\"item?.progress\" aria-valuemin=\"0\"\r\n aria-valuemax=\"100\" [class.file-uploaded]=\"item?.progress < 100\" [style.width.%]=\"item?.progress\"\r\n *ngIf=\"item?.progress > 0\">\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Validation and description section -->\r\n <div class=\"subtext-container\" *ngIf=\"!options.isReadonly\">\r\n <!-- Validation messages -->\r\n <div class=\"bbsf-validation\" *ngIf=\"fileUploadFormControl.invalid && fileUploadFormControl.touched\">\r\n <span [innerHTML]=\"getErrorValidation(fileUploadFormControl.errors | keyvalue)\"></span>\r\n </div>\r\n\r\n <!-- Control description -->\r\n <div class=\"bbsf-control-desc\" *ngIf=\"options.labelDescription\">\r\n {{ options.labelDescription }}\r\n </div>\r\n\r\n <!-- Reset error state -->\r\n <div *ngIf=\"(group.valid && group.dirty && group.touched) || (group.untouched && group.invalid && group.dirty)\">\r\n {{ resetError() }}\r\n </div>\r\n </div>\r\n</div>", dependencies: [{ kind: "directive", type: i6.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i6.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i6.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i7.FileDropDirective, selector: "[ng2FileDrop]", inputs: ["uploader"], outputs: ["fileOver", "onFileDrop"] }, { kind: "directive", type: i7.FileSelectDirective, selector: "[ng2FileSelect]", inputs: ["uploader"], outputs: ["onFileSelected"] }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "pipe", type: i6.KeyValuePipe, name: "keyvalue" }] }); }
700
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: FileUploadComponent, deps: [{ token: i1.ControlContainer, optional: true }, { token: i1.FormGroupDirective }, { token: i2.ControlUtility }, { token: i3.UtilityService }, { token: i3.ControlValidationService }, { token: i2.GlobalSettings }, { token: i2.FileUploadService }], target: i0.ɵɵFactoryTarget.Component }); }
701
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "17.3.12", type: FileUploadComponent, selector: "BBSF-FileUpload", inputs: { group: "group", options: "options" }, outputs: { OnChange: "OnChange", isUploadComplete: "isUploadComplete" }, viewQueries: [{ propertyName: "fileInput", first: true, predicate: ["fileInput"], descendants: true }], ngImport: i0, template: "<div class=\"form-group bbsf-control bbsf-file-upload\" [formGroup]=\"group\">\r\n <div [ngClass]=\"options.viewType == 1 ? 'bbsf-vertical' : 'bbsf-horizontal'\">\r\n <!--label-->\r\n <label [hidden]=\"options.hideLabel\" class=\"bbsf-label {{ options.labelExtraClasses }}\">\r\n {{ options.labelValue }}\r\n <!--Asterisk-->\r\n <span *ngIf=\"((options.showAsterisk && options.isRequired) || options.isRequired) && !options.isReadonly\"\r\n class=\"text-danger\">*</span>\r\n </label>\r\n <!--Allow dropZone-->\r\n <div ng2FileDrop class=\"bbsf-input-container {{ options.extraClasses }}\"\r\n *ngIf=\"options.isDropZone && !(options.isMultipleFile == false && uploader.queue.length > 0) && !options.isReadonly\"\r\n [ngClass]=\"{ 'another-file-over-class': hasAnotherDropZoneOver }\" (onFileDrop)=\"onFileChange()\"\r\n (fileOver)=\"fileOverAnother($event)\" [uploader]=\"uploader\" [accept]=\"acceptedType\" id=\"{{ options.name }}\"\r\n multiple=\"{{ options.isMultipleFile ? 'multiple' : '' }}\" aria-describedby=\"email-error\" aria-invalid=\"true\"\r\n type=\"file\" [class.is-invalid]=\"fileUploadFormControl.invalid && fileUploadFormControl.touched\"\r\n (click)=\"fileInputDropZone.click()\">\r\n <div class=\"dropzone-label\">\r\n <div class=\"svg-and-validation\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"70\" height=\"70\" viewBox=\"0 0 70 70\" fill=\"none\">\r\n <path opacity=\"0.4\"\r\n d=\"M58.333 48.8332C61.8957 45.8908 64.1663 41.4397 64.1663 36.4583C64.1663 27.5988 56.9843 20.4167 48.1247 20.4167C47.4874 20.4167 46.8912 20.0842 46.5675 19.5351C42.7641 13.0808 35.7417 8.75 27.708 8.75C15.6268 8.75 5.83301 18.5438 5.83301 30.625C5.83301 36.6511 8.26974 42.1082 12.2116 46.0644\"\r\n stroke=\"#4B5489\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\r\n <path d=\"M23.333 46.6667L34.9997 35M34.9997 35L46.6663 46.6667M34.9997 35V61.25\" stroke=\"#4B5489\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\r\n </svg>\r\n <!--Validation text-->\r\n <div class=\"bbsf-validation-msg validation-msg-header text-center\">\r\n {{ UtilityService.getResourceValue('DragAndDropHere') }}\r\n </div>\r\n <div class=\"bbsf-validation-msg text-center\" *ngIf=\"validationMessage\" [innerHTML]=\"validationMessage\"></div>\r\n <div class=\"bbsf-validation-msg ng-star-inserted text-center text-danger\"\r\n *ngIf=\"validationCountMessage && options.isMultipleFile && options.maxNoOfFiles > 0\"\r\n [innerHTML]=\"validationCountMessage\"></div>\r\n </div>\r\n </div>\r\n <input ng2FileSelect [uploader]=\"uploader\" [accept]=\"acceptedType\"\r\n class=\"fileSelector customFileUploadPlacment hidden v-required-multiplefiles d-none\"\r\n multiple=\"{{ options.isMultipleFile ? 'multiple' : '' }}\" name=\"file\" type=\"file\" value=\"\" autocomplete=\"off\"\r\n (change)=\"onFileChange()\" [ngClass]=\"options.viewType == 1 ? '' : 'col-md-9'\" id=\"{{ options.name }}\"\r\n aria-describedby=\"email-error\" aria-invalid=\"true\" #fileInputDropZone\r\n [class.is-invalid]=\"fileUploadFormControl.invalid && fileUploadFormControl.touched\" />\r\n </div>\r\n <!--Not allowed dropZone-->\r\n <div class=\"bbsf-input-container\" *ngIf=\"!options.isDropZone && !isHideInput() && !options.isReadonly\"\r\n (click)=\"fileInput.click()\">\r\n <div class=\"dropzone-label\">\r\n <div class=\"svg-and-validation\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"70\" height=\"70\" viewBox=\"0 0 70 70\" fill=\"none\">\r\n <path opacity=\"0.4\"\r\n d=\"M58.333 48.8332C61.8957 45.8908 64.1663 41.4397 64.1663 36.4583C64.1663 27.5988 56.9843 20.4167 48.1247 20.4167C47.4874 20.4167 46.8912 20.0842 46.5675 19.5351C42.7641 13.0808 35.7417 8.75 27.708 8.75C15.6268 8.75 5.83301 18.5438 5.83301 30.625C5.83301 36.6511 8.26974 42.1082 12.2116 46.0644\"\r\n stroke=\"#4B5489\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\r\n <path d=\"M23.333 46.6667L34.9997 35M34.9997 35L46.6663 46.6667M34.9997 35V61.25\" stroke=\"#4B5489\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\r\n </svg>\r\n <!--Validation text-->\r\n <div class=\"bbsf-validation-msg text-center\">{{ UtilityService.getResourceValue('Upload') }}</div>\r\n <div class=\"bbsf-validation-msg text-center\" *ngIf=\"validationMessage\" [innerHTML]=\"validationMessage\"></div>\r\n <div class=\"bbsf-validation-msg ng-star-inserted text-center text-danger\"\r\n *ngIf=\"validationCountMessage && options.isMultipleFile && options.maxNoOfFiles > 0\"\r\n [innerHTML]=\"validationCountMessage\"></div>\r\n </div>\r\n </div>\r\n <input ng2FileSelect [uploader]=\"uploader\" [accept]=\"acceptedType\"\r\n class=\"fileSelector customFileUploadPlacment hidden v-required-multiplefiles d-none\"\r\n multiple=\"{{ options.isMultipleFile ? 'multiple' : '' }}\" name=\"file\" type=\"file\" value=\"\" autocomplete=\"off\"\r\n (change)=\"onFileChange()\" [ngClass]=\"options.viewType == 1 ? '' : 'col-md-9'\" id=\"{{ options.name }}\"\r\n aria-describedby=\"email-error\" aria-invalid=\"true\" #fileInput\r\n [class.is-invalid]=\"fileUploadFormControl.invalid && fileUploadFormControl.touched\" />\r\n </div>\r\n <!-- readonly -->\r\n <div *ngIf=\"options.isReadonly && !options.value\">\r\n <span class=\"readonly-view\">{{ UtilityService.getResourceValue('NA') }}</span>\r\n </div>\r\n </div>\r\n <!--items uploaded-->\r\n <div class=\"uploaded-items\">\r\n <div class=\"btn-group\" *ngFor=\"let item of uploader.queue\">\r\n <ng-container *ngIf=\"item?.progress == 100 && options.isUploadFileAsync\">\r\n <a *ngIf=\"item?.file?.rawFile['url']\" href=\"{{ item?.file?.rawFile['url'] }}\"\r\n class=\"btn-download-file btn-sm btn-progress-upload\" download>\r\n <span class=\"file-name\">{{ sanitizeFileName(item?.file?.name || '') }}</span>\r\n </a>\r\n <a *ngIf=\"item?.file?.rawFile['url'] == null\" class=\"btn-download-file btn-sm btn-progress-upload\">\r\n <span class=\"file-name\">{{ sanitizeFileName(item?.file?.name || '') }}</span>\r\n </a>\r\n <button *ngIf=\"!options.isReadonly\" class=\"btn btn-download-file btn-sm\"\r\n (click)=\"item.remove(); removeFromControlValue(item)\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\">\r\n <path opacity=\"0.4\"\r\n d=\"M9.33301 3.70584V3.26663C9.33301 2.65166 9.33301 2.34419 9.20587 2.1093C9.09405 1.9027 8.91555 1.73471 8.69604 1.62944C8.44647 1.50977 8.11977 1.50977 7.46638 1.50977H6.53305C5.87965 1.50977 5.55296 1.50977 5.30339 1.62944C5.08387 1.73471 4.90539 1.9027 4.79354 2.1093C4.66638 2.34419 4.66638 2.65166 4.66638 3.26663V3.70584\"\r\n stroke=\"#D83731\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\r\n <path\r\n d=\"M1.75 3.70605H12.25M11.0834 3.70605V9.8551C11.0834 10.7775 11.0834 11.2387 10.8926 11.591C10.7248 11.901 10.4571 12.1529 10.1278 12.3109C9.75345 12.4904 9.26345 12.4904 8.28334 12.4904H5.71666C4.73658 12.4904 4.24653 12.4904 3.87218 12.3109C3.5429 12.1529 3.27519 11.901 3.10741 11.591C2.91666 11.2387 2.91666 10.7775 2.91666 9.8551V3.70605\"\r\n stroke=\"#D83731\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\r\n </svg>\r\n </button>\r\n </ng-container>\r\n <ng-container *ngIf=\"!options.isUploadFileAsync\">\r\n <a href=\"{{ item?.file?.rawFile['url'] }}\" class=\"btn btn-download-file btn-sm\" download>\r\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path\r\n d=\"M21 22H3C2.4 22 2 21.6 2 21C2 20.4 2.4 20 3 20H21C21.6 20 22 20.4 22 21C22 21.6 21.6 22 21 22ZM13 13.4V3C13 2.4 12.6 2 12 2C11.4 2 11 2.4 11 3V13.4H13Z\"\r\n fill=\"currentColor\"></path>\r\n <path opacity=\"0.3\" d=\"M7 13.4H17L12.7 17.7C12.3 18.1 11.7 18.1 11.3 17.7L7 13.4Z\" fill=\"currentColor\">\r\n </path>\r\n </svg>\r\n <span class=\"file-name\">{{ sanitizeFileName(item?.file?.name || '') }}</span>\r\n </a>\r\n <button *ngIf=\"!options.isReadonly\" class=\"btn btn-download-file btn-sm btn-danger\"\r\n (click)=\"item.remove(); removeFromControlValue(item)\">\r\n <i class=\"fa fa-times px-0\"></i>\r\n </button>\r\n </ng-container>\r\n </div>\r\n </div>\r\n <!--progress bar file upload-->\r\n <div *ngFor=\"let item of uploader.queue\">\r\n <div class=\"upload-items\" [ngClass]=\"{ 'mt-4': options.isMultipleFile == true }\"\r\n *ngIf=\"item?.progress < 100 && options.isUploadFileAsync\">\r\n <div class=\"upload-items-toolbar\">\r\n <h4>{{ item?.file?.name }}</h4>\r\n <span (click)=\"item.remove(); removeFromControlValue(item)\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 18 18\" fill=\"none\">\r\n <g clip-path=\"url(#clip0_1324_13216)\">\r\n <path opacity=\"0.4\"\r\n d=\"M9 16.5C13.1421 16.5 16.5 13.1421 16.5 9C16.5 4.85786 13.1421 1.5 9 1.5C4.85786 1.5 1.5 4.85786 1.5 9C1.5 13.1421 4.85786 16.5 9 16.5Z\"\r\n stroke=\"#DBE1F0\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\r\n <path d=\"M11.25 6.75L6.75 11.25M6.75 6.75L11.25 11.25\" stroke=\"#DBE1F0\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\" />\r\n </g>\r\n <defs>\r\n <clipPath id=\"clip0_1324_13216\">\r\n <rect width=\"18\" height=\"18\" fill=\"white\" />\r\n </clipPath>\r\n </defs>\r\n </svg>\r\n </span>\r\n </div>\r\n <div class=\"progress\">\r\n <div class=\"progress-bar\" role=\"progressbar\" aria-valuenow=\"70\" aria-valuemin=\"0\" aria-valuemax=\"100\"\r\n [class.file-uploaded]=\"item?.progress < 100\" [style.width.%]=\"item?.progress\" *ngIf=\"item?.progress > 0\">\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"subtext-container\" *ngIf=\"!options.isReadonly\">\r\n <!-- required text-->\r\n <div class=\"bbsf-validation\" *ngIf=\"fileUploadFormControl.invalid && fileUploadFormControl.touched\">\r\n {{ getErrorValidation(fileUploadFormControl.errors | keyvalue) }}\r\n </div>\r\n <!-- LabelDescription-->\r\n <div class=\"bbsf-control-desc\" *ngIf=\"options.labelDescription != null\">{{ options.labelDescription }}</div>\r\n <div *ngIf=\"(group.valid && group.dirty && group.touched) || (group.untouched && group.invalid && group.dirty)\">\r\n {{ resetError() }}\r\n </div>\r\n </div>\r\n</div>", dependencies: [{ kind: "directive", type: i4.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i4.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i5.FileDropDirective, selector: "[ng2FileDrop]", inputs: ["uploader"], outputs: ["fileOver", "onFileDrop"] }, { kind: "directive", type: i5.FileSelectDirective, selector: "[ng2FileSelect]", inputs: ["uploader"], outputs: ["onFileSelected"] }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "pipe", type: i4.KeyValuePipe, name: "keyvalue" }] }); }
1076
702
  }
1077
703
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: FileUploadComponent, decorators: [{
1078
704
  type: Component,
1079
- args: [{ selector: 'BBSF-FileUpload', standalone: false, template: "<div class=\"form-group bbsf-control bbsf-file-upload\" [formGroup]=\"group\">\r\n <div [ngClass]=\"options.viewType === 1 ? 'bbsf-vertical' : 'bbsf-horizontal'\">\r\n <!-- Label -->\r\n <label [hidden]=\"options.hideLabel\" class=\"bbsf-label {{ options.labelExtraClasses }}\">\r\n {{ options.labelValue }}\r\n <!-- Required asterisk -->\r\n <span *ngIf=\"options.isRequired && !options.isReadonly && (options.showAsterisk || true)\"\r\n class=\"text-danger\">*</span>\r\n </label>\r\n <!-- Drop zone enabled -->\r\n <div ng2FileDrop class=\"bbsf-input-container {{ options.extraClasses }}\"\r\n *ngIf=\"options.isDropZone && !isHideInput() && !options.isReadonly\"\r\n [ngClass]=\"{ 'another-file-over-class': hasAnotherDropZoneOver }\" (onFileDrop)=\"onFileChange()\"\r\n (fileOver)=\"fileOverAnother($event)\" [uploader]=\"uploader\" [accept]=\"acceptedType\" [id]=\"options.name\"\r\n [attr.multiple]=\"options.isMultipleFile ? 'multiple' : null\"\r\n [class.is-invalid]=\"fileUploadFormControl.invalid && fileUploadFormControl.touched\"\r\n (click)=\"fileInputControl.click()\">\r\n\r\n <div class=\"dropzone-label\">\r\n <div class=\"svg-and-validation\">\r\n <!-- Upload icon -->\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"70\" height=\"70\" viewBox=\"0 0 70 70\" fill=\"none\">\r\n <path opacity=\"0.4\"\r\n d=\"M58.333 48.8332C61.8957 45.8908 64.1663 41.4397 64.1663 36.4583C64.1663 27.5988 56.9843 20.4167 48.1247 20.4167C47.4874 20.4167 46.8912 20.0842 46.5675 19.5351C42.7641 13.0808 35.7417 8.75 27.708 8.75C15.6268 8.75 5.83301 18.5438 5.83301 30.625C5.83301 36.6511 8.26974 42.1082 12.2116 46.0644\"\r\n stroke=\"#4B5489\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\r\n <path d=\"M23.333 46.6667L34.9997 35M34.9997 35L46.6663 46.6667M34.9997 35V61.25\" stroke=\"#4B5489\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\r\n </svg>\r\n\r\n <!-- Instruction text -->\r\n <div class=\"bbsf-validation-msg validation-msg-header text-center\">\r\n {{ utilityService.getResourceValue('DragAndDropHere') }}\r\n </div>\r\n\r\n <!-- Validation messages -->\r\n <div class=\"bbsf-validation-msg text-center\" *ngIf=\"validationMessage\" [innerHTML]=\"validationMessage\">\r\n </div>\r\n\r\n <div class=\"bbsf-validation-msg text-center text-danger\"\r\n *ngIf=\"validationCountMessage && options.isMultipleFile && options.maxNoOfFiles > 0\"\r\n [innerHTML]=\"validationCountMessage\">\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Hidden file input -->\r\n <input ng2FileSelect [uploader]=\"uploader\" [accept]=\"acceptedType\"\r\n class=\"fileSelector customFileUploadPlacment hidden v-required-multiplefiles d-none\"\r\n [attr.multiple]=\"options.isMultipleFile ? 'multiple' : null\" name=\"file\" type=\"file\" autocomplete=\"off\"\r\n (change)=\"onFileChange()\" [ngClass]=\"options.viewType === 1 ? '' : 'col-md-9'\" [id]=\"options.name\"\r\n #fileInputControl [class.is-invalid]=\"fileUploadFormControl.invalid && fileUploadFormControl.touched\" />\r\n </div>\r\n <!-- Click to upload (no drop zone) -->\r\n <div class=\"bbsf-input-container\" *ngIf=\"!options.isDropZone && !isHideInput() && !options.isReadonly\"\r\n (click)=\"fileInput.click()\">\r\n\r\n <div class=\"dropzone-label\">\r\n <div class=\"svg-and-validation\">\r\n <!-- Upload icon -->\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"70\" height=\"70\" viewBox=\"0 0 70 70\" fill=\"none\">\r\n <path opacity=\"0.4\"\r\n d=\"M58.333 48.8332C61.8957 45.8908 64.1663 41.4397 64.1663 36.4583C64.1663 27.5988 56.9843 20.4167 48.1247 20.4167C47.4874 20.4167 46.8912 20.0842 46.5675 19.5351C42.7641 13.0808 35.7417 8.75 27.708 8.75C15.6268 8.75 5.83301 18.5438 5.83301 30.625C5.83301 36.6511 8.26974 42.1082 12.2116 46.0644\"\r\n stroke=\"#4B5489\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\r\n <path d=\"M23.333 46.6667L34.9997 35M34.9997 35L46.6663 46.6667M34.9997 35V61.25\" stroke=\"#4B5489\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\r\n </svg>\r\n\r\n <!-- Upload text -->\r\n <div class=\"bbsf-validation-msg text-center\">\r\n {{ utilityService.getResourceValue('Upload') }}\r\n </div>\r\n\r\n <!-- Validation messages -->\r\n <div class=\"bbsf-validation-msg text-center\" *ngIf=\"validationMessage\" [innerHTML]=\"validationMessage\">\r\n </div>\r\n\r\n <div class=\"bbsf-validation-msg text-center text-danger\"\r\n *ngIf=\"validationCountMessage && options.isMultipleFile && options.maxNoOfFiles > 0\"\r\n [innerHTML]=\"validationCountMessage\">\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Hidden file input -->\r\n <input ng2FileSelect [uploader]=\"uploader\" [accept]=\"acceptedType\"\r\n class=\"fileSelector customFileUploadPlacment hidden v-required-multiplefiles d-none\"\r\n [attr.multiple]=\"options.isMultipleFile ? 'multiple' : null\" name=\"file\" type=\"file\" autocomplete=\"off\"\r\n (change)=\"onFileChange()\" [ngClass]=\"options.viewType === 1 ? '' : 'col-md-9'\" [id]=\"options.name\" #fileInput\r\n [class.is-invalid]=\"fileUploadFormControl.invalid && fileUploadFormControl.touched\" />\r\n </div>\r\n <!-- Read-only state with no files -->\r\n <div *ngIf=\"options.isReadonly && (!options.value || (uploader.queue && uploader.queue.length === 0))\">\r\n <span class=\"readonly-view\">{{ utilityService.getResourceValue('NA') }}</span>\r\n </div>\r\n </div>\r\n <!-- Uploaded files list -->\r\n <div class=\"uploaded-items\" *ngIf=\"shouldShowFileList()\">\r\n <div class=\"btn-group\" *ngFor=\"let item of uploader.queue; trackBy: trackByFunction\">\r\n\r\n <!-- Async upload completed files -->\r\n <ng-container *ngIf=\"item?.progress === 100 && options.isUploadFileAsync\">\r\n <!-- Download link - always visible -->\r\n <button *ngIf=\"getFileDownloadUrl(item); else noUrlTemplate\" type=\"button\"\r\n class=\"btn-download-file btn-sm btn-progress-upload\" (click)=\"downloadFile(item)\"\r\n [title]=\"'Download ' + getFileName(item)\">\r\n <span class=\"file-name\">{{ getFileName(item) }}</span>\r\n </button>\r\n\r\n <!-- File name display when no URL available -->\r\n <ng-template #noUrlTemplate>\r\n <span class=\"btn-download-file btn-sm btn-progress-upload\" [title]=\"getFileName(item)\">\r\n <span class=\"file-name\">{{ getFileName(item) }}</span>\r\n </span>\r\n </ng-template>\r\n\r\n <!-- Remove button - only show when not readonly and not disabled -->\r\n <button *ngIf=\"isRemoveEnabled()\" class=\"btn btn-download-file btn-sm\" type=\"button\"\r\n (click)=\"item.remove(); removeFromControlValue(item)\" [attr.aria-label]=\"'Remove ' + getFileName(item)\"\r\n [title]=\"'Remove ' + getFileName(item)\">\r\n <!-- Delete icon -->\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\">\r\n <path opacity=\"0.4\"\r\n d=\"M9.33301 3.70584V3.26663C9.33301 2.65166 9.33301 2.34419 9.20587 2.1093C9.09405 1.9027 8.91555 1.73471 8.69604 1.62944C8.44647 1.50977 8.11977 1.50977 7.46638 1.50977H6.53305C5.87965 1.50977 5.55296 1.50977 5.30339 1.62944C5.08387 1.73471 4.90539 1.9027 4.79354 2.1093C4.66638 2.34419 4.66638 2.65166 4.66638 3.26663V3.70584\"\r\n stroke=\"#D83731\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\r\n <path\r\n d=\"M1.75 3.70605H12.25M11.0834 3.70605V9.8551C11.0834 10.7775 11.0834 11.2387 10.8926 11.591C10.7248 11.901 10.4571 12.1529 10.1278 12.3109C9.75345 12.4904 9.26345 12.4904 8.28334 12.4904H5.71666C4.73658 12.4904 4.24653 12.4904 3.87218 12.3109C3.5429 12.1529 3.27519 11.901 3.10741 11.591C2.91666 11.2387 2.91666 10.7775 2.91666 9.8551V3.70605\"\r\n stroke=\"#D83731\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\r\n </svg>\r\n </button>\r\n </ng-container>\r\n\r\n <!-- Sync upload files -->\r\n <ng-container *ngIf=\"!options.isUploadFileAsync\">\r\n <!-- Download link - always visible -->\r\n <button type=\"button\" class=\"btn btn-download-file btn-sm\" (click)=\"downloadFile(item)\"\r\n [title]=\"'Download ' + getFileName(item)\">\r\n <!-- Download icon -->\r\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path\r\n d=\"M21 22H3C2.4 22 2 21.6 2 21C2 20.4 2.4 20 3 20H21C21.6 20 22 20.4 22 21C22 21.6 21.6 22 21 22ZM13 13.4V3C13 2.4 12.6 2 12 2C11.4 2 11 2.4 11 3V13.4H13Z\"\r\n fill=\"currentColor\"></path>\r\n <path opacity=\"0.3\" d=\"M7 13.4H17L12.7 17.7C12.3 18.1 11.7 18.1 11.3 17.7L7 13.4Z\" fill=\"currentColor\">\r\n </path>\r\n </svg>\r\n <span class=\"file-name\">{{ getFileName(item) }}</span>\r\n </button>\r\n\r\n <!-- Remove button - only show when not readonly and not disabled -->\r\n <button *ngIf=\"isRemoveEnabled()\" class=\"btn btn-download-file btn-sm btn-danger\" type=\"button\"\r\n (click)=\"item.remove(); removeFromControlValue(item)\" [attr.aria-label]=\"'Remove ' + getFileName(item)\"\r\n [title]=\"'Remove ' + getFileName(item)\">\r\n <i class=\"fa fa-times px-0\" aria-hidden=\"true\"></i>\r\n </button>\r\n </ng-container>\r\n </div>\r\n </div>\r\n <!-- File upload progress indicators -->\r\n <div *ngFor=\"let item of uploader.queue; trackBy: trackByFunction\">\r\n <div class=\"upload-items\" [ngClass]=\"{ 'mt-4': options.isMultipleFile }\"\r\n *ngIf=\"item?.progress < 100 && options.isUploadFileAsync && !options.isReadonly\">\r\n\r\n <div class=\"upload-items-toolbar\">\r\n <h4>{{ getFileName(item) }}</h4>\r\n <button *ngIf=\"isRemoveEnabled()\" type=\"button\" class=\"btn-cancel-upload\"\r\n (click)=\"item.remove(); removeFromControlValue(item)\"\r\n [attr.aria-label]=\"'Cancel upload for ' + getFileName(item)\">\r\n <!-- Cancel icon -->\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 18 18\" fill=\"none\">\r\n <g clip-path=\"url(#clip0_1324_13216)\">\r\n <path opacity=\"0.4\"\r\n d=\"M9 16.5C13.1421 16.5 16.5 13.1421 16.5 9C16.5 4.85786 13.1421 1.5 9 1.5C4.85786 1.5 1.5 4.85786 1.5 9C1.5 13.1421 4.85786 16.5 9 16.5Z\"\r\n stroke=\"#DBE1F0\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\r\n <path d=\"M11.25 6.75L6.75 11.25M6.75 6.75L11.25 11.25\" stroke=\"#DBE1F0\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\" />\r\n </g>\r\n <defs>\r\n <clipPath id=\"clip0_1324_13216\">\r\n <rect width=\"18\" height=\"18\" fill=\"white\" />\r\n </clipPath>\r\n </defs>\r\n </svg>\r\n </button>\r\n </div>\r\n\r\n <div class=\"progress\">\r\n <div class=\"progress-bar\" role=\"progressbar\" [attr.aria-valuenow]=\"item?.progress\" aria-valuemin=\"0\"\r\n aria-valuemax=\"100\" [class.file-uploaded]=\"item?.progress < 100\" [style.width.%]=\"item?.progress\"\r\n *ngIf=\"item?.progress > 0\">\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <!-- Validation and description section -->\r\n <div class=\"subtext-container\" *ngIf=\"!options.isReadonly\">\r\n <!-- Validation messages -->\r\n <div class=\"bbsf-validation\" *ngIf=\"fileUploadFormControl.invalid && fileUploadFormControl.touched\">\r\n <span [innerHTML]=\"getErrorValidation(fileUploadFormControl.errors | keyvalue)\"></span>\r\n </div>\r\n\r\n <!-- Control description -->\r\n <div class=\"bbsf-control-desc\" *ngIf=\"options.labelDescription\">\r\n {{ options.labelDescription }}\r\n </div>\r\n\r\n <!-- Reset error state -->\r\n <div *ngIf=\"(group.valid && group.dirty && group.touched) || (group.untouched && group.invalid && group.dirty)\">\r\n {{ resetError() }}\r\n </div>\r\n </div>\r\n</div>" }]
705
+ args: [{ selector: 'BBSF-FileUpload', standalone: false, template: "<div class=\"form-group bbsf-control bbsf-file-upload\" [formGroup]=\"group\">\r\n <div [ngClass]=\"options.viewType == 1 ? 'bbsf-vertical' : 'bbsf-horizontal'\">\r\n <!--label-->\r\n <label [hidden]=\"options.hideLabel\" class=\"bbsf-label {{ options.labelExtraClasses }}\">\r\n {{ options.labelValue }}\r\n <!--Asterisk-->\r\n <span *ngIf=\"((options.showAsterisk && options.isRequired) || options.isRequired) && !options.isReadonly\"\r\n class=\"text-danger\">*</span>\r\n </label>\r\n <!--Allow dropZone-->\r\n <div ng2FileDrop class=\"bbsf-input-container {{ options.extraClasses }}\"\r\n *ngIf=\"options.isDropZone && !(options.isMultipleFile == false && uploader.queue.length > 0) && !options.isReadonly\"\r\n [ngClass]=\"{ 'another-file-over-class': hasAnotherDropZoneOver }\" (onFileDrop)=\"onFileChange()\"\r\n (fileOver)=\"fileOverAnother($event)\" [uploader]=\"uploader\" [accept]=\"acceptedType\" id=\"{{ options.name }}\"\r\n multiple=\"{{ options.isMultipleFile ? 'multiple' : '' }}\" aria-describedby=\"email-error\" aria-invalid=\"true\"\r\n type=\"file\" [class.is-invalid]=\"fileUploadFormControl.invalid && fileUploadFormControl.touched\"\r\n (click)=\"fileInputDropZone.click()\">\r\n <div class=\"dropzone-label\">\r\n <div class=\"svg-and-validation\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"70\" height=\"70\" viewBox=\"0 0 70 70\" fill=\"none\">\r\n <path opacity=\"0.4\"\r\n d=\"M58.333 48.8332C61.8957 45.8908 64.1663 41.4397 64.1663 36.4583C64.1663 27.5988 56.9843 20.4167 48.1247 20.4167C47.4874 20.4167 46.8912 20.0842 46.5675 19.5351C42.7641 13.0808 35.7417 8.75 27.708 8.75C15.6268 8.75 5.83301 18.5438 5.83301 30.625C5.83301 36.6511 8.26974 42.1082 12.2116 46.0644\"\r\n stroke=\"#4B5489\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\r\n <path d=\"M23.333 46.6667L34.9997 35M34.9997 35L46.6663 46.6667M34.9997 35V61.25\" stroke=\"#4B5489\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\r\n </svg>\r\n <!--Validation text-->\r\n <div class=\"bbsf-validation-msg validation-msg-header text-center\">\r\n {{ UtilityService.getResourceValue('DragAndDropHere') }}\r\n </div>\r\n <div class=\"bbsf-validation-msg text-center\" *ngIf=\"validationMessage\" [innerHTML]=\"validationMessage\"></div>\r\n <div class=\"bbsf-validation-msg ng-star-inserted text-center text-danger\"\r\n *ngIf=\"validationCountMessage && options.isMultipleFile && options.maxNoOfFiles > 0\"\r\n [innerHTML]=\"validationCountMessage\"></div>\r\n </div>\r\n </div>\r\n <input ng2FileSelect [uploader]=\"uploader\" [accept]=\"acceptedType\"\r\n class=\"fileSelector customFileUploadPlacment hidden v-required-multiplefiles d-none\"\r\n multiple=\"{{ options.isMultipleFile ? 'multiple' : '' }}\" name=\"file\" type=\"file\" value=\"\" autocomplete=\"off\"\r\n (change)=\"onFileChange()\" [ngClass]=\"options.viewType == 1 ? '' : 'col-md-9'\" id=\"{{ options.name }}\"\r\n aria-describedby=\"email-error\" aria-invalid=\"true\" #fileInputDropZone\r\n [class.is-invalid]=\"fileUploadFormControl.invalid && fileUploadFormControl.touched\" />\r\n </div>\r\n <!--Not allowed dropZone-->\r\n <div class=\"bbsf-input-container\" *ngIf=\"!options.isDropZone && !isHideInput() && !options.isReadonly\"\r\n (click)=\"fileInput.click()\">\r\n <div class=\"dropzone-label\">\r\n <div class=\"svg-and-validation\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"70\" height=\"70\" viewBox=\"0 0 70 70\" fill=\"none\">\r\n <path opacity=\"0.4\"\r\n d=\"M58.333 48.8332C61.8957 45.8908 64.1663 41.4397 64.1663 36.4583C64.1663 27.5988 56.9843 20.4167 48.1247 20.4167C47.4874 20.4167 46.8912 20.0842 46.5675 19.5351C42.7641 13.0808 35.7417 8.75 27.708 8.75C15.6268 8.75 5.83301 18.5438 5.83301 30.625C5.83301 36.6511 8.26974 42.1082 12.2116 46.0644\"\r\n stroke=\"#4B5489\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\r\n <path d=\"M23.333 46.6667L34.9997 35M34.9997 35L46.6663 46.6667M34.9997 35V61.25\" stroke=\"#4B5489\"\r\n stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\r\n </svg>\r\n <!--Validation text-->\r\n <div class=\"bbsf-validation-msg text-center\">{{ UtilityService.getResourceValue('Upload') }}</div>\r\n <div class=\"bbsf-validation-msg text-center\" *ngIf=\"validationMessage\" [innerHTML]=\"validationMessage\"></div>\r\n <div class=\"bbsf-validation-msg ng-star-inserted text-center text-danger\"\r\n *ngIf=\"validationCountMessage && options.isMultipleFile && options.maxNoOfFiles > 0\"\r\n [innerHTML]=\"validationCountMessage\"></div>\r\n </div>\r\n </div>\r\n <input ng2FileSelect [uploader]=\"uploader\" [accept]=\"acceptedType\"\r\n class=\"fileSelector customFileUploadPlacment hidden v-required-multiplefiles d-none\"\r\n multiple=\"{{ options.isMultipleFile ? 'multiple' : '' }}\" name=\"file\" type=\"file\" value=\"\" autocomplete=\"off\"\r\n (change)=\"onFileChange()\" [ngClass]=\"options.viewType == 1 ? '' : 'col-md-9'\" id=\"{{ options.name }}\"\r\n aria-describedby=\"email-error\" aria-invalid=\"true\" #fileInput\r\n [class.is-invalid]=\"fileUploadFormControl.invalid && fileUploadFormControl.touched\" />\r\n </div>\r\n <!-- readonly -->\r\n <div *ngIf=\"options.isReadonly && !options.value\">\r\n <span class=\"readonly-view\">{{ UtilityService.getResourceValue('NA') }}</span>\r\n </div>\r\n </div>\r\n <!--items uploaded-->\r\n <div class=\"uploaded-items\">\r\n <div class=\"btn-group\" *ngFor=\"let item of uploader.queue\">\r\n <ng-container *ngIf=\"item?.progress == 100 && options.isUploadFileAsync\">\r\n <a *ngIf=\"item?.file?.rawFile['url']\" href=\"{{ item?.file?.rawFile['url'] }}\"\r\n class=\"btn-download-file btn-sm btn-progress-upload\" download>\r\n <span class=\"file-name\">{{ sanitizeFileName(item?.file?.name || '') }}</span>\r\n </a>\r\n <a *ngIf=\"item?.file?.rawFile['url'] == null\" class=\"btn-download-file btn-sm btn-progress-upload\">\r\n <span class=\"file-name\">{{ sanitizeFileName(item?.file?.name || '') }}</span>\r\n </a>\r\n <button *ngIf=\"!options.isReadonly\" class=\"btn btn-download-file btn-sm\"\r\n (click)=\"item.remove(); removeFromControlValue(item)\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" fill=\"none\">\r\n <path opacity=\"0.4\"\r\n d=\"M9.33301 3.70584V3.26663C9.33301 2.65166 9.33301 2.34419 9.20587 2.1093C9.09405 1.9027 8.91555 1.73471 8.69604 1.62944C8.44647 1.50977 8.11977 1.50977 7.46638 1.50977H6.53305C5.87965 1.50977 5.55296 1.50977 5.30339 1.62944C5.08387 1.73471 4.90539 1.9027 4.79354 2.1093C4.66638 2.34419 4.66638 2.65166 4.66638 3.26663V3.70584\"\r\n stroke=\"#D83731\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\r\n <path\r\n d=\"M1.75 3.70605H12.25M11.0834 3.70605V9.8551C11.0834 10.7775 11.0834 11.2387 10.8926 11.591C10.7248 11.901 10.4571 12.1529 10.1278 12.3109C9.75345 12.4904 9.26345 12.4904 8.28334 12.4904H5.71666C4.73658 12.4904 4.24653 12.4904 3.87218 12.3109C3.5429 12.1529 3.27519 11.901 3.10741 11.591C2.91666 11.2387 2.91666 10.7775 2.91666 9.8551V3.70605\"\r\n stroke=\"#D83731\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\r\n </svg>\r\n </button>\r\n </ng-container>\r\n <ng-container *ngIf=\"!options.isUploadFileAsync\">\r\n <a href=\"{{ item?.file?.rawFile['url'] }}\" class=\"btn btn-download-file btn-sm\" download>\r\n <svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\">\r\n <path\r\n d=\"M21 22H3C2.4 22 2 21.6 2 21C2 20.4 2.4 20 3 20H21C21.6 20 22 20.4 22 21C22 21.6 21.6 22 21 22ZM13 13.4V3C13 2.4 12.6 2 12 2C11.4 2 11 2.4 11 3V13.4H13Z\"\r\n fill=\"currentColor\"></path>\r\n <path opacity=\"0.3\" d=\"M7 13.4H17L12.7 17.7C12.3 18.1 11.7 18.1 11.3 17.7L7 13.4Z\" fill=\"currentColor\">\r\n </path>\r\n </svg>\r\n <span class=\"file-name\">{{ sanitizeFileName(item?.file?.name || '') }}</span>\r\n </a>\r\n <button *ngIf=\"!options.isReadonly\" class=\"btn btn-download-file btn-sm btn-danger\"\r\n (click)=\"item.remove(); removeFromControlValue(item)\">\r\n <i class=\"fa fa-times px-0\"></i>\r\n </button>\r\n </ng-container>\r\n </div>\r\n </div>\r\n <!--progress bar file upload-->\r\n <div *ngFor=\"let item of uploader.queue\">\r\n <div class=\"upload-items\" [ngClass]=\"{ 'mt-4': options.isMultipleFile == true }\"\r\n *ngIf=\"item?.progress < 100 && options.isUploadFileAsync\">\r\n <div class=\"upload-items-toolbar\">\r\n <h4>{{ item?.file?.name }}</h4>\r\n <span (click)=\"item.remove(); removeFromControlValue(item)\">\r\n <svg xmlns=\"http://www.w3.org/2000/svg\" width=\"18\" height=\"18\" viewBox=\"0 0 18 18\" fill=\"none\">\r\n <g clip-path=\"url(#clip0_1324_13216)\">\r\n <path opacity=\"0.4\"\r\n d=\"M9 16.5C13.1421 16.5 16.5 13.1421 16.5 9C16.5 4.85786 13.1421 1.5 9 1.5C4.85786 1.5 1.5 4.85786 1.5 9C1.5 13.1421 4.85786 16.5 9 16.5Z\"\r\n stroke=\"#DBE1F0\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" />\r\n <path d=\"M11.25 6.75L6.75 11.25M6.75 6.75L11.25 11.25\" stroke=\"#DBE1F0\" stroke-width=\"2\"\r\n stroke-linecap=\"round\" stroke-linejoin=\"round\" />\r\n </g>\r\n <defs>\r\n <clipPath id=\"clip0_1324_13216\">\r\n <rect width=\"18\" height=\"18\" fill=\"white\" />\r\n </clipPath>\r\n </defs>\r\n </svg>\r\n </span>\r\n </div>\r\n <div class=\"progress\">\r\n <div class=\"progress-bar\" role=\"progressbar\" aria-valuenow=\"70\" aria-valuemin=\"0\" aria-valuemax=\"100\"\r\n [class.file-uploaded]=\"item?.progress < 100\" [style.width.%]=\"item?.progress\" *ngIf=\"item?.progress > 0\">\r\n </div>\r\n </div>\r\n </div>\r\n </div>\r\n\r\n <div class=\"subtext-container\" *ngIf=\"!options.isReadonly\">\r\n <!-- required text-->\r\n <div class=\"bbsf-validation\" *ngIf=\"fileUploadFormControl.invalid && fileUploadFormControl.touched\">\r\n {{ getErrorValidation(fileUploadFormControl.errors | keyvalue) }}\r\n </div>\r\n <!-- LabelDescription-->\r\n <div class=\"bbsf-control-desc\" *ngIf=\"options.labelDescription != null\">{{ options.labelDescription }}</div>\r\n <div *ngIf=\"(group.valid && group.dirty && group.touched) || (group.untouched && group.invalid && group.dirty)\">\r\n {{ resetError() }}\r\n </div>\r\n </div>\r\n</div>" }]
1080
706
  }], ctorParameters: () => [{ type: i1.ControlContainer, decorators: [{
1081
707
  type: Optional
1082
- }] }, { type: i1.FormGroupDirective }, { type: i2.ControlUtility }, { type: i3.UtilityService }, { type: i3.ControlValidationService }, { type: i4.GlobalSettings }, { type: i5.FileUploadService }], propDecorators: { fileInput: [{
708
+ }] }, { type: i1.FormGroupDirective }, { type: i2.ControlUtility }, { type: i3.UtilityService }, { type: i3.ControlValidationService }, { type: i2.GlobalSettings }, { type: i2.FileUploadService }], propDecorators: { fileInput: [{
1083
709
  type: ViewChild,
1084
710
  args: ['fileInput', { static: false }]
1085
711
  }], group: [{
@@ -1091,4 +717,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
1091
717
  }], isUploadComplete: [{
1092
718
  type: Output
1093
719
  }] } });
1094
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRmlsZVVwbG9hZC5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9iYnNmLWNvbnRyb2xzL3NyYy9saWIvY29udHJvbHMvRmlsZVVwbG9hZC9GaWxlVXBsb2FkLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2Jic2YtY29udHJvbHMvc3JjL2xpYi9jb250cm9scy9GaWxlVXBsb2FkL0ZpbGVVcGxvYWQuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUNMLFNBQVMsRUFJVCxLQUFLLEVBQ0wsUUFBUSxFQUNSLFNBQVMsRUFFVCxNQUFNLEVBQ04sWUFBWSxFQUNiLE1BQU0sZUFBZSxDQUFDO0FBQ3ZCLE9BQU8sRUFDTCxXQUFXLEVBQ1gsVUFBVSxFQU1YLE1BQU0sZ0JBQWdCLENBQUM7QUFHeEIsT0FBTyxFQUFFLFlBQVksRUFBaUQsTUFBTSxpQkFBaUIsQ0FBQztBQUM5RixPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0scUNBQXFDLENBQUM7QUFDdEUsT0FBTyxFQUFFLHVCQUF1QixFQUFFLE1BQU0sNkNBQTZDLENBQUM7QUFLdEYsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQ3JELE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxNQUFNLENBQUM7Ozs7Ozs7OztBQWdEcEMsTUFBTSxPQUFPLG1CQUFtQjthQUNmLDJCQUFzQixHQUE0QixJQUFJLEFBQWhDLENBQWlDO0lBbUN0RSxZQUNzQixnQkFBa0MsRUFDL0MsNkJBQWlELEVBQ2hELGNBQThCLEVBQy9CLGNBQThCLEVBQzdCLHdCQUFrRCxFQUNsRCxjQUE4QixFQUM5QixpQkFBb0M7UUFOeEIscUJBQWdCLEdBQWhCLGdCQUFnQixDQUFrQjtRQUMvQyxrQ0FBNkIsR0FBN0IsNkJBQTZCLENBQW9CO1FBQ2hELG1CQUFjLEdBQWQsY0FBYyxDQUFn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dUJBQUMsV0FBVyxFQUFFLEVBQUUsTUFBTSxFQUFFLEtBQUssRUFBRTtnQkFHaEMsS0FBSztzQkFBYixLQUFLO2dCQUNHLE9BQU87c0JBQWYsS0FBSztnQkFDSSxRQUFRO3NCQUFqQixNQUFNO2dCQUNHLGdCQUFnQjtzQkFBekIsTUFBTSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XHJcbiAgQ29tcG9uZW50LFxyXG4gIE9uSW5pdCxcclxuICBBZnRlclZpZXdJbml0LFxyXG4gIE9uRGVzdHJveSxcclxuICBJbnB1dCxcclxuICBPcHRpb25hbCxcclxuICBWaWV3Q2hpbGQsXHJcbiAgRWxlbWVudFJlZixcclxuICBPdXRwdXQsXHJcbiAgRXZlbnRFbWl0dGVyXHJcbn0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XHJcbmltcG9ydCB7XHJcbiAgRm9ybUNvbnRyb2wsXHJcbiAgVmFsaWRhdG9ycyxcclxuICBGb3JtR3JvdXAsXHJcbiAgQWJzdHJhY3RDb250cm9sLFxyXG4gIENvbnRyb2xDb250YWluZXIsXHJcbiAgRm9ybUdyb3VwRGlyZWN0aXZlLFxyXG4gIFZhbGlkYXRvckZuXHJcbn0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xyXG5pbXBvcnQgeyBGaWxlVXBsb2FkT3B0aW9ucyB9IGZyb20gJy4uLy4uL1NoYXJlZC9Nb2RlbHMvRmlsZVVwbG9hZE9wdGlvbnMnO1xyXG5pbXBvcnQgeyBDb250cm9sVXRpbGl0eSB9IGZyb20gJy4uLy4uL1NoYXJlZC9zZXJ2aWNlcy9Db250cm9sVXRpbGl0eSc7XHJcbmltcG9ydCB7IEZpbGVVcGxvYWRlciwgRmlsZUxpa2VPYmplY3QsIEZpbGVVcGxvYWRlck9wdGlvbnMsIEZpbGVJdGVtIH0gZnJvbSAnbmcyLWZpbGUtdXBsb2FkJztcclxuaW1wb3J0IHsgRmlsZVVwbG9hZE1vZGVsIH0gZnJvbSAnLi4vLi4vU2hhcmVkL01vZGVscy9GaWxlVXBsb2FkTW9kZWwnO1xyXG5pbXBvcnQgeyBNdWx0aXBsZUZpbGVVcGxvYWRNb2RlbCB9IGZyb20gJy4uLy4uL1NoYXJlZC9Nb2RlbHMvTXVsdGlwbGVGaWxlVXBsb2FkTW9kZWwnO1xyXG5pbXBvcnQgeyBDb250cm9sVmFsaWRhdGlvblNlcnZpY2UsIFV0aWxpdHlTZXJ2aWNlIH0gZnJvbSAnQGJuc2lnaHRzL2Jic2YtdXRpbGl0aWVzJztcclxuaW1wb3J0IHsgR2xvYmFsU2V0dGluZ3MgfSBmcm9tICcuLi8uLi9TaGFyZWQvc2VydmljZXMvR2xvYmFsU2V0dGluZ3Muc2VydmljZSc7XHJcbmltcG9ydCB7IEZpbGVEVE8gfSBmcm9tICcuLi8uLi9TaGFyZWQvTW9kZWxzL0ZpbGVEVE8nO1xyXG5pbXBvcnQgeyBGaWxlVXBsb2FkU2VydmljZSB9IGZyb20gJy4uLy4uL1NoYXJlZC9zZXJ2aWNlcy9maWxlLXVwbG9hZC5zZXJ2aWNlJztcclxuaW1wb3J0IHsgSHR0cEV2ZW50VHlwZSB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbi9odHRwJztcclxuaW1wb3J0IHsgU3Vic2NyaXB0aW9uIH0gZnJvbSAncnhqcyc7XHJcbmludGVyZmFjZSBGaWxlSXRlbUV4dGVuZGVkIGV4dGVuZHMgRmlsZUl0ZW0ge1xyXG4gIF9maWxlOiBGaWxlRXh0ZW5kZWQ7XHJcbn1cclxuXHJcbmludGVyZmFjZSBGaWxlRXh0ZW5kZWQgZXh0ZW5kcyBGaWxlIHtcclxuICBpRF9HVUlEPzogc3RyaW5nO1xyXG4gIGlzTmV3PzogYm9vbGVhbjtcclxuICB1cmw/OiBzdHJpbmc7XHJcbiAgcmF3RmlsZT86IEZpbGU7XHJcbn1cclxuXHJcbmludGVyZmFjZSBGaWxlVmFsaWRhdGlvblJlc3VsdCB7XHJcbiAgaXNWYWxpZDogYm9vbGVhbjtcclxuICBlcnJvcnM6IHN0cmluZ1tdO1xyXG4gIGludmFsaWRGaWxlczogRmlsZUl0ZW1bXTtcclxufVxyXG5cclxuaW50ZXJmYWNlIEZpbGVQcm9jZXNzaW5nUmVzdWx0IHtcclxuICB2YWxpZEZpbGVzOiBGaWxlSXRlbVtdO1xyXG4gIGludmFsaWRGaWxlczogRmlsZUl0ZW1bXTtcclxuICBlcnJvcnM6IHN0cmluZ1tdO1xyXG59XHJcblxyXG5pbnRlcmZhY2UgRG93bmxvYWRJbmZvIHtcclxuICB1cmw6IHN0cmluZyB8IG51bGw7XHJcbiAgZmlsZU5hbWU6IHN0cmluZztcclxufVxyXG5cclxuaW50ZXJmYWNlIFVwbG9hZFByb2dyZXNzRXZlbnQge1xyXG4gIGxvYWRlZDogbnVtYmVyO1xyXG4gIHRvdGFsOiBudW1iZXI7XHJcbiAgdHlwZTogbnVtYmVyO1xyXG59XHJcblxyXG5pbnRlcmZhY2UgVXBsb2FkQ29tcGxldGVFdmVudCB7XHJcbiAgYm9keToge1xyXG4gICAgdmFsOiBzdHJpbmc7XHJcbiAgICBkb3dubG9hZFVybD86IHN0cmluZztcclxuICB9O1xyXG4gIHR5cGU6IG51bWJlcjtcclxufVxyXG5cclxuQENvbXBvbmVudCh7XHJcbiAgc2VsZWN0b3I6ICdCQlNGLUZpbGVVcGxvYWQnLFxyXG4gIHRlbXBsYXRlVXJsOiAnLi9GaWxlVXBsb2FkLmNvbXBvbmVudC5odG1sJyxcclxuICBzdGFuZGFsb25lOiBmYWxzZVxyXG59KVxyXG5leHBvcnQgY2xhc3MgRmlsZVVwbG9hZENvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCwgQWZ0ZXJWaWV3SW5pdCwgT25EZXN0cm95IHtcclxuICBwcml2YXRlIHN0YXRpYyBjb250cm9sQ29udGFpbmVyU3RhdGljOiBDb250cm9sQ29udGFpbmVyIHwgbnVsbCA9IG51bGw7XHJcblxyXG4gIHByaXZhdGUgcmVhZG9ubHkgQllURVNfVE9fTUIgPSAxMDI0ICogMTAyNDtcclxuICBwcml2YXRlIHJlYWRvbmx5IFBST0dSRVNTX0NPTVBMRVRFID0gMTAwO1xyXG4gIHByaXZhdGUgcmVhZG9ubHkgUFJPR1JFU1NfTkVBUl9DT01QTEVURSA9IDk1O1xyXG4gIHByaXZhdGUgcmVhZG9ubHkgRVJST1JfRElTUExBWV9EVVJBVElPTiA9IDUwMDA7XHJcbiAgcHJpdmF0ZSByZWFkb25seSBNQVhfTUVNT1JZX1VTQUdFID0gMTAwICogMTAyNCAqIDEwMjQ7IC8vIDEwME1CIGxpbWl0XHJcbiAgcHJpdmF0ZSBjdXJyZW50TWVtb3J5VXNhZ2UgPSAwO1xyXG5cclxuICBAVmlld0NoaWxkKCdmaWxlSW5wdXQnLCB7IHN0YXRpYzogZmFsc2UgfSkgZmlsZUlucHV0ITogRWxlbWVudFJlZjxIVE1MSW5wdXRFbGVtZW50PjtcclxuXHJcbiAgaXNTdWJtaXR0ZWQgPSBmYWxzZTtcclxuICBASW5wdXQoKSBncm91cCE6IEZvcm1Hcm91cDtcclxuICBASW5wdXQoKSBvcHRpb25zITogRmlsZVVwbG9hZE9wdGlvbnM7XHJcbiAgQE91dHB1dCgpIE9uQ2hhbmdlID0gbmV3IEV2ZW50RW1pdHRlcjxhbnk+KCk7XHJcbiAgQE91dHB1dCgpIGlzVXBsb2FkQ29tcGxldGUgPSBuZXcgRXZlbnRFbWl0dGVyPGJvb2xlYW4+KCk7XHJcblxyXG4gIGZpbGVVcGxvYWRGb3JtQ29udHJvbCE6IEFic3RyYWN0Q29udHJvbDtcclxuICB2YWxpZGF0aW9uTWVzc2FnZSA9ICcnO1xyXG4gIHZhbGlkYXRpb25Db3VudE1lc3NhZ2UgPSAnJztcclxuICB1cGxvYWRlciE6IEZpbGVVcGxvYWRlcjtcclxuICBoYXNBbm90aGVyRHJvcFpvbmVPdmVyID0gZmFsc2U7XHJcbiAgYWNjZXB0ZWRUeXBlID0gJyc7XHJcbiAgYWNjZXB0ZWRUeXBlQXJyYXk6IHN0cmluZ1tdID0gW107XHJcbiAgdG9vbFRpcFR5cGVBcnJheTogc3RyaW5nW10gPSBbXTtcclxuICBmaWxlTGlrZU9iamVjdCE6IEZpbGVMaWtlT2JqZWN0O1xyXG4gIG1hcmtBbGxBc1RvdWNoZWQgPSBmYWxzZTtcclxuICB2YWxpZGF0aW9uUnVsZXM6IFZhbGlkYXRvckZuW10gPSBbXTtcclxuICB2YWxpZGF0aW9uUnVsZXNBc3luYzogVmFsaWRhdG9yRm5bXSA9IFtdO1xyXG4gIGZpbGVVcGxvYWRNb2RlbCE6IEZpbGVVcGxvYWRNb2RlbDtcclxuICBtdWx0aXBsZUZpbGVVcGxvYWRNb2RlbCE6IE11bHRpcGxlRmlsZVVwbG9hZE1vZGVsO1xyXG4gIGZpbGU6IEZpbGVEVE8gfCBudWxsID0gbnVsbDtcclxuICBkZWxldGVkRmlsZXM6IEZpbGVEVE9bXSA9IFtdO1xyXG4gIHByaXZhdGUgc3Vic2NyaXB0aW9ucyA9IG5ldyBTdWJzY3JpcHRpb24oKTtcclxuXHJcbiAgY29uc3RydWN0b3IoXHJcbiAgICBAT3B0aW9uYWwoKSBwcml2YXRlIGNvbnRyb2xDb250YWluZXI6IENvbnRyb2xDb250YWluZXIsXHJcbiAgICBwdWJsaWMgbXVsdGlwbGVGaWxlVXBsb2FkQ29udHJvbEhvc3Q6IEZvcm1Hcm91cERpcmVjdGl2ZSxcclxuICAgIHByaXZhdGUgY29udHJvbFV0aWxpdHk6IENvbnRyb2xVdGlsaXR5LFxyXG4gICAgcHVibGljIHV0aWxpdHlTZXJ2aWNlOiBVdGlsaXR5U2VydmljZSxcclxuICAgIHByaXZhdGUgY29udHJvbFZhbGlkYXRpb25TZXJ2aWNlOiBDb250cm9sVmFsaWRhdGlvblNlcnZpY2UsXHJcbiAgICBwcml2YXRlIGdsb2JhbFNldHRpbmdzOiBHbG9iYWxTZXR0aW5ncyxcclxuICAgIHByaXZhdGUgZmlsZVVwbG9hZFNlcnZpY2U6IEZpbGVVcGxvYWRTZXJ2aWNlXHJcbiAgKSB7XHJcbiAgICBGaWxlVXBsb2FkQ29tcG9uZW50LmNvbnRyb2xDb250YWluZXJTdGF0aWMgPSB0aGlzLmNvbnRyb2xDb250YWluZXI7XHJcbiAgICB0aGlzLmluaXRpYWxpemVVcGxvYWRlcigpO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBpbml0aWFsaXplVXBsb2FkZXIoKTogdm9pZCB7XHJcbiAgICB0aGlzLnVwbG9hZGVyID0gbmV3IEZpbGVVcGxvYWRlcih7XHJcbiAgICAgIGRpc2FibGVNdWx0aXBhcnQ6IGZhbHNlXHJcbiAgICB9IGFzIEZpbGVVcGxvYWRlck9wdGlvbnMpO1xyXG4gIH1cclxuXHJcbiAgbmdPbkluaXQoKTogdm9pZCB7XHJcbiAgICB0aGlzLmluaXRpYWxpemVNb2RlbHMoKTtcclxuICAgIHRoaXMuc2V0Vmlld1R5cGUoKTtcclxuICAgIHRoaXMucHJvY2Vzc0luaXRpYWxWYWx1ZSgpO1xyXG4gICAgdGhpcy5zZXR1cExhYmVscygpO1xyXG4gICAgdGhpcy5zZXR1cEZpbGVUeXBlVmFsaWRhdGlvbigpO1xyXG4gICAgdGhpcy5zZXR1cEZvcm1Db250cm9sKCk7XHJcbiAgICB0aGlzLnNldHVwU3Vic2NyaXB0aW9ucygpO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBpbml0aWFsaXplTW9kZWxzKCk6IHZvaWQge1xyXG4gICAgdGhpcy5maWxlVXBsb2FkTW9kZWwgPSBuZXcgRmlsZVVwbG9hZE1vZGVsKCk7XHJcbiAgICB0aGlzLm11bHRpcGxlRmlsZVVwbG9hZE1vZGVsID0gbmV3IE11bHRpcGxlRmlsZVVwbG9hZE1vZGVsKCk7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIHNldFZpZXdUeXBlKCk6IHZvaWQge1xyXG4gICAgaWYgKCF0aGlzLm9wdGlvbnMudmlld1R5cGUpIHtcclxuICAgICAgdGhpcy5vcHRpb25zLnZpZXdUeXBlID0gdGhpcy5nbG9iYWxTZXR0aW5ncy52aWV3VHlwZTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIHByaXZhdGUgcHJvY2Vzc0luaXRpYWxWYWx1ZSgpOiB2b2lkIHtcclxuXHJcbiAgICBpZiAodGhpcy5vcHRpb25zLnZhbHVlID09IG51bGwpIHtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG5cclxuICAgIGlmICh0aGlzLm9wdGlvbnMuaXNNdWx0aXBsZUZpbGUpIHtcclxuICAgICAgdGhpcy5wcm9jZXNzTXVsdGlwbGVGaWxlVmFsdWUoKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIHRoaXMucHJvY2Vzc1NpbmdsZUZpbGVWYWx1ZSgpO1xyXG4gICAgfVxyXG5cclxuICAgIHRoaXMudXBsb2FkZXIucXVldWUuZm9yRWFjaCgoZWxlbWVudCkgPT4ge1xyXG4gICAgICBlbGVtZW50LnByb2dyZXNzID0gdGhpcy5QUk9HUkVTU19DT01QTEVURTtcclxuICAgIH0pO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBwcm9jZXNzTXVsdGlwbGVGaWxlVmFsdWUoKTogdm9pZCB7XHJcbiAgICBjb25zdCBmaWxlczogRmlsZUxpa2VPYmplY3RbXSA9IFtdO1xyXG4gICAgdGhpcy5tdWx0aXBsZUZpbGVVcGxvYWRNb2RlbC5leGlzdGluZ0ZpbGVzID0gdGhpcy5vcHRpb25zLnZhbHVlLmV4aXN0aW5nRmlsZXM7XHJcbiAgICB0aGlzLm11bHRpcGxlRmlsZVVwbG9hZE1vZGVsLnVwbG9hZGVkRmlsZXMgPSBbXTtcclxuXHJcbiAgICBmb3IgKGNvbnN0IGVsZW1lbnQgb2YgdGhpcy5vcHRpb25zLnZhbHVlLmV4aXN0aW5nRmlsZXMpIHtcclxuICAgICAgY29uc3QgZmlsZUxpa2VPYmplY3QgPSB0aGlzLmNyZWF0ZUZpbGVMaWtlT2JqZWN0KGVsZW1lbnQpO1xyXG4gICAgICBmaWxlcy5wdXNoKGZpbGVMaWtlT2JqZWN0KTtcclxuICAgIH1cclxuXHJcbiAgICB0aGlzLnVwbG9hZGVyLmFkZFRvUXVldWUoZmlsZXMgYXMgYW55KTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgcHJvY2Vzc1NpbmdsZUZpbGVWYWx1ZSgpOiB2b2lkIHtcclxuICAgIGNvbnN0IGVsZW1lbnQgPSB0aGlzLm9wdGlvbnMudmFsdWUuZmlsZSA/PyB0aGlzLm9wdGlvbnMudmFsdWU7XHJcbiAgICBjb25zdCBmaWxlTGlrZU9iamVjdCA9IHRoaXMuY3JlYXRlRmlsZUxpa2VPYmplY3QoZWxlbWVudCk7XHJcbiAgICB0aGlzLmZpbGUgPSBlbGVtZW50O1xyXG4gICAgdGhpcy51cGxvYWRlci5hZGRUb1F1ZXVlKFtmaWxlTGlrZU9iamVjdF0gYXMgYW55KTtcclxuXHJcbiAgICBpZiAoIXRoaXMub3B0aW9ucy52YWx1ZS5maWxlKSB7XHJcbiAgICAgIHRoaXMuZmlsZVVwbG9hZE1vZGVsID0gbmV3IEZpbGVVcGxvYWRNb2RlbCgpO1xyXG4gICAgICB0aGlzLmZpbGVVcGxvYWRNb2RlbC5maWxlID0gdGhpcy5vcHRpb25zLnZhbHVlO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgdGhpcy5maWxlVXBsb2FkTW9kZWwgPSB0aGlzLm9wdGlvbnMudmFsdWU7XHJcbiAgICB9XHJcbiAgICB0aGlzLm9wdGlvbnMudmFsdWUgPSB0aGlzLmZpbGVVcGxvYWRNb2RlbDtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgY3JlYXRlRmlsZUxpa2VPYmplY3QoZWxlbWVudDogRmlsZURUTyk6IGFueSB7XHJcbiAgICBjb25zdCBieXRlcyA9IG5ldyBVaW50OEFycmF5KGVsZW1lbnQuYnl0ZXMpO1xyXG4gICAgY29uc3QgYmFzZTY0ID0gYnRvYShTdHJpbmcuZnJvbUNoYXJDb2RlKC4uLmJ5dGVzKSk7XHJcbiAgICByZXR1cm4ge1xyXG4gICAgICBuYW1lOiBlbGVtZW50Lm5hbWVXaXRoRXh0ZW5zaW9uIHx8IGVsZW1lbnQuZmlsZU5hbWUsXHJcbiAgICAgIHR5cGU6IGVsZW1lbnQubWltZVR5cGUgfHwgZWxlbWVudC5maWxlVHlwZSxcclxuICAgICAgcmF3RmlsZTogYmFzZTY0LFxyXG4gICAgICBzaXplOiBlbGVtZW50LmZpbGVTaXplSW5NQiA/IGVsZW1lbnQuZmlsZVNpemVJbk1CICogdGhpcy5CWVRFU19UT19NQiA6IDAsXHJcbiAgICAgIGxhc3RNb2RpZmllZERhdGU6IG5ldyBEYXRlKCksXHJcbiAgICAgIHVybDogZWxlbWVudC5mdWxsRmlsZVVSTFxyXG4gICAgfTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgc2V0dXBMYWJlbHMoKTogdm9pZCB7XHJcblxyXG4gICAgaWYgKHRoaXMub3B0aW9ucy5sYWJlbEtleSkge1xyXG4gICAgICB0aGlzLm9wdGlvbnMubGFiZWxWYWx1ZSA9IHRoaXMudXRpbGl0eVNlcnZpY2UuZ2V0UmVzb3VyY2VWYWx1ZSh0aGlzLm9wdGlvbnMubGFiZWxLZXkpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBzZXR1cEZpbGVUeXBlVmFsaWRhdGlvbigpOiB2b2lkIHtcclxuICAgIGlmICghdGhpcy5vcHRpb25zLmZpbGVVcGxvYWRBY2NlcHRzVHlwZXM/Lmxlbmd0aCkge1xyXG4gICAgICBjb25zb2xlLndhcm4oJ0ZpbGVVcGxvYWQ6IE5vIGZpbGUgdHlwZXMgc3BlY2lmaWVkIGluIGZpbGVVcGxvYWRBY2NlcHRzVHlwZXMnKTtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG5cclxuICAgIHRyeSB7XHJcbiAgICAgIHRoaXMucHJvY2Vzc0FjY2VwdGVkVHlwZXMoKTtcclxuICAgICAgdGhpcy5idWlsZFZhbGlkYXRpb25NZXNzYWdlKCk7XHJcblxyXG4gICAgICAvLyBMb2cgdGhlIHByb2Nlc3NlZCB0eXBlcyBmb3IgZGVidWdnaW5nXHJcbiAgICAgIGNvbnNvbGUubG9nKCdGaWxlVXBsb2FkOiBQcm9jZXNzZWQgZmlsZSB0eXBlczonLCB7XHJcbiAgICAgICAgb3JpZ2luYWw6IHRoaXMub3B0aW9ucy5maWxlVXBsb2FkQWNjZXB0c1R5cGVzLFxyXG4gICAgICAgIHByb2Nlc3NlZDogdGhpcy5hY2NlcHRlZFR5cGVBcnJheSxcclxuICAgICAgICBhY2NlcHRBdHRyaWJ1dGU6IHRoaXMuYWNjZXB0ZWRUeXBlLFxyXG4gICAgICAgIGRpc3BsYXlUeXBlczogdGhpcy50b29sVGlwVHlwZUFycmF5XHJcbiAgICAgIH0pO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgY29uc29sZS5lcnJvcignRmlsZVVwbG9hZDogRXJyb3IgcHJvY2Vzc2luZyBmaWxlIHR5cGVzOicsIGVycm9yKTtcclxuICAgICAgLy8gRmFsbGJhY2sgdG8gYWNjZXB0aW5nIGFsbCBmaWxlcyBpZiBwcm9jZXNzaW5nIGZhaWxzXHJcbiAgICAgIHRoaXMuYWNjZXB0ZWRUeXBlID0gJyc7XHJcbiAgICAgIHRoaXMuYWNjZXB0ZWRUeXBlQXJyYXkgPSBbXTtcclxuICAgICAgdGhpcy50b29sVGlwVHlwZUFycmF5ID0gW107XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIHByb2Nlc3NBY2NlcHRlZFR5cGVzKCk6IHZvaWQge1xyXG4gICAgLy8gUHJvY2VzcyBlYWNoIGZpbGUgdHlwZSBhbmQgZXh0cmFjdCBpbmRpdmlkdWFsIE1JTUUgdHlwZXNcclxuICAgIGNvbnN0IGFsbE1pbWVUeXBlczogc3RyaW5nW10gPSBbXTtcclxuXHJcbiAgICBmb3IgKGNvbnN0IGZpbGVUeXBlIG9mIHRoaXMub3B0aW9ucy5maWxlVXBsb2FkQWNjZXB0c1R5cGVzKSB7XHJcbiAgICAgIGlmIChmaWxlVHlwZS5pbmNsdWRlcygnLCcpKSB7XHJcbiAgICAgICAgLy8gSGFuZGxlIHR5cGVzIGxpa2UgSW1hZ2VUeXBlcyB0aGF0IGNvbnRhaW4gbXVsdGlwbGUgTUlNRSB0eXBlc1xyXG4gICAgICAgIGNvbnN0IG1pbWVUeXBlcyA9IGZpbGVUeXBlLnNwbGl0KCcsJykubWFwKHR5cGUgPT4gdHlwZS50cmltKCkpO1xyXG4gICAgICAgIGFsbE1pbWVUeXBlcy5wdXNoKC4uLm1pbWVUeXBlcyk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgLy8gU2luZ2xlIE1JTUUgdHlwZVxyXG4gICAgICAgIGFsbE1pbWVUeXBlcy5wdXNoKGZpbGVUeXBlKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIEZpbHRlciBvdXQgZW1wdHkgc3RyaW5ncyBhbmQgbm9ybWFsaXplIE1JTUUgdHlwZXNcclxuICAgIGNvbnN0IG5vcm1hbGl6ZWRNaW1lVHlwZXMgPSBhbGxNaW1lVHlwZXNcclxuICAgICAgLmZpbHRlcih0eXBlID0+IHR5cGUudHJpbSgpKVxyXG4gICAgICAubWFwKHR5cGUgPT4gdHlwZS50cmltKCkudG9Mb3dlckNhc2UoKSk7XHJcblxyXG4gICAgLy8gQ3JlYXRlIHRoZSBhY2NlcHQgYXR0cmlidXRlIHN0cmluZyBmb3IgSFRNTCBpbnB1dFxyXG4gICAgdGhpcy5hY2NlcHRlZFR5cGUgPSBub3JtYWxpemVkTWltZVR5cGVzLmpvaW4oJywnKTtcclxuXHJcbiAgICAvLyBTdG9yZSB0aGUgcHJvY2Vzc2VkIGFycmF5IGZvciB2YWxpZGF0aW9uIChrZWVwIG9yaWdpbmFsIGNhc2UgZm9yIGRpc3BsYXkpXHJcbiAgICB0aGlzLmFjY2VwdGVkVHlwZUFycmF5ID0gYWxsTWltZVR5cGVzLmZpbHRlcih0eXBlID0+IHR5cGUudHJpbSgpKTtcclxuXHJcbiAgICBjb25zdCBtaW1lVHlwZU1hcCA9IHRoaXMuZ2V0TWltZVR5cGVNYXAoKTtcclxuXHJcbiAgICBmb3IgKGNvbnN0IHR5cGUgb2YgdGhpcy5hY2NlcHRlZFR5cGVBcnJheSkge1xyXG4gICAgICBjb25zdCBkaXNwbGF5VHlwZSA9IG1pbWVUeXBlTWFwW3R5cGVdO1xyXG4gICAgICBpZiAoZGlzcGxheVR5cGUgJiYgIXRoaXMudG9vbFRpcFR5cGVBcnJheS5pbmNsdWRlcyhkaXNwbGF5VHlwZSkpIHtcclxuICAgICAgICB0aGlzLnRvb2xUaXBUeXBlQXJyYXkucHVzaChkaXNwbGF5VHlwZSk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcblxyXG4gIHByaXZhdGUgZ2V0TWltZVR5cGVNYXAoKTogUmVjb3JkPHN0cmluZywgc3RyaW5nPiB7XHJcbiAgICByZXR1cm4ge1xyXG4gICAgICAnYXBwbGljYXRpb24vcGRmJzogJ1BERicsXHJcbiAgICAgICdhcHBsaWNhdGlvbi9tc3dvcmQnOiAnV29yZCcsXHJcbiAgICAgICdhcHBsaWNhdGlvbi92bmQub3BlbnhtbGZvcm1hdHMtb2ZmaWNlZG9jdW1lbnQud29yZHByb2Nlc3NpbmdtbC5kb2N1bWVudCc6ICdXb3JkJyxcclxuICAgICAgJ2FwcGxpY2F0aW9uL3ZuZC5tcy1leGNlbCc6ICdFeGNlbCcsXHJcbiAgICAgICdhcHBsaWNhdGlvbi92bmQub3BlbnhtbGZvcm1hdHMtb2ZmaWNlZG9jdW1lbnQuc3ByZWFkc2hlZXRtbC5zaGVldCc6ICdFeGNlbCcsXHJcbiAgICAgICdhcHBsaWNhdGlvbi92bmQubXMtcG93ZXJwb2ludCc6ICdQb3dlclBvaW50JyxcclxuICAgICAgJ2FwcGxpY2F0aW9uL3ZuZC5vcGVueG1sZm9ybWF0cy1vZmZpY2Vkb2N1bWVudC5wcmVzZW50YXRpb25tbC5wcmVzZW50YXRpb24nOiAnUG93ZXJQb2ludCcsXHJcbiAgICAgICdpbWFnZS9wbmcnOiAnUE5HJyxcclxuICAgICAgJ2ltYWdlL2JtcCc6ICdCTVAnLFxyXG4gICAgICAnaW1hZ2UvanBlZyc6ICdKUEVHJyxcclxuICAgICAgJ2ltYWdlL3N2Zyt4bWwnOiAnU1ZHJyxcclxuICAgICAgJ2FwcGxpY2F0aW9uL3ppcCc6ICdaSVAnLFxyXG4gICAgICAnYXBwbGljYXRpb24veC1yYXItY29tcHJlc3NlZCc6ICdSQVInLFxyXG4gICAgICAndmlkZW8vd2VibSc6ICdXZWJNJyxcclxuICAgICAgJ3ZpZGVvL29nZyc6ICdPR0cnLFxyXG4gICAgICAndmlkZW8vbXA0JzogJ01QNCcsXHJcbiAgICAgICd2aWRlby9xdWlja3RpbWUnOiAnTU9WJyxcclxuICAgICAgJ3ZpZGVvL3gtbXN2aWRlbyc6ICdBVkknLFxyXG4gICAgICAndmlkZW8veC1tcy13bXYnOiAnV01WJyxcclxuICAgICAgJ3ZpZGVvL2F2aSc6ICdBVkknLFxyXG4gICAgICAndmlkZW8vbXBlZyc6ICdNUEVHJyxcclxuICAgICAgJ3ZpZGVvL3gtZmx2JzogJ0ZMVicsXHJcbiAgICAgICdhdWRpby9tcGVnJzogJ01QMycsXHJcbiAgICAgICd0ZXh0L3BsYWluJzogJ1R4dCcsXHJcbiAgICAgICd0ZXh0L3htbCc6ICdYTUwnLFxyXG4gICAgICAnYXBwbGljYXRpb24vanNvbic6ICdKU09OJyxcclxuICAgICAgJ2FwcGxpY2F0aW9uL29jdGV0LXN0cmVhbSc6ICdCaW5hcnknLFxyXG4gICAgICAnYXBwbGljYXRpb24vQk4nOiAnTGljZW5zZSdcclxuICAgIH07XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGJ1aWxkVmFsaWRhdGlvbk1lc3NhZ2UoKTogdm9pZCB7XHJcbiAgICBjb25zdCBtZXNzYWdlczogc3RyaW5nW10gPSBbXTtcclxuXHJcbiAgICBpZiAodGhpcy50b29sVGlwVHlwZUFycmF5Lmxlbmd0aCkge1xyXG4gICAgICBtZXNzYWdlcy5wdXNoKGAke3RoaXMudXRpbGl0eVNlcnZpY2UuZ2V0UmVzb3VyY2VWYWx1ZSgnRXh0ZW5zaW9ucycpfSAoJHt0aGlzLnRvb2xUaXBUeXBlQXJyYXkuam9pbignLCAnKX0pYCk7XHJcbiAgICB9XHJcbiAgICBpZiAodGhpcy5vcHRpb25zLmZpbGVNYXhTaXplSW5NQiA+IDApIHtcclxuICAgICAgbWVzc2FnZXMucHVzaChgJHt0aGlzLnV0aWxpdHlTZXJ2aWNlLmdldFJlc291cmNlVmFsdWUoJ0ZpbGVNYXhTaXplSW5NQicpfSR7dGhpcy5vcHRpb25zLmZpbGVNYXhTaXplSW5NQn1gKTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAodGhpcy5vcHRpb25zLm1pbk5vT2ZGaWxlcyA+IDApIHtcclxuICAgICAgbWVzc2FnZXMucHVzaChgJHt0aGlzLnV0aWxpdHlTZXJ2aWNlLmdldFJlc291cmNlVmFsdWUoJ01pbkZpbGVDb3VudFZhbGlkYXRpb25LZXknKX0ke3RoaXMub3B0aW9ucy5taW5Ob09mRmlsZXN9YCk7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKHRoaXMub3B0aW9ucy5tYXhOb09mRmlsZXMgPiAwKSB7XHJcbiAgICAgIG1lc3NhZ2VzLnB1c2goYCR7dGhpcy51dGlsaXR5U2VydmljZS5nZXRSZXNvdXJjZVZhbHVlKCdNYXhGaWxlQ291bnRWYWxpZGF0aW9uS2V5Jyl9JHt0aGlzLm9wdGlvbnMubWF4Tm9PZkZpbGVzfWApO1xyXG4gICAgfVxyXG5cclxuICAgIHRoaXMudmFsaWRhdGlvbk1lc3NhZ2UgPSBtZXNzYWdlcy5qb2luKCcgPGJyLz4gJyk7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIHNldHVwRm9ybUNvbnRyb2woKTogdm9pZCB7XHJcbiAgICB0aGlzLmdyb3VwLmFkZENvbnRyb2wodGhpcy5vcHRpb25zLm5hbWUsIG5ldyBGb3JtQ29udHJvbCgnJykpO1xyXG4gICAgdGhpcy5maWxlVXBsb2FkRm9ybUNvbnRyb2wgPSB0aGlzLmdyb3VwLmNvbnRyb2xzW3RoaXMub3B0aW9ucy5uYW1lXTtcclxuXHJcbiAgICB0aGlzLnNldHVwVmFsaWRhdG9ycygpO1xyXG4gICAgdGhpcy5zZXR1cENvdW50TWVzc2FnZSgpO1xyXG4gICAgdGhpcy5hcHBseVZhbGlkYXRvcnNBbmRTdGF0ZSgpO1xyXG4gICAgdGhpcy5maWxlVXBsb2FkRm9ybUNvbnRyb2wuc2V0VmFsdWUodGhpcy5vcHRpb25zLnZhbHVlLCB7IGVtaXRFdmVudDogZmFsc2UgfSk7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIHNldHVwVmFsaWRhdG9ycygpOiB2b2lkIHtcclxuICAgIGlmICh0aGlzLm9wdGlvbnMuY3VzdG9tVmFsaWRhdGlvbj8ubGVuZ3RoKSB7XHJcbiAgICAgIGZvciAoY29uc3QgdmFsaWRhdGlvbiBvZiB0aGlzLm9wdGlvbnMuY3VzdG9tVmFsaWRhdGlvbikge1xyXG4gICAgICAgIHRoaXMudmFsaWRhdGlvblJ1bGVzLnB1c2godmFsaWRhdGlvbi5mdW5jdGlvbkJvZHkpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKHRoaXMub3B0aW9ucy5pc1JlcXVpcmVkKSB7XHJcbiAgICAgIHRoaXMudmFsaWRhdGlvblJ1bGVzLnB1c2goVmFsaWRhdG9ycy5yZXF1aXJlZCk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIHNldHVwQ291bnRNZXNzYWdlKCk6IHZvaWQge1xyXG4gICAgaWYgKHRoaXMub3B0aW9ucy5pc011bHRpcGxlRmlsZSAmJiB0aGlzLm9wdGlvbnMubWF4Tm9PZkZpbGVzID4gMCkge1xyXG4gICAgICB0aGlzLnZhbGlkYXRpb25Db3VudE1lc3NhZ2UgPSBgJHt0aGlzLnV0aWxpdHlTZXJ2aWNlLmdldFJlc291cmNlVmFsdWUoJ01heEZpbGVzQ291bnQnKX0gOiAke3RoaXMub3B0aW9ucy5tYXhOb09mRmlsZXN9YDtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIHByaXZhdGUgYXBwbHlWYWxpZGF0b3JzQW5kU3RhdGUoKTogdm9pZCB7XHJcbiAgICB0aGlzLmZpbGVVcGxvYWRGb3JtQ29udHJvbC5zZXRWYWxpZGF0b3JzKHRoaXMudmFsaWRhdGlvblJ1bGVzKTtcclxuICAgIGlmICh0aGlzLnZhbGlkYXRpb25SdWxlc0FzeW5jLmxlbmd0aCA+IDApIHtcclxuICAgICAgdGhpcy5maWxlVXBsb2FkRm9ybUNvbnRyb2wuc2V0QXN5bmNWYWxpZGF0b3JzKHRoaXMudmFsaWRhdGlvblJ1bGVzQXN5bmMgYXMgYW55KTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAodGhpcy5vcHRpb25zLmlzRGlzYWJsZWQpIHtcclxuICAgICAgdGhpcy5maWxlVXBsb2FkRm9ybUNvbnRyb2wuZGlzYWJsZSgpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBzZXR1cFN1YnNjcmlwdGlvbnMoKTogdm9pZCB7XHJcbiAgICB0aGlzLm11bHRpcGxlRmlsZVVwbG9hZENvbnRyb2xIb3N0Lm5nU3VibWl0LnN1YnNjcmliZSgoKSA9PiB7XHJcbiAgICAgIHRoaXMuZ3JvdXAubWFya0FsbEFzVG91Y2hlZCgpO1xyXG4gICAgICB0aGlzLm1hcmtBbGxBc1RvdWNoZWQgPSB0cnVlO1xyXG4gICAgfSk7XHJcbiAgfVxyXG5cclxuICBuZ0FmdGVyVmlld0luaXQoKTogdm9pZCB7XHJcbiAgICB0aGlzLmFwcGx5QXR0cmlidXRlcygpO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBhcHBseUF0dHJpYnV0ZXMoKTogdm9pZCB7XHJcbiAgICBpZiAoIXRoaXMub3B0aW9ucy5hdHRyaWJ1dGVMaXN0Py5sZW5ndGgpIHtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0IGVsZW1lbnQgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCh0aGlzLm9wdGlvbnMubmFtZSk7XHJcbiAgICBpZiAoZWxlbWVudCkge1xyXG4gICAgICBmb3IgKGNvbnN0IGF0dHJpYnV0ZSBvZiB0aGlzLm9wdGlvbnMuYXR0cmlidXRlTGlzdCkge1xyXG4gICAgICAgIGVsZW1lbnQuc2V0QXR0cmlidXRlKGF0dHJpYnV0ZS5rZXksIGF0dHJpYnV0ZS52YWx1ZSk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcblxyXG4gIHJlc2V0RXJyb3IgPSAoKTogdm9pZCA9PiB7XHJcbiAgICB0aGlzLmNvbnRyb2xWYWxpZGF0aW9uU2VydmljZS5yZW1vdmVHbG9iYWxFcnJvcigpO1xyXG4gIH07XHJcblxyXG4gIHNob3dHbG9iYWxFcnJvcigpOiB2b2lkIHtcclxuICAgIHRoaXMuY29udHJvbFV0aWxpdHkuc2hvd0dsb2JhbEVycm9yKCk7XHJcbiAgfVxyXG5cclxuICBnZXRFcnJvclZhbGlkYXRpb24oZXJyb3JMaXN0OiBhbnkpOiBzdHJpbmcge1xyXG4gICAgaWYgKHRoaXMubWFya0FsbEFzVG91Y2hlZCAmJiB0aGlzLmdyb3VwLmludmFsaWQpIHtcclxuICAgICAgdGhpcy5zaG93R2xvYmFsRXJyb3IoKTtcclxuICAgICAgdGhpcy5tYXJrQWxsQXNUb3VjaGVkID0gZmFsc2U7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKGVycm9yTGlzdCAmJiBlcnJvckxpc3QubGVuZ3RoID4gMCkge1xyXG4gICAgICBmb3IgKGNvbnN0IGVycm9yIG9mIGVycm9yTGlzdCkge1xyXG4gICAgICAgIGlmIChlcnJvci5rZXkgPT09ICdJbnZhbGlkRmlsZXMnKSB7XHJcbiAgICAgICAgICByZXR1cm4gZXJyb3IudmFsdWU7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIHRoaXMuY29udHJvbFV0aWxpdHkuZ2V0RXJyb3JWYWxpZGF0aW9uTWFzc2FnZShlcnJvckxpc3QsIHRoaXMuZ3JvdXAsIHRoaXMub3B0aW9ucyk7XHJcbiAgfVxyXG5cclxuICBmaWxlT3ZlckFub3RoZXIoZXZlbnQ6IGFueSk6IHZvaWQge1xyXG4gICAgdGhpcy5oYXNBbm90aGVyRHJvcFpvbmVPdmVyID0gISFldmVudDtcclxuICB9XHJcblxyXG4gIGlzSGlkZUlucHV0KCk6IGJvb2xlYW4ge1xyXG4gICAgaWYgKHRoaXMub3B0aW9ucy5pc011bHRpcGxlRmlsZSkge1xyXG4gICAgICByZXR1cm4gdGhpcy5vcHRpb25zLm1heE5vT2ZGaWxlcyA+IDAgJiZcclxuICAgICAgICB0aGlzLm9wdGlvbnMubWF4Tm9PZkZpbGVzID09PSB0aGlzLnVwbG9hZGVyLnF1ZXVlLmxlbmd0aDtcclxuICAgIH1cclxuICAgIHJldHVybiB0aGlzLnVwbG9hZGVyLnF1ZXVlLmxlbmd0aCA+IDA7XHJcbiAgfVxyXG4gIG9uRmlsZUNoYW5nZSgpOiB2b2lkIHtcclxuICAgIHRoaXMudmFsaWRhdGVGaWxlQ29uc3RyYWludHMoKTtcclxuXHJcbiAgICBjb25zdCBmaWxlUHJvY2Vzc2luZ1Jlc3VsdCA9IHRoaXMucHJvY2Vzc05ld2x5QWRkZWRGaWxlcygpO1xyXG5cclxuICAgIHRoaXMuaGFuZGxlRmlsZVZhbGlkYXRpb25SZXN1bHRzKGZpbGVQcm9jZXNzaW5nUmVzdWx0KTtcclxuXHJcbiAgICB0aGlzLnByb2Nlc3NWYWxpZEZpbGVzRm9yVXBsb2FkKCk7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIHByb2Nlc3NOZXdseUFkZGVkRmlsZXMoKTogRmlsZVByb2Nlc3NpbmdSZXN1bHQge1xyXG4gICAgY29uc3QgYWRkZWRRdWV1ZSA9IHRoaXMuZ2V0TmV3bHlBZGRlZEZpbGVzKCk7XHJcbiAgICBjb25zdCB2YWxpZGF0aW9uUmVzdWx0ID0gdGhpcy52YWxpZGF0ZUZpbGVzSW5RdWV1ZShhZGRlZFF1ZXVlKTtcclxuXHJcbiAgICByZXR1cm4ge1xyXG4gICAgICB2YWxpZEZpbGVzOiBhZGRlZFF1ZXVlLmZpbHRlcihmaWxlID0+ICF2YWxpZGF0aW9uUmVzdWx0LmludmFsaWRGaWxlcy5pbmNsdWRlcyhmaWxlKSksXHJcbiAgICAgIGludmFsaWRGaWxlczogdmFsaWRhdGlvblJlc3VsdC5pbnZhbGlkRmlsZXMsXHJcbiAgICAgIGVycm9yczogdmFsaWRhdGlvblJlc3VsdC5lcnJvcnNcclxuICAgIH07XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGdldE5ld2x5QWRkZWRGaWxlcygpOiBGaWxlSXRlbVtdIHtcclxuICAgIHJldHVybiB0aGlzLnVwbG9hZGVyLnF1ZXVlLmZpbHRlcigob2JqKSA9PiBvYmpbJ3NvbWUnXT8ubGFzdE1vZGlmaWVkICE9IG51bGwpO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSB2YWxpZGF0ZUZpbGVzSW5RdWV1ZShmaWxlUXVldWU6IEZpbGVJdGVtW10pOiBGaWxlVmFsaWRhdGlvblJlc3VsdCB7XHJcbiAgICBjb25zdCB2YWxpZGF0aW9uRXJyb3JzOiBzdHJpbmdbXSA9IFtdO1xyXG4gICAgY29uc3QgaW52YWxpZEZpbGVzOiBGaWxlSXRlbVtdID0gW107XHJcbiAgICBjb25zdCBwcm9jZXNzZWREdXBsaWNhdGVOYW1lcyA9IG5ldyBTZXQ8c3RyaW5nPigpO1xyXG5cclxuICAgIGZvciAoY29uc3QgZWxlbWVudCBvZiBmaWxlUXVldWUpIHtcclxuICAgICAgY29uc3QgZmlsZSA9IGVsZW1lbnQuZmlsZTtcclxuICAgICAgaWYgKCFmaWxlKSBjb250aW51ZTtcclxuXHJcbiAgICAgIGNvbnN0IGZpbGVWYWxpZGF0aW9uID0gdGhpcy52YWxpZGF0ZVNpbmdsZUZpbGUoZmlsZSwgZWxlbWVudCwgcHJvY2Vzc2VkRHVwbGljYXRlTmFtZXMpO1xyXG5cclxuICAgICAgaWYgKCFmaWxlVmFsaWRhdGlvbi5pc1ZhbGlkKSB7XHJcbiAgICAgICAgaW52YWxpZEZpbGVzLnB1c2goZWxlbWVudCk7XHJcbiAgICAgICAgdmFsaWRhdGlvbkVycm9ycy5wdXNoKC4uLmZpbGVWYWxpZGF0aW9uLmVycm9ycyk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4ge1xyXG4gICAgICBpc1ZhbGlkOiBpbnZhbGlkRmlsZXMubGVuZ3RoID09PSAwLFxyXG4gICAgICBlcnJvcnM6IHZhbGlkYXRpb25FcnJvcnMsXHJcbiAgICAgIGludmFsaWRGaWxlc1xyXG4gICAgfTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgdmFsaWRhdGVTaW5nbGVGaWxlKGZpbGU6IEZpbGVMaWtlT2JqZWN0LCBlbGVtZW50OiBGaWxlSXRlbSwgcHJvY2Vzc2VkRHVwbGljYXRlTmFtZXM6IFNldDxzdHJpbmc+KTogRmlsZVZhbGlkYXRpb25SZXN1bHQge1xyXG4gICAgY29uc3QgZXJyb3JzOiBzdHJpbmdbXSA9IFtdO1xyXG5cclxuICAgIGNvbnN0IHNpemVWYWxpZCA9IHRoaXMudmFsaWRhdGVJbmRpdmlkdWFsRmlsZVNpemUoZmlsZSk7XHJcbiAgICBjb25zdCB0eXBlVmFsaWQgPSB0aGlzLnZhbGlkYXRlSW5kaXZpZHVhbEZpbGVUeXBlKGZpbGUpO1xyXG4gICAgY29uc3QgbmFtZVZhbGlkID0gdGhpcy52YWxpZGF0ZUR1cGxpY2F0ZUZpbGVOYW1lKGZpbGUsIGVsZW1lbnQpO1xyXG5cclxuICAgIGlmICghc2l6ZVZhbGlkKSB7XHJcbiAgICAgIGVycm9ycy5wdXNoKHRoaXMuY3JlYXRlRmlsZVNpemVFcnJvck1lc3NhZ2UoZmlsZS5uYW1lKSk7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKCF0eXBlVmFsaWQpIHtcclxuICAgICAgZXJyb3JzLnB1c2godGhpcy5jcmVhdGVGaWxlVHlwZUVycm9yTWVzc2FnZShmaWxlLm5hbWUpKTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAoIW5hbWVWYWxpZCkge1xyXG4gICAgICBjb25zdCBkdXBsaWNhdGVFcnJvciA9IHRoaXMuY3JlYXRlRHVwbGljYXRlRmlsZUVycm9yTWVzc2FnZShmaWxlLm5hbWUsIHByb2Nlc3NlZER1cGxpY2F0ZU5hbWVzKTtcclxuICAgICAgaWYgKGR1cGxpY2F0ZUVycm9yKSB7XHJcbiAgICAgICAgZXJyb3JzLnB1c2goZHVwbGljYXRlRXJyb3IpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIHtcclxuICAgICAgaXNWYWxpZDogc2l6ZVZhbGlkICYmIHR5cGVWYWxpZCAmJiBuYW1lVmFsaWQsXHJcbiAgICAgIGVycm9ycyxcclxuICAgICAgaW52YWxpZEZpbGVzOiBbXVxyXG4gICAgfTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgY3JlYXRlRmlsZVNpemVFcnJvck1lc3NhZ2UoZmlsZU5hbWU6IHN0cmluZyk6IHN0cmluZyB7XHJcbiAgICByZXR1cm4gdGhpcy51dGlsaXR5U2VydmljZS5nZXRSZXNvdXJjZVZhbHVlKCdGaWxlRXhjZWVkc01heFNpemUnKVxyXG4gICAgICAucmVwbGFjZSgne2ZpbGVOYW1lfScsIGZpbGVOYW1lKVxyXG4gICAgICAucmVwbGFjZSgne21heFNpemV9JywgdGhpcy5vcHRpb25zLmZpbGVNYXhTaXplSW5NQi50b1N0cmluZygpKTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgY3JlYXRlRmlsZVR5cGVFcnJvck1lc3NhZ2UoZmlsZU5hbWU6IHN0cmluZyk6IHN0cmluZyB7XHJcbiAgICByZXR1cm4gdGhpcy51dGlsaXR5U2VydmljZS5nZXRSZXNvdXJjZVZhbHVlKCdGaWxlVHlwZU5vdEFjY2VwdGVkJylcclxuICAgICAgLnJlcGxhY2UoJ3tmaWxlTmFtZX0nLCBmaWxlTmFtZSk7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGNyZWF0ZUR1cGxpY2F0ZUZpbGVFcnJvck1lc3NhZ2UoZmlsZU5hbWU6IHN0cmluZywgcHJvY2Vzc2VkRHVwbGljYXRlTmFtZXM6IFNldDxzdHJpbmc+KTogc3RyaW5nIHwgbnVsbCB7XHJcbiAgICBjb25zdCBmaWxlTmFtZUxvd2VyID0gZmlsZU5hbWUudG9Mb3dlckNhc2UoKTtcclxuXHJcbiAgICBpZiAocHJvY2Vzc2VkRHVwbGljYXRlTmFtZXMuaGFzKGZpbGVOYW1lTG93ZXIpKSB7XHJcbiAgICAgIHJldHVybiBudWxsO1xyXG4gICAgfVxyXG5cclxuICAgIHByb2Nlc3NlZER1cGxpY2F0ZU5hbWVzLmFkZChmaWxlTmFtZUxvd2VyKTtcclxuXHJcbiAgICBsZXQgZHVwbGljYXRlRXJyb3JNc2cgPSB0aGlzLnV0aWxpdHlTZXJ2aWNlLmdldFJlc291cmNlVmFsdWUoJ0R1cGxpY2F0ZUZpbGVOYW1lJyk7XHJcblxyXG4gICAgaWYgKCFkdXBsaWNhdGVFcnJvck1zZyB8fCBkdXBsaWNhdGVFcnJvck1zZyA9PT0gJ0R1cGxpY2F0ZUZpbGVOYW1lJykge1xyXG4gICAgICBkdXBsaWNhdGVFcnJvck1zZyA9IGBGaWxlICd7ZmlsZU5hbWV9JyBhbHJlYWR5IGV4aXN0cy4gUGxlYXNlIGNob29zZSBhIGRpZmZlcmVudCBmaWxlIG9yIHJlbmFtZSBpdC5gO1xyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiBkdXBsaWNhdGVFcnJvck1zZy5yZXBsYWNlKCd7ZmlsZU5hbWV9JywgZmlsZU5hbWUpO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBoYW5kbGVGaWxlVmFsaWRhdGlvblJlc3VsdHMocmVzdWx0OiBGaWxlUHJvY2Vzc2luZ1Jlc3VsdCk6IHZvaWQge1xyXG4gICAgaWYgKHJlc3VsdC5pbnZhbGlkRmlsZXMubGVuZ3RoID4gMCkge1xyXG4gICAgICB0aGlzLnJlbW92ZUludmFsaWRGaWxlcyhyZXN1bHQuaW52YWxpZEZpbGVzKTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAocmVzdWx0LmVycm9ycy5sZW5ndGggPiAwKSB7XHJcbiAgICAgIHRoaXMuc2hvd1ZhbGlkYXRpb25FcnJvcnMocmVzdWx0LmVycm9ycyk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIHByb2Nlc3NWYWxpZEZpbGVzRm9yVXBsb2FkKCk6IHZvaWQge1xyXG4gICAgY29uc3QgZmlsZXNBcnJheTogRmlsZURUT1tdID0gW107XHJcbiAgICBjb25zdCB2YWxpZFF1ZXVlID0gdGhpcy5nZXROZXdseUFkZGVkRmlsZXMoKTtcclxuXHJcbiAgICBmb3IgKGNvbnN0IGVsZW1lbnQgb2YgdmFsaWRRdWV1ZSkge1xyXG4gICAgICBjb25zdCBmaWxlID0gZWxlbWVudC5maWxlO1xyXG4gICAgICBpZiAoIWZpbGUpIGNvbnRpbnVlO1xyXG5cclxuICAgICAgaWYgKHRoaXMuc2hvdWxkVXNlQXN5bmNVcGxvYWQoZWxlbWVudCkpIHtcclxuICAgICAgICB0aGlzLmhhbmRsZUFzeW5jRmlsZVVwbG9hZChlbGVtZW50LCBmaWxlc0FycmF5KTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICB0aGlzLmhhbmRsZVN5bmNGaWxlVXBsb2FkKGZpbGUsIGZpbGVzQXJyYXkpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIHNob3VsZFVzZUFzeW5jVXBsb2FkKGVsZW1lbnQ6IEZpbGVJdGVtKTogYm9vbGVhbiB7XHJcbiAgICByZXR1cm4gdGhpcy5vcHRpb25zLmlzVXBsb2FkRmlsZUFzeW5jICYmICFlbGVtZW50Ll9maWxlWydpRF9HVUlEJ107XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIHZhbGlkYXRlRmlsZUNvbnN0cmFpbnRzKCk6IGJvb2xlYW4ge1xyXG4gICAgaWYgKHRoaXMub3B0aW9ucy5pc011bHRpcGxlRmlsZSkge1xyXG4gICAgICBpZiAoIXRoaXMudmFsaWRhdGVNaW5GaWxlQ291bnQoKSB8fCAhdGhpcy52YWxpZGF0ZU1heEZpbGVDb3VudCgpIHx8ICF0aGlzLnZhbGlkYXRlVG90YWxGaWxlU2l6ZSgpKSB7XHJcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgICByZXR1cm4gdHJ1ZTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgdmFsaWRhdGVNaW5GaWxlQ291bnQoKTogYm9vbGVhbiB7XHJcbiAgICBpZiAodGhpcy5vcHRpb25zLm1pbk5vT2ZGaWxlcyA+IDAgJiYgdGhpcy5vcHRpb25zLm1pbk5vT2ZGaWxlcyA+IHRoaXMudXBsb2FkZXIucXVldWUubGVuZ3RoKSB7XHJcbiAgICAgIGNvbnN0IG1pbkZpbGVNc2cgPSB0aGlzLnV0aWxpdHlTZXJ2aWNlLmdldFJlc291cmNlVmFsdWUoJ01pbmltdW1GaWxlc1JlcXVpcmVkJylcclxuICAgICAgICAucmVwbGFjZSgne2NvdW50fScsIHRoaXMub3B0aW9ucy5taW5Ob09mRmlsZXMudG9TdHJpbmcoKSk7XHJcbiAgICAgIHRoaXMuc2hvd0ZpbGVDb3VudEVycm9yKCdNaW5GaWxlQ291bnRWYWxpZGF0aW9uS2V5JywgbWluRmlsZU1zZyk7XHJcbiAgICAgIHJldHVybiBmYWxzZTtcclxuICAgIH1cclxuICAgIHJldHVybiB0cnVlO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSB2YWxpZGF0ZU1heEZpbGVDb3VudCgpOiBib29sZWFuIHtcclxuICAgIGlmICh0aGlzLm9wdGlvbnMubWF4Tm9PZkZpbGVzID4gMCAmJiB0aGlzLm9wdGlvbnMubWF4Tm9PZkZpbGVzIDwgdGhpcy51cGxvYWRlci5xdWV1ZS5sZW5ndGgpIHtcclxuICAgICAgY29uc3QgbWF4RmlsZU1zZyA9IHRoaXMudXRpbGl0eVNlcnZpY2UuZ2V0UmVzb3VyY2VWYWx1ZSgnTWF4aW11bUZpbGVzRXhjZWVkZWQnKSB8fFxyXG4gICAgICAgIGBNYXhpbXVtIHttYXhDb3VudH0gZmlsZXMgYWxsb3dlZC4gWW91IGhhdmUgc2VsZWN0ZWQge2N1cnJlbnRDb3VudH0gZmlsZXMuYDtcclxuICAgICAgY29uc3QgZmluYWxNc2cgPSBtYXhGaWxlTXNnXHJcbiAgICAgICAgLnJlcGxhY2UoJ3ttYXhDb3VudH0nLCB0aGlzLm9wdGlvbnMubWF4Tm9PZkZpbGVzLnRvU3RyaW5nKCkpXHJcbiAgICAgICAgLnJlcGxhY2UoJ3tjdXJyZW50Q291bnR9JywgdGhpcy51cGxvYWRlci5xdWV1ZS5sZW5ndGgudG9TdHJpbmcoKSk7XHJcbiAgICAgIHRoaXMuc2hvd0ZpbGVDb3VudEVycm9yKCdNYXhGaWxlQ291bnRWYWxpZGF0aW9uS2V5JywgZmluYWxNc2cpO1xyXG4gICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gdHJ1ZTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgc2hvd0ZpbGVDb3VudEVycm9yKGVycm9yS2V5OiBzdHJpbmcsIG1lc3NhZ2U6IHN0cmluZyk6IHZvaWQge1xyXG4gICAgY29uc3QgY3VycmVudEVycm9ycyA9IHRoaXMuZmlsZVVwbG9hZEZvcm1Db250cm9sLmVycm9ycyB8fCB7fTtcclxuICAgIGN1cnJlbnRFcnJvcnNbZXJyb3JLZXldID0gbWVzc2FnZTtcclxuXHJcbiAgICB0aGlzLmZpbGVVcGxvYWRGb3JtQ29udHJvbC5zZXRFcnJvcnMoY3VycmVudEVycm9ycyk7XHJcbiAgICB0aGlzLmZpbGVVcGxvYWRGb3JtQ29udHJvbC5tYXJrQXNUb3VjaGVkKCk7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGNsZWFyRmlsZUNvdW50RXJyb3IoZXJyb3JLZXk6IHN0cmluZyk6IHZvaWQge1xyXG4gICAgY29uc3QgY3VycmVudEVycm9ycyA9IHRoaXMuZmlsZVVwbG9hZEZvcm1Db250cm9sLmVycm9ycztcclxuICAgIGlmIChjdXJyZW50RXJyb3JzICYmIGN1cnJlbnRFcnJvcnNbZXJyb3JLZXldKSB7XHJcbiAgICAgIGRlbGV0ZSBjdXJyZW50RXJyb3JzW2Vycm9yS2V5XTtcclxuXHJcbiAgICAgIGlmIChPYmplY3Qua2V5cyhjdXJyZW50RXJyb3JzKS5sZW5ndGggPT09IDApIHtcclxuICAgICAgICB0aGlzLmZpbGVVcGxvYWRGb3JtQ29udHJvbC5zZXRFcnJvcnMobnVsbCk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgdGhpcy5maWxlVXBsb2FkRm9ybUNvbnRyb2wuc2V0RXJyb3JzKGN1cnJlbnRFcnJvcnMpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIHZhbGlkYXRlVG90YWxGaWxlU2l6ZSgpOiBib29sZWFuIHtcclxuICAgIGlmICh0aGlzLm9wdGlvbnMubWF4U2l6ZUZvckFsbEZpbGVzSW5NQiA+IDApIHtcclxuICAgICAgY29uc3QgdG90YWxTaXplID0gdGhpcy51cGxvYWRlci5xdWV1ZS5yZWR1Y2UoKHN1bSwgZWxlbWVudCkgPT4gc3VtICsgZWxlbWVudC5maWxlLnNpemUsIDApO1xyXG4gICAgICBjb25zdCBtYXhTaXplQnl0ZXMgPSB0aGlzLm9wdGlvbnMubWF4U2l6ZUZvckFsbEZpbGVzSW5NQiAqIHRoaXMuQllURVNfVE9fTUI7XHJcblxyXG4gICAgICBpZiAodG90YWxTaXplID4gbWF4U2l6ZUJ5dGVzKSB7XHJcbiAgICAgICAgdGhpcy5zaG93VG90YWxTaXplRXJyb3IoKTtcclxuICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICAgIHJldHVybiB0cnVlO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBzaG93VG90YWxTaXplRXJyb3IoKTogdm9pZCB7XHJcbiAgICBjb25zdCB0b3RhbFNpemVNc2cgPSB0aGlzLnV0aWxpdHlTZXJ2aWNlLmdldFJlc291cmNlVmFsdWUoJ1RvdGFsRmlsZVNpemVFeGNlZWRlZCcpXHJcbiAgICAgIC5yZXBsYWNlKCd7bWF4U2l6ZX0nLCB0aGlzLm9wdGlvbnMubWF4U2l6ZUZvckFsbEZpbGVzSW5NQi50b1N0cmluZygpKTtcclxuXHJcbiAgICBjb25zdCBjdXJyZW50RXJyb3JzID0gdGhpcy5maWxlVXBsb2FkRm9ybUNvbnRyb2wuZXJyb3JzIHx8IHt9O1xyXG4gICAgY3VycmVudEVycm9yc1snTWF4U2l6ZUZvckFsbEZpbGVzSW5NQiddID0gdG90YWxTaXplTXNnO1xyXG5cclxuICAgIHRoaXMuZmlsZVVwbG9hZEZvcm1Db250cm9sLnNldEVycm9ycyhjdXJyZW50RXJyb3JzKTtcclxuICAgIHRoaXMuZmlsZVVwbG9hZEZvcm1Db250cm9sLm1hcmtBc1RvdWNoZWQoKTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgdmFsaWRhdGVGaWxlU2l6ZShmaWxlOiBGaWxlTGlrZU9iamVjdCk6IGJvb2xlYW4ge1xyXG4gICAgY29uc3QgbWF4RmlsZVNpemUgPSB0aGlzLm9wdGlvbnMuZmlsZU1heFNpemVJbk1CICogdGhpcy5CWVRFU19UT19NQjtcclxuICAgIGlmIChmaWxlLnNpemUgPiBtYXhGaWxlU2l6ZSkge1xyXG4gICAgICB0aGlzLnNldEZvcm1Db250cm9sRXJyb3IoJ0ZpbGVNYXhTaXplSW5NQicsIGAke3RoaXMub3B0aW9ucy5maWxlTWF4U2l6ZUluTUJ9TUJgKTtcclxuICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIHRydWU7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIHZhbGlkYXRlRmlsZVR5cGUoZmlsZTogRmlsZUxpa2VPYmplY3QpOiBib29sZWFuIHtcclxuICAgIGlmICh0aGlzLm9wdGlvbnMuZmlsZVVwbG9hZEFjY2VwdHNUeXBlcz8ubGVuZ3RoKSB7XHJcbiAgICAgIGNvbnN0IGZpbGVUeXBlID0gZmlsZS50eXBlO1xyXG4gICAgICBjb25zdCBpc0FjY2VwdGVkID0gdGhpcy5hY2NlcHRlZFR5cGVBcnJheS5zb21lKHR5cGUgPT5cclxuICAgICAgICB0eXBlLnRvTG93ZXJDYXNlKCkgPT09IGZpbGVUeXBlLnRvTG93ZXJDYXNlKClcclxuICAgICAgKTtcclxuXHJcbiAgICAgIGlmICghaXNBY2NlcHRlZCkge1xyXG4gICAgICAgIHRoaXMuc2V0Rm9ybUNvbnRyb2xFcnJvcignVG9vbFRpcFR5cGVFcnJvcicsIHRoaXMudG9vbFRpcFR5cGVBcnJheSk7XHJcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgICByZXR1cm4gdHJ1ZTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgdmFsaWRhdGVJbmRpdmlkdWFsRmlsZVNpemUoZmlsZTogRmlsZUxpa2VPYmplY3QpOiBib29sZWFuIHtcclxuICAgIGNvbnN0IG1heEZpbGVTaXplID0gdGhpcy5vcHRpb25zLmZpbGVNYXhTaXplSW5NQiAqIHRoaXMuQllURVNfVE9fTUI7XHJcbiAgICByZXR1cm4gZmlsZS5zaXplIDw9IG1heEZpbGVTaXplO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSB2YWxpZGF0ZUluZGl2aWR1YWxGaWxlVHlwZShmaWxlOiBGaWxlTGlrZU9iamVjdCk6IGJvb2xlYW4ge1xyXG4gICAgaWYgKCF0aGlzLm9wdGlvbnMuZmlsZVVwbG9hZEFjY2VwdHNUeXBlcz8ubGVuZ3RoKSB7XHJcbiAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0IGZpbGVUeXBlID0gZmlsZS50eXBlPy50b0xvd2VyQ2FzZSgpO1xyXG4gICAgaWYgKCFmaWxlVHlwZSkge1xyXG4gICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIHRoaXMuYWNjZXB0ZWRUeXBlQXJyYXkuc29tZSh0eXBlID0+XHJcbiAgICAgIHR5cGUudG9Mb3dlckNhc2UoKSA9PT0gZmlsZVR5cGVcclxuICAgICk7XHJcbiAgfVxyXG5cclxuXHJcbiAgcHJpdmF0ZSB2YWxpZGF0ZUR1cGxpY2F0ZUZpbGVOYW1lKGZpbGU6IEZpbGVMaWtlT2JqZWN0LCBjdXJyZW50RWxlbWVudDogRmlsZUl0ZW0pOiBib29sZWFuIHtcclxuICAgIGlmICghZmlsZT8ubmFtZSkge1xyXG4gICAgICByZXR1cm4gdHJ1ZTtcclxuICAgIH1cclxuXHJcbiAgICBjb25zdCBjdXJyZW50RmlsZU5hbWUgPSBmaWxlLm5hbWUudG9Mb3dlckNhc2UoKTtcclxuXHJcbiAgICBjb25zdCBleGlzdGluZ0ZpbGVzID0gdGhpcy51cGxvYWRlci5xdWV1ZS5maWx0ZXIoaXRlbSA9PiBpdGVtICE9PSBjdXJyZW50RWxlbWVudCk7XHJcbiAgICBjb25zdCBkdXBsaWNhdGVFeGlzdHMgPSBleGlzdGluZ0ZpbGVzLnNvbWUoaXRlbSA9PiB7XHJcbiAgICAgIGNvbnN0IGV4aXN0aW5nRmlsZU5hbWUgPSBpdGVtLmZpbGU/Lm5hbWUgfHwgaXRlbS5fZmlsZT8ubmFtZTtcclxuICAgICAgcmV0dXJuIGV4aXN0aW5nRmlsZU5hbWUgJiYgZXhpc3RpbmdGaWxlTmFtZS50b0xvd2VyQ2FzZSgpID09PSBjdXJyZW50RmlsZU5hbWU7XHJcbiAgICB9KTtcclxuXHJcbiAgICBpZiAoZHVwbGljYXRlRXhpc3RzKSB7XHJcbiAgICAgIHJldHVybiBmYWxzZTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAodGhpcy5vcHRpb25zLnZhbHVlKSB7XHJcbiAgICAgIGNvbnN0IHVwbG9hZGVkRmlsZXMgPSBBcnJheS5pc0FycmF5KHRoaXMub3B0aW9ucy52YWx1ZSkgPyB0aGlzLm9wdGlvbnMudmFsdWUgOiBbdGhpcy5vcHRpb25zLnZhbHVlXTtcclxuICAgICAgY29uc3QgZHVwbGljYXRlSW5VcGxvYWRlZCA9IHVwbG9hZGVkRmlsZXMuc29tZSh1cGxvYWRlZEZpbGUgPT4ge1xyXG4gICAgICAgIGNvbnN0IHVwbG9hZGVkRmlsZU5hbWUgPSB1cGxvYWRlZEZpbGU/LmZpbGVOYW1lIHx8IHVwbG9hZGVkRmlsZT8ubmFtZTtcclxuICAgICAgICByZXR1cm4gdXBsb2FkZWRGaWxlTmFtZSAmJiB1cGxvYWRlZEZpbGVOYW1lLnRvTG93ZXJDYXNlKCkgPT09IGN1cnJlbnRGaWxlTmFtZTtcclxuICAgICAgfSk7XHJcblxyXG4gICAgICByZXR1cm4gIWR1cGxpY2F0ZUluVXBsb2FkZWQ7XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIHRydWU7XHJcbiAgfVxyXG5cclxuXHJcblxyXG4gIHByaXZhdGUgcmVtb3ZlSW52YWxpZEZpbGVzKGludmFsaWRGaWxlczogRmlsZUl0ZW1bXSk6IHZvaWQge1xyXG4gICAgaW52YWxpZEZpbGVzLmZvckVhY2goaW52YWxpZEZpbGUgPT4ge1xyXG4gICAgICBjb25zdCBpbmRleCA9IHRoaXMudXBsb2FkZXIucXVldWUuaW5kZXhPZihpbnZhbGlkRmlsZSk7XHJcbiAgICAgIGlmIChpbmRleCA+IC0xKSB7XHJcbiAgICAgICAgdGhpcy51cGxvYWRlci5xdWV1ZS5zcGxpY2UoaW5kZXgsIDEpO1xyXG4gICAgICB9XHJcbiAgICB9KTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgc2hvd1ZhbGlkYXRpb25FcnJvcnMoZXJyb3JzOiBzdHJpbmdbXSk6IHZvaWQge1xyXG4gICAgaWYgKGVycm9ycy5sZW5ndGggPT09IDApIHJldHVybjtcclxuXHJcbiAgICBjb25zdCBlcnJvck1lc3NhZ2UgPSBlcnJvcnMuam9pbignPGJyLz4nKTtcclxuXHJcbiAgICB0aGlzLnNldFZhbGlkYXRpb25FcnJvcignSW52YWxpZEZpbGVzJywgZXJyb3JNZXNzYWdlKTtcclxuICAgIHNldFRpbWVvdXQoKCkgPT4ge1xyXG4gICAgICB0aGlzLmNsZWFySW52YWxpZEZpbGVzRXJyb3IoKTtcclxuICAgIH0sIHRoaXMuRVJST1JfRElTUExBWV9EVVJBVElPTik7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIHNldFZhbGlkYXRpb25FcnJvcihlcnJvcktleTogc3RyaW5nLCBlcnJvck1lc3NhZ2U6IHN0cmluZyk6IHZvaWQge1xyXG4gICAgY29uc3QgY3VycmVudEVycm9ycyA9IHRoaXMuZmlsZVVwbG9hZEZvcm1Db250cm9sLmVycm9ycyB8fCB7fTtcclxuICAgIGN1cnJlbnRFcnJvcnNbZXJyb3JLZXldID0gZXJyb3JNZXNzYWdlO1xyXG5cclxuICAgIHRoaXMuZmlsZVVwbG9hZEZvcm1Db250cm9sLnNldEVycm9ycyhjdXJyZW50RXJyb3JzKTtcclxuICAgIHRoaXMuZmlsZVVwbG9hZEZvcm1Db250cm9sLm1hcmtBc1RvdWNoZWQoKTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgY2xlYXJJbnZhbGlkRmlsZXNFcnJvcigpOiB2b2lkIHtcclxuICAgIGNvbnN0IGN1cnJlbnRFcnJvcnMgPSB0aGlzLmZpbGVVcGxvYWRGb3JtQ29udHJvbC5lcnJvcnM7XHJcbiAgICBpZiAoY3VycmVudEVycm9ycyAmJiBjdXJyZW50RXJyb3JzWydJbnZhbGlkRmlsZXMnXSkge1xyXG4gICAgICBkZWxldGUgY3VycmVudEVycm9yc1snSW52YWxpZEZpbGVzJ107XHJcblxyXG4gICAgICBpZiAoT2JqZWN0LmtleXMoY3VycmVudEVycm9ycykubGVuZ3RoID09PSAwKSB7XHJcbiAgICAgICAgdGhpcy5maWxlVXBsb2FkRm9ybUNvbnRyb2wuc2V0RXJyb3JzKG51bGwpO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIHRoaXMuZmlsZVVwbG9hZEZvcm1Db250cm9sLnNldEVycm9ycyhjdXJyZW50RXJyb3JzKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBzZXRGb3JtQ29udHJvbEVycm9yKGVycm9yS2V5OiBzdHJpbmcsIGVycm9yVmFsdWU6IGFueSk6IHZvaWQge1xyXG4gICAgdGhpcy5maWxlVXBsb2FkRm9ybUNvbnRyb2wuc2V0RXJyb3JzKHsgW2Vycm9yS2V5XTogZXJyb3JWYWx1ZSB9KTtcclxuICAgIHRoaXMuZmlsZVVwbG9hZEZvcm1Db250cm9sLm1hcmtBc1RvdWNoZWQoKTtcclxuICAgIHRoaXMudXBsb2FkZXIucXVldWUgPSBbXTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgaGFuZGxlQXN5bmNGaWxlVXBsb2FkKGVsZW1lbnQ6IEZpbGVJdGVtLCBmaWxlc0FycmF5OiBGaWxlRFRPW10pOiB2b2lkIHtcclxuICAgIGNvbnN0IHVwbG9hZFN1YnNjcmlwdGlvbiA9IHRoaXMuZmlsZVVwbG9hZFNlcnZpY2UudXBsb2FkRmlsZShlbGVtZW50Ll9maWxlKS5zdWJzY3JpYmUoe1xyXG4gICAgICBuZXh0OiAoZXZlbnQ6IGFueSkgPT4ge1xyXG4gICAgICAgIGlmIChldmVudC50eXBlID09PSBIdHRwRXZlbnRUeXBlLlVwbG9hZFByb2dyZXNzKSB7XHJcbiAgICAgICAgICB0aGlzLmhhbmRsZVVwbG9hZFByb2dyZXNzKGVsZW1lbnQsIGV2ZW50KTtcclxuICAgICAgICB9IGVsc2UgaWYgKGV2ZW50LnR5cGUgPT09IEh0dHBFdmVudFR5cGUuUmVzcG9uc2UpIHtcclxuICAgICAgICAgIHRoaXMuaGFuZGxlVXBsb2FkQ29tcGxldGUoZWxlbWVudCwgZXZlbnQsIGZpbGVzQXJyYXkpO1xyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgZXJyb3I6IChlcnJvcikgPT4ge1xyXG4gICAgICAgIGNvbnNvbGUuZXJyb3IoJ1VwbG9hZCBmYWlsZWQ6JywgZXJyb3IpO1xyXG4gICAgICAgIC8vIEhhbmRsZSB1cGxvYWQgZXJyb3IgLSB5b3UgY2FuIGFkZCBjdXN0b20gZXJyb3IgaGFuZGxpbmcgaGVyZVxyXG4gICAgICB9XHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBTdG9yZSBzdWJzY3JpcHRpb24gZm9yIGNsZWFudXBcclxuICAgIHRoaXMuc3Vic2NyaXB0aW9ucy5hZGQodXBsb2FkU3Vic2NyaXB0aW9uKTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgaGFuZGxlVXBsb2FkUHJvZ3Jlc3MoZWxlbWVudDogRmlsZUl0ZW0sIGV2ZW50OiBVcGxvYWRQcm9ncmVzc0V2ZW50KTogdm9pZCB7XHJcbiAgICBjb25zdCBxdWV1ZUluZGV4ID0gdGhpcy51cGxvYWRlci5xdWV1ZS5maW5kSW5kZXgoKGZpbGUpID0+IGZpbGUgPT09IGVsZW1lbnQpO1xyXG4gICAgaWYgKHF1ZXVlSW5kZXggPT09IC0xKSByZXR1cm47XHJcblxyXG4gICAgY29uc3QgcHJvZ3Jlc3MgPSBNYXRoLnJvdW5kKCgxMDAgKiBldmVudC5sb2FkZWQpIC8gZXZlbnQudG90YWwpO1xyXG4gICAgdGhpcy51cGxvYWRlci5xdWV1ZVtxdWV1ZUluZGV4XS5wcm9ncmVzcyA9XHJcbiAgICAgIHByb2dyZXNzID49IHRoaXMuUFJPR1JFU1NfTkVBUl9DT01QTEVURSA/IHRoaXMuUFJPR1JFU1NfTkVBUl9DT01QTEVURSA6IHByb2dyZXNzO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBoYW5kbGVVcGxvYWRDb21wbGV0ZShlbGVtZW50OiBGaWxlSXRlbSwgZXZlbnQ6IFVwbG9hZENvbXBsZXRlRXZlbnQsIGZpbGVzQXJyYXk6IEZpbGVEVE9bXSk6IHZvaWQge1xyXG4gICAgY29uc3QgcXVldWVJbmRleCA9IHRoaXMudXBsb2FkZXIucXVldWUuZmluZEluZGV4KChmaWxlKSA9PiBmaWxlID09PSBlbGVtZW50KTtcclxuICAgIGlmIChxdWV1ZUluZGV4ID09PSAtMSkgcmV0dXJuO1xyXG5cclxuICAgIHRoaXMudXBsb2FkZXIucXVldWVbcXVldWVJbmRleF0ucHJvZ3Jlc3MgPSB0aGlzLlBST0dSRVNTX0NPTVBMRVRFO1xyXG5cclxuICAgIGNvbnN0IGZpbGVJRCA9IGV2ZW50LmJvZHkudmFsO1xyXG4gICAgdGhpcy51cGRhdGVFbGVtZW50V2l0aEZpbGVJbmZvKGVsZW1lbnQsIGZpbGVJRCwgZXZlbnQuYm9keS5kb3dubG9hZFVybCk7XHJcblxyXG4gICAgY29uc3QgYWRkZWRGaWxlID0gdGhpcy5jcmVhdGVGaWxlRFRPKGVsZW1lbnQsIGZpbGVJRCwgZXZlbnQuYm9keS5kb3dubG9hZFVybCk7XHJcbiAgICB0aGlzLnVwZGF0ZUZvcm1WYWx1ZShhZGRlZEZpbGUsIGZpbGVzQXJyYXkpO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSB1cGRhdGVFbGVtZW50V2l0aEZpbGVJbmZvKGVsZW1lbnQ6IEZpbGVJdGVtLCBmaWxlSUQ6IHN0cmluZywgZG93bmxvYWRVcmw/OiBzdHJpbmcpOiB2b2lkIHtcclxuICAgIGVsZW1lbnQuX2ZpbGVbJ2lEX0dVSUQnXSA9IGZpbGVJRDtcclxuICAgIGVsZW1lbnQuX2ZpbGVbJ2lzTmV3J10gPSB0cnVlO1xyXG5cclxuICAgIGlmIChkb3dubG9hZFVybCkge1xyXG4gICAgICBlbGVtZW50Ll9maWxlWyd1cmwnXSA9IGRvd25sb2FkVXJsO1xyXG4gICAgICAoZWxlbWVudC5maWxlIGFzIGFueSkudXJsID0gZG93bmxvYWRVcmw7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGNyZWF0ZUZpbGVEVE8oZWxlbWVudDogRmlsZUl0ZW0sIGZpbGVJRDogc3RyaW5nLCBkb3dubG9hZFVybD86IHN0cmluZyk6IEZpbGVEVE8ge1xyXG4gICAgcmV0dXJuIHtcclxuICAgICAgaURfR1VJRDogZmlsZUlELFxyXG4gICAgICBmaWxlTmFtZTogZWxlbWVudC5fZmlsZVsnbmFtZSddLFxyXG4gICAgICBmaWxlVHlwZTogZWxlbWVudC5fZmlsZVsndHlwZSddLFxyXG4gICAgICBpc05ldzogdHJ1ZSxcclxuICAgICAgZmlsZUJhc2U2NDogJycsXHJcbiAgICAgIGZpbGVTaXplSW5NQjogZWxlbWVudC5fZmlsZS5zaXplIC8gdGhpcy5CWVRFU19UT19NQixcclxuICAgICAgbmFtZVdpdGhFeHRlbnNpb246IGVsZW1lbnQuX2ZpbGVbJ25hbWUnXSxcclxuICAgICAgZnVsbEZpbGVVUkw6IGRvd25sb2FkVXJsIHx8IG51bGxcclxuICAgIH07XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGhhbmRsZVN5bmNGaWxlVXBsb2FkKGZpbGU6IEZpbGVMaWtlT2JqZWN0LCBmaWxlc0FycmF5OiBGaWxlRFRPW10pOiB2b2lkIHtcclxuICAgIHRoaXMudHJhY2tNZW1vcnlVc2FnZShmaWxlLnNpemUpO1xyXG4gICAgY29uc3QgcmVhZGVyID0gbmV3IEZpbGVSZWFkZXIoKTtcclxuXHJcbiAgICAvLyBTdG9yZSByZWFkZXIgcmVmZXJlbmNlIGZvciBjbGVhbnVwXHJcbiAgICBjb25zdCByZWFkZXJSZWYgPSByZWFkZXI7XHJcblxyXG4gICAgcmVhZGVyLm9ubG9hZCA9ICgpID0+IHtcclxuICAgICAgdHJ5IHtcclxuICAgICAgICBjb25zdCBleGlzdGluZ0dVSUQgPSB0aGlzLmdldEV4aXN0aW5nRmlsZUdVSUQoZmlsZSk7XHJcbiAgICAgICAgdGhpcy51cGRhdGVRdWV1ZUl0ZW1Gb3JTeW5jKGZpbGUpO1xyXG5cclxuICAgICAgICBjb25zdCBhZGRlZEZpbGUgPSB0aGlzLmNyZWF0ZVN5bmNGaWxlRFRPKGZpbGUsIHJlYWRlci5yZXN1bHQgYXMgc3RyaW5nLCBleGlzdGluZ0dVSUQpO1xyXG4gICAgICAgIHRoaXMudXBkYXRlRm9ybVZhbHVlKGFkZGVkRmlsZSwgZmlsZXNBcnJheSk7XHJcbiAgICAgICAgdGhpcy5oYW5kbGVQYXRjaEFuZEVtaXQoKTtcclxuICAgICAgfSBmaW5hbGx5IHtcclxuICAgICAgICAvLyBDbGVhbiB1cCByZWFkZXJcclxuICAgICAgICByZWFkZXJSZWYub25sb2FkID0gbnVsbDtcclxuICAgICAgICByZWFkZXJSZWYub25lcnJvciA9IG51bGw7XHJcbiAgICAgICAgcmVhZGVyUmVmLm9uYWJvcnQgPSBudWxsO1xyXG4gICAgICB9XHJcbiAgICB9O1xyXG5cclxuICAgIHJlYWRlci5vbmVycm9yID0gKCkgPT4ge1xyXG4gICAgICBjb25zb2xlLmVycm9yKCdGaWxlIHJlYWRpbmcgZmFpbGVkJyk7XHJcbiAgICAgIHJlYWRlclJlZi5vbmxvYWQgPSBudWxsO1xyXG4gICAgICByZWFkZXJSZWYub25lcnJvciA9IG51bGw7XHJcbiAgICAgIHJlYWRlclJlZi5vbmFib3J0ID0gbnVsbDtcclxuICAgIH07XHJcblxyXG4gICAgcmVhZGVyLnJlYWRBc0RhdGFVUkwoZmlsZS5yYXdGaWxlIGFzIEZpbGUpO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSB1cGRhdGVRdWV1ZUl0ZW1Gb3JTeW5jKGZpbGU6IEZpbGVMaWtlT2JqZWN0KTogdm9pZCB7XHJcbiAgICBjb25zdCBxdWV1ZUl0ZW0gPSB0aGlzLmZpbmRRdWV1ZUl0ZW1CeUZpbGUoZmlsZSk7XHJcblxyXG4gICAgaWYgKHF1ZXVlSXRlbSkge1xyXG4gICAgICB0aGlzLnByZXNlcnZlRmlsZVJlZmVyZW5jZShxdWV1ZUl0ZW0sIGZpbGUpO1xyXG4gICAgICBxdWV1ZUl0ZW0ucHJvZ3Jlc3MgPSB0aGlzLlBST0dSRVNTX0NPTVBMRVRFO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBmaW5kUXVldWVJdGVtQnlGaWxlKGZpbGU6IEZpbGVMaWtlT2JqZWN0KTogRmlsZUl0ZW0gfCB1bmRlZmluZWQge1xyXG4gICAgcmV0dXJuIHRoaXMudXBsb2FkZXIucXVldWUuZmluZChpdGVtID0+XHJcbiAgICAgIGl0ZW0uZmlsZS5uYW1lID09PSBmaWxlLm5hbWUgJiYgaXRlbS5maWxlLnNpemUgPT09IGZpbGUuc2l6ZVxyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgcHJlc2VydmVGaWxlUmVmZXJlbmNlKHF1ZXVlSXRlbTogRmlsZUl0ZW0sIGZpbGU6IEZpbGVMaWtlT2JqZWN0KTogdm9pZCB7XHJcbiAgICAocXVldWVJdGVtLl9maWxlIGFzIGFueSkucmF3RmlsZSA9IGZpbGUucmF3RmlsZTtcclxuICAgIChxdWV1ZUl0ZW0uZmlsZSBhcyBhbnkpLnJhd0ZpbGUgPSBmaWxlLnJhd0ZpbGU7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGNyZWF0ZVN5bmNGaWxlRFRPKGZpbGU6IEZpbGVMaWtlT2JqZWN0LCByZWFkZXJSZXN1bHQ6IHN0cmluZywgZXhpc3RpbmdHVUlEOiBzdHJpbmcgfCBudWxsKTogRmlsZURUTyB7XHJcbiAgICByZXR1cm4ge1xyXG4gICAgICBmaWxlTmFtZTogZmlsZS5uYW1lLFxyXG4gICAgICBmaWxlVHlwZTogZmlsZS50eXBlLFxyXG4gICAgICBmaWxlQmFzZTY0OiByZWFkZXJSZXN1bHQuc3BsaXQoJywnKVsxXSxcclxuICAgICAgZmlsZVNpemVJbk1COiBmaWxlLnNpemUgLyB0aGlzLkJZVEVTX1RPX01CLFxyXG4gICAgICBuYW1lV2l0aEV4dGVuc2lvbjogZmlsZS5uYW1lLFxyXG4gICAgICBpRF9HVUlEOiBleGlzdGluZ0dVSUQsXHJcbiAgICAgIGlzTmV3OiB0cnVlLFxyXG4gICAgICBmdWxsRmlsZVVSTDogbnVsbFxyXG4gICAgfTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgZ2V0RXhpc3RpbmdGaWxlR1VJRChmaWxlOiBGaWxlTGlrZU9iamVjdCk6IHN0cmluZyB8IG51bGwge1xyXG4gICAgaWYgKCF0aGlzLm9wdGlvbnMuaXNNdWx0aXBsZUZpbGUgJiYgdGhpcy5maWxlKSB7XHJcbiAgICAgIHJldHVybiB0aGlzLmZpbGUubmFtZVdpdGhFeHRlbnNpb24gPT09IGZpbGUubmFtZSA/IHRoaXMuZmlsZS5pRF9HVUlEIDogbnVsbDtcclxuICAgIH1cclxuICAgIHJldHVybiBudWxsO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSB1cGRhdGVGb3JtVmFsdWUoYWRkZWRGaWxlOiBGaWxlRFRPLCBmaWxlc0FycmF5OiBGaWxlRFRPW10pOiB2b2lkIHtcclxuICAgIGlmICghdGhpcy5vcHRpb25zLmlzTXVsdGlwbGVGaWxlKSB7XHJcbiAgICAgIHRoaXMuZmlsZVVwbG9hZE1vZGVsID0gbmV3IEZpbGVVcGxvYWRNb2RlbCgpO1xyXG4gICAgICB0aGlzLmZpbGVVcGxvYWRNb2RlbC5maWxlID0gYWRkZWRGaWxlO1xyXG4gICAgICB0aGlzLnVwZGF0ZUZvcm1Db250cm9sKHRoaXMuZmlsZVVwbG9hZE1vZGVsKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIGZpbGVzQXJyYXkucHVzaChhZGRlZEZpbGUpO1xyXG4gICAgICB0aGlzLm11bHRpcGxlRmlsZVVwbG9hZE1vZGVsLnVwbG9hZGVkRmlsZXMgPSBmaWxlc0FycmF5O1xyXG4gICAgICB0aGlzLnNldHVwTXVsdGlwbGVGaWxlTW9kZWwoKTtcclxuICAgICAgdGhpcy51cGRhdGVGb3JtQ29udHJvbCh0aGlzLm11bHRpcGxlRmlsZVVwbG9hZE1vZGVsKTtcclxuICAgICAgdGhpcy5pc1VwbG9hZENvbXBsZXRlLmVtaXQodHJ1ZSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIHNldHVwTXVsdGlwbGVGaWxlTW9kZWwoKTogdm9pZCB7XHJcbiAgICBpZiAodGhpcy5vcHRpb25zLnZhbHVlPy5jb3JyZWxhdGlvbklEX0dVSUQgPT0gbnVsbCkge1xyXG4gICAgICB0aGlzLm11bHRpcGxlRmlsZVVwbG9hZE1vZGVsLnJlbW92ZWRGaWxlcyA9IFtdO1xyXG4gICAgfVxyXG4gICAgdGhpcy5tdWx0aXBsZUZpbGVVcGxvYWRNb2RlbC5jb3JyZWxhdGlvbklEX0dVSUQgPSB0aGlzLm9wdGlvbnMudmFsdWU/LmNvcnJlbGF0aW9uSURfR1VJRDtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgdXBkYXRlRm9ybUNvbnRyb2wodmFsdWU6IEZpbGVVcGxvYWRNb2RlbCB8IE11bHRpcGxlRmlsZVVwbG9hZE1vZGVsKTogdm9pZCB7XHJcbiAgICB0aGlzLnByZXNlcnZlRXJyb3JzQW5kVXBkYXRlVmFsdWUodmFsdWUpO1xyXG4gICAgdGhpcy5vcHRpb25zLnZhbHVlID0gdmFsdWU7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIHByZXNlcnZlRXJyb3JzQW5kVXBkYXRlVmFsdWUodmFsdWU6IEZpbGVVcGxvYWRNb2RlbCB8IE11bHRpcGxlRmlsZVVwbG9hZE1vZGVsKTogdm9pZCB7XHJcbiAgICBjb25zdCBjdXJyZW50RXJyb3JzID0gdGhpcy5maWxlVXBsb2FkRm9ybUNvbnRyb2wuZXJyb3JzO1xyXG5cclxuICAgIHRoaXMuZmlsZVVwbG9hZEZvcm1Db250cm9sLnNldFZhbHVlKHZhbHVlLCB7IGVtaXRFdmVudDogZmFsc2UgfSk7XHJcbiAgICB0aGlzLmdyb3VwLmdldCh0aGlzLm9wdGlvbnMubmFtZSk/LnNldFZhbHVlKHZhbHVlLCB7IGVtaXRFdmVudDogZmFsc2UgfSk7XHJcbiAgICBpZiAoY3VycmVudEVycm9ycykge1xyXG4gICAgICB0aGlzLmZpbGVVcGxvYWRGb3JtQ29udHJvbC5zZXRFcnJvcnMoY3VycmVudEVycm9ycyk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGhhbmRsZVBhdGNoQW5kRW1pdCgpOiB2b2lkIHtcclxuICAgIGNvbnN0IG9yaWdpbmFsVmFsdWUgPSB0aGlzLmdyb3VwLmdldCh0aGlzLm9wdGlvbnMubmFtZSk/LnZhbHVlO1xyXG5cclxuICAgIGlmICh0aGlzLm9wdGlvbnMucGF0Y2hGdW5jdGlvbiAmJiB0aGlzLm9wdGlvbnMucGF0Y2hQYXRoICYmIHRoaXMuZ3JvdXAuZ2V0KHRoaXMub3B0aW9ucy5uYW1lKT8udmFsaWQpIHtcclxuICAgICAgdGhpcy5jb250cm9sVXRpbGl0eS5wYXRjaENvbnRyb2xWYWx1ZShcclxuICAgICAgICBvcmlnaW5hbFZhbHVlLFxyXG4gICAgICAgIHRoaXMub3B0aW9ucy5wYXRjaEZ1bmN0aW9uLFxyXG4gICAgICAgIHRoaXMub3B0aW9ucy5wYXRjaFBhdGhcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICB0aGlzLk9uQ2hhbmdlLmVtaXQob3JpZ2luYWxWYWx1ZSk7XHJcbiAgfVxyXG4gIHJlbW92ZUZyb21Db250cm9sVmFsdWUoaXRlbTogRmlsZUl0ZW0pOiB2b2lkIHtcclxuICAgIC8vIENsZWFuIHVwIGJsb2IgVVJMIGJlZm9yZSByZW1vdmluZ1xyXG4gICAgY29uc3QgZG93bmxvYWRVcmwgPSB0aGlzLmdldEZpbGVEb3dubG9hZFVybChpdGVtKTtcclxuICAgIGlmIChkb3dubG9hZFVybCAmJiBkb3dubG9hZFVybC5zdGFydHNXaXRoKCdibG9iOicpKSB7XHJcbiAgICAgIHRoaXMuY2xlYW51cEJsb2JVcmwoZG93bmxvYWRVcmwpO1xyXG4gICAgfVxyXG5cclxuICAgIHRoaXMuaGFuZGxlQXN5bmNGaWxlRGVsZXRpb24oaXRlbSk7XHJcblxyXG4gICAgaWYgKCF0aGlzLm9wdGlvbnMuaXNNdWx0aXBsZUZpbGUpIHtcclxuICAgICAgdGhpcy5oYW5kbGVTaW5nbGVGaWxlUmVtb3ZhbCgpO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgdGhpcy5oYW5kbGVNdWx0aXBsZUZpbGVSZW1vdmFsKGl0ZW0pO1xyXG4gICAgfVxyXG5cclxuICAgIHRoaXMuY2hlY2tBbmRDbGVhck1heEZpbGVDb3VudFZhbGlkYXRpb24oKTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgaGFuZGxlQXN5bmNGaWxlRGVsZXRpb24oaXRlbTogRmlsZUl0ZW0pOiB2b2lkIHtcclxuICAgIGlmICh0aGlzLm9wdGlvbnMuaXNVcGxvYWRGaWxlQXN5bmMgJiZcclxuICAgICAgaXRlbS5wcm9ncmVzcyA9PT0gdGhpcy5QUk9HUkVTU19DT01QTEVURSAmJlxyXG4gICAgICBpdGVtLl9maWxlWydpc05ldyddKSB7XHJcblxyXG4gICAgICBjb25zdCBkZWxldGVTdWJzY3JpcHRpb24gPSB0aGlzLmZpbGVVcGxvYWRTZXJ2aWNlLmRlbGV0ZUZpbGUoaXRlbS5fZmlsZVsnaURfR1VJRCddKS5zdWJzY3JpYmUoe1xyXG4gICAgICAgIGVycm9yOiAoZXJyb3IpID0+IGNvbnNvbGUuZXJyb3IoJ0RlbGV0ZSBmYWlsZWQ6JywgZXJyb3IpXHJcbiAgICAgIH0pO1xyXG5cclxuICAgICAgdGhpcy5zdWJzY3JpcHRpb25zLmFkZChkZWxldGVTdWJzY3JpcHRpb24pO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBoYW5kbGVTaW5nbGVGaWxlUmVtb3ZhbCgpOiB2b2lkIHtcclxuICAgIHRoaXMudXBsb2FkZXIucXVldWUgPSBbXTtcclxuXHJcbiAgICB0aGlzLmZpbGVVcGxvYWRNb2RlbCA9IG51bGwgYXMgYW55O1xyXG5cclxuICAgIGlmICh0aGlzLm9wdGlvbnMuaXNSZXF1aXJlZCkge1xyXG4gICAgICB0aGlzLmZpbGVVcGxvYWRGb3JtQ29udHJvbC5tYXJrQXNUb3VjaGVkKCk7XHJcbiAgICB9XHJcblxyXG4gICAgY29uc3QgY3VycmVudEVycm9ycyA9IHRoaXMuZmlsZVVwbG9hZEZvcm1Db250cm9sLmVycm9ycztcclxuXHJcbiAgICB0aGlzLmdyb3VwLmdldCh0aGlzLm9wdGlvbnMubmFtZSk/LnNldFZhbHVlKHRoaXMuZmlsZVVwbG9hZE1vZGVsLCB7IGVtaXRFdmVudDogZmFsc2UgfSk7XHJcbiAgICBpZiAoY3VycmVudEVycm9ycykge1xyXG4gICAgICB0aGlzLmZpbGVVcGxvYWRGb3JtQ29udHJvbC5zZXRFcnJvcnMoY3VycmVudEVycm9ycyk7XHJcbiAgICB9XHJcbiAgICB0aGlzLm9wdGlvbnMudmFsdWUgPSB0aGlzLmZpbGVVcGxvYWRNb2RlbDtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgaGFuZGxlTXVsdGlwbGVGaWxlUmVtb3ZhbChpdGVtOiBGaWxlSXRlbSk6IHZvaWQge1xyXG4gICAgLy8gQ2xlYW4gdXAgYmxvYiBVUkxcclxuICAgIGNvbnN0IGRvd25sb2FkVXJsID0gdGhpcy5nZXRGaWxlRG93bmxvYWRVcmwoaXRlbSk7XHJcbiAgICBpZiAoZG93bmxvYWRVcmwgJiYgZG93bmxvYWRVcmwuc3RhcnRzV2l0aCgnYmxvYjonKSkge1xyXG4gICAgICB0aGlzLmNsZWFudXBCbG9iVXJsKGRvd25sb2FkVXJsKTtcclxuICAgIH1cclxuXHJcbiAgICBjb25zdCBxdWV1ZUluZGV4ID0gdGhpcy51cGxvYWRlci5xdWV1ZS5pbmRleE9mKGl0ZW0pO1xyXG4gICAgaWYgKHF1ZXVlSW5kZXggPiAtMSkge1xyXG4gICAgICB0aGlzLnVwbG9hZGVyLnF1ZXVlLnNwbGljZShxdWV1ZUluZGV4LCAxKTtcclxuICAgIH1cclxuXHJcbiAgICB0aGlzLnByb2Nlc3NGaWxlUmVtb3ZhbEZyb21FeGlzdGluZyhpdGVtKTtcclxuICAgIHRoaXMucmVtb3ZlRnJvbVVwbG9hZGVkRmlsZXMoaXRlbSk7XHJcbiAgICB0aGlzLnZhbGlkYXRlUmVtYWluaW5nRmlsZXMoKTtcclxuICAgIHRoaXMudXBkYXRlTXVsdGlwbGVGaWxlTW9kZWwoKTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgcHJvY2Vzc0ZpbGVSZW1vdmFsRnJvbUV4aXN0aW5nKGl0ZW06IEZpbGVJdGVtKTogdm9pZCB7XHJcbiAgICBpZiAoIXRoaXMub3B0aW9ucy52YWx1ZSkge1xyXG4gICAgICB0aGlzLnJlc2V0RGVsZXRlZEZpbGVzKCk7XHJcbiAgICAgIHJldHVybjtcclxuICAgIH1cclxuXHJcbiAgICBpZiAoIXRoaXMub3B0aW9ucy52YWx1ZS5jb3JyZWxhdGlvbklEX0dVSUQpIHtcclxuICAgICAgdGhpcy5yZXNldERlbGV0ZWRGaWxlcygpO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgdGhpcy5oYW5kbGVFeGlzdGluZ0ZpbGVSZW1vdmFsKGl0ZW0pO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSByZXNldERlbGV0ZWRGaWxlcygpOiB2b2lkIHtcclxuICAgIHRoaXMuZGVsZXRlZEZpbGVzID0gW107XHJcbiAgICB0aGlzLm11bHRpcGxlRmlsZVVwbG9hZE1vZGVsLnJlbW92ZWRGaWxlcyA9IFtdO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBoYW5kbGVFeGlzdGluZ0ZpbGVSZW1vdmFsKGl0ZW06IEZpbGVJdGVtKTogdm9pZCB7XHJcbiAgICBjb25zdCBmaWxlTmFtZSA9IGl0ZW0uZmlsZS5yYXdGaWxlLm5hbWU7XHJcbiAgICBjb25zdCBleGlzdGluZ0ZpbGUgPSB0aGlzLm11bHRpcGxlRmlsZVVwbG9hZE1vZGVsLmV4aXN0aW5nRmlsZXNcclxuICAgICAgLmZpbmQob2JqID0+IG9iai5uYW1lV2l0aEV4dGVuc2lvbiA9PT0gZmlsZU5hbWUpO1xyXG5cclxuICAgIGlmIChleGlzdGluZ0ZpbGUgJiYgIXRoaXMuZGVsZXRlZEZpbGVzLnNvbWUob2JqID0+IG9iai5uYW1lV2l0aEV4dGVuc2lvbiA9PT0gZmlsZU5hbWUpKSB7XHJcbiAgICAgIHRoaXMubXVsdGlwbGVGaWxlVXBsb2FkTW9kZWwuZXhpc3RpbmdGaWxlcyA9XHJcbiAgICAgICAgdGhpcy5tdWx0aXBsZUZpbGVVcGxvYWRNb2RlbC5leGlzdGluZ0ZpbGVzLmZpbHRlcihcclxuICAgICAgICAgIG9iaiA9PiBvYmoubmFtZVdpdGhFeHRlbnNpb24gIT09IGZpbGVOYW1lXHJcbiAgICAgICAgKTtcclxuICAgICAgdGhpcy5kZWxldGVkRmlsZXMucHVzaChleGlzdGluZ0ZpbGUpO1xyXG4gICAgICB0aGlzLm11bHRpcGxlRmlsZVVwbG9hZE1vZGVsLnJlbW92ZWRGaWxlcy5wdXNoKGV4aXN0aW5nRmlsZS5pRF9HVUlEKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIHByaXZhdGUgcmVtb3ZlRnJvbVVwbG9hZGVkRmlsZXMoaXRlbTogRmlsZUl0ZW0pOiB2b2lkIHtcclxuICAgIGNvbnN0IGl0ZW1GaWxlTmFtZSA9IGl0ZW0uX2ZpbGUubmFtZSB8fCBpdGVtLmZpbGUubmFtZTtcclxuICAgIGNvbnN0IGl0ZW1GaWxlU2l6ZSA9IGl0ZW0uX2ZpbGUuc2l6ZSB8fCBpdGVtLmZpbGUuc2l6ZTtcclxuICAgIGNvbnN0IGl0ZW1HVUlEID0gaXRlbS5fZmlsZVsnaURfR1VJRCddO1xyXG5cclxuICAgIHRoaXMubXVsdGlwbGVGaWxlVXBsb2FkTW9kZWwudXBsb2FkZWRGaWxlcyA9XHJcbiAgICAgIHRoaXMubXVsdGlwbGVGaWxlVXBsb2FkTW9kZWwudXBsb2FkZWRGaWxlcy5maWx0ZXIob2JqID0+IHtcclxuICAgICAgICBpZiAoaXRlbUdVSUQgJiYgb2JqLmlEX0dVSUQpIHtcclxuICAgICAgICAgIHJldHVybiBvYmouaURfR1VJRCAhPT0gaXRlbUdVSUQ7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGNvbnN0IG9iakZpbGVOYW1lID0gb2JqLm5hbWVXaXRoRXh0ZW5zaW9uIHx8IG9iai5maWxlTmFtZTtcclxuICAgICAgICBjb25zdCBvYmpGaWxlU2l6ZSA9IG9iai5maWxlU2l6ZUluTUIgPyBvYmouZmlsZVNpemVJbk1CICogdGhpcy5CWVRFU19UT19NQiA6IDA7XHJcblxyXG4gICAgICAgIHJldHVybiAhKG9iakZpbGVOYW1lID09PSBpdGVtRmlsZU5hbWUgJiYgTWF0aC5hYnMob2JqRmlsZVNpemUgLSBpdGVtRmlsZVNpemUpIDwgMTAwMCk7XHJcbiAgICAgIH0pO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSB2YWxpZGF0ZVJlbWFpbmluZ0ZpbGVzKCk6IHZvaWQge1xyXG4gICAgaWYgKCghdGhpcy5tdWx0aXBsZUZpbGVVcGxvYWRNb2RlbC51cGxvYWRlZEZpbGVzIHx8XHJcbiAgICAgIHRoaXMubXVsdGlwbGVGaWxlVXBsb2FkTW9kZWwudXBsb2FkZWRGaWxlcy5sZW5ndGggPT09IDApICYmXHJcbiAgICAgIHRoaXMub3B0aW9ucy5pc1JlcXVpcmVkKSB7XHJcbiAgICAgIHRoaXMuZmlsZVVwbG9hZEZvcm1Db250cm9sLnNldEVycm9ycyh7XHJcbiAgICAgICAgTWluRmlsZUNvdW50VmFsaWRhdGlvbktleTogdGhpcy5vcHRpb25zLm1pbk5vT2ZGaWxlc1xyXG4gICAgICB9KTtcclxuICAgICAgdGhpcy5maWxlVXBsb2FkRm9ybUNvbnRyb2wubWFya0FzVG91Y2hlZCgpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSB1cGRhdGVNdWx0aXBsZUZpbGVNb2RlbCgpOiB2b2lkIHtcclxuICAgIHRoaXMubXVsdGlwbGVGaWxlVXBsb2FkTW9kZWwuY29ycmVsYXRpb25JRF9HVUlEID0gdGhpcy5vcHRpb25zLnZhbHVlPy5jb3JyZWxhdGlvbklEX0dVSUQ7XHJcblxyXG4gICAgY29uc3QgY3VycmVudEVycm9ycyA9IHRoaXMuZmlsZVVwbG9hZEZvcm1Db250cm9sLmVycm9ycztcclxuXHJcbiAgICB0aGlzLmZpbGVVcGxvYWRGb3JtQ29udHJvbC5zZXRWYWx1ZSh0aGlzLm11bHRpcGxlRmlsZVVwbG9hZE1vZGVsLCB7IGVtaXRFdmVudDogZmFsc2UgfSk7XHJcbiAgICB0aGlzLmdyb3VwLmdldCh0aGlzLm9wdGlvbnMubmFtZSk/LnNldFZhbHVlKHRoaXMubXVsdGlwbGVGaWxlVXBsb2FkTW9kZWwsIHsgZW1pdEV2ZW50OiBmYWxzZSB9KTtcclxuICAgIHRoaXMub3B0aW9ucy52YWx1ZSA9IHRoaXMubXVsdGlwbGVGaWxlVXBsb2FkTW9kZWw7XHJcbiAgICBpZiAoY3VycmVudEVycm9ycykge1xyXG4gICAgICB0aGlzLmZpbGVVcGxvYWRGb3JtQ29udHJvbC5zZXRFcnJvcnMoY3VycmVudEVycm9ycyk7XHJcbiAgICB9XHJcbiAgfVxyXG4gIHJlbW92ZVJlcXVpcmVkVmFsaWRhdGlvbiA9ICgpOiB2b2lkID0+IHtcclxuICAgIHRoaXMuY29udHJvbFV0aWxpdHkucmVtb3ZlUmVxdWlyZWRWYWxpZGF0aW9uKFxyXG4gICAgICB0aGlzLmZpbGVVcGxvYWRGb3JtQ29udHJvbCxcclxuICAgICAgdGhpcy52YWxpZGF0aW9uUnVsZXMsXHJcbiAgICAgIHRoaXMub3B0aW9uc1xyXG4gICAgKTtcclxuICB9O1xyXG5cclxuICBhZGRSZXF1aXJlZFZhbGlkYXRpb24gPSAoKTogdm9pZCA9PiB7XHJcbiAgICB0aGlzLmNvbnRyb2xVdGlsaXR5LmFkZFJlcXVpcmVkVmFsaWRhdGlvbihcclxuICAgICAgdGhpcy5maWxlVXBsb2FkRm9ybUNvbnRyb2wsXHJcbiAgICAgIHRoaXMudmFsaWRhdGlvblJ1bGVzLFxyXG4gICAgICB0aGlzLm9wdGlvbnNcclxuICAgICk7XHJcbiAgfTtcclxuXHJcbiAgcmVtb3ZlQ3VzdG9tVmFsaWRhdGlvbiA9IChjdXN0b21WYWxpZGF0aW9uOiBhbnkpOiB2b2lkID0+IHtcclxuICAgIHRoaXMuY29udHJvbFV0aWxpdHkucmVtb3ZlQ3VzdG9tVmFsaWRhdGlvbihcclxuICAgICAgdGhpcy5maWxlVXBsb2FkRm9ybUNvbnRyb2wsXHJcbiAgICAgIHRoaXMudmFsaWRhdGlvblJ1bGVzLFxyXG4gICAgICBjdXN0b21WYWxpZGF0aW9uXHJcbiAgICApO1xyXG4gIH07XHJcblxyXG4gIGFkZEN1c3RvbVZhbGlkYXRpb24gPSAoY3VzdG9tVmFsaWRhdGlvbjogYW55KTogdm9pZCA9PiB7XHJcbiAgICB0aGlzLmNvbnRyb2xVdGlsaXR5LmFkZEN1c3RvbVZhbGlkYXRpb24oXHJcbiAgICAgIHRoaXMuZmlsZVVwbG9hZEZvcm1Db250cm9sLFxyXG4gICAgICB0aGlzLnZhbGlkYXRpb25SdWxlcyxcclxuICAgICAgY3VzdG9tVmFsaWRhdGlvblxyXG4gICAgKTtcclxuICB9O1xyXG5cclxuICBpc1ZhbGlkID0gKCk6IGJvb2xlYW4gPT4ge1xyXG4gICAgdGhpcy5jb250cm9sVXRpbGl0eS5pc1ZhbGlkKHRoaXMuZmlsZVVwbG9hZEZvcm1Db250cm9sKTtcclxuICAgIHJldHVybiB0aGlzLmZpbGVVcGxvYWRGb3JtQ29udHJvbC52YWxpZDtcclxuICB9O1xyXG4gIGNvbnZlcnRTaXplVG9NQihzaXplOiBudW1iZXIpOiBudW1iZXIge1xyXG4gICAgaWYgKHNpemUgPT09IDApIHtcclxuICAgICAgcmV0dXJuIDA7XHJcbiAgICB9XHJcblxyXG4gICAgY29uc3QgQllURVNfVE9fTUJfQUNDVVJBVEUgPSAxMDI0ICogMTAyNDtcclxuICAgIGNvbnN0IG1lZ2FieXRlcyA9IHNpemUgLyBCWVRFU19UT19NQl9BQ0NVUkFURTtcclxuICAgIHJldHVybiBNYXRoLnJvdW5kKG1lZ2FieXRlcyAqIDEwMCkgLyAxMDA7XHJcbiAgfVxyXG5cclxuICB0cmFja0J5RnVuY3Rpb24oaW5kZXg6IG51bWJlciwgaXRlbTogRmlsZUl0ZW0pOiBhbnkge1xyXG4gICAgcmV0dXJuIGl0ZW0uX2ZpbGUgPyBpdGVtLl9maWxlLm5hbWUgKyBpdGVtLl9maWxlLnNpemUgOiBpbmRleDtcclxuICB9XHJcblxyXG4gIHNob3VsZFNob3dGaWxlTGlzdCgpOiBib29sZWFuIHtcclxuICAgIHJldHVybiB0aGlzLnVwbG9hZGVyPy5xdWV1ZSAmJiB0aGlzLnVwbG9hZGVyLnF1ZXVlLmxlbmd0aCA+IDA7XHJcbiAgfVxyXG5cclxuICBpc0Rvd25sb2FkRW5hYmxlZCgpOiBib29sZWFuIHtcclxuICAgIHJldHVybiB0cnVlO1xyXG4gIH1cclxuXHJcbiAgaXNSZW1vdmVFbmFibGVkKCk6IGJvb2xlYW4ge1xyXG4gICAgcmV0dXJuICF0aGlzLm9wdGlvbnMuaXNSZWFkb25seSAmJiAhdGhpcy5vcHRpb25zLmlzRGlzYWJsZWQ7XHJcbiAgfVxyXG5cclxuICBnZXRGaWxlRG93bmxvYWRVcmwoaXRlbTogRmlsZUl0ZW0pOiBzdHJpbmcgfCBudWxsIHtcclxuICAgIGNvbnN0IGV4aXN0aW5nVXJsID0gdGhpcy5nZXRFeGlzdGluZ0ZpbGVVcmwoaXRlbSk7XHJcbiAgICBpZiAoZXhpc3RpbmdVcmwpIHtcclxuICAgICAgcmV0dXJuIGV4aXN0aW5nVXJsO1xyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiB0aGlzLmNyZWF0ZUZpbGVVcmwoaXRlbSk7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGdldEV4aXN0aW5nRmlsZVVybChpdGVtOiBGaWxlSXRlbSk6IHN0cmluZyB8IG51bGwge1xyXG4gICAgcmV0dXJuIChpdGVtPy5maWxlIGFzIGFueSk/LnVybCB8fFxyXG4gICAgICAoaXRlbT8uX2ZpbGUgYXMgYW55KT8udXJsIHx8XHJcbiAgICAgIChpdGVtIGFzIGFueSk/LnVybCB8fFxyXG4gICAgICAoaXRlbT8uZmlsZSBhcyBhbnkpPy5yYXdGaWxlPy51cmwgfHxcclxuICAgICAgKGl0ZW0/Ll9maWxlIGFzIGFueSk/LnJhd0ZpbGU/LnVybCB8fFxyXG4gICAgICBudWxsO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBjcmVhdGVGaWxlVXJsKGl0ZW06IEZpbGVJdGVtKTogc3RyaW5nIHwgbnVsbCB7XHJcbiAgICBjb25zdCBmaWxlTmFtZSA9IHRoaXMuZ2V0RmlsZU5hbWUoaXRlbSk7XHJcbiAgICBjb25zdCBmaWxlVHlwZSA9IGl0ZW0/LmZpbGU/LnR5cGUgfHwgKGl0ZW0/Ll9maWxlIGFzIGFueSk/LnR5cGU7XHJcblxyXG4gICAgY29uc3Qgb3JpZ2luYWxGaWxlID0gKGl0ZW0/Ll9maWxlIGFzIGFueSk/LnJhd0ZpbGUgfHwgKGl0ZW0/LmZpbGUgYXMgYW55KT8ucmF3RmlsZTtcclxuICAgIGlmIChvcmlnaW5hbEZpbGUgJiYgb3JpZ2luYWxGaWxlIGluc3RhbmNlb2YgRmlsZSkge1xyXG4gICAgICByZXR1cm4gVVJMLmNyZWF0ZU9iamVjdFVSTChvcmlnaW5hbEZpbGUpO1xyXG4gICAgfVxyXG5cclxuICAgIGNvbnN0IGJhc2U2NERhdGEgPSB0eXBlb2Ygb3JpZ2luYWxGaWxlID09PSAnc3RyaW5nJyA/IG9yaWdpbmFsRmlsZSA6IG51bGw7XHJcbiAgICBpZiAoYmFzZTY0RGF0YSAmJiBmaWxlTmFtZSkge1xyXG4gICAgICByZXR1cm4gdGhpcy5jcmVhdGVCbG9iVXJsV2l0aEZpbGVuYW1lKGJhc2U2NERhdGEsIGZpbGVUeXBlLCBmaWxlTmFtZSk7XHJcbiAgICB9XHJcblxyXG4gICAgY29uc3QgZmlsZUlkID0gKGl0ZW0/Ll9maWxlIGFzIGFueSk/LlsnaURfR1VJRCddO1xyXG4gICAgaWYgKGZpbGVJZCAmJiB0aGlzLm9wdGlvbnMuaXNVcGxvYWRGaWxlQXN5bmMpIHtcclxuICAgICAgcmV0dXJuIHRoaXMuY29uc3RydWN0RG93bmxvYWRVcmwoZmlsZUlkLCBmaWxlTmFtZSk7XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIG51bGw7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGNyZWF0ZUJsb2JVcmxXaXRoRmlsZW5hbWUoYmFzZTY0RGF0YTogc3RyaW5nLCBmaWxlVHlwZTogc3RyaW5nLCBmaWxlTmFtZTogc3RyaW5nKTogc3RyaW5nIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIGNvbnN0IGJ5dGVDaGFyYWN0ZXJzID0gYXRvYihiYXNlNjREYXRhKTtcclxuICAgICAgY29uc3QgYnl0ZU51bWJlcnMgPSBuZXcgQXJyYXkoYnl0ZUNoYXJhY3RlcnMubGVuZ3RoKTtcclxuICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCBieXRlQ2hhcmFjdGVycy5sZW5ndGg7IGkrKykge1xyXG4gICAgICAgIGJ5dGVOdW1iZXJzW2ldID0gYnl0ZUNoYXJhY3RlcnMuY2hhckNvZGVBdChpKTtcclxuICAgICAgfVxyXG4gICAgICBjb25zdCBieXRlQXJyYXkgPSBuZXcgVWludDhBcnJheShieXRlTnVtYmVycyk7XHJcbiAgICAgIGNvbnN0IGJsb2IgPSBuZXcgQmxvYihbYnl0ZUFycmF5XSwgeyB0eXBlOiBmaWxlVHlwZSB8fCAnYXBwbGljYXRpb24vb2N0ZXQtc3RyZWFtJyB9KTtcclxuXHJcbiAgICAgIHJldHVybiBVUkwuY3JlYXRlT2JqZWN0VVJMKGJsb2IpO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgY29uc3QgZXJyb3JNc2cgPSB0aGlzLnV0aWxpdHlTZXJ2aWNlLmdldFJlc291cmNlVmFsdWUoJ0Vycm9yQ3JlYXRpbmdCbG9iVXJsJyk7XHJcbiAgICAgIGNvbnNvbGUuZXJyb3IoZXJyb3JNc2csIGVycm9yKTtcclxuICAgICAgcmV0dXJuIGBkYXRhOiR7ZmlsZVR5cGUgfHwgJ2FwcGxpY2F0aW9uL29jdGV0LXN0cmVhbSd9O2Jhc2U2NCwke2Jhc2U2NERhdGF9YDtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIHByaXZhdGUgY29uc3RydWN0RG93bmxvYWRVcmwoZmlsZUlkOiBzdHJpbmcsIGZpbGVOYW1lPzogc3RyaW5nKTogc3RyaW5nIHtcclxuICAgIGNvbnN0IGRvd25sb2FkQmFzZVVybCA9ICh0aGlzLm9wdGlvbnMgYXMgYW55KS5kb3dubG9hZEJhc2VVcmw7XHJcbiAgICBsZXQgdXJsOiBzdHJpbmc7XHJcblxyXG4gICAgaWYgKGRvd25sb2FkQmFzZVVybCkge1xyXG4gICAgICB1cmwgPSBgJHtkb3dubG9hZEJhc2VVcmx9LyR7ZmlsZUlkfWA7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICB1cmwgPSBgL2FwaS9maWxlcy9kb3dubG9hZC8ke2ZpbGVJZH1gO1xyXG4gICAgfVxyXG5cclxuICAgIGlmIChmaWxlTmFtZSkge1xyXG4gICAgICBjb25zdCBzZXBhcmF0b3IgPSB1cmwuaW5jbHVkZXMoJz8nKSA/ICcmJyA6ICc/JztcclxuICAgICAgdXJsICs9IGAke3NlcGFyYXRvcn1maWxlbmFtZT0ke2VuY29kZVVSSUNvbXBvbmVudChmaWxlTmFtZSl9YDtcclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4gdXJsO1xyXG4gIH1cclxuXHJcbiAgZ2V0RmlsZU5hbWUoaXRlbTogRmlsZUl0ZW0pOiBzdHJpbmcge1xyXG4gICAgcmV0dXJuIGl0ZW0/LmZpbGU/Lm5hbWUgfHwgKGl0ZW0/Ll9maWxlIGFzIGFueSk/Lm5hbWUgfHwgJ2ZpbGUnO1xyXG4gIH1cclxuXHJcbiAgZG93bmxvYWRGaWxlKGl0ZW06IEZpbGVJdGVtKTogdm9pZCB7XHJcbiAgICBjb25zdCBkb3dubG9hZEluZm8gPSB0aGlzLnByZXBhcmVGaWxlRG93bmxvYWQoaXRlbSk7XHJcblxyXG4gICAgaWYgKCFkb3dubG9hZEluZm8udXJsKSB7XHJcbiAgICAgIHRoaXMuaGFuZGxlRG93bmxvYWRFcnJvcihkb3dubG9hZEluZm8uZmlsZU5hbWUpO1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcblxyXG4gICAgdGhpcy5leGVjdXRlRmlsZURvd25sb2FkKGRvd25sb2FkSW5mby51cmwsIGRvd25sb2FkSW5mby5maWxlTmFtZSk7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIHByZXBhcmVGaWxlRG93bmxvYWQoaXRlbTogRmlsZUl0ZW0pOiBEb3dubG9hZEluZm8ge1xyXG4gICAgcmV0dXJuIHtcclxuICAgICAgdXJsOiB0aGlzLmdldEZpbGVEb3dubG9hZFVybChpdGVtKSxcclxuICAgICAgZmlsZU5hbWU6IHRoaXMuZ2V0RmlsZU5hbWUoaXRlbSlcclxuICAgIH07XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGhhbmRsZURvd25sb2FkRXJyb3IoZmlsZU5hbWU6IHN0cmluZyk6IHZvaWQge1xyXG4gICAgY29uc3QgZXJyb3JNc2cgPSB0aGlzLnV0aWxpdHlTZXJ2aWNlLmdldFJlc291cmNlVmFsdWUoJ05vRG93bmxvYWRVcmxBdmFpbGFibGUnKVxyXG4gICAgICAucmVwbGFjZSgne2ZpbGVOYW1lfScsIGZpbGVOYW1lKTtcclxuICAgIGNvbnNvbGUuZXJyb3IoZXJyb3JNc2cpO1xyXG5cclxuICB9XHJcblxyXG4gIHByaXZhdGUgZXhlY3V0ZUZpbGVEb3dubG9hZCh1cmw6IHN0cmluZywgZmlsZU5hbWU6IHN0cmluZyk6IHZvaWQge1xyXG4gICAgY29uc3QgbGluayA9IHRoaXMuY3JlYXRlRG93bmxvYWRMaW5rKHVybCwgZmlsZU5hbWUpO1xyXG4gICAgdGhpcy50cmlnZ2VyRG93bmxvYWQobGluayk7XHJcbiAgICB0aGlzLmNsZWFudXBCbG9iVXJsKHVybCk7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGNyZWF0ZURvd25sb2FkTGluayh1cmw6IHN0cmluZywgZmlsZU5hbWU6IHN0cmluZyk6IEhUTUxBbmNob3JFbGVtZW50IHtcclxuICAgIGNvbnN0IGxpbmsgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdhJyk7XHJcbiAgICBsaW5rLmhyZWYgPSB1cmw7XHJcbiAgICBsaW5rLmRvd25sb2FkID0gZmlsZU5hbWU7XHJcbiAgICBsaW5rLnN0eWxlLmRpc3BsYXkgPSAnbm9uZSc7XHJcbiAgICByZXR1cm4gbGluaztcclxuICB9XHJcblxyXG4gIHByaXZhdGUgdHJpZ2dlckRvd25sb2FkKGxpbms6IEhUTUxBbmNob3JFbGVtZW50KTogdm9pZCB7XHJcbiAgICBkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKGxpbmspO1xyXG4gICAgbGluay5jbGljaygpO1xyXG4gICAgZG9jdW1lbnQuYm9keS5yZW1vdmVDaGlsZChsaW5rKTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgY2xlYW51cEJsb2JVcmwodXJsOiBzdHJpbmcpOiB2b2lkIHtcclxuICAgIGlmICh1cmwuc3RhcnRzV2l0aCgnYmxvYjonKSkge1xyXG4gICAgICBzZXRUaW1lb3V0KCgpID0+IHtcclxuICAgICAgICBVUkwucmV2b2tlT2JqZWN0VVJMKHVybCk7XHJcbiAgICAgIH0sIDEwMCk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIHRyYWNrTWVtb3J5VXNhZ2UoZmlsZVNpemU6IG51bWJlcik6IHZvaWQge1xyXG4gICAgdGhpcy5jdXJyZW50TWVtb3J5VXNhZ2UgKz0gZmlsZVNpemU7XHJcblxyXG4gICAgLy8gSWYgbWVtb3J5IHVzYWdlIGV4Y2VlZHMgbGltaXQsIGNsZWFuIHVwIG9sZCBmaWxlc1xyXG4gICAgaWYgKHRoaXMuY3VycmVudE1lbW9yeVVzYWdlID4gdGhpcy5NQVhfTUVNT1JZX1VTQUdFKSB7XHJcbiAgICAgIHRoaXMuY2xlYW51cE9sZEZpbGVzKCk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGNsZWFudXBPbGRGaWxlcygpOiB2b2lkIHtcclxuICAgIGlmICh0aGlzLnVwbG9hZGVyPy5xdWV1ZSAmJiB0aGlzLnVwbG9hZGVyLnF1ZXVlLmxlbmd0aCA+IDApIHtcclxuICAgICAgLy8gUmVtb3ZlIG9sZGVzdCBmaWxlcyB0byBmcmVlIG1lbW9yeVxyXG4gICAgICBjb25zdCBvbGRlc3RGaWxlID0gdGhpcy51cGxvYWRlci5xdWV1ZS5zaGlmdCgpO1xyXG4gICAgICBpZiAob2xkZXN0RmlsZSkge1xyXG4gICAgICAgIGNvbnN0IHVybCA9IHRoaXMuZ2V0RmlsZURvd25sb2FkVXJsKG9sZGVzdEZpbGUpO1xyXG4gICAgICAgIGlmICh1cmwgJiYgdXJsLnN0YXJ0c1dpdGgoJ2Jsb2I6JykpIHtcclxuICAgICAgICAgIHRoaXMuY2xlYW51cEJsb2JVcmwodXJsKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgdGhpcy5jdXJyZW50TWVtb3J5VXNhZ2UgLT0gKG9sZGVzdEZpbGUuZmlsZT8uc2l6ZSB8fCAwKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBjbGVhbnVwRXZlbnRMaXN0ZW5lcnMoKTogdm9pZCB7XHJcbiAgICAvLyBDbGVhciBmaWxlIGlucHV0IHJlZmVyZW5jZXNcclxuICAgIGlmICh0aGlzLmZpbGVJbnB1dD8ubmF0aXZlRWxlbWVudCkge1xyXG4gICAgICB0aGlzLmZpbGVJbnB1dC5uYXRpdmVFbGVtZW50LnZhbHVlID0gJyc7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ2xlYXIgdXBsb2FkZXIgcXVldWUgdG8gcHJldmVudCBtZW1vcnkgbGVha3NcclxuICAgIGlmICh0aGlzLnVwbG9hZGVyPy5xdWV1ZSkge1xyXG4gICAgICB0aGlzLnVwbG9hZGVyLnF1ZXVlID0gW107XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGNsZWFudXBVcGxvYWRlclF1ZXVlKCk6IHZvaWQge1xyXG4gICAgaWYgKHRoaXMudXBsb2FkZXI/LnF1ZXVlKSB7XHJcbiAgICAgIC8vIENsZWFyIGFsbCBpdGVtcyBhbmQgdGhlaXIgYXNzb2NpYXRlZCByZXNvdXJjZXNcclxuICAgICAgdGhpcy51cGxvYWRlci5xdWV1ZS5mb3JFYWNoKGl0ZW0gPT4ge1xyXG4gICAgICAgIC8vIENsZWFuIHVwIGJsb2IgVVJMc1xyXG4gICAgICAgIGNvbnN0IHVybCA9IHRoaXMuZ2V0RmlsZURvd25sb2FkVXJsKGl0ZW0pO1xyXG4gICAgICAgIGlmICh1cmwgJiYgdXJsLnN0YXJ0c1dpdGgoJ2Jsb2I6JykpIHtcclxuICAgICAgICAgIHRoaXMuY2xlYW51cEJsb2JVcmwodXJsKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIENsZWFyIGZpbGUgcmVmZXJlbmNlc1xyXG4gICAgICAgIGlmIChpdGVtLl9maWxlKSB7XHJcbiAgICAgICAgICBpdGVtLl9maWxlID0gbnVsbCBhcyBhbnk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGlmIChpdGVtLmZpbGUpIHtcclxuICAgICAgICAgIGl0ZW0uZmlsZSA9IG51bGwgYXMgYW55O1xyXG4gICAgICAgIH1cclxuICAgICAgfSk7XHJcblxyXG4gICAgICAvLyBDbGVhciB0aGUgcXVldWVcclxuICAgICAgdGhpcy51cGxvYWRlci5xdWV1ZSA9IFtdO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgbmdPbkRlc3Ryb3koKTogdm9pZCB7XHJcbiAgICAvLyBDbGVhbiB1cCBzdWJzY3JpcHRpb25zXHJcbiAgICB0aGlzLnN1YnNjcmlwdGlvbnMudW5zdWJzY3JpYmUoKTtcclxuXHJcbiAgICAvLyBDbGVhbiB1cCB1cGxvYWRlciBxdWV1ZVxyXG4gICAgdGhpcy5jbGVhbnVwVXBsb2FkZXJRdWV1ZSgpO1xyXG5cclxuICAgIC8vIENsZWFuIHVwIGV2ZW50IGxpc3RlbmVyc1xyXG4gICAgdGhpcy5jbGVhbnVwRXZlbnRMaXN0ZW5lcnMoKTtcclxuXHJcbiAgICAvLyBDbGVhbiB1cCBibG9iIFVSTHNcclxuICAgIGlmICh0aGlzLnVwbG9hZGVyPy5xdWV1ZSkge1xyXG4gICAgICB0aGlzLnVwbG9hZGVyLnF1ZXVlLmZvckVhY2goaXRlbSA9PiB7XHJcbiAgICAgICAgY29uc3QgdXJsID0gdGhpcy5nZXRGaWxlRG93bmxvYWRVcmwoaXRlbSk7XHJcbiAgICAgICAgaWYgKHVybCAmJiB1cmwuc3RhcnRzV2l0aCgnYmxvYjonKSkge1xyXG4gICAgICAgICAgVVJMLnJldm9rZU9iamVjdFVSTCh1cmwpO1xyXG4gICAgICAgIH1cclxuICAgICAgfSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGNoZWNrQW5kQ2xlYXJNYXhGaWxlQ291bnRWYWxpZGF0aW9uKCk6IHZvaWQge1xyXG4gICAgaWYgKCF0aGlzLm9wdGlvbnMubWF4Tm9PZkZpbGVzIHx8IHRoaXMub3B0aW9ucy5tYXhOb09mRmlsZXMgPD0gMCkge1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcblxyXG4gICAgY29uc3QgY3VycmVudFF1ZXVlTGVuZ3RoID0gdGhpcy51cGxvYWRlci5xdWV1ZS5sZW5ndGg7XHJcbiAgICBpZiAoY3VycmVudFF1ZXVlTGVuZ3RoIDw9IHRoaXMub3B0aW9ucy5tYXhOb09mRmlsZXMpIHtcclxuICAgICAgdGhpcy5jbGVhckZpbGVDb3VudEVycm9yKCdNYXhGaWxlQ291bnRWYWxpZGF0aW9uS2V5Jyk7XHJcbiAgICB9XHJcbiAgfVxyXG59XHJcbiIsIjxkaXYgY2xhc3M9XCJmb3JtLWdyb3VwIGJic2YtY29udHJvbCBiYnNmLWZpbGUtdXBsb2FkXCIgW2Zvcm1Hcm91cF09XCJncm91cFwiPlxyXG4gIDxkaXYgW25nQ2xhc3NdPVwib3B0aW9ucy52aWV3VHlwZSA9PT0gMSA/ICdiYnNmLXZlcnRpY2FsJyA6ICdiYnNmLWhvcml6b250YWwnXCI+XHJcbiAgICA8IS0tIExhYmVsIC0tPlxyXG4gICAgPGxhYmVsIFtoaWRkZW5dPVwib3B0aW9ucy5oaWRlTGFiZWxcIiBjbGFzcz1cImJic2YtbGFiZWwge3sgb3B0aW9ucy5sYWJlbEV4dHJhQ2xhc3NlcyB9fVwiPlxyXG4gICAgICB7eyBvcHRpb25zLmxhYmVsVmFsdWUgfX1cclxuICAgICAgPCEtLSBSZXF1aXJlZCBhc3RlcmlzayAtLT5cclxuICAgICAgPHNwYW4gKm5nSWY9XCJvcHRpb25zLmlzUmVxdWlyZWQgJiYgIW9wdGlvbnMuaXNSZWFkb25seSAmJiAob3B0aW9ucy5zaG93QXN0ZXJpc2sgfHwgdHJ1ZSlcIlxyXG4gICAgICAgIGNsYXNzPVwidGV4dC1kYW5nZXJcIj4qPC9zcGFuPlxyXG4gICAgPC9sYWJlbD5cclxuICAgIDwhLS0gRHJvcCB6b25lIGVuYWJsZWQgLS0+XHJcbiAgICA8ZGl2IG5nMkZpbGVEcm9wIGNsYXNzPVwiYmJzZi1pbnB1dC1jb250YWluZXIge3sgb3B0aW9ucy5leHRyYUNsYXNzZXMgfX1cIlxyXG4gICAgICAqbmdJZj1cIm9wdGlvbnMuaXNEcm9wWm9uZSAmJiAhaXNIaWRlSW5wdXQoKSAmJiAhb3B0aW9ucy5pc1JlYWRvbmx5XCJcclxuICAgICAgW25nQ2xhc3NdPVwieyAnYW5vdGhlci1maWxlLW92ZXItY2xhc3MnOiBoYXNBbm90aGVyRHJvcFpvbmVPdmVyIH1cIiAob25GaWxlRHJvcCk9XCJvbkZpbGVDaGFuZ2UoKVwiXHJcbiAgICAgIChmaWxlT3Zlcik9XCJmaWxlT3ZlckFub3RoZXIoJGV2ZW50KVwiIFt1cGxvYWRlcl09XCJ1cGxvYWRlclwiIFthY2NlcHRdPVwiYWNjZXB0ZWRUeXBlXCIgW2lkXT1cIm9wdGlvbnMubmFtZVwiXHJcbiAgICAgIFthdHRyLm11bHRpcGxlXT1cIm9wdGlvbnMuaXNNdWx0aXBsZUZpbGUgPyAnbXVsdGlwbGUnIDogbnVsbFwiXHJcbiAgICAgIFtjbGFzcy5pcy1pbnZhbGlkXT1cImZpbGVVcGxvYWRGb3JtQ29udHJvbC5pbnZhbGlkICYmIGZpbGVVcGxvYWRGb3JtQ29udHJvbC50b3VjaGVkXCJcclxuICAgICAgKGNsaWNrKT1cImZpbGVJbnB1dENvbnRyb2wuY2xpY2soKVwiPlxyXG5cclxuICAgICAgPGRpdiBjbGFzcz1cImRyb3B6b25lLWxhYmVsXCI+XHJcbiAgICAgICAgPGRpdiBjbGFzcz1cInN2Zy1hbmQtdmFsaWRhdGlvblwiPlxyXG4gICAgICAgICAgPCEtLSBVcGxvYWQgaWNvbiAtLT5cclxuICAgICAgICAgIDxzdmcgeG1sbnM9XCJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2Z1wiIHdpZHRoPVwiNzBcIiBoZWlnaHQ9XCI3MFwiIHZpZXdCb3g9XCIwIDAgNzAgNzBcIiBmaWxsPVwibm9uZVwiPlxyXG4gICAgICAgICAgICA8cGF0aCBvcGFjaXR5PVwiMC40XCJcclxuICAgICAgICAgICAgICBkPVwiTTU4LjMzMyA0OC44MzMyQzYxLjg5NTcgNDUuODkwOCA2NC4xNjYzIDQxLjQzOTcgNjQuMTY2MyAzNi40NTgzQzY0LjE2NjMgMjcuNTk4OCA1Ni45ODQzIDIwLjQxNjcgNDguMTI0NyAyMC40MTY3QzQ3LjQ4NzQgMjAuNDE2NyA0Ni44OTEyIDIwLjA4NDIgNDYuNTY3NSAxOS41MzUxQzQyLjc2NDEgMTMuMDgwOCAzNS43NDE3IDguNzUgMjcuNzA4IDguNzVDMTUuNjI2OCA4Ljc1IDUuODMzMDEgMTguNTQzOCA1LjgzMzAxIDMwLjYyNUM1LjgzMzAxIDM2LjY1MTEgOC4yNjk3NCA0Mi4xMDgyIDEyLjIxMTYgNDYuMDY0NFwiXHJcbiAgICAgICAgICAgICAgc3Ryb2tlPVwiIzRCNTQ4OVwiIHN0cm9rZS13aWR0aD1cIjJcIiBzdHJva2UtbGluZWNhcD1cInJvdW5kXCIgc3Ryb2tlLWxpbmVqb2luPVwicm91bmRcIiAvPlxyXG4gICAgICAgICAgICA8cGF0aCBkPVwiTTIzLjMzMyA0Ni42NjY3TDM0Ljk5OTcgMzVNMzQuOTk5NyAzNUw0Ni42NjYzIDQ2LjY2NjdNMzQuOTk5NyAzNVY2MS4yNVwiIHN0cm9rZT1cIiM0QjU0ODlcIlxyXG4gICAgICAgICAgICAgIHN0cm9rZS13aWR0aD1cIjJcIiBzdHJva2UtbGluZWNhcD1cInJvdW5kXCIgc3Ryb2tlLWxpbmVqb2luPVwicm91bmRcIiAvPlxyXG4gICAgICAgICAgPC9zdmc+XHJcblxyXG4gICAgICAgICAgPCEtLSBJbnN0cnVjdGlvbiB0ZXh0IC0tPlxyXG4gICAgICAgICAgPGRpdiBjbGFzcz1cImJic2YtdmFsaWRhdGlvbi1tc2cgdmFsaWRhdGlvbi1tc2ctaGVhZGVyIHRleHQtY2VudGVyXCI+XHJcbiAgICAgICAgICAgIHt7IHV0aWxpdHlTZXJ2aWNlLmdldFJlc291cmNlVmFsdWUoJ0RyYWdBbmREcm9wSGVyZScpIH19XHJcbiAgICAgICAgICA8L2Rpdj5cclxuXHJcbiAgICAgICAgICA8IS0tIFZhbGlkYXRpb24gbWVzc2FnZXMgLS0+XHJcbiAgICAgICAgICA8ZGl2IGNsYXNzPVwiYmJzZi12YWxpZGF0aW9uLW1zZyB0ZXh0LWNlbnRlclwiICpuZ0lmPVwidmFsaWRhdGlvbk1lc3NhZ2VcIiBbaW5uZXJIVE1MXT1cInZhbGlkYXRpb25NZXNzYWdlXCI+XHJcbiAgICAgICAgICA8L2Rpdj5cclxuXHJcbiAgICAgICAgICA8ZGl2IGNsYXNzPVwiYmJzZi12YWxpZGF0aW9uLW1zZyB0ZXh0LWNlbnRlciB0ZXh0LWRhbmdlclwiXHJcbiAgICAgICAgICAgICpuZ0lmPVwidmFsaWRhdGlvbkNvdW50TWVzc2FnZSAmJiBvcHRpb25zLmlzTXVsdGlwbGVGaWxlICYmIG9wdGlvbnMubWF4Tm9PZkZpbGVzID4gMFwiXHJcbiAgICAgICAgICAgIFtpbm5lckhUTUxdPVwidmFsaWRhdGlvbkNvdW50TWVzc2FnZVwiPlxyXG4gICAgICAgICAgPC9kaXY+XHJcbiAgICAgICAgPC9kaXY+XHJcbiAgICAgIDwvZGl2PlxyXG5cclxuICAgICAgPCEtLSBIaWRkZW4gZmlsZSBpbnB1dCAtLT5cclxuICAgICAgPGlucHV0IG5nMkZpbGVTZWxlY3QgW3VwbG9hZGVyXT1cInVwbG9hZGVyXCIgW2FjY2VwdF09XCJhY2NlcHRlZFR5cGVcIlxyXG4gICAgICAgIGNsYXNzPVwiZmlsZVNlbGVjdG9yIGN1c3RvbUZpbGVVcGxvYWRQbGFjbWVudCBoaWRkZW4gdi1yZXF1aXJlZC1tdWx0aXBsZWZpbGVzIGQtbm9uZVwiXHJcbiAgICAgICAgW2F0dHIubXVsdGlwbGVdPVwib3B0aW9ucy5pc011bHRpcGxlRmlsZSA/ICdtdWx0aXBsZScgOiBudWxsXCIgbmFtZT1cImZpbGVcIiB0eXBlPVwiZmlsZVwiIGF1dG9jb21wbGV0ZT1cIm9mZlwiXHJcbiAgICAgICAgKGNoYW5nZSk9XCJvbkZpbGVDaGFuZ2UoKVwiIFtuZ0NsYXNzXT1cIm9wdGlvbnMudmlld1R5cGUgPT09IDEgPyAnJyA6ICdjb2wtbWQtOSdcIiBbaWRdPVwib3B0aW9ucy5uYW1lXCJcclxuICAgICAgICAjZmlsZUlucHV0Q29udHJvbCBbY2xhc3MuaXMtaW52YWxpZF09XCJmaWxlVXBsb2FkRm9ybUNvbnRyb2wuaW52YWxpZCAmJiBmaWxlVXBsb2FkRm9ybUNvbnRyb2wudG91Y2hlZFwiIC8+XHJcbiAgICA8L2Rpdj5cclxuICAgIDwhLS0gQ2xpY2sgdG8gdXBsb2FkIChubyBkcm9wIHpvbmUpIC0tPlxyXG4gICAgPGRpdiBjbGFzcz1cImJic2YtaW5wdXQtY29udGFpbmVyXCIgKm5nSWY9XCIhb3B0aW9ucy5pc0Ryb3Bab25lICYmICFpc0hpZGVJbnB1dCgpICYmICFvcHRpb25zLmlzUmVhZG9ubHlcIlxyXG4gICAgICAoY2xpY2spPVwiZmlsZUlucHV0LmNsaWNrKClcIj5cclxuXHJcbiAgICAgIDxkaXYgY2xhc3M9XCJkcm9wem9uZS1sYWJlbFwiPlxyXG4gICAgICAgIDxkaXYgY2xhc3M9XCJzdmctYW5kLXZhbGlkYXRpb25cIj5cclxuICAgICAgICAgIDwhLS0gVXBsb2FkIGljb24gLS0+XHJcbiAgICAgICAgICA8c3ZnIHhtbG5zPVwiaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmdcIiB3aWR0aD1cIjcwXCIgaGVpZ2h0PVwiNzBcIiB2aWV3Qm94PVwiMCAwIDcwIDcwXCIgZmlsbD1cIm5vbmVcIj5cclxuICAgICAgICAgICAgPHBhdGggb3BhY2l0eT1cIjAuNFwiXHJcbiAgICAgICAgICAgICAgZD1cIk01OC4zMzMgNDguODMzMkM2MS44OTU3IDQ1Ljg5MDggNjQuMTY2MyA0MS40Mzk3IDY0LjE2NjMgMzYuNDU4M0M2NC4xNjYzIDI3LjU5ODggNTYuOTg0MyAyMC40MTY3IDQ4LjEyNDcgMjAuNDE2N0M0Ny40ODc0IDIwLjQxNjcgNDYuODkxMiAyMC4wODQyIDQ2LjU2NzUgMTkuNTM1MUM0Mi43NjQxIDEzLjA4MDggMzUuNzQxNyA4Ljc1IDI3LjcwOCA4Ljc1QzE1LjYyNjggOC43NSA1LjgzMzAxIDE4LjU0MzggNS44MzMwMSAzMC42MjVDNS44MzMwMSAzNi42NTExIDguMjY5NzQgNDIuMTA4MiAxMi4yMTE2IDQ2LjA2NDRcIlxyXG4gICAgICAgICAgICAgIHN0cm9rZT1cIiM0QjU0ODlcIiBzdHJva2Utd2lkdGg9XCIyXCIgc3Ryb2tlLWxpbmVjYXA9XCJyb3VuZFwiIHN0cm9rZS1saW5lam9pbj1cInJvdW5kXCIgLz5cclxuICAgICAgICAgICAgPHBhdGggZD1cIk0yMy4zMzMgNDYuNjY2N0wzNC45OTk3IDM1TTM0Ljk5OTcgMzVMNDYuNjY2MyA0Ni42NjY3TTM0Ljk5OTcgMzVWNjEuMjVcIiBzdHJva2U9XCIjNEI1NDg5XCJcclxuICAgICAgICAgICAgICBzdHJva2Utd2lkdGg9XCIyXCIgc3Ryb2tlLWxpbmVjYXA9XCJyb3VuZFwiIHN0cm9rZS1saW5lam9pbj1cInJvdW5kXCIgLz5cclxuICAgICAgICAgIDwvc3ZnPlxyXG5cclxuICAgICAgICAgIDwhLS0gVXBsb2FkIHRleHQgLS0+XHJcbiAgICAgICAgICA8ZGl2IGNsYXNzPVwiYmJzZi12YWxpZGF0aW9uLW1zZyB0ZXh0LWNlbnRlclwiPlxyXG4gICAgICAgICAgICB7eyB1dGlsaXR5U2VydmljZS5nZXRSZXNvdXJjZVZhbHVlKCdVcGxvYWQnKSB9fVxyXG4gICAgICAgICAgPC9kaXY+XHJcblxyXG4gICAgICAgICAgPCEtLSBWYWxpZGF0aW9uIG1lc3NhZ2VzIC0tPlxyXG4gICAgICAgICAgPGRpdiBjbGFzcz1cImJic2YtdmFsaWRhdGlvbi1tc2cgdGV4dC1jZW50ZXJcIiAqbmdJZj1cInZhbGlkYXRpb25NZXNzYWdlXCIgW2lubmVySFRNTF09XCJ2YWxpZGF0aW9uTWVzc2FnZVwiPlxyXG4gICAgICAgICAgPC9kaXY+XHJcblxyXG4gICAgICAgICAgPGRpdiBjbGFzcz1cImJic2YtdmFsaWRhdGlvbi1tc2cgdGV4dC1jZW50ZXIgdGV4dC1kYW5nZXJcIlxyXG4gICAgICAgICAgICAqbmdJZj1cInZhbGlkYXRpb25Db3VudE1lc3NhZ2UgJiYgb3B0aW9ucy5pc011bHRpcGxlRmlsZSAmJiBvcHRpb25zLm1heE5vT2ZGaWxlcyA+IDBcIlxyXG4gICAgICAgICAgICBbaW5uZXJIVE1MXT1cInZhbGlkYXRpb25Db3VudE1lc3NhZ2VcIj5cclxuICAgICAgICAgIDwvZGl2PlxyXG4gICAgICAgIDwvZGl2PlxyXG4gICAgICA8L2Rpdj5cclxuXHJcbiAgICAgIDwhLS0gSGlkZGVuIGZpbGUgaW5wdXQgLS0+XHJcbiAgICAgIDxpbnB1dCBuZzJGaWxlU2VsZWN0IFt1cGxvYWRlcl09XCJ1cGxvYWRlclwiIFthY2NlcHRdPVwiYWNjZXB0ZWRUeXBlXCJcclxuICAgICAgICBjbGFzcz1cImZpbGVTZWxlY3RvciBjdXN0b21GaWxlVXBsb2FkUGxhY21lbnQgaGlkZGVuIHYtcmVxdWlyZWQtbXVsdGlwbGVmaWxlcyBkLW5vbmVcIlxyXG4gICAgICAgIFthdHRyLm11bHRpcGxlXT1cIm9wdGlvbnMuaXNNdWx0aXBsZUZpbGUgPyAnbXVsdGlwbGUnIDogbnVsbFwiIG5hbWU9XCJmaWxlXCIgdHlwZT1cImZpbGVcIiBhdXRvY29tcGxldGU9XCJvZmZcIlxyXG4gICAgICAgIChjaGFuZ2UpPVwib25GaWxlQ2hhbmdlKClcIiBbbmdDbGFzc109XCJvcHRpb25zLnZpZXdUeXBlID09PSAxID8gJycgOiAnY29sLW1kLTknXCIgW2lkXT1cIm9wdGlvbnMubmFtZVwiICNmaWxlSW5wdXRcclxuICAgICAgICBbY2xhc3MuaXMtaW52YWxpZF09XCJmaWxlVXBsb2FkRm9ybUNvbnRyb2wuaW52YWxpZCAmJiBmaWxlVXBsb2FkRm9ybUNvbnRyb2wudG91Y2hlZFwiIC8+XHJcbiAgICA8L2Rpdj5cclxuICAgIDwhLS0gUmVhZC1vbmx5IHN0YXRlIHdpdGggbm8gZmlsZXMgLS0+XHJcbiAgICA8ZGl2ICpuZ0lmPVwib3B0aW9ucy5pc1JlYWRvbmx5ICYmICghb3B0aW9ucy52YWx1ZSB8fCAodXBsb2FkZXIucXVldWUgJiYgdXBsb2FkZXIucXVldWUubGVuZ3RoID09PSAwKSlcIj5cclxuICAgICAgPHNwYW4gY2xhc3M9XCJyZWFkb25seS12aWV3XCI+e3sgdXRpbGl0eVNlcnZpY2UuZ2V0UmVzb3VyY2VWYWx1ZSgnTkEnKSB9fTwvc3Bhbj5cclxuICAgIDwvZGl2PlxyXG4gIDwvZGl2PlxyXG4gIDwhLS0gVXBsb2FkZWQgZmlsZXMgbGlzdCAtLT5cclxuICA8ZGl2IGNsYXNzPVwidXBsb2FkZWQtaXRlbXNcIiAqbmdJZj1cInNob3VsZFNob3dGaWxlTGlzdCgpXCI+XHJcbiAgICA8ZGl2IGNsYXNzPVwiYnRuLWdyb3VwXCIgKm5nRm9yPVwibGV0IGl0ZW0gb2YgdXBsb2FkZXIucXVldWU7IHRyYWNrQnk6IHRyYWNrQnlGdW5jdGlvblwiPlxyXG5cclxuICAgICAgPCEtLSBBc3luYyB1cGxvYWQgY29tcGxldGVkIGZpbGVzIC0tPlxyXG4gICAgICA8bmctY29udGFpbmVyICpuZ0lmPVwiaXRlbT8ucHJvZ3Jlc3MgPT09IDEwMCAmJiBvcHRpb25zLmlzVXBsb2FkRmlsZUFzeW5jXCI+XHJcbiAgICAgICAgPCEtLSBEb3dubG9hZCBsaW5rIC0gYWx3YXlzIHZpc2libGUgLS0+XHJcbiAgICAgICAgPGJ1dHRvbiAqbmdJZj1cImdldEZpbGVEb3dubG9hZFVybChpdGVtKTsgZWxzZSBub1VybFRlbXBsYXRlXCIgdHlwZT1cImJ1dHRvblwiXHJcbiAgICAgICAgICBjbGFzcz1cImJ0bi1kb3dubG9hZC1maWxlIGJ0bi1zbSBidG4tcHJvZ3Jlc3MtdXBsb2FkXCIgKGNsaWNrKT1cImRvd25sb2FkRmlsZShpdGVtKVwiXHJcbiAgICAgICAgICBbdGl0bGVdPVwiJ0Rvd25sb2FkICcgKyBnZXRGaWxlTmFtZShpdGVtKVwiPlxyXG4gICAgICAgICAgPHNwYW4gY2xhc3M9XCJmaWxlLW5hbWVcIj57eyBnZXRGaWxlTmFtZShpdGVtKSB9fTwvc3Bhbj5cclxuICAgICAgICA8L2J1dHRvbj5cclxuXHJcbiAgICAgICAgPCEtLSBGaWxlIG5hbWUgZGlzcGxheSB3aGVuIG5vIFVSTCBhdmFpbGFibGUgLS0+XHJcbiAgICAgICAgPG5nLXRlbXBsYXRlICNub1VybFRlbXBsYXRlPlxyXG4gICAgICAgICAgPHNwYW4gY2xhc3M9XCJidG4tZG93bmxvYWQtZmlsZSBidG4tc20gYnRuLXByb2dyZXNzLXVwbG9hZFwiIFt0aXRsZV09XCJnZXRGaWxlTmFtZShpdGVtKVwiPlxyXG4gICAgICAgICAgICA8c3BhbiBjbGFzcz1cImZpbGUtbmFtZVwiPnt7IGdldEZpbGVOYW1lKGl0ZW0pIH19PC9zcGFuPlxyXG4gICAgICAgICAgPC9zcGFuPlxyXG4gICAgICAgIDwvbmctdGVtcGxhdGU+XHJcblxyXG4gICAgICAgIDwhLS0gUmVtb3ZlIGJ1dHRvbiAtIG9ubHkgc2hvdyB3aGVuIG5vdCByZWFkb25seSBhbmQgbm90IGRpc2FibGVkIC0tPlxyXG4gICAgICAgIDxidXR0b24gKm5nSWY9XCJpc1JlbW92ZUVuYWJsZWQoKVwiIGNsYXNzPVwiYnRuIGJ0bi1kb3dubG9hZC1maWxlIGJ0bi1zbVwiIHR5cGU9XCJidXR0b25cIlxyXG4gICAgICAgICAgKGNsaWNrKT1cIml0ZW0ucmVtb3ZlKCk7IHJlbW92ZUZyb21Db250cm9sVmFsdWUoaXRlbSlcIiBbYXR0ci5hcmlhLWxhYmVsXT1cIidSZW1vdmUgJyArIGdldEZpbGVOYW1lKGl0ZW0pXCJcclxuICAgICAgICAgIFt0aXRsZV09XCInUmVtb3ZlICcgKyBnZXRGaWxlTmFtZShpdGVtKVwiPlxyXG4gICAgICAgICAgPCEtLSBEZWxldGUgaWNvbiAtLT5cclxuICAgICAgICAgIDxzdmcgeG1sbnM9XCJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2Z1wiIHdpZHRoPVwiMTRcIiBoZWlnaHQ9XCIxNFwiIHZpZXdCb3g9XCIwIDAgMTQgMTRcIiBmaWxsPVwibm9uZVwiPlxyXG4gICAgICAgICAgICA8cGF0aCBvcGFjaXR5PVwiMC40XCJcclxuICAgICAgICAgICAgICBkPVwiTTkuMzMzMDEgMy43MDU4NFYzLjI2NjYzQzkuMzMzMDEgMi42NTE2NiA5LjMzMzAxIDIuMzQ0MTkgOS4yMDU4NyAyLjEwOTNDOS4wOTQwNSAxLjkwMjcgOC45MTU1NSAxLjczNDcxIDguNjk2MDQgMS42Mjk0NEM4LjQ0NjQ3IDEuNTA5NzcgOC4xMTk3NyAxLjUwOTc3IDcuNDY2MzggMS41MDk3N0g2LjUzMzA1QzUuODc5NjUgMS41MDk3NyA1LjU1Mjk2IDEuNTA5NzcgNS4zMDMzOSAxLjYyOTQ0QzUuMDgzODcgMS43MzQ3MSA0LjkwNTM5IDEuOTAyNyA0Ljc5MzU0IDIuMTA5M0M0LjY2NjM4IDIuMzQ0MTkgNC42NjYzOCAyLjY1MTY2IDQuNjY2MzggMy4yNjY2M1YzLjcwNTg0XCJcclxuICAgICAgICAgICAgICBzdHJva2U9XCIjRDgzNzMxXCIgc3Ryb2tlLXdpZHRoPVwiMS41XCIgc3Ryb2tlLWxpbmVjYXA9XCJyb3VuZFwiIHN0cm9rZS1saW5lam9pbj1cInJvdW5kXCIgLz5cclxuICAgICAgICAgICAgPHBhdGhcclxuICAgICAgICAgICAgICBkPVwiTTEuNzUgMy43MDYwNUgxMi4yNU0xMS4wODM0IDMuNzA2MDVWOS44NTUxQzExLjA4MzQgMTAuNzc3NSAxMS4wODM0IDExLjIzODcgMTAuODkyNiAxMS41OTFDMTAuNzI0OCAxMS45MDEgMTAuNDU3MSAxMi4xNTI5IDEwLjEyNzggMTIuMzEwOUM5Ljc1MzQ1IDEyLjQ5MDQgOS4yNjM0NSAxMi40OTA0IDguMjgzMzQgMTIuNDkwNEg1LjcxNjY2QzQuNzM2NTggMTIuNDkwNCA0LjI0NjUzIDEyLjQ5MDQgMy44NzIxOCAxMi4zMTA5QzMuNTQyOSAxMi4xNTI5IDMuMjc1MTkgMTEuOTAxIDMuMTA3NDEgMTEuNTkxQzIuOTE2NjYgMTEuMjM4NyAyLjkxNjY2IDEwLjc3NzUgMi45MTY2NiA5Ljg1NTFWMy43MDYwNVwiXHJcbiAgICAgICAgICAgICAgc3Ryb2tlPVwiI0Q4MzczMVwiIHN0cm9rZS13aWR0aD1cIjEuNVwiIHN0cm9rZS1saW5lY2FwPVwicm91bmRcIiBzdHJva2UtbGluZWpvaW49XCJyb3VuZFwiIC8+XHJcbiAgICAgICAgICA8L3N2Zz5cclxuICAgICAgICA8L2J1dHRvbj5cclxuICAgICAgPC9uZy1jb250YWluZXI+XHJcblxyXG4gICAgICA8IS0tIFN5bmMgdXBsb2FkIGZpbGVzIC0tPlxyXG4gICAgICA8bmctY29udGFpbmVyICpuZ0lmPVwiIW9wdGlvbnMuaXNVcGxvYWRGaWxlQXN5bmNcIj5cclxuICAgICAgICA8IS0tIERvd25sb2FkIGxpbmsgLSBhbHdheXMgdmlzaWJsZSAtLT5cclxuICAgICAgICA8YnV0dG9uIHR5cGU9XCJidXR0b25cIiBjbGFzcz1cImJ0biBidG4tZG93bmxvYWQtZmlsZSBidG4tc21cIiAoY2xpY2spPVwiZG93bmxvYWRGaWxlKGl0ZW0pXCJcclxuICAgICAgICAgIFt0aXRsZV09XCInRG93bmxvYWQgJyArIGdldEZpbGVOYW1lKGl0ZW0pXCI+XHJcbiAgICAgICAgICA8IS0tIERvd25sb2FkIGljb24gLS0+XHJcbiAgICAgICAgICA8c3ZnIHdpZHRoPVwiMjRcIiBoZWlnaHQ9XCIyNFwiIHZpZXdCb3g9XCIwIDAgMjQgMjRcIiBmaWxsPVwibm9uZVwiIHhtbG5zPVwiaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmdcIj5cclxuICAgICAgICAgICAgPHBhdGhcclxuICAgICAgICAgICAgICBkPVwiTTIxIDIySDNDMi40IDIyIDIgMjEuNiAyIDIxQzIgMjAuNCAyLjQgMjAgMyAyMEgyMUMyMS42IDIwIDIyIDIwLjQgMjIgMjFDMjIgMjEuNiAyMS42IDIyIDIxIDIyWk0xMyAxMy40VjNDMTMgMi40IDEyLjYgMiAxMiAyQzExLjQgMiAxMSAyLjQgMTEgM1YxMy40SDEzWlwiXHJcbiAgICAgICAgICAgICAgZmlsbD1cImN1cnJlbnRDb2xvclwiPjwvcGF0aD5cclxuICAgICAgICAgICAgPHBhdGggb3BhY2l0eT1cIjAuM1wiIGQ9XCJNNyAxMy40SDE3TDEyLjcgMTcuN0MxMi4zIDE4LjEgMTEuNyAxOC4xIDExLjMgMTcuN0w3IDEzLjRaXCIgZmlsbD1cImN1cnJlbnRDb2xvclwiPlxyXG4gICAgICAgICAgICA8L3BhdGg+XHJcbiAgICAgICAgICA8L3N2Zz5cclxuICAgICAgICAgIDxzcGFuIGNsYXNzPVwiZmlsZS1uYW1lXCI+e3sgZ2V0RmlsZU5hbWUoaXRlbSkgfX08L3NwYW4+XHJcbiAgICAgICAgPC9idXR0b24+XHJcblxyXG4gICAgICAgIDwhLS0gUmVtb3ZlIGJ1dHRvbiAtIG9ubHkgc2hvdyB3aGVuIG5vdCByZWFkb25seSBhbmQgbm90IGRpc2FibGVkIC0tPlxyXG4gICAgICAgIDxidXR0b24gKm5nSWY9XCJpc1JlbW92ZUVuYWJsZWQoKVwiIGNsYXNzPVwiYnRuIGJ0bi1kb3dubG9hZC1maWxlIGJ0bi1zbSBidG4tZGFuZ2VyXCIgdHlwZT1cImJ1dHRvblwiXHJcbiAgICAgICAgICAoY2xpY2spPVwiaXRlbS5yZW1vdmUoKTsgcmVtb3ZlRnJvbUNvbnRyb2xWYWx1ZShpdGVtKVwiIFthdHRyLmFyaWEtbGFiZWxdPVwiJ1JlbW92ZSAnICsgZ2V0RmlsZU5hbWUoaXRlbSlcIlxyXG4gICAgICAgICAgW3RpdGxlXT1cIidSZW1vdmUgJyArIGdldEZpbGVOYW1lKGl0ZW0pXCI+XHJcbiAgICAgICAgICA8aSBjbGFzcz1cImZhIGZhLXRpbWVzIHB4LTBcIiBhcmlhLWhpZGRlbj1cInRydWVcIj48L2k+XHJcbiAgICAgICAgPC9idXR0b24+XHJcbiAgICAgIDwvbmctY29udGFpbmVyPlxyXG4gICAgPC9kaXY+XHJcbiAgPC9kaXY+XHJcbiAgPCEtLSBGaWxlIHVwbG9hZCBwcm9ncmVzcyBpbmRpY2F0b3JzIC0tPlxyXG4gIDxkaXYgKm5nRm9yPVwibGV0IGl0ZW0gb2YgdXBsb2FkZXIucXVldWU7IHRyYWNrQnk6IHRyYWNrQnlGdW5jdGlvblwiPlxyXG4gICAgPGRpdiBjbGFzcz1cInVwbG9hZC1pdGVtc1wiIFtuZ0NsYXNzXT1cInsgJ210LTQnOiBvcHRpb25zLmlzTXVsdGlwbGVGaWxlIH1cIlxyXG4gICAgICAqbmdJZj1cIml0ZW0/LnByb2dyZXNzIDwgMTAwICYmIG9wdGlvbnMuaXNVcGxvYWRGaWxlQXN5bmMgJiYgIW9wdGlvbnMuaXNSZWFkb25seVwiPlxyXG5cclxuICAgICAgPGRpdiBjbGFzcz1cInVwbG9hZC1pdGVtcy10b29sYmFyXCI+XHJcbiAgICAgICAgPGg0Pnt7IGdldEZpbGVOYW1lKGl0ZW0pIH19PC9oND5cclxuICAgICAgICA8YnV0dG9uICpuZ0lmPVwiaXNSZW1vdmVFbmFibGVkKClcIiB0eXBlPVwiYnV0dG9uXCIgY2xhc3M9XCJidG4tY2FuY2VsLXVwbG9hZFwiXHJcbiAgICAgICAgICAoY2xpY2spPVwiaXRlbS5yZW1vdmUoKTsgcmVtb3ZlRnJvbUNvbnRyb2xWYWx1ZShpdGVtKVwiXHJcbiAgICAgICAgICBbYXR0ci5hcmlhLWxhYmVsXT1cIidDYW5jZWwgdXBsb2FkIGZvciAnICsgZ2V0RmlsZU5hbWUoaXRlbSlcIj5cclxuICAgICAgICAgIDwhLS0gQ2FuY2VsIGljb24gLS0+XHJcbiAgICAgICAgICA8c3ZnIHhtbG5zPVwiaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmdcIiB3aWR0aD1cIjE4XCIgaGVpZ2h0PVwiMThcIiB2aWV3Qm94PVwiMCAwIDE4IDE4XCIgZmlsbD1cIm5vbmVcIj5cclxuICAgICAgICAgICAgPGcgY2xpcC1wYXRoPVwidXJsKCNjbGlwMF8xMzI0XzEzMjE2KVwiPlxyXG4gICAgICAgICAgICAgIDxwYXRoIG9wYWNpdHk9XCIwLjRcIlxyXG4gICAgICAgICAgICAgICAgZD1cIk05IDE2LjVDMTMuMTQyMSAxNi41IDE2LjUgMTMuMTQyMSAxNi41IDlDMTYuNSA0Ljg1Nzg2IDEzLjE0MjEgMS41IDkgMS41QzQuODU3ODYgMS41IDEuNSA0Ljg1Nzg2IDEuNSA5QzEuNSAxMy4xNDIxIDQuODU3ODYgMTYuNSA5IDE2LjVaXCJcclxuICAgICAgICAgICAgICAgIHN0cm9rZT1cIiNEQkUxRjBcIiBzdHJva2Utd2lkdGg9XCIyXCIgc3Ryb2tlLWxpbmVjYXA9XCJyb3VuZFwiIHN0cm9rZS1saW5lam9pbj1cInJvdW5kXCIgLz5cclxuICAgICAgICAgICAgICA8cGF0aCBkPVwiTTExLjI1IDYuNzVMNi43NSAxMS4yNU02Ljc1IDYuNzVMMTEuMjUgMTEuMjVcIiBzdHJva2U9XCIjREJFMUYwXCIgc3Ryb2tlLXdpZHRoPVwiMlwiXHJcbiAgICAgICAgICAgICAgICBzdHJva2UtbGluZWNhcD1cInJvdW5kXCIgc3Ryb2tlLWxpbmVqb2luPVwicm91bmRcIiAvPlxyXG4gICAgICAgICAgICA8L2c+XHJcbiAgICAgICAgICAgIDxkZWZzPlxyXG4gICAgICAgICAgICAgIDxjbGlwUGF0aCBpZD1cImNsaXAwXzEzMjRfMTMyMTZcIj5cclxuICAgICAgICAgICAgICAgIDxyZWN0IHdpZHRoPVwiMThcIiBoZWlnaHQ9XCIxOFwiIGZpbGw9XCJ3aGl0ZVwiIC8+XHJcbiAgICAgICAgICAgICAgPC9jbGlwUGF0aD5cclxuICAgICAgICAgICAgPC9kZWZzPlxyXG4gICAgICAgICAgPC9zdmc+XHJcbiAgICAgICAgPC9idXR0b24+XHJcbiAgICAgIDwvZGl2PlxyXG5cclxuICAgICAgPGRpdiBjbGFzcz1cInByb2dyZXNzXCI+XHJcbiAgICAgICAgPGRpdiBjbGFzcz1cInByb2dyZXNzLWJhclwiIHJvbGU9XCJwcm9ncmVzc2JhclwiIFthdHRyLmFyaWEtdmFsdWVub3ddPVwiaXRlbT8ucHJvZ3Jlc3NcIiBhcmlhLXZhbHVlbWluPVwiMFwiXHJcbiAgICAgICAgICBhcmlhLXZhbHVlbWF4PVwiMTAwXCIgW2NsYXNzLmZpbGUtdXBsb2FkZWRdPVwiaXRlbT8ucHJvZ3Jlc3MgPCAxMDBcIiBbc3R5bGUud2lkdGguJV09XCJpdGVtPy5wcm9ncmVzc1wiXHJcbiAgICAgICAgICAqbmdJZj1cIml0ZW0/LnByb2dyZXNzID4gMFwiPlxyXG4gICAgICAgIDwvZGl2PlxyXG4gICAgICA8L2Rpdj5cclxuICAgIDwvZGl2PlxyXG4gIDwvZGl2PlxyXG5cclxuICA8IS0tIFZhbGlkYXRpb24gYW5kIGRlc2NyaXB0aW9uIHNlY3Rpb24gLS0+XHJcbiAgPGRpdiBjbGFzcz1cInN1YnRleHQtY29udGFpbmVyXCIgKm5nSWY9XCIhb3B0aW9ucy5pc1JlYWRvbmx5XCI+XHJcbiAgICA8IS0tIFZhbGlkYXRpb24gbWVzc2FnZXMgLS0+XHJcbiAgICA8ZGl2IGNsYXNzPVwiYmJzZi12YWxpZGF0aW9uXCIgKm5nSWY9XCJmaWxlVXBsb2FkRm9ybUNvbnRyb2wuaW52YWxpZCAmJiBmaWxlVXBsb2FkRm9ybUNvbnRyb2wudG91Y2hlZFwiPlxyXG4gICAgICA8c3BhbiBbaW5uZXJIVE1MXT1cImdldEVycm9yVmFsaWRhdGlvbihmaWxlVXBsb2FkRm9ybUNvbnRyb2wuZXJyb3JzIHwga2V5dmFsdWUpXCI+PC9zcGFuPlxyXG4gICAgPC9kaXY+XHJcblxyXG4gICAgPCEtLSBDb250cm9sIGRlc2NyaXB0aW9uIC0tPlxyXG4gICAgPGRpdiBjbGFzcz1cImJic2YtY29udHJvbC1kZXNjXCIgKm5nSWY9XCJvcHRpb25zLmxhYmVsRGVzY3JpcHRpb25cIj5cclxuICAgICAge3sgb3B0aW9ucy5sYWJlbERlc2NyaXB0aW9uIH19XHJcbiAgICA8L2Rpdj5cclxuXHJcbiAgICA8IS0tIFJlc2V0IGVycm9yIHN0YXRlIC0tPlxyXG4gICAgPGRpdiAqbmdJZj1cIihncm91cC52YWxpZCAmJiBncm91cC5kaXJ0eSAmJiBncm91cC50b3VjaGVkKSB8fCAoZ3JvdXAudW50b3VjaGVkICYmIGdyb3VwLmludmFsaWQgJiYgZ3JvdXAuZGlydHkpXCI+XHJcbiAgICAgIHt7IHJlc2V0RXJyb3IoKSB9fVxyXG4gICAgPC9kaXY+XHJcbiAgPC9kaXY+XHJcbjwvZGl2PiJdfQ==
720
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiRmlsZVVwbG9hZC5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9iYnNmLWNvbnRyb2xzL3NyYy9saWIvY29udHJvbHMvRmlsZVVwbG9hZC9GaWxlVXBsb2FkLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uLy4uL3Byb2plY3RzL2Jic2YtY29udHJvbHMvc3JjL2xpYi9jb250cm9scy9GaWxlVXBsb2FkL0ZpbGVVcGxvYWQuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFNBQVMsRUFBeUIsS0FBSyxFQUFFLFFBQVEsRUFBRSxTQUFTLEVBQWMsTUFBTSxFQUFFLFlBQVksRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUMvSCxPQUFPLEVBQUUsV0FBVyxFQUFFLFVBQVUsRUFBb0UsTUFBTSxnQkFBZ0IsQ0FBQztBQUMzSCxPQUFPLEVBQUUsWUFBWSxFQUFpRCxNQUFNLGlCQUFpQixDQUFDO0FBRTlGLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUVyRCxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQy9CLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUMzQyxPQUFPLEVBQVcsZUFBZSxFQUFxQix1QkFBdUIsRUFBRSxNQUFNLHFCQUFxQixDQUFDOzs7Ozs7O0FBUzNHLE1BQU0sT0FBTyxtQkFBbUI7YUFDdkIsMkJBQXNCLEdBQUcsSUFBSSxBQUFQLENBQVE7SUE2QnJDLFlBQ3NCLGdCQUFrQyxFQUMvQyw2QkFBaUQsRUFDaEQsY0FBOEIsRUFDL0IsY0FBOEIsRUFDN0Isd0JBQWtELEVBQ2xELGNBQThCLEVBQzlCLGlCQUFvQztRQU54QixxQkFBZ0IsR0FBaEIsZ0JBQWdCLENBQWtCO1FBQy9DLGtDQUE2QixHQUE3Qiw2QkFBNkIsQ0FBb0I7UUFDaEQsbUJBQWMsR0FBZCxj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QixtQkFBbUIsd1JDakJoQyw2bVdBOEpNOzs0RkQ3SU8sbUJBQW1CO2tCQUwvQixTQUFTOytCQUNFLGlCQUFpQixjQUVmLEtBQUs7OzBCQWlDZCxRQUFRO3dPQTVCZ0MsU0FBUztzQkFBbkQsU0FBUzt1QkFBQyxXQUFXLEVBQUUsRUFBRSxNQUFNLEVBQUUsS0FBSyxFQUFFO2dCQUdoQyxLQUFLO3NCQUFiLEtBQUs7Z0JBQ0csT0FBTztzQkFBZixLQUFLO2dCQUNJLFFBQVE7c0JBQWpCLE1BQU07Z0JBQ0csZ0JBQWdCO3NCQUF6QixNQUFNIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29tcG9uZW50LCBPbkluaXQsIEFmdGVyVmlld0luaXQsIElucHV0LCBPcHRpb25hbCwgVmlld0NoaWxkLCBFbGVtZW50UmVmLCBPdXRwdXQsIEV2ZW50RW1pdHRlciB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xyXG5pbXBvcnQgeyBGb3JtQ29udHJvbCwgVmFsaWRhdG9ycywgRm9ybUdyb3VwLCBBYnN0cmFjdENvbnRyb2wsIENvbnRyb2xDb250YWluZXIsIEZvcm1Hcm91cERpcmVjdGl2ZSB9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcclxuaW1wb3J0IHsgRmlsZVVwbG9hZGVyLCBGaWxlTGlrZU9iamVjdCwgRmlsZVVwbG9hZGVyT3B0aW9ucywgRmlsZUl0ZW0gfSBmcm9tICduZzItZmlsZS11cGxvYWQnO1xyXG5pbXBvcnQgeyBDb250cm9sVmFsaWRhdGlvblNlcnZpY2UsIFV0aWxpdHlTZXJ2aWNlIH0gZnJvbSAnQGJuc2lnaHRzL2Jic2YtdXRpbGl0aWVzJztcclxuaW1wb3J0IHsgSHR0cEV2ZW50VHlwZSB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbi9odHRwJztcclxuaW1wb3J0IHsgT25EZXN0cm95IH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XHJcbmltcG9ydCB7IFN1YmplY3QgfSBmcm9tICdyeGpzJztcclxuaW1wb3J0IHsgdGFrZVVudGlsIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xyXG5pbXBvcnQgeyBGaWxlRFRPLCBGaWxlVXBsb2FkTW9kZWwsIEZpbGVVcGxvYWRPcHRpb25zLCBNdWx0aXBsZUZpbGVVcGxvYWRNb2RlbCB9IGZyb20gJy4uLy4uL1NoYXJlZC9Nb2RlbHMnO1xyXG5pbXBvcnQgeyBDb250cm9sVXRpbGl0eSwgRmlsZVVwbG9hZFNlcnZpY2UsIEdsb2JhbFNldHRpbmdzIH0gZnJvbSAnLi4vLi4vU2hhcmVkL3NlcnZpY2VzJztcclxuXHJcblxyXG5AQ29tcG9uZW50KHtcclxuICBzZWxlY3RvcjogJ0JCU0YtRmlsZVVwbG9hZCcsXHJcbiAgdGVtcGxhdGVVcmw6ICcuL0ZpbGVVcGxvYWQuY29tcG9uZW50Lmh0bWwnLFxyXG4gIHN0YW5kYWxvbmU6IGZhbHNlXHJcbn0pXHJcbmV4cG9ydCBjbGFzcyBGaWxlVXBsb2FkQ29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0LCBBZnRlclZpZXdJbml0LCBPbkRlc3Ryb3kge1xyXG4gIHN0YXRpYyBjb250cm9sQ29udGFpbmVyU3RhdGljID0gbnVsbDtcclxuXHJcbiAgQFZpZXdDaGlsZCgnZmlsZUlucHV0JywgeyBzdGF0aWM6IGZhbHNlIH0pIGZpbGVJbnB1dDogRWxlbWVudFJlZjtcclxuXHJcbiAgaXNTdWJtaXR0ZWQ6IGJvb2xlYW47XHJcbiAgQElucHV0KCkgZ3JvdXA6IEZvcm1Hcm91cDtcclxuICBASW5wdXQoKSBvcHRpb25zOiBGaWxlVXBsb2FkT3B0aW9ucztcclxuICBAT3V0cHV0KCkgT25DaGFuZ2UgPSBuZXcgRXZlbnRFbWl0dGVyKCk7XHJcbiAgQE91dHB1dCgpIGlzVXBsb2FkQ29tcGxldGUgPSBuZXcgRXZlbnRFbWl0dGVyKCk7XHJcblxyXG4gIGZpbGVVcGxvYWRGb3JtQ29udHJvbDogQWJzdHJhY3RDb250cm9sO1xyXG4gIHZhbGlkYXRpb25NZXNzYWdlID0gJyc7XHJcbiAgdmFsaWRhdGlvbkNvdW50TWVzc2FnZSA9ICcnO1xyXG4gIHVwbG9hZGVyOiBGaWxlVXBsb2FkZXI7XHJcbiAgaGFzQW5vdGhlckRyb3Bab25lT3ZlcjogYm9vbGVhbjtcclxuICBhY2NlcHRlZFR5cGU6IHN0cmluZyA9ICcnO1xyXG4gIGFjY2VwdGVkVHlwZUFycmF5OiBzdHJpbmdbXSA9IFtdO1xyXG4gIHRvb2xUaXBUeXBlQXJyYXk6IHN0cmluZ1tdID0gW107XHJcbiAgZmlsZUxpa2VPYmplY3Q6IEZpbGVMaWtlT2JqZWN0O1xyXG4gIG1hcmtBbGxBc1RvdWNoZWQ6IGJvb2xlYW4gPSBmYWxzZTtcclxuICB2YWxpZGF0aW9uUnVsZXMgPSBbXTtcclxuICB2YWxpZGF0aW9uUnVsZXNBc3luYyA9IFtdO1xyXG4gIGZpbGVVcGxvYWRNb2RlbDogRmlsZVVwbG9hZE1vZGVsO1xyXG4gIG11bHRpcGxlRmlsZVVwbG9hZE1vZGVsOiBNdWx0aXBsZUZpbGVVcGxvYWRNb2RlbDtcclxuICBmaWxlOiBhbnk7XHJcbiAgZGVsZXRlZEZpbGVzOiBGaWxlRFRPW10gPSBbXTtcclxuICBwcml2YXRlIGRlc3Ryb3kkID0gbmV3IFN1YmplY3Q8dm9pZD4oKTtcclxuICBwcml2YXRlIHBlbmRpbmdWYWxpZGF0aW9uRXJyb3JzOiBhbnkgPSBudWxsO1xyXG5cclxuICBjb25zdHJ1Y3RvcihcclxuICAgIEBPcHRpb25hbCgpIHByaXZhdGUgY29udHJvbENvbnRhaW5lcjogQ29udHJvbENvbnRhaW5lcixcclxuICAgIHB1YmxpYyBNdWx0aXBsZUZpbGVVcGxvYWRDb250cm9sSG9zdDogRm9ybUdyb3VwRGlyZWN0aXZlLFxyXG4gICAgcHJpdmF0ZSBjb250cm9sVXRpbGl0eTogQ29udHJvbFV0aWxpdHksXHJcbiAgICBwdWJsaWMgVXRpbGl0eVNlcnZpY2U6IFV0aWxpdHlTZXJ2aWNlLFxyXG4gICAgcHJpdmF0ZSBjb250cm9sVmFsaWRhdGlvblNlcnZpY2U6IENvbnRyb2xWYWxpZGF0aW9uU2VydmljZSxcclxuICAgIHByaXZhdGUgZ2xvYmFsU2V0dGluZ3M6IEdsb2JhbFNldHRpbmdzLFxyXG4gICAgcHJpdmF0ZSBmaWxlVXBsb2FkU2VydmljZTogRmlsZVVwbG9hZFNlcnZpY2VcclxuICApIHtcclxuICAgIEZpbGVVcGxvYWRDb21wb25lbnQuY29udHJvbENvbnRhaW5lclN0YXRpYyA9IHRoaXMuY29udHJvbENvbnRhaW5lcjtcclxuICAgIC8vIEluaXRpYWxpemUgdXBsb2FkZXIgd2l0aCBtaW5pbWFsIG9wdGlvbnMsIFVSTCB3aWxsIGJlIHNldCBpbiBuZ09uSW5pdCBvbmx5IGlmIG5lZWRlZFxyXG4gICAgdGhpcy51cGxvYWRlciA9IG5ldyBGaWxlVXBsb2FkZXIoe1xyXG4gICAgICB1cmw6ICcnLCAvLyBFbXB0eSBVUkwgaW5pdGlhbGx5LCB3aWxsIGJlIHNldCBpbiBuZ09uSW5pdCBvbmx5IGlmIGlzVXBsb2FkRmlsZUFzeW5jIGlzIHRydWVcclxuICAgICAgZGlzYWJsZU11bHRpcGFydDogZmFsc2UgLy8gJ0Rpc2FibGVNdWx0aXBhcnQnIG11c3QgYmUgJ3RydWUnIGZvciBmb3JtYXREYXRhRnVuY3Rpb24gdG8gYmUgY2FsbGVkLlxyXG4gICAgfSBhcyBGaWxlVXBsb2FkZXJPcHRpb25zKTtcclxuICAgIHRoaXMuaGFzQW5vdGhlckRyb3Bab25lT3ZlciA9IGZhbHNlO1xyXG4gIH1cclxuXHJcbiAgbmdPbkluaXQoKSB7XHJcbiAgICB0aGlzLmZpbGVVcGxvYWRNb2RlbCA9IG5ldyBGaWxlVXBsb2FkTW9kZWwoKTtcclxuICAgIHRoaXMubXVsdGlwbGVGaWxlVXBsb2FkTW9kZWwgPSBuZXcgTXVsdGlwbGVGaWxlVXBsb2FkTW9kZWwoKTtcclxuICAgIGlmICghdGhpcy5vcHRpb25zLnZpZXdUeXBlKSB0aGlzLm9wdGlvbnMudmlld1R5cGUgPSB0aGlzLmdsb2JhbFNldHRpbmdzLnZpZXdUeXBlO1xyXG5cclxuICAgIC8vIENvbmZpZ3VyZSB1cGxvYWRlciBvcHRpb25zIC0gbm8gVVJMIG5lZWRlZCBzaW5jZSB3ZSBoYW5kbGUgdXBsb2FkcyB2aWEgRmlsZVVwbG9hZFNlcnZpY2VcclxuICAgIC8vIE5vdGU6IGFsbG93ZWRNaW1lVHlwZSBpbiBuZzItZmlsZS11cGxvYWQgZG9lc24ndCB3b3JrIHdlbGwgd2l0aCBjb21tYS1zZXBhcmF0ZWQgZW51bSB2YWx1ZXNcclxuICAgIC8vIFdlIGhhbmRsZSBNSU1FIHR5cGUgdmFsaWRhdGlvbiBtYW51YWxseSBpbiBvbkZpbGVDaGFuZ2VcclxuICAgIHRoaXMudXBsb2FkZXIuc2V0T3B0aW9ucyh7XHJcbiAgICAgIHVybDogJycsIC8vIE5vdCB1c2VkIC0gdXBsb2FkcyBoYW5kbGVkIGJ5IEZpbGVVcGxvYWRTZXJ2aWNlIHdoZW4gaXNVcGxvYWRGaWxlQXN5bmMgaXMgdHJ1ZVxyXG4gICAgICBkaXNhYmxlTXVsdGlwYXJ0OiBmYWxzZSxcclxuICAgICAgYXV0b1VwbG9hZDogZmFsc2UgLy8gV2UgbWFudWFsbHkgY29udHJvbCB1cGxvYWRzXHJcbiAgICAgIC8vIGFsbG93ZWRNaW1lVHlwZSByZW1vdmVkIC0gd2UgaGFuZGxlIHZhbGlkYXRpb24gbWFudWFsbHkgZm9yIGJldHRlciBjb250cm9sXHJcbiAgICB9KTtcclxuXHJcbiAgICBpZiAodGhpcy5vcHRpb25zLnZhbHVlID09IG51bGwpIHtcclxuICAgICAgaWYgKHRoaXMub3B0aW9ucy5pc011bHRpcGxlRmlsZSA9PSB0cnVlKSB7XHJcbiAgICAgICAgLy90aGlzLm9wdGlvbnMuVmFsdWU9dGhpcy5tdWx0aXBsZUZpbGVVcGxvYWRNb2RlbFxyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIC8vIHRoaXMub3B0aW9ucy5WYWx1ZT10aGlzLmZpbGVVcGxvYWRNb2RlbFxyXG4gICAgICB9XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBpZiAodGhpcy5vcHRpb25zLmlzTXVsdGlwbGVGaWxlID09IHRydWUpIHtcclxuICAgICAgICBsZXQgZmlsZXM6IGFueVtdID0gW107XHJcbiAgICAgICAgdGhpcy5tdWx0aXBsZUZpbGVVcGxvYWRNb2RlbC5leGlzdGluZ0ZpbGVzID0gdGhpcy5vcHRpb25zLnZhbHVlLmV4aXN0aW5nRmlsZXM7XHJcbiAgICAgICAgdGhpcy5tdWx0aXBsZUZpbGVVcGxvYWRNb2RlbC51cGxvYWRlZEZpbGVzID0gW107XHJcbiAgICAgICAgZm9yIChsZXQgaW5kZXggPSAwOyBpbmRleCA8IHRoaXMub3B0aW9ucy52YWx1ZS5leGlzdGluZ0ZpbGVzLmxlbmd0aDsgaW5kZXgrKykge1xyXG4gICAgICAgICAgY29uc3QgZWxlbWVudCA9IHRoaXMub3B0aW9ucy52YWx1ZS5leGlzdGluZ0ZpbGVzW2luZGV4XTtcclxuICAgICAgICAgIHZhciBieXRlcyA9IG5ldyBVaW50OEFycmF5KGVsZW1lbnQuYnl0ZXMpO1xyXG4gICAgICAgICAgdmFyIGJhc2U2NCA9IGJ0b2EoU3RyaW5nLmZyb21DaGFyQ29kZSguLi5BcnJheS5mcm9tKGJ5dGVzKSkpO1xyXG4gICAgICAgICAgdGhpcy5maWxlTGlrZU9iamVjdCA9IDxGaWxlTGlrZU9iamVjdD57XHJcbiAgICAgICAgICAgIG5hbWU6IGVsZW1lbnQubmFtZVdpdGhFeHRlbnNpb24sXHJcbiAgICAgICAgICAgIHR5cGU6IGVsZW1lbnQubWltZVR5cGUsXHJcbiAgICAgICAgICAgIHJhd0ZpbGU6IDxhbnk+YmFzZTY0XHJcbiAgICAgICAgICB9O1xyXG4gICAgICAgICAgLy8gbGV0IGJsb2I6IGFueTtcclxuICAgICAgICAgIC8vIGJsb2IgPSBuZXcgQmxvYihbJyddKSBhcyBhbnk7XHJcbiAgICAgICAgICAvLyBibG9iLm5hbWUgPSBlbGVtZW50LkZpbGVOYW1lO1xyXG4gICAgICAgICAgLy8gYmxvYi5sYXN0TW9kaWZpZWREYXRlID0gbnVsbDtcclxuICAgICAgICAgIC8vIGJsb2Iud2Via2l0UmVsYXRpdmVQYXRoID0gJyc7XHJcbiAgICAgICAgICBsZXQgZmlsZSA9IHRoaXMuZmlsZUxpa2VPYmplY3QgYXMgYW55O1xyXG4gICAgICAgICAgZmlsZS51cmwgPSBlbGVtZW50LmZpbGVVUkw7XHJcbiAgICAgICAgICBmaWxlcy5wdXNoKGZpbGUpO1xyXG4gICAgICAgIH1cclxuICAgICAgICB0aGlzLnVwbG9hZGVyLmFkZFRvUXVldWUoZmlsZXMpO1xyXG4gICAgICAgIGNvbnNvbGUubG9nKHRoaXMudXBsb2FkZXIucXVldWUpO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIGNvbnN0IGVsZW1lbnQgPSB0aGlzLm9wdGlvbnMudmFsdWUuZmlsZSA/PyB0aGlzLm9wdGlvbnMudmFsdWU7XHJcbiAgICAgICAgdmFyIGJ5dGVzID0gbmV3IFVpbnQ4QXJyYXkoZWxlbWVudC5ieXRlcyk7XHJcbiAgICAgICAgdmFyIGJhc2U2NCA9IGJ0b2EoU3RyaW5nLmZyb21DaGFyQ29kZSguLi5BcnJheS5mcm9tKGJ5dGVzKSkpO1xyXG4gICAgICAgIHRoaXMuZmlsZUxpa2VPYmplY3QgPSA8RmlsZUxpa2VPYmplY3Q+e1xyXG4gICAgICAgICAgbmFtZTogZWxlbWVudC5uYW1lV2l0aEV4dGVuc2lvbixcclxuICAgICAgICAgIHR5cGU6IGVsZW1lbnQubWltZVR5cGUsXHJcbiAgICAgICAgICByYXdGaWxlOiA8YW55PmJhc2U2NFxyXG4gICAgICAgIH07XHJcbiAgICAgICAgdGhpcy5maWxlID0gZWxlbWVudDtcclxuICAgICAgICBsZXQgZmlsZSA9IHRoaXMuZmlsZUxpa2VPYmplY3QgYXMgYW55O1xyXG4gICAgICAgIGZpbGUudXJsID0gZWxlbWVudC5maWxlVVJMO1xyXG4gICAgICAgIHRoaXMudXBsb2FkZXIuYWRkVG9RdWV1ZShbZmlsZV0pO1xyXG4gICAgICAgIGlmICghdGhpcy5vcHRpb25zLnZhbHVlLmZpbGUpIHtcclxuICAgICAgICAgIHRoaXMuZmlsZVVwbG9hZE1vZGVsID0gbmV3IEZpbGVVcGxvYWRNb2RlbCgpO1xyXG4gICAgICAgICAgdGhpcy5maWxlVXBsb2FkTW9kZWwuZmlsZSA9IHRoaXMub3B0aW9ucy52YWx1ZTtcclxuICAgICAgICB9IGVsc2UgdGhpcy5maWxlVXBsb2FkTW9kZWwgPSB0aGlzLm9wdGlvbnMudmFsdWU7XHJcbiAgICAgICAgdGhpcy5vcHRpb25zLnZhbHVlID0gdGhpcy5maWxlVXBsb2FkTW9kZWw7XHJcbiAgICAgIH1cclxuICAgICAgdGhpcy51cGxvYWRlci5xdWV1ZS5mb3JFYWNoKChlbGVtZW50KSA9PiB7XHJcbiAgICAgICAgZWxlbWVudC5wcm9ncmVzcyA9IDEwMDtcclxuICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKHRoaXMub3B0aW9ucy5sYWJlbEtleSAhPSBudWxsICYmIHRoaXMub3B0aW9ucy5sYWJlbEtleSAhPSAnJylcclxuICAgICAgdGhpcy5vcHRpb25zLmxhYmVsVmFsdWUgPSB0aGlzLlV0aWxpdHlTZXJ2aWNlLmdldFJlc291cmNlVmFsdWUodGhpcy5vcHRpb25zLmxhYmVsS2V5KTtcclxuXHJcbiAgICBpZiAoXHJcbiAgICAgIHRoaXMub3B0aW9ucy5maWxlVXBsb2FkQWNjZXB0c1R5cGVzICE9IG51bGwgJiZcclxuICAgICAgdGhpcy5vcHRpb25zLmZpbGVVcGxvYWRBY2NlcHRzVHlwZXMubGVuZ3RoID4gMFxyXG4gICAgKSB7XHJcbiAgICAgIC8vIFByb2Nlc3MgRmlsZVR5cGUgZW51bSB2YWx1ZXMgd2hpY2ggbWF5IGNvbnRhaW4gY29tbWEtc2VwYXJhdGVkIE1JTUUgdHlwZXNcclxuICAgICAgZm9yIChsZXQgaW5kZXggPSAwOyBpbmRleCA8IHRoaXMub3B0aW9ucy5maWxlVXBsb2FkQWNjZXB0c1R5cGVzLmxlbmd0aDsgaW5kZXgrKykge1xyXG4gICAgICAgIGNvbnN0IFR5cGUgPSB0aGlzLm9wdGlvbnMuZmlsZVVwbG9hZEFjY2VwdHNUeXBlc1tpbmRleF07XHJcbiAgICAgICAgdGhpcy5hY2NlcHRlZFR5cGUgPSB0aGlzLmFjY2VwdGVkVHlwZSArIFR5cGUgKyAnLCc7XHJcbiAgICAgIH1cclxuICAgICAgdGhpcy5hY2NlcHRlZFR5cGVBcnJheSA9IHRoaXMuYWNjZXB0ZWRUeXBlLnNwbGl0KCcsJyk7XHJcbiAgICAgIHRoaXMuYWNjZXB0ZWRUeXBlQXJyYXkgPSB0aGlzLmFjY2VwdGVkVHlwZUFycmF5LmZpbHRlcigodmFsdWUpID0+IHZhbHVlLnRyaW0oKSAhPSAnJyk7XHJcblxyXG4gICAgICAvLyBSZWJ1aWxkIGFjY2VwdGVkVHlwZSBzdHJpbmcgZm9yIEhUTUwgYWNjZXB0IGF0dHJpYnV0ZSAocHJvcGVybHkgZm9ybWF0dGVkKVxyXG4gICAgICB0aGlzLmFjY2VwdGVkVHlwZSA9IHRoaXMuYWNjZXB0ZWRUeXBlQXJyYXkuam9pbignLCcpO1xyXG4gICAgICAvLyBQcm9jZXNzIGVhY2ggYWNjZXB0ZWQgTUlNRSB0eXBlIHRvIGJ1aWxkIHRvb2x0aXAgZGlzcGxheSBuYW1lc1xyXG4gICAgICBmb3IgKGxldCBpbmRleCA9IDA7IGluZGV4IDwgdGhpcy5hY2NlcHRlZFR5cGVBcnJheS5sZW5ndGg7IGluZGV4KyspIHtcclxuICAgICAgICBjb25zdCBlbGVtZW50ID0gdGhpcy5hY2NlcHRlZFR5cGVBcnJheVtpbmRleF0udHJpbSgpO1xyXG4gICAgICAgIHN3aXRjaCAoZWxlbWVudCkge1xyXG4gICAgICAgICAgY2FzZSAnYXBwbGljYXRpb24vcGRmJzpcclxuICAgICAgICAgICAgaWYgKCF0aGlzLnRvb2xUaXBUeXBlQXJyYXkuaW5jbHVkZXMoJ1BERicpKSB0aGlzLnRvb2xUaXBUeXBlQXJyYXkucHVzaCgnUERGJyk7XHJcbiAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgY2FzZSAnYXBwbGljYXRpb24vbXN3b3JkJzpcclxuICAgICAgICAgICAgaWYgKCF0aGlzLnRvb2xUaXBUeXBlQXJyYXkuaW5jbHVkZXMoJ1dvcmQnKSkgdGhpcy50b29sVGlwVHlwZUFycmF5LnB1c2goJ1dvcmQnKTtcclxuICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgICBjYXNlICdhcHBsaWNhdGlvbi92bmQub3BlbnhtbGZvcm1hdHMtb2ZmaWNlZG9jdW1lbnQud29yZHByb2Nlc3NpbmdtbC5kb2N1bWVudCc6XHJcbiAgICAgICAgICAgIGlmICghdGhpcy50b29sVGlwVHlwZUFycmF5LmluY2x1ZGVzKCdXb3JkJykpIHRoaXMudG9vbFRpcFR5cGVBcnJheS5wdXNoKCdXb3JkJyk7XHJcbiAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgY2FzZSAnYXBwbGljYXRpb24vdm5kLm1zLWV4Y2VsJzpcclxuICAgICAgICAgICAgaWYgKCF0aGlzLnRvb2xUaXBUeXBlQXJyYXkuaW5jbHVkZXMoJ0V4Y2VsJykpIHRoaXMudG9vbFRpcFR5cGVBcnJheS5wdXNoKCdFeGNlbCcpO1xyXG4gICAgICAgICAgICBicmVhaztcclxuICAgICAgICAgIGNhc2UgJ2FwcGxpY2F0aW9uL3ZuZC5vcGVueG1sZm9ybWF0cy1vZmZpY2Vkb2N1bWVudC5zcHJlYWRzaGVldG1sLnNoZWV0JzpcclxuICAgICAgICAgICAgaWYgKCF0aGlzLnRvb2xUaXBUeXBlQXJyYXkuaW5jbHVkZXMoJ0V4Y2VsJykpIHRoaXMudG9vbFRpcFR5cGVBcnJheS5wdXNoKCdFeGNlbCcpO1xyXG4gICAgICAgICAgICBicmVhaztcclxuICAgICAgICAgIGNhc2UgJ2FwcGxpY2F0aW9uL3ZuZC5tcy1wb3dlcnBvaW50JzpcclxuICAgICAgICAgICAgaWYgKCF0aGlzLnRvb2xUaXBUeXBlQXJyYXkuaW5jbHVkZXMoJ1Bvd2VyUG9pbnQnKSlcclxuICAgICAgICAgICAgICB0aGlzLnRvb2xUaXBUeXBlQXJyYXkucHVzaCgnUG93ZXJQb2ludCcpO1xyXG4gICAgICAgICAgICBicmVhaztcclxuICAgICAgICAgIGNhc2UgJ2FwcGxpY2F0aW9uL3ZuZC5vcGVueG1sZm9ybWF0cy1vZmZpY2Vkb2N1bWVudC5wcmVzZW50YXRpb25tbC5wcmVzZW50YXRpb24nOlxyXG4gICAgICAgICAgICBpZiAoIXRoaXMudG9vbFRpcFR5cGVBcnJheS5pbmNsdWRlcygnUG93ZXJQb2ludCcpKVxyXG4gICAgICAgICAgICAgIHRoaXMudG9vbFRpcFR5cGVBcnJheS5wdXNoKCdQb3dlclBvaW50Jyk7XHJcbiAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgY2FzZSAnaW1hZ2UvcG5nJzpcclxuICAgICAgICAgICAgaWYgKCF0aGlzLnRvb2xUaXBUeXBlQXJyYXkuaW5jbHVkZXMoJ1BORycpKSB0aGlzLnRvb2xUaXBUeXBlQXJyYXkucHVzaCgnUE5HJyk7XHJcbiAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgY2FzZSAnaW1hZ2UvYm1wJzpcclxuICAgICAgICAgICAgaWYgKCF0aGlzLnRvb2xUaXBUeXBlQXJyYXkuaW5jbHVkZXMoJ0JNUCcpKSB0aGlzLnRvb2xUaXBUeXBlQXJyYXkucHVzaCgnQk1QJyk7XHJcbiAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgY2FzZSAnaW1hZ2UvanBlZyc6XHJcbiAgICAgICAgICAgIGlmICghdGhpcy50b29sVGlwVHlwZUFycmF5LmluY2x1ZGVzKCdKUEVHJykpIHRoaXMudG9vbFRpcFR5cGVBcnJheS5wdXNoKCdKUEVHJyk7XHJcbiAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgY2FzZSAnYXBwbGljYXRpb24vemlwJzpcclxuICAgICAgICAgICAgaWYgKCF0aGlzLnRvb2xUaXBUeXBlQXJyYXkuaW5jbHVkZXMoJ1pJUCcpKSB0aGlzLnRvb2xUaXBUeXBlQXJyYXkucHVzaCgnWklQJyk7XHJcbiAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgY2FzZSAnYXBwbGljYXRpb24veC1yYXItY29tcHJlc3NlZCc6XHJcbiAgICAgICAgICAgIGlmICghdGhpcy50b29sVGlwVHlwZUFycmF5LmluY2x1ZGVzKCdSQVInKSkgdGhpcy50b29sVGlwVHlwZUFycmF5LnB1c2goJ1JBUicpO1xyXG4gICAgICAgICAgICBicmVhaztcclxuICAgICAgICAgIGNhc2UgJ3ZpZGVvL21wNCc6XHJcbiAgICAgICAgICAgIGlmICghdGhpcy50b29sVGlwVHlwZUFycmF5LmluY2x1ZGVzKCdNUDQnKSkgdGhpcy50b29sVGlwVHlwZUFycmF5LnB1c2goJ01QNCcpO1xyXG4gICAgICAgICAgICBicmVhaztcclxuICAgICAgICAgIGNhc2UgJ3ZpZGVvL2F2aSc6XHJcbiAgICAgICAgICAgIGlmICghdGhpcy50b29sVGlwVHlwZUFycmF5LmluY2x1ZGVzKCdBVkknKSkgdGhpcy50b29sVGlwVHlwZUFycmF5LnB1c2goJ0FWSScpO1xyXG4gICAgICAgICAgICBicmVhaztcclxuICAgICAgICAgIGNhc2UgJ3ZpZGVvL3F1aWNrdGltZSc6XHJcbiAgICAgICAgICAgIGlmICghdGhpcy50b29sVGlwVHlwZUFycmF5LmluY2x1ZGVzKCdNT1YnKSkgdGhpcy50b29sVGlwVHlwZUFycmF5LnB1c2goJ01PVicpO1xyXG4gICAgICAgICAgICBicmVhaztcclxuICAgICAgICAgIGNhc2UgJ3ZpZGVvL21wZWcnOlxyXG4gICAgICAgICAgICBpZiAoIXRoaXMudG9vbFRpcFR5cGVBcnJheS5pbmNsdWRlcygnTVBFRycpKSB0aGlzLnRvb2xUaXBUeXBlQXJyYXkucHVzaCgnTVBFRycpO1xyXG4gICAgICAgICAgICBicmVhaztcclxuICAgICAgICAgIGNhc2UgJ2F1ZGlvL21wZWcnOlxyXG4gICAgICAgICAgICBpZiAoIXRoaXMudG9vbFRpcFR5cGVBcnJheS5pbmNsdWRlcygnTVAzJykpIHRoaXMudG9vbFRpcFR5cGVBcnJheS5wdXNoKCdNUDMnKTtcclxuICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgICBjYXNlICd2aWRlby94LWZsdic6XHJcbiAgICAgICAgICAgIGlmICghdGhpcy50b29sVGlwVHlwZUFycmF5LmluY2x1ZGVzKCdGTFYnKSkgdGhpcy50b29sVGlwVHlwZUFycmF5LnB1c2goJ0ZMVicpO1xyXG4gICAgICAgICAgICBicmVhaztcclxuICAgICAgICAgIGNhc2UgJ3ZpZGVvL3gtbXMtd212JzpcclxuICAgICAgICAgICAgaWYgKCF0aGlzLnRvb2xUaXBUeXBlQXJyYXkuaW5jbHVkZXMoJ1dNVicpKSB0aGlzLnRvb2xUaXBUeXBlQXJyYXkucHVzaCgnV01WJyk7XHJcbiAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgY2FzZSAnaW1hZ2Uvc3ZnK3htbCc6XHJcbiAgICAgICAgICAgIGlmICghdGhpcy50b29sVGlwVHlwZUFycmF5LmluY2x1ZGVzKCdTVkcnKSkgdGhpcy50b29sVGlwVHlwZUFycmF5LnB1c2goJ1NWRycpO1xyXG4gICAgICAgICAgICBicmVhaztcclxuICAgICAgICAgIGNhc2UgJ3RleHQvcGxhaW4nOlxyXG4gICAgICAgICAgICBpZiAoIXRoaXMudG9vbFRpcFR5cGVBcnJheS5pbmNsdWRlcygnVHh0JykpIHRoaXMudG9vbFRpcFR5cGVBcnJheS5wdXNoKCdUeHQnKTtcclxuICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgICBjYXNlICdhcHBsaWNhdGlvbi9CTic6XHJcbiAgICAgICAgICAgIGlmICghdGhpcy50b29sVGlwVHlwZUFycmF5LmluY2x1ZGVzKCdMaWNlbnNlJykpIHRoaXMudG9vbFRpcFR5cGVBcnJheS5wdXNoKCdMaWNlbnNlJyk7XHJcbiAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgZGVmYXVsdDpcclxuICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICAgIHRoaXMudmFsaWRhdGlvbk1lc3NhZ2UgPSB0aGlzLnZhbGlkYXRpb25NZXNzYWdlICsgYCR7dGhpcy5VdGlsaXR5U2VydmljZS5nZXRSZXNvdXJjZVZhbHVlKCdFeHRlbnNpb25zJyl9ICgke3RoaXMudG9vbFRpcFR5cGVBcnJheX0pIGA7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKHRoaXMub3B0aW9ucy5maWxlTWF4U2l6ZUluTUIgPiAwKSB7XHJcbiAgICAgIHRoaXMudmFsaWRhdGlvbk1lc3NhZ2UgPSB0aGlzLnZhbGlkYXRpb25NZXNzYWdlICsgYDxiciAvPiAgJHt0aGlzLlV0aWxpdHlTZXJ2aWNlLmdldFJlc291cmNlVmFsdWUoJ0ZpbGVNYXhTaXplSW5NQicpICsgdGhpcy5vcHRpb25zLmZpbGVNYXhTaXplSW5NQiArICcgJyArIHRoaXMuVXRpbGl0eVNlcnZpY2UuZ2V0UmVzb3VyY2VWYWx1ZSgnTUInKX1gO1xyXG4gICAgfVxyXG5cclxuICAgIGlmICh0aGlzLm9wdGlvbnMubWluTm9PZkZpbGVzID4gMCkge1xyXG4gICAgICB0aGlzLnZhbGlkYXRpb25NZXNzYWdlID0gdGhpcy52YWxpZGF0aW9uTWVzc2FnZSArIGA8YnIgLz4gJHt0aGlzLlV0aWxpdHlTZXJ2aWNlLmdldFJlc291cmNlVmFsdWUoJ01pbkZpbGVDb3VudFZhbGlkYXRpb25LZXknKSArIHRoaXMub3B0aW9ucy5taW5Ob09mRmlsZXN9YDtcclxuICAgIH1cclxuXHJcbiAgICBpZiAodGhpcy5vcHRpb25zLm1heE5vT2ZGaWxlcyA+IDApIHtcclxuICAgICAgdGhpcy52YWxpZGF0aW9uTWVzc2FnZSA9IHRoaXMudmFsaWRhdGlvbk1lc3NhZ2UgKyBgPGJyIC8+ICR7dGhpcy5VdGlsaXR5U2VydmljZS5nZXRSZXNvdXJjZVZhbHVlKCdNYXhGaWxlQ291bnRWYWxpZGF0aW9uS2V5JykgKyB0aGlzLm9wdGlvbnMubWF4Tm9PZkZpbGVzfWA7XHJcbiAgICB9XHJcblxyXG4gICAgdGhpcy5ncm91cC5hZGRDb250cm9sKHRoaXMub3B0aW9ucy5uYW1lLCBuZXcgRm9ybUNvbnRyb2woJycpKTtcclxuICAgIHRoaXMuZmlsZVVwbG9hZEZvcm1Db250cm9sID0gdGhpcy5ncm91cC5jb250cm9sc1t0aGlzLm9wdGlvbnMubmFtZV07XHJcblxyXG4gICAgaWYgKHRoaXMub3B0aW9ucy5jdXN0b21WYWxpZGF0aW9uLmxlbmd0aCA+IDApIHtcclxuICAgICAgbGV0IFZhbGlkYXRpb25zID0gdGhpcy5vcHRpb25zLmN1c3RvbVZhbGlkYXRpb247XHJcbiAgICAgIGZvciAobGV0IGluZGV4ID0gMDsgaW5kZXggPCBWYWxpZGF0aW9ucy5sZW5ndGg7IGluZGV4KyspIHtcclxuICAgICAgICBjb25zdCBWYWxpZGF0aW9uID0gVmFsaWRhdGlvbnNbaW5kZXhdO1xyXG4gICAgICAgIHRoaXMudmFsaWRhdGlvblJ1bGVzLnB1c2goVmFsaWRhdGlvbi5mdW5jdGlvbkJvZHkpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKHRoaXMub3B0aW9ucy5pc011bHRpcGxlRmlsZSAmJiB0aGlzLm9wdGlvbnMubWF4Tm9PZkZpbGVzID4gMCkge1xyXG4gICAgICB0aGlzLnZhbGlkYXRpb25Db3VudE1lc3NhZ2UgPSBgJHt0aGlzLlV0aWxpdHlTZXJ2aWNlLmdldFJlc291cmNlVmFsdWUoJ01heEZpbGVzQ291bnQnKX0gOiAke3RoaXMub3B0aW9ucy5tYXhOb09mRmlsZXN9YDtcclxuICAgIH1cclxuICAgIGlmICh0aGlzLm9wdGlvbnMuaXNSZXF1aXJlZCkge1xyXG4gICAgICB0aGlzLnZhbGlkYXRpb25SdWxlcy5wdXNoKFZhbGlkYXRvcnMucmVxdWlyZWQpO1xyXG4gICAgfVxyXG5cclxuICAgIHRoaXMuZmlsZVVwbG9hZEZvcm1Db250cm9sLnNldFZhbGlkYXRvcnModGhpcy52YWxpZGF0aW9uUnVsZXMpO1xyXG4gICAgdGhpcy5maWxlVXBsb2FkRm9ybUNvbnRyb2wuc2V0QXN5bmNWYWxpZGF0b3JzKHRoaXMudmFsaWRhdGlvblJ1bGVzQXN5bmMpO1xyXG4gICAgaWYgKHRoaXMub3B0aW9ucy5pc0Rpc2FibGVkKSB7XHJcbiAgICAgIHRoaXMuZmlsZVVwbG9hZEZvcm1Db250cm9sLmRpc2FibGUoKTtcclxuICAgIH1cclxuXHJcbiAgICB0aGlzLk11bHRpcGxlRmlsZVVwbG9hZENvbnRyb2xIb3N0Lm5nU3VibWl0XHJcbiAgICAgIC5waXBlKHRha2VVbnRpbCh0aGlzLmRlc3Ryb3kkKSlcclxuICAgICAgLnN1YnNjcmliZSgodmFsdWUpID0+IHtcclxuICAgICAgICB0aGlzLmdyb3VwLm1hcmtBbGxBc1RvdWNoZWQoKTtcclxuICAgICAgICB0aGlzLm1hcmtBbGxBc1RvdWNoZWQgPSB0cnVlO1xyXG4gICAgICB9KTtcclxuXHJcbiAgICB0aGlzLmZpbGVVcGxvYWRGb3JtQ29udHJvbC5zZXRWYWx1ZSh0aGlzLm9wdGlvbnMudmFsdWUpO1xyXG4gIH1cclxuXHJcbiAgbmdBZnRlclZpZXdJbml0KCk6IHZvaWQge1xyXG4gICAgaWYgKHRoaXMub3B0aW9ucy5hdHRyaWJ1dGVMaXN0ICE9IG51bGwpIHtcclxuICAgICAgdmFyIGVsZW1lbnQgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCh0aGlzLm9wdGlvbnMubmFtZSk7XHJcbiAgICAgIGZvciAobGV0IGluZGV4ID0gMDsgaW5kZXggPCB0aGlzLm9wdGlvbnMuYXR0cmlidXRlTGlzdC5sZW5ndGg7IGluZGV4KyspIHtcclxuICAgICAgICBlbGVtZW50LnNldEF0dHJpYnV0ZShcclxuICAgICAgICAgIHRoaXMub3B0aW9ucy5hdHRyaWJ1dGVMaXN0W2luZGV4XS5rZXksXHJcbiAgICAgICAgICB0aGlzLm9wdGlvbnMuYXR0cmlidXRlTGlzdFtpbmRleF0udmFsdWVcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICByZXNldEVycm9yID0gKCkgPT4ge1xyXG4gICAgdGhpcy5jb250cm9sVmFsaWRhdGlvblNlcnZpY2UucmVtb3ZlR2xvYmFsRXJyb3IoKTtcclxuICB9O1xyXG5cclxuICBzaG93R2xvYmFsRXJyb3IoKSB7XHJcbiAgICB0aGlzLmNvbnRyb2xVdGlsaXR5LnNob3dHbG9iYWxFcnJvcigpO1xyXG4gIH1cclxuXHJcbiAgZ2V0RXJyb3JWYWxpZGF0aW9uKEVycm9yTGlzdCkge1xyXG4gICAgaWYgKHRoaXMubWFya0FsbEFzVG91Y2hlZCAmJiB0aGlzLmdyb3VwLmludmFsaWQpIHtcclxuICAgICAgdGhpcy5zaG93R2xvYmFsRXJyb3IoKTtcclxuICAgICAgdGhpcy5tYXJrQWxsQXNUb3VjaGVkID0gZmFsc2U7XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIHRoaXMuY29udHJvbFV0aWxpdHkuZ2V0RXJyb3JWYWxpZGF0aW9uTWFzc2FnZShFcnJvckxpc3QsIHRoaXMuZ3JvdXAsIHRoaXMub3B0aW9ucyk7XHJcbiAgfVxyXG5cclxuICBmaWxlT3ZlckFub3RoZXIoZXZlbnQ6IGFueSk6IHZvaWQge1xyXG4gICAgdGhpcy5oYXNBbm90aGVyRHJvcFpvbmVPdmVyID0gZXZlbnQ7XHJcbiAgfVxyXG5cclxuICBpc0hpZGVJbnB1dCgpIHtcclxuICAgIGlmICh0aGlzLm9wdGlvbnMuaXNNdWx0aXBsZUZpbGUpIHtcclxuICAgICAgaWYgKFxyXG4gICAgICAgIHRoaXMub3B0aW9ucy5tYXhOb09mRmlsZXMgIT0gbnVsbCAmJlxyXG4gICAgICAgIHRoaXMub3B0aW9ucy5tYXhOb09mRmlsZXMgPiAwICYmXHJcbiAgICAgICAgdGhpcy5vcHRpb25zLm1heE5vT2ZGaWxlcyA9PSB0aGlzLnVwbG9hZGVyLnF1ZXVlLmxlbmd0aFxyXG4gICAgICApIHtcclxuICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgICAgfVxyXG4gICAgfSBlbHNlIHtcclxuICAgICAgaWYgKHRoaXMudXBsb2FkZXIucXVldWUubGVuZ3RoID4gMCkge1xyXG4gICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgICByZXR1cm4gZmFsc2U7XHJcbiAgfVxyXG5cclxuICBvbkZpbGVDaGFuZ2UoKSB7XHJcbiAgICBsZXQgRmlsZXNBcnJheTogRmlsZURUT1tdID0gW107XHJcbiAgICAvLyBDbGVhciBhbnkgcHJldmlvdXMgdmFsaWRhdGlvbiBlcnJvcnMgYXQgdGhlIHN0YXJ0IG9mIGZpbGUgY2hhbmdlXHJcbiAgICB0aGlzLnBlbmRpbmdWYWxpZGF0aW9uRXJyb3JzID0gbnVsbDtcclxuXHJcbiAgICAvLyBDaGVjayBmb3IgZHVwbGljYXRlIGZpbGUgbmFtZXMgaW4gdGhlIHF1ZXVlXHJcbiAgICBjb25zdCBkdXBsaWNhdGVGaWxlcyA9IHRoaXMuZmluZER1cGxpY2F0ZUZpbGVzKCk7XHJcbiAgICBpZiAoZHVwbGljYXRlRmlsZXMubGVuZ3RoID4gMCkge1xyXG4gICAgICAvLyBSZW1vdmUgb25seSB0aGUgbmV3bHkgYWRkZWQgZHVwbGljYXRlIGZpbGVzIGZyb20gcXVldWUgKGtlZXAgZXhpc3RpbmcgZmlsZXMpXHJcbiAgICAgIHRoaXMucmVtb3ZlRHVwbGljYXRlRmlsZXNGcm9tUXVldWUoZHVwbGljYXRlRmlsZXMpO1xyXG5cclxuICAgICAgLy8gU2V0IHZhbGlkYXRpb24gZXJyb3IgZm9yIGR1cGxpY2F0ZSBmaWxlc1xyXG4gICAgICBjb25zdCBkdXBsaWNhdGVGaWxlTmFtZXMgPSBkdXBsaWNhdGVGaWxlcy5tYXAoZiA9PiBmLmZpbGU/Lm5hbWUpLmpvaW4oJywgJyk7XHJcbiAgICAgIGNvbnN0IGZvcm1Db250cm9sID0gdGhpcy5maWxlVXBsb2FkRm9ybUNvbnRyb2w7XHJcbiAgICAgIGNvbnN0IHJlc291cmNlVmFsdWUgPSB0aGlzLlV0aWxpdHlTZXJ2aWNlLmdldFJlc291cmNlVmFsdWUoJ0R1cGxpY2F0ZUZpbGVFcnJvcicpO1xyXG4gICAgICAvLyBJZiByZXNvdXJjZSB2YWx1ZSBpcyB0aGUgc2FtZSBhcyB0aGUga2V5LCBpdCBtZWFucyB0aGUgcmVzb3VyY2Ugd2Fzbid0IGZvdW5kXHJcbiAgICAgIGNvbnN0IGVycm9yTWVzc2FnZSA9IChyZXNvdXJjZVZhbHVlICYmIHJlc291cmNlVmFsdWUgIT09ICdEdXBsaWNhdGVGaWxlRXJyb3InKSA/IHJlc291cmNlVmFsdWUgOiAnRmlsZShzKSBhbHJlYWR5IGV4aXN0JztcclxuICAgICAgY29uc3QgZXJyb3JPYmogPSB7XHJcbiAgICAgICAgRHVwbGljYXRlRmlsZUVycm9yOiBgJHtlcnJvck1lc3NhZ2V9OiAke2R1cGxpY2F0ZUZpbGVOYW1lc31gXHJcbiAgICAgIH07XHJcbiAgICAgIHRoaXMucGVuZGluZ1ZhbGlkYXRpb25FcnJvcnMgPSBlcnJvck9iajtcclxuICAgICAgZm9ybUNvbnRyb2wuc2V0RXJyb3JzKGVycm9yT2JqKTtcclxuICAgICAgZm9ybUNvbnRyb2wubWFya0FzVG91Y2hlZCgpO1xyXG5cclxuICAgICAgLy8gQXV0by1jbGVhciBkdXBsaWNhdGUgZXJyb3IgYWZ0ZXIgNSBzZWNvbmRzIHRvIGFsbG93IGZvcm0gc3VibWlzc2lvblxyXG4gICAgICBzZXRUaW1lb3V0KCgpID0+IHtcclxuICAgICAgICAvLyBPbmx5IGNsZWFyIGlmIHRoZSBjdXJyZW50IGVycm9yIGlzIHN0aWxsIHRoZSBkdXBsaWNhdGUgZXJyb3Igd2Ugc2V0XHJcbiAgICAgICAgY29uc3QgY3VycmVudEVycm9ycyA9IGZvcm1Db250cm9sLmVycm9ycztcclxuICAgICAgICBpZiAoY3VycmVudEVycm9ycyAmJiBjdXJyZW50RXJyb3JzLkR1cGxpY2F0ZUZpbGVFcnJvciA9PT0gZXJyb3JPYmouRHVwbGljYXRlRmlsZUVycm9yKSB7XHJcbiAgICAgICAgICBmb3JtQ29udHJvbC5zZXRFcnJvcnMobnVsbCk7XHJcbiAgICAgICAgICB0aGlzLnBlbmRpbmdWYWxpZGF0aW9uRXJyb3JzID0gbnVsbDtcclxuICAgICAgICB9XHJcbiAgICAgIH0sIDUwMDApO1xyXG5cclxuICAgICAgLy8gSWYgYWxsIGZpbGVzIHdlcmUgZHVwbGljYXRlcywgcmV0dXJuIGVhcmx5XHJcbiAgICAgIGlmICh0aGlzLnVwbG9hZGVyLnF1ZXVlLmZpbHRlcihpdGVtID0+IGl0ZW1bJ3NvbWUnXS5sYXN0TW9kaWZpZWQgIT0gbnVsbCkubGVuZ3RoID09PSAwKSB7XHJcbiAgICAgICAgcmV0dXJuO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgICBpZiAodGhpcy5vcHRpb25zLmlzTXVsdGlwbGVGaWxlICYmIHRoaXMub3B0aW9ucy5taW5Ob09mRmlsZXMgIT0gbnVsbCAmJiB0aGlzLm9wdGlvbnMubWluTm9PZkZpbGVzID4gMCAmJiB0aGlzLm9wdGlvbnMubWluTm9PZkZpbGVzID4gdGhpcy51cGxvYWRlci5xdWV1ZS5sZW5ndGgpIHtcclxuICAgICAgY29uc3QgZm9ybUNvbnRyb2wgPSB0aGlzLmZpbGVVcGxvYWRGb3JtQ29udHJvbDtcclxuICAgICAgY29uc3QgZXhpc3RpbmdFcnJvcnMgPSBmb3JtQ29udHJvbC5lcnJvcnMgfHwge307XHJcbiAgICAgIGNvbnN0IG5ld0Vycm9ycyA9IHtcclxuICAgICAgICAuLi5leGlzdGluZ0Vycm9ycyxcclxuICAgICAgICBNaW5GaWxlQ291bnRWYWxpZGF0aW9uS2V5OiB0aGlzLm9wdGlvbnMubWluTm9PZkZpbGVzXHJcbiAgICAgIH07XHJcbiAgICAgIGZvcm1Db250cm9sLnNldEVycm9ycyhuZXdFcnJvcnMpO1xyXG4gICAgICBmb3JtQ29udHJvbC5tYXJrQXNUb3VjaGVkKCk7XHJcbiAgICAgIHRoaXMudXBsb2FkZXIucXVldWUgPSBbXTtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG5cclxuICAgIGlmICh0aGlzLm9wdGlvbnMuaXNNdWx0aXBsZUZpbGUgJiYgdGhpcy5vcHRpb25zLm1heE5vT2ZGaWxlcyAhPSBudWxsICYmIHRoaXMub3B0aW9ucy5tYXhOb09mRmlsZXMgPiAwICYmIHRoaXMub3B0aW9ucy5tYXhOb09mRmlsZXMgPCB0aGlzLnVwbG9hZGVyLnF1ZXVlLmxlbmd0aCkge1xyXG4gICAgICBjb25zdCBmb3JtQ29udHJvbCA9IHRoaXMuZmlsZVVwbG9hZEZvcm1Db250cm9sO1xyXG4gICAgICBjb25zdCBleGlzdGluZ0Vycm9ycyA9IGZvcm1Db250cm9sLmVycm9ycyB8fCB7fTtcclxuICAgICAgY29uc3QgbmV3RXJyb3JzID0ge1xyXG4gICAgICAgIC4uLmV4aXN0aW5nRXJyb3JzLFxyXG4gICAgICAgIE1heEZpbGVDb3VudFZhbGlkYXRpb25LZXk6IHRoaXMub3B0aW9ucy5tYXhOb09mRmlsZXNcclxuICAgICAgfTtcclxuICAgICAgZm9ybUNvbnRyb2wuc2V0RXJyb3JzKG5ld0Vycm9ycyk7XHJcbiAgICAgIGZvcm1Db250cm9sLm1hcmtBc1RvdWNoZWQoKTtcclxuICAgICAgdGhpcy51cGxvYWRlci5xdWV1ZSA9IFtdO1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKHRoaXMub3B0aW9ucy5pc011bHRpcGxlRmlsZSAmJiB0aGlzLm9wdGlvbnMubWF4U2l6ZUZvckFsbEZpbGVzSW5NQiAhPSBudWxsICYmIHRoaXMub3B0aW9ucy5tYXhTaXplRm9yQWxsRmlsZXNJbk1CID4gMCkge1xyXG4gICAgICBsZXQgQWxsU2l6ZUZpbGUgPSAwO1xyXG4gICAgICBmb3IgKGxldCBpbmRleCA9IDA7IGluZGV4IDwgdGhpcy51cGxvYWRlci5xdWV1ZS5sZW5ndGg7IGluZGV4KyspIHtcclxuICAgICAgICBjb25zdCBlbGVtZW50ID0gdGhpcy51cGxvYWRlci5xdWV1ZVtpbmRleF07XHJcbiAgICAgICAgY29uc3QgZmlsZSA9IGVsZW1lbnQuZmlsZTtcclxuICAgICAgICBBbGxTaXplRmlsZSA9IEFsbFNpemVGaWxlICsgZmlsZS5zaXplO1xyXG4gICAgICB9XHJcbiAgICAgIGNvbnN0IE1heFNpemVGb3JBbGxGaWxlcyA9IHRoaXMub3B0aW9ucy5tYXhTaXplRm9yQWxsRmlsZXNJbk1CICogMTAwMCAqIDEwMDA7XHJcbiAgICAgIGlmIChBbGxTaXplRmlsZSA+IE1heFNpemVGb3JBbGxGaWxlcykge1xyXG4gICAgICAgIGNvbnN0IGZvcm1Db250cm9sID0gdGhpcy5maWxlVXBsb2FkRm9ybUNvbnRyb2w7XHJcbiAgICAgICAgY29uc3QgZXhpc3RpbmdFcnJvcnMgPSBmb3JtQ29udHJvbC5lcnJvcnMgfHwge307XHJcbiAgICAgICAgY29uc3QgbmV3RXJyb3JzID0ge1xyXG4gICAgICAgICAgLi4uZXhpc3RpbmdFcnJvcnMsXHJcbiAgICAgICAgICBNYXhTaXplRm9yQWxsRmlsZXNJbk1COiB0aGlzLm9wdGlvbnMubWF4U2l6ZUZvckFsbEZpbGVzSW5NQiArICcgJyArIHRoaXMuVXRpbGl0eVNlcnZpY2UuZ2V0UmVzb3VyY2VWYWx1ZSgnTUInKVxyXG4gICAgICAgIH07XHJcbiAgICAgICAgZm9ybUNvbnRyb2wuc2V0RXJyb3JzKG5ld0Vycm9ycyk7XHJcbiAgICAgICAgZm9ybUNvbnRyb2wubWFya0FzVG91Y2hlZCgpO1xyXG4gICAgICAgIHRoaXMudXBsb2FkZXIucXVldWUgPSBbXTtcclxuICAgICAgICByZXR1cm47XHJcbiAgICAgIH1cclxuICAgIH1cclxuICAgIGxldCBBZGRlZFF1ZXVlID0gdGhpcy51cGxvYWRlci5xdWV1ZS5maWx0ZXIoKG9iaikgPT4gb2JqWydzb21lJ10ubGFzdE1vZGlmaWVkICE9IG51bGwpO1xyXG4gICAgbGV0IGhhc1ZhbGlkYXRpb25FcnJvciA9IGZhbHNlO1xyXG4gICAgbGV0IHZhbGlkYXRpb25FcnJvclR5cGUgPSAnJztcclxuICAgIGxldCB2YWxpZGF0aW9uRXJyb3JWYWx1ZTogYW55ID0gJyc7XHJcblxyXG4gICAgZm9yIChsZXQgaW5kZXggPSAwOyBpbmRleCA8IEFkZGVkUXVldWUubGVuZ3RoOyBpbmRleCsrKSB7XHJcbiAgICAgIGNvbnN0IGVsZW1lbnQgPSBBZGRlZFF1ZXVlW2luZGV4XTtcclxuICAgICAgY29uc3QgZmlsZSA9IGVsZW1lbnQuZmlsZTtcclxuICAgICAgY29uc3QgbWF4RmlsZVNpemUgPSB0aGlzLm9wdGlvbnMuZmlsZU1heFNpemVJbk1CICogMTAwMCAqIDEwMDA7XHJcbiAgICAgIGlmIChmaWxlKSB7XHJcbiAgICAgICAgY29uc3QgZmlsZVR5cGUgPSBmaWxlLnR5cGU7XHJcbiAgICAgICAgaWYgKGZpbGUuc2l6ZSA+IG1heEZpbGVTaXplKSB7XHJcbiAgICAgICAgICAvLyBSZW1vdmUgb25seSB0aGUgZmlsZSB0aGF0IHZpb2xhdGVzIHRoZSBzaXplIGxpbWl0XHJcbiAgICAgICAgICB0aGlzLnVwbG9hZGVyLnF1ZXVlID0gdGhpcy51cGxvYWRlci5xdWV1ZS5maWx0ZXIocXVldWVJdGVtID0+XHJcbiAgICAgICAgICAgIHF1ZXVlSXRlbS5maWxlLm5hbWUgIT09IGZpbGUubmFtZVxyXG4gICAgICAgICAgKTtcclxuICAgICAgICAgIGhhc1ZhbGlkYXRpb25FcnJvciA9IHRydWU7XHJcbiAgICAgICAgICB2YWxpZGF0aW9uRXJyb3JUeXBlID0gJ0ZpbGVNYXhTaXplSW5NQic7XHJcbiAgICAgICAgICB2YWxpZGF0aW9uRXJyb3JWYWx1ZSA9IHRoaXMub3B0aW9ucy5maWxlTWF4U2l6ZUluTUIgKyAnICcgKyB0aGlzLlV0aWxpdHlTZXJ2aWNlLmdldFJlc291cmNlVmFsdWUoJ01CJyk7XHJcbiAgICAgICAgICAvLyBDb250aW51ZSBjaGVja2luZyBvdGhlciBmaWxlcyBpbnN0ZWFkIG9mIHJldHVybmluZyBpbW1lZGlhdGVseVxyXG4gICAgICAgIH1cclxuICAgICAgICBpZiAoXHJcbiAgICAgICAgICB0aGlzLm9wdGlvbnMuZmlsZVVwbG9hZEFjY2VwdHNUeXBlcyAhPSBudWxsICYmXHJcbiAgICAgICAgICB0aGlzLm9wdGlvbnMuZmlsZVVwbG9hZEFjY2VwdHNUeXBlcy5sZW5ndGggPiAwICYmXHJcbiAgICAgICAgICAhdGhpcy5pc0ZpbGVUeXBlQWNjZXB0ZWQoZmlsZVR5cGUpXHJcbiAgICAgICAgKSB7XHJcbiAgICAgICAgICAvLyBSZW1vdmUgb25seSB0aGUgZmlsZSB0aGF0IHZpb2xhdGVzIHRoZSBmaWxlIHR5cGUgcmVzdHJpY3Rpb25cclxuICAgICAgICAgIHRoaXMudXBsb2FkZXIucXVldWUgPSB0aGlzLnVwbG9hZGVyLnF1ZXVlLmZpbHRlcihxdWV1ZUl0ZW0gPT5cclxuICAgICAgICAgICAgcXVldWVJdGVtLmZpbGUubmFtZSAhPT0gZmlsZS5uYW1lXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgICAgaGFzVmFsaWRhdGlvbkVycm9yID0gdHJ1ZTtcclxuICAgICAgICAgIHZhbGlkYXRpb25FcnJvclR5cGUgPSAnVG9vbFRpcFR5cGVFcnJvcic7XHJcbiAgICAgICAgICB2YWxpZGF0aW9uRXJyb3JWYWx1ZSA9IHRoaXMudG9vbFRpcFR5cGVBcnJheTtcclxuICAgICAgICAgIC8vIENvbnRpbnVlIGNoZWNraW5nIG90aGVyIGZpbGVzIGluc3RlYWQgb2YgcmV0dXJuaW5nIGltbWVkaWF0ZWx5XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gU2V0IHZhbGlkYXRpb24gZXJyb3IgaWYgYW55IGZpbGVzIHdlcmUgcmVtb3ZlZCBkdWUgdG8gdmFsaWRhdGlvbiBmYWlsdXJlc1xyXG4gICAgdGhpcy5wZW5kaW5nVmFsaWRhdGlvbkVycm9ycyA9IG51bGw7XHJcbiAgICBpZiAoaGFzVmFsaWRhdGlvbkVycm9yKSB7XHJcbiAgICAgIGNvbnN0IGZvcm1Db250cm9sID0gdGhpcy5maWxlVXBsb2FkRm9ybUNvbnRyb2w7XHJcbiAgICAgIGNvbnN0IGVycm9yT2JqID0ge307XHJcbiAgICAgIGVycm9yT2JqW3ZhbGlkYXRpb25FcnJvclR5cGVdID0gdmFsaWRhdGlvbkVycm9yVmFsdWU7XHJcbiAgICAgIHRoaXMucGVuZGluZ1ZhbGlkYXRpb25FcnJvcnMgPSBlcnJvck9iajsgLy8gU3RvcmUgZXJyb3JzIHRvIHJlYXBwbHkgbGF0ZXJcclxuICAgICAgZm9ybUNvbnRyb2wuc2V0RXJyb3JzKGVycm9yT2JqKTtcclxuICAgICAgZm9ybUNvbnRyb2wubWFya0FzVG91Y2hlZCgpO1xyXG4gICAgICAvLyBEb24ndCByZXR1cm4gaGVyZSwgY29udGludWUgcHJvY2Vzc2luZyB2YWxpZCBmaWxlc1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFJlLWZpbHRlciB0aGUgcXVldWUgdG8gZ2V0IG9ubHkgdmFsaWQgZmlsZXMgZm9yIHByb2Nlc3NpbmdcclxuICAgIEFkZGVkUXVldWUgPSB0aGlzLnVwbG9hZGVyLnF1ZXVlLmZpbHRlcigob2JqKSA9PiBvYmpbJ3NvbWUnXS5sYXN0TW9kaWZpZWQgIT0gbnVsbCk7XHJcblxyXG4gICAgZm9yIChsZXQgaW5kZXggPSAwOyBpbmRleCA8IEFkZGVkUXVldWUubGVuZ3RoOyBpbmRleCsrKSB7XHJcbiAgICAgIGNvbnN0IGVsZW1lbnQgPSBBZGRlZFF1ZXVlW2luZGV4XTtcclxuICAgICAgY29uc3QgZmlsZSA9IGVsZW1lbnQuZmlsZTtcclxuICAgICAgaWYgKGZpbGUpIHtcclxuICAgICAgICBpZiAodGhpcy5vcHRpb25zLmlzVXBsb2FkRmlsZUFzeW5jICYmICFlbGVtZW50Ll9maWxlWydpRF9HVUlEJ10pIHtcclxuICAgICAgICAgIHRoaXMuZmlsZVVwbG9hZFNlcnZpY2UudXBsb2FkRmlsZShlbGVtZW50Ll9maWxlKVxyXG4gICAgICAgICAgICAucGlwZSh0YWtlVW50aWwodGhpcy5kZXN0cm95JCkpXHJcbiAgICAgICAgICAgIC5zdWJzY3JpYmUoe1xyXG4gICAgICAgICAgICAgIG5leHQ6IChldmVudDogYW55KSA9PiB7XHJcbiAgICAgICAgICAgICAgICBsZXQgcXVldWVJbmRleCA9IHRoaXMudXBsb2FkZXIucXVldWUuZmluZEluZGV4KChmaWxlKSA9PiBmaWxlID09IGVsZW1lbnQpO1xyXG4gICAgICAgICAgICAgICAgaWYgKGV2ZW50LnR5cGUgPT09IEh0dHBFdmVudFR5cGUuVXBsb2FkUHJvZ3Jlc3MpIHtcclxuICAgICAgICAgICAgICAgICAgbGV0IHZhbHVlID0gTWF0aC5yb3VuZCgoMTAwICogZXZlbnQubG9hZGVkKSAvIGV2ZW50LnRvdGFsKTtcclxuICAgICAgICAgICAgICAgICAgdGhpcy51cGxvYWRlci5xdWV1ZVtxdWV1ZUluZGV4XS5wcm9ncmVzcyA9IHZhbHVlID49IDk1ID8gOTUgOiB2YWx1ZTtcclxuICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAoZXZlbnQudHlwZSA9PT0gSHR0cEV2ZW50VHlwZS5SZXNwb25zZSkge1xyXG4gICAgICAgICAgICAgICAgICB0aGlzLnVwbG9hZGVyLnF1ZXVlW3F1ZXVlSW5kZXhdLnByb2dyZXNzID0gMTAwO1xyXG4gICAgICAgICAgICAgICAgICBsZXQgZmlsZUlEID0gZXZlbnQuYm9keS52YWwgYXMgYW55O1xyXG4gICAgICAgICAgICAgICAgICB0aGlzLnVwbG9hZGVyLnF1ZXVlW3F1ZXVlSW5kZXhdLl9maWxlWydpRF9HVUlEJ10gPSBmaWxlSUQ7XHJcbiAgICAgICAgICAgICAgICAgIHRoaXMudXBsb2FkZXIucXVldWVbcXVldWVJbmRleF0uX2ZpbGVbJ2lzTmV3J10gPSB0cnVlO1xyXG4gICAgICAgICAgICAgICAgICBsZXQgQWRkZWRGaWxlID0gPEZpbGVEVE8+e1xyXG4gICAgICAgICAgICAgICAgICAgIGlEX0dVSUQ6IGZpbGVJRCxcclxuICAgICAgICAgICAgICAgICAgICBmaWxlTmFtZTogdGhpcy51cGxvYWRlci5xdWV1ZVtxdWV1ZUluZGV4XS5fZmlsZVsnbmFtZSddLFxyXG4gICAgICAgICAgICAgICAgICAgIGZpbGVUeXBlOiB0aGlzLnVwbG9hZGVyLnF1ZXVlW3F1ZXVlSW5kZXhdLl9maWxlWyd0eXBlJ10sXHJcbiAgICAgICAgICAgICAgICAgICAgaXNOZXc6IHRydWVcclxuICAgICAgICAgICAgICAgICAgfTtcclxuICAgICAgICAgICAgICAgICAgaWYgKHRoaXMub3B0aW9ucy5pc011bHRpcGxlRmlsZSA9PSBmYWxzZSkge1xyXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuZmlsZVVwbG9hZE1vZGVsID0gbmV3IEZpbGVVcGxvYWRNb2RlbCgpO1xyXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuZmlsZVVwbG9hZE1vZGVsLmZpbGUgPSBBZGRlZEZpbGU7XHJcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5zZXRWYWx1ZVByZXNlcnZpbmdFcnJvcnModGhpcy5maWxlVXBsb2FkTW9kZWwsIHRoaXMucGVuZGluZ1ZhbGlkYXRpb25FcnJvcnMpO1xyXG4gICAgICAgICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgICAgICAgIEZpbGVzQXJyYXkucHVzaChBZGRlZEZpbGUpO1xyXG4gICAgICAgICAgICAgICAgICAgIHRoaXMubXVsdGlwbGVGaWxlVXBsb2FkTW9kZWwudXBsb2FkZWRGaWxlcyA9IEZpbGVzQXJyYXk7XHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKHRoaXMub3B0aW9ucy52YWx1ZSAhPSBudWxsICYmIHRoaXMub3B0aW9ucy52YWx1ZSAhPSB1bmRlZmluZWQpIHtcclxuICAgICAgICAgICAgICAgICAgICAgIGlmICh0aGlzLm9wdGlvbnMudmFsdWUuY29ycmVsYXRpb25JRF9HVUlEID09IG51bGwpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5tdWx0aXBsZUZpbGVVcGxvYWRNb2RlbC5yZW1vdmVkRmlsZXMgPSBbXTtcclxuICAgICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5tdWx0aXBsZUZpbGVVcGxvYWRNb2RlbC5jb3JyZWxhdGlvbklEX0dVSUQgPVxyXG4gICAgICAgICAgICAgICAgICAgICAgdGhpcy5vcHRpb25zLnZhbHVlPy5jb3JyZWxhdGlvbklEX0dVSUQ7XHJcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5zZXRWYWx1ZVByZXNlcnZpbmdFcnJvcnModGhpcy5tdWx0aXBsZUZpbGVVcGxvYWRNb2RlbCwgdGhpcy5wZW5kaW5nVmFsaWRhdGlvbkVycm9ycyk7XHJcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5pc1VwbG9hZENvbXBsZXRlLmVtaXQodHJ1ZSk7XHJcbiAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH0pO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICBsZXQgcmVhZGVyID0gbmV3IEZpbGVSZWFkZXIoKTtcclxuICAgICAgICAgIGxldCBmaWxlT2JqZWN0ID0gZmlsZS5yYXdGaWxlIGFzIGFueTtcclxuICAgICAgICAgIHJlYWRlci5yZWFkQXNEYXRhVVJMKGZpbGVPYmplY3QpO1xyXG4gICAgICAgICAgcmVhZGVyLm9ubG9hZCA9ICgpID0+IHtcclxuICAgICAgICAgICAgbGV0IGV4aXN0aW5nSURfR1VJRCA9IG51bGw7XHJcblxyXG4gICAgICAgICAgICBpZiAoIXRoaXMub3B0aW9ucy5pc011bHRpcGxlRmlsZSAmJiB0aGlzLmZpbGUpXHJcbiAgICAgICAgICAgICAgZXhpc3RpbmdJRF9HVUlEID0gdGhpcy5maWxlLk5hbWVXaXRoRXh0ZW5zaW9uID09IGZpbGUubmFtZSA/IHRoaXMuZmlsZS5pRF9HVUlEIDogbnVsbDtcclxuXHJcbiAgICAgICAgICAgIGxldCBBZGRlZEZpbGU6IEZpbGVEVE8gPSB7XHJcbiAgICAgICAgICAgICAgZmlsZU5hbWU6IGZpbGUubmFtZSxcclxuICAgICAgICAgICAgICBmaWxlVHlwZTogZmlsZS50eXBlLFxyXG4gICAgICAgICAgICAgIGZpbGVCYXNlNjQ6IHJlYWRlci5yZXN1bHQudG9TdHJpbmcoKS5zcGxpdCgnLCcpWzFdLFxyXG4gICAgICAgICAgICAgIGZpbGVTaXplSW5NQjogZmlsZS5zaXplIC8gMTAwMCAvIDEwMDAsXHJcbiAgICAgICAgICAgICAgbmFtZVdpdGhFeHRlbnNpb246IGZpbGUubmFtZSxcclxuICAgICAgICAgICAgICBpRF9HVUlEOiBleGlzdGluZ0lEX0dVSUQsXHJcbiAgICAgICAgICAgICAgaXNOZXc6IHRydWVcclxuICAgICAgICAgICAgfTtcclxuXHJcbiAgICAgICAgICAgIGlmICh0aGlzLm9wdGlvbnMuaXNNdWx0aXBsZUZpbGUgPT0gZmFsc2UpIHtcclxuICAgICAgICAgICAgICB0aGlzLmZpbGVVcGxvYWRNb2RlbCA9IG5ldyBGaWxlVXBsb2FkTW9kZWwoKTtcclxuICAgICAgICAgICAgICB0aGlzLmZpbGVVcGxvYWRNb2RlbC5maWxlID0gQWRkZWRGaWxlO1xyXG4gICAgICAgICAgICAgIHRoaXMuc2V0VmFsdWVQcmVzZXJ2aW5nRXJyb3JzKHRoaXMuZmlsZVVwbG9hZE1vZGVsLCB0aGlzLnBlbmRpbmdWYWxpZGF0aW9uRXJyb3JzKTtcclxuICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICBGaWxlc0FycmF5LnB1c2goQWRkZWRGaWxlKTtcclxuICAgICAgICAgICAgICB0aGlzLm11bHRpcGxlRmlsZVVwbG9hZE1vZGVsLnVwbG9hZGVkRmlsZXMgPSBGaWxlc0FycmF5O1xyXG4gICAgICAgICAgICAgIGlmICh0aGlzLm9wdGlvbnMudmFsdWUgIT0gbnVsbCAmJiB0aGlzLm9wdGlvbnMudmFsdWUgIT0gdW5kZWZpbmVkKSB7XHJcbiAgICAgICAgICAgICAgICBpZiAodGhpcy5vcHRpb25zLnZhbHVlLmNvcnJlbGF0aW9uSURfR1VJRCA9PSBudWxsKSB7XHJcbiAgICAgICAgICAgICAgICAgIHRoaXMubXVsdGlwbGVGaWxlVXBsb2FkTW9kZWwucmVtb3ZlZEZpbGVzID0gW107XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgIHRoaXMubXVsdGlwbGVGaWxlVXBsb2FkTW9kZWwuY29ycmVsYXRpb25JRF9HVUlEID1cclxuICAgICAgICAgICAgICAgIHRoaXMub3B0aW9ucy52YWx1ZT8uY29ycmVsYXRpb25JRF9HVUlEO1xyXG4gICAgICAgICAgICAgIHRoaXMuc2V0VmFsdWVQcmVzZXJ2aW5nRXJyb3JzKHRoaXMubXVsdGlwbGVGaWxlVXBsb2FkTW9kZWwsIHRoaXMucGVuZGluZ1ZhbGlkYXRpb25FcnJvcnMpO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9O1xyXG4gICAgICAgICAgbGV0IG9yaWdpbmFsVmFsdWUgPSB0aGlzLmdyb3VwLmdldCh0aGlzLm9wdGlvbnMubmFtZSkudmFsdWU7XHJcbiAgICAgICAgICBpZiAoXHJcbiAgICAgICAgICAgIHRoaXMub3B0aW9ucy5wYXRjaEZ1bmN0aW9uICYmXHJcbiAgICAgICAgICAgIHRoaXMub3B0aW9ucy5wYXRjaFBhdGggJiZcclxuICAgICAgICAgICAgdGhpcy5ncm91cC5nZXQodGhpcy5vcHRpb25zLm5hbWUpLnZhbGlkXHJcbiAgICAgICAgICApIHtcclxuICAgICAgICAgICAgdGhpcy5jb250cm9sVXRpbGl0eS5wYXRjaENvbnRyb2xWYWx1ZShcclxuICAgICAgICAgICAgICBvcmlnaW5hbFZhbHVlLFxyXG4gICAgICAgICAgICAgIHRoaXMub3B0aW9ucy5wYXRjaEZ1bmN0aW9uLFxyXG4gICAgICAgICAgICAgIHRoaXMub3B0aW9ucy5wYXRjaFBhdGhcclxuICAgICAgICAgICAgKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICAgIHRoaXMuT25DaGFuZ2UuZW1pdChvcmlnaW5hbFZhbHVlKTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcblxyXG4gIHJlbW92ZUZyb21Db250cm9sVmFsdWUoaXRlbTogRmlsZUl0ZW0pIHtcclxuICAgIGlmICh0aGlzLm9wdGlvbnMuaXNVcGxvYWRGaWxlQXN5bmMgJiYgaXRlbS5wcm9ncmVzcyA9PSAxMDAgJiYgaXRlbS5fZmlsZVsnaXNOZXcnXSkge1xyXG4gICAgICB0aGlzLmZpbGVVcGxvYWRTZXJ2aWNlLmRlbGV0ZUZpbGUoaXRlbS5fZmlsZVsnaURfR1VJRCddKVxyXG4gICAgICAgIC5waXBlKHRha2VVbnRpbCh0aGlzLmRlc3Ryb3kkKSlcclxuICAgICAgICAuc3Vic2NyaWJlKChyZXMpID0+IHsgfSk7XHJcbiAgICB9XHJcbiAgICBpZiAodGhpcy5vcHRpb25zLmlzTXVsdGlwbGVGaWxlID09IGZhbHNlKSB7XHJcbiAgICAgIHRoaXMuZmlsZVVwbG9hZE1vZGVsID0gbnVsbDtcclxuICAgICAgaWYgKHRoaXMub3B0aW9ucy5pc1JlcXVpcmVkID09IHRydWUpIHtcclxuICAgICAgICB0aGlzLmZpbGVVcGxvYWRGb3JtQ29udHJvbC5tYXJrQXNUb3VjaGVkKCk7XHJcbiAgICAgICAgdGhpcy5maWxlVXBsb2FkRm9ybUNvbnRyb2wudXBkYXRlVmFsdWVBbmRWYWxpZGl0eSgpOyAvLyBUcmlnZ2VyIHZhbGlkYXRpb24gY2hlY2tcclxuICAgICAgfVxyXG4gICAgICB0aGlzLmdyb3VwLmdldCh0aGlzLm9wdGlvbnMubmFtZSkuc2V0VmFsdWUodGhpcy5maWxlVXBsb2FkTW9kZWwpO1xyXG4gICAgICB0aGlzLm9wdGlvbnMudmFsdWUgPSB0aGlzLmZpbGVVcGxvYWRNb2RlbDtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIGlmICh0aGlzLm9wdGlvbnMudmFsdWUgIT0gbnVsbCAmJiB0aGlzLm9wdGlvbnMudmFsdWUgIT0gdW5kZWZpbmVkKSB7XHJcbiAgICAgICAgaWYgKHRoaXMub3B0aW9ucy52YWx1ZS5jb3JyZWxhdGlvbklEX0dVSUQgPT0gbnVsbCkge1xyXG4gICAgICAgICAgdGhpcy5kZWxldGVkRmlsZXMgPSBbXTtcclxuICAgICAgICAgIHRoaXMubXVsdGlwbGVGaWxlVXBsb2FkTW9kZWwucmVtb3ZlZEZpbGVzID0gW107XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIGlmICh0aGlzLm11bHRpcGxlRmlsZVVwbG9hZE1vZGVsLnJlbW92ZWRGaWxlcy5sZW5ndGggPT0gMCkge1xyXG4gICAgICAgICAgICBsZXQgRmlsZU9iamVjdCA9IGl0ZW0uZmlsZS5yYXdGaWxlO1xyXG4gICAgICAgICAgICBsZXQgRGVsZXRlZEl0ZW0gPSB0aGlzLm11bHRpcGxlRmlsZVVwbG9hZE1vZGVsLmV4aXN0aW5nRmlsZXMuZmlsdGVyKFxyXG4gICAgICAgICAgICAgIChvYmopID0+IG9iai5uYW1lV2l0aEV4dGVuc2lvbiA9PSBGaWxlT2JqZWN0Lm5hbWVcclxuICAgICAgICAgICAgKVswXTtcclxuICAgICAgICAgICAgdGhpcy5tdWx0aXBsZUZpbGVVcGxvYWRNb2RlbC5leGlzdGluZ0ZpbGVzID1cclxuICAgICAgICAgICAgICB0aGlzLm11bHRpcGxlRmlsZVVwbG9hZE1vZGVsLmV4aXN0aW5nRmlsZXMuZmlsdGVyKFxyXG4gICAgICAgICAgICAgICAgKG9iaikgPT4gb2JqLm5hbWVXaXRoRXh0ZW5zaW9uICE9IEZpbGVPYmplY3QubmFtZVxyXG4gICAgICAgICAgICAgICk7XHJcbiAgICAgICAgICAgIHRoaXMuZGVsZXRlZEZpbGVzLnB1c2goRGVsZXRlZEl0ZW0pO1xyXG4gICAgICAgICAgICB0aGlzLm11bHRpcGxlRmlsZVVwbG9hZE1vZGVsLnJlbW92ZWRGaWxlcy5wdXNoKERlbGV0ZWRJdGVtLmlEX0dVSUQpO1xyXG4gICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgbGV0IEZpbGVPYmplY3QgPSBpdGVtLmZpbGUucmF3RmlsZTtcclxuICAgICAgICAgICAgbGV0IGRlbGV0ZWRMaXN0ID0gdGhpcy5kZWxldGVkRmlsZXMuZmlsdGVyKFxyXG4gICAgICAgICAgICAgIChvYmopID0+IG9iai5uYW1lV2l0aEV4dGVuc2lvbiA9PSBGaWxlT2JqZWN0Lm5hbWVcclxuICAgICAgICAgICAgKTtcclxuICAgICAgICAgICAgaWYgKGRlbGV0ZWRMaXN0Lmxlbmd0aCA9PSAwIHx8IGRlbGV0ZWRMaXN0ID09IHVuZGVmaW5lZCkge1xyXG4gICAgICAgICAgICAgIGxldCBEZWxldGVkSXRlbSA9IHRoaXMubXVsdGlwbGVGaWxlVXBsb2FkTW9kZWwuZXhpc3RpbmdGaWxlcy5maWx0ZXIoXHJcbiAgICAgICAgICAgICAgICAob2JqKSA9PiBvYmoubmFtZVdpdGhFeHRlbnNpb24gPT0gRmlsZU9iamVjdC5uYW1lXHJcbiAgICAgICAgICAgICAgKVswXTtcclxuICAgICAgICAgICAgICB0aGlzLm11bHRpcGxlRmlsZVVwbG9hZE1vZGVsLmV4aXN0aW5nRmlsZXMgPVxyXG4gICAgICAgICAgICAgICAgdGhpcy5tdWx0aXBsZUZpbGVVcGxvYWRNb2RlbC5leGlzdGluZ0ZpbGVzLmZpbHRlcihcclxuICAgICAgICAgICAgICAgICAgKG9iaikgPT4gb2JqLm5hbWVXaXRoRXh0ZW5zaW9uICE9IEZpbGVPYmplY3QubmFtZVxyXG4gICAgICAgICAgICAgICAgKTtcclxuICAgICAgICAgICAgICB0aGlzLmRlbGV0ZWRGaWxlcy5wdXNoKERlbGV0ZWRJdGVtKTtcclxuICAgICAgICAgICAgICB0aGlzLm11bHRpcGxlRmlsZVVwbG9hZE1vZGVsLnJlbW92ZWRGaWxlcy5wdXNoKERlbGV0ZWRJdGVtLmlEX0dVSUQpO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIHRoaXMuZGVsZXRlZEZpbGVzID0gW107XHJcbiAgICAgICAgdGhpcy5tdWx0aXBsZUZpbGVVcGxvYWRNb2RlbC5yZW1vdmVkRmlsZXMgPSBbXTtcclxuICAgICAgfVxyXG4gICAgICB0aGlzLm11bHRpcGxlRmlsZVVwbG9hZE1vZGVsLnVwbG9hZGVkRmlsZXMgPVxyXG4gICAgICAgIHRoaXMubXVsdGlwbGVGaWxlVXBsb2FkTW9kZWwudXBsb2FkZWRGaWxlcy5maWx0ZXIoXHJcbiAgICAgICAgICAob2JqKSA9PlxyXG4gICAgICAgICAgICAob2JqLm5hbWVXaXRoRXh0ZW5zaW9uICYmIG9iai5uYW1lV2l0aEV4dGVuc2lvbiAhPSBpdGVtLl9maWxlLm5hbWUpIHx8XHJcbiAgICAgICAgICAgIG9iai5pRF9HVUlEICE9IGl0ZW0uX2ZpbGVbJ2lEX0dVSUQnXVxyXG4gICAgICAgICk7XHJcblxyXG4gICAgICBpZiAoXHJcbiAgICAgICAgKHRoaXMubXVsdGlwbGVGaWxlVXBsb2FkTW9kZWwudXBsb2FkZWRGaWxlcyA9PSBudWxsIHx8XHJcbiAgICAgICAgICB0aGlzLm11bHRpcGxlRmlsZVVwbG9hZE1vZGVsLnVwbG9hZGVkRmlsZXMubGVuZ3RoID09IDApICYmXHJcbiAgICAgICAgdGhpcy5vcHRpb25zLmlzUmVxdWlyZWRcclxuICAgICAgKSB7XHJcbiAgICAgICAgY29uc3QgZm9ybUNvbnRyb2wgPSB0aGlzLmZpbGVVcGxvYWRGb3JtQ29udHJvbDtcclxuICAgICAgICBmb3JtQ29udHJvbC5zZXRFcnJvcnMoe1xyXG4gICAgICAgICAgTWluRmlsZUNvdW50VmFsaWRhdGlvbktleTogdGhpcy5vcHRpb25zLm1pbk5vT2ZGaWxlc1xyXG4gICAgICAgIH0pO1xyXG4gICAgICAgIHRoaXMuZmlsZVVwbG9hZEZvcm1Db250cm9sLm1hcmtBc1RvdWNoZWQoKTtcclxuICAgICAgICB0aGlzLmZpbGVVcGxvYWRGb3JtQ29udHJvbC51cGRhdGVWYWx1ZUFuZFZhbGlkaXR5KCk7IC8vIFRyaWdnZXIgdmFsaWRhdGlvbiBjaGVja1xyXG4gICAgICB9XHJcbiAgICAgIHRoaXMubXVsdGlwbGVGaWxlVXBsb2FkTW9kZWwuY29ycmVsYXRpb25JRF9HVUlEID0gdGhpcy5vcHRpb25zLnZhbHVlPy5jb3JyZWxhdGlvbklEX0dVSUQ7XHJcbiAgICAgIHRoaXMuZmlsZVVwbG9hZEZvcm1Db250cm9sLnNldFZhbHVlKHRoaXMubXVsdGlwbGVGaWxlVXBsb2FkTW9kZWwpO1xyXG4gICAgICB0aGlzLmdyb3VwLmdldCh0aGlzLm9wdGlvbnMubmFtZSkuc2V0VmFsdWUodGhpcy5tdWx0aXBsZUZpbGVVcGxvYWRNb2RlbCk7XHJcbiAgICAgIHRoaXMuZmlsZVVwbG9hZEZvcm1Db250cm9sLnVwZGF0ZVZhbHVlQW5kVmFsaWRpdHkoKTtcclxuICAgICAgLy9Vc2UgdGhpcyBsaW5lIHRvIGVuYWJsZSB0d28gd2F5IGJpbmRpbmcuXHJcbiAgICAgIHRoaXMub3B0aW9ucy52YWx1ZSA9IHRoaXMubXVsdGlwbGVGaWxlVXBsb2FkTW9kZWw7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvL0V4dGVybmFsIE1ldGhvZFxyXG4gIHJlbW92ZVJlcXVpcmVkVmFsaWRhdGlvbiA9ICgpID0+IHtcclxuICAgIHRoaXMuY29udHJvbFV0aWxpdHkucmVtb3ZlUmVxdWlyZWRWYWxpZGF0aW9uKFxyXG4gICAgICB0aGlzLmZpbGVVcGxvYWRGb3JtQ29udHJvbCxcclxuICAgICAgdGhpcy52YWxpZGF0aW9uUnVsZXMsXHJcbiAgICAgIHRoaXMub3B0aW9uc1xyXG4gICAgKTtcclxuICB9O1xyXG5cclxuICAvL0V4dGVybmFsIE1ldGhvZFxyXG4gIGFkZFJlcXVpcmVkVmFsaWRhdGlvbiA9ICgpID0+IHtcclxuICAgIHRoaXMuY29udHJvbFV0aWxpdHkuYWRkUmVxdWlyZWRWYWxpZGF0aW9uKFxyXG4gICAgICB0aGlzLmZpbGVVcGxvYWRGb3JtQ29udHJvbCxcclxuICAgICAgdGhpcy52YWxpZGF0aW9uUnVsZXMsXHJcbiAgICAgIHRoaXMub3B0aW9uc1xyXG4gICAgKTtcclxuICB9O1xyXG5cclxuICAvL0V4dGVybmFsIE1ldGhvZFxyXG4gIHJlbW92ZUN1c3RvbVZhbGlkYXRpb24gPSAoY3VzdG9tVmFsaWRhdGlvbikgPT4ge1xyXG4gICAgdGhpcy5jb250cm9sVXRpbGl0eS5yZW1vdmVDdXN0b21WYWxpZGF0aW9uKFxyXG4gICAgICB0aGlzLmZpbGVVcGxvYWRGb3JtQ29udHJvbCxcclxuICAgICAgdGhpcy52YWxpZGF0aW9uUnVsZXMsXHJcbiAgICAgIGN1c3RvbVZhbGlkYXRpb25cclxuICAgICk7XHJcbiAgfTtcclxuXHJcbiAgLy9FeHRlcm5hbCBNZXRob2RcclxuICBhZGRDdXN0b21WYWxpZGF0aW9uID0gKGN1c3RvbVZhbGlkYXRpb24pID0+IHtcclxuICAgIHRoaXMuY29udHJvbFV0aWxpdHkuYWRkQ3VzdG9tVmFsaWRhdGlvbihcclxuICAgICAgdGhpcy5maWxlVXBsb2FkRm9ybUNvbnRyb2wsXHJcbiAgICAgIHRoaXMudmFsaWRhdGlvblJ1bGVzLFxyXG4gICAgICBjdXN0b21WYWxpZGF0aW9uXHJcbiAgICApO1xyXG4gIH07XHJcblxyXG4gIC8vRXh0ZXJuYWwgTWV0aG9kXHJcbiAgaXNWYWxpZCA9ICgpID0+IHtcclxuICAgIHRoaXMuY29udHJvbFV0aWxpdHkuaXNWYWxpZCh0aGlzLmZpbGVVcGxvYWRGb3JtQ29udHJvbCk7XHJcbiAgfTtcclxuXHJcbiAgY29udmVydFNpemVUb01CKHNpemU6IG51bWJlcik6IG51bWJlciB7XHJcbiAgICBpZiAoc2l6ZSA9PT0gMCkge1xyXG4gICAgICByZXR1cm4gMDtcclxuICAgIH1cclxuXHJcbiAgICAvLyBDb252ZXJ0IHNpemUgdG8gbWVnYWJ5dGVzXHJcbiAgICBjb25zdCBtZWdhYnl0ZXMgPSBzaXplIC8gKDEwMjQgKiAxMDI0KTtcclxuXHJcbiAgICAvLyBSb3VuZCB0byB0d28gZGVjaW1hbCBwbGFjZXNcclxuICAgIGNvbnN0IHJvdW5kZWRNZWdhYnl0ZXMgPSBNYXRoLnJvdW5kKG1lZ2FieXRlcyAqIDEwMCkgLyAxMDA7XHJcblxyXG4gICAgcmV0dXJuIHJvdW5kZWRNZWdhYnl0ZXM7XHJcbiAgfVxyXG5cclxuICBuZ09uRGVzdHJveSgpOiB2b2lkIHtcclxuICAgIC8vIENvbXBsZXRlIGFsbCBzdWJzY3JpcHRpb25zIHRvIHByZXZlbnQgbWVtb3J5IGxlYWtzXHJcbiAgICB0aGlzLmRlc3Ryb3kkLm5leHQoKTtcclxuICAgIHRoaXMuZGVzdHJveSQuY29tcGxldGUoKTtcclxuXHJcbiAgICAvLyBDbGVhciB1cGxvYWRlciBxdWV1ZSB0byBmcmVlIG1lbW9yeVxyXG4gICAgaWYgKHRoaXMudXBsb2FkZXIpIHtcclxuICAgICAgdGhpcy51cGxvYWRlci5jbGVhclF1ZXVlKCk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICBwdWJsaWMgc2FuaXRpemVGaWxlTmFtZShmaWxlTmFtZTogc3RyaW5nKTogc3RyaW5nIHtcclxuICAgIC8vIFJlbW92ZSBwb3RlbnRpYWxseSBkYW5nZXJvdXMgY2hhcmFjdGVycyBmcm9tIGZpbGUgbmFtZXNcclxuICAgIHJldHVybiBmaWxlTmFtZS5yZXBsYWNlKC9bPD46XCIvXFxcXHw/Kl0vZywgJ18nKS50cmltKCk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBGaW5kIGR1cGxpY2F0ZSBmaWxlcyBpbiB0aGUgY3VycmVudCB1cGxvYWQgcXVldWVcclxuICAgKiBAcmV0dXJucyBBcnJheSBvZiBuZXdseSBhZGRlZCBkdXBsaWNhdGUgRmlsZUl0ZW0gb2JqZWN0cyB0aGF0IHNob3VsZCBiZSByZWplY3RlZFxyXG4gICAqL1xyXG4gIHByaXZhdGUgZmluZER1cGxpY2F0ZUZpbGVzKCk6IGFueVtdIHtcclxuICAgIGNvbnN0IGR1cGxpY2F0ZUZpbGVzOiBhbnlbXSA9IFtdO1xyXG4gICAgY29uc3QgZXhpc3RpbmdGaWxlTmFtZXMgPSBuZXcgU2V0PHN0cmluZz4oKTtcclxuXHJcbiAgICAvLyBGaXJzdCBwYXNzOiBjb2xsZWN0IG5hbWVzIG9mIGV4aXN0aW5nIGZpbGVzIChhbHJlYWR5IGluIHF1ZXVlIGJlZm9yZSB0aGlzIHVwbG9hZClcclxuICAgIGNvbnN0IGV4aXN0aW5nRmlsZXMgPSB0aGlzLnVwbG9hZGVyLnF1ZXVlLmZpbHRlcihpdGVtID0+IGl0ZW1bJ3NvbWUnXS5sYXN0TW9kaWZpZWQgPT0gbnVsbCk7XHJcbiAgICBmb3IgKGNvbnN0IGl0ZW0gb2YgZXhpc3RpbmdGaWxlcykge1xyXG4gICAgICBjb25zdCBmaWxlTmFtZSA9IGl0ZW0uZmlsZS5uYW1lLnRvTG93ZXJDYXNlKCkudHJpbSgpO1xyXG4gICAgICBleGlzdGluZ0ZpbGVOYW1lcy5hZGQoZmlsZU5hbWUpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFNlY29uZCBwYXNzOiBjaGVjayBuZXdseSBhZGRlZCBmaWxlcyBhZ2FpbnN0IGV4aXN0aW5nIGZpbGUgbmFtZXNcclxuICAgIGNvbnN0IG5ld2x5QWRkZWRGaWxlcyA9IHRoaXMudXBsb2FkZXIucXVldWUuZmlsdGVyKGl0ZW0gPT4gaXRlbVsnc29tZSddLmxhc3RNb2RpZmllZCAhPSBudWxsKTtcclxuXHJcbiAgICBmb3IgKGNvbnN0IGl0ZW0gb2YgbmV3bHlBZGRlZEZpbGVzKSB7XHJcbiAgICAgIGNvbnN0IGZpbGVOYW1lID0gaXRlbS5maWxlLm5hbWUudG9Mb3dlckNhc2UoKS50cmltKCk7XHJcblxyXG4gICAgICAvLyBJZiB0aGlzIG5ldyBmaWxlIG5hbWUgYWxyZWFkeSBleGlzdHMgaW4gdGhlIHF1ZXVlLCBpdCdzIGEgZHVwbGljYXRlXHJcbiAgICAgIGlmIChleGlzdGluZ0ZpbGVOYW1lcy5oYXMoZmlsZU5hbWUpKSB7XHJcbiAgICAgICAgZHVwbGljYXRlRmlsZXMucHVzaChpdGVtKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICAvLyBBZGQgdGhpcyBuZXcgZmlsZSBuYW1lIHRvIHRoZSBzZXQgc28gc3Vic2VxdWVudCBmaWxlcyB3aXRoIHNhbWUgbmFtZSBhcmUgYWxzbyBmbGFnZ2VkXHJcbiAgICAgICAgZXhpc3RpbmdGaWxlTmFtZXMuYWRkKGZpbGVOYW1lKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiBkdXBsaWNhdGVGaWxlcztcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFJlbW92ZSBkdXBsaWNhdGUgZmlsZXMgZnJvbSB0aGUgdXBsb2FkZXIgcXVldWVcclxuICAgKiBAcGFyYW0gZHVwbGljYXRlRmlsZXMgQXJyYXkgb2YgZHVwbGljYXRlIEZpbGVJdGVtIG9iamVjdHMgdG8gcmVtb3ZlXHJcbiAgICovXHJcbiAgcHJpdmF0ZSByZW1vdmVEdXBsaWNhdGVGaWxlc0Zyb21RdWV1ZShkdXBsaWNhdGVGaWxlczogYW55W10pOiB2b2lkIHtcclxuICAgIGZvciAoY29uc3QgZHVwbGljYXRlRmlsZSBvZiBkdXBsaWNhdGVGaWxlcykge1xyXG4gICAgICBjb25zdCBpbmRleCA9IHRoaXMudXBsb2FkZXIucXVldWUuaW5kZXhPZihkdXBsaWNhdGVGaWxlKTtcclxuICAgICAgaWYgKGluZGV4ID4gLTEpIHtcclxuICAgICAgICB0aGlzLnVwbG9hZGVyLnF1ZXVlLnNwbGljZShpbmRleCwgMSk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcblxyXG4gIHByaXZhdGUgaXNGaWxlVHlwZUFjY2VwdGVkKGZpbGVUeXBlOiBzdHJpbmcpOiBib29sZWFuIHtcclxuICAgIGlmICghdGhpcy5hY2NlcHRlZFR5cGVBcnJheSB8fCB0aGlzLmFjY2VwdGVkVHlwZUFycmF5Lmxlbmd0aCA9PT0gMCkge1xyXG4gICAgICByZXR1cm4gdHJ1ZTsgLy8gTm8gcmVzdHJpY3Rpb25zXHJcbiAgICB9XHJcblxyXG4gICAgLy8gTm9ybWFsaXplIHRoZSBmaWxlIHR5cGUgZm9yIGNvbXBhcmlzb25cclxuICAgIGNvbnN0IG5vcm1hbGl6ZWRGaWxlVHlwZSA9IGZpbGVUeXBlLnRvTG93ZXJDYXNlKCkudHJpbSgpO1xyXG5cclxuICAgIC8vIENoZWNrIGFnYWluc3QgYWxsIGFjY2VwdGVkIHR5cGVzIChjYXNlLWluc2Vuc2l0aXZlIGFuZCB0cmltbWVkKVxyXG4gICAgcmV0dXJuIHRoaXMuYWNjZXB0ZWRUeXBlQXJyYXkuc29tZShhY2NlcHRlZFR5cGUgPT4ge1xyXG4gICAgICBjb25zdCBub3JtYWxpemVkQWNjZXB0ZWRUeXBlID0gYWNjZXB0ZWRUeXBlLnRvTG93ZXJDYXNlKCkudHJpbSgpO1xyXG4gICAgICByZXR1cm4gbm9ybWFsaXplZEFjY2VwdGVkVHlwZSA9PT0gbm9ybWFsaXplZEZpbGVUeXBlO1xyXG4gICAgfSk7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIHNldFZhbHVlUHJlc2VydmluZ0Vycm9ycyh2YWx1ZTogYW55LCBwcmVzZXJ2ZUVycm9ycz86IGFueSk6IHZvaWQge1xyXG4gICAgLy8gQ2FwdHVyZSBjdXJyZW50IGR1cGxpY2F0ZSBlcnJvcnMgYmVmb3JlIHNldFZhbHVlIGNsZWFycyB0aGVtXHJcbiAgICBjb25zdCBjdXJyZW50RXJyb3JzID0gdGhpcy5maWxlVXBsb2FkRm9ybUNvbnRyb2wuZXJyb3JzO1xyXG4gICAgY29uc3QgZHVwbGljYXRlRXJyb3IgPSBjdXJyZW50RXJyb3JzPy5EdXBsaWNhdGVGaWxlRXJyb3IgPyB7IER1cGxpY2F0ZUZpbGVFcnJvcjogY3VycmVudEVycm9ycy5EdXBsaWNhdGVGaWxlRXJyb3IgfSA6IG51bGw7XHJcblxyXG4gICAgLy8gU2V0IHRoZSBmb3JtIGNvbnRyb2wgdmFsdWVcclxuICAgIHRoaXMuZmlsZVVwbG9hZEZvcm1Db250cm9sLnNldFZhbHVlKHZhbHVlKTtcclxuICAgIHRoaXMuZ3JvdXAuZ2V0KHRoaXMub3B0aW9ucy5uYW1lKS5zZXRWYWx1ZSh2YWx1ZSk7XHJcblxyXG4gICAgLy8gQXBwbHkgZXJyb3JzIGluIHByaW9yaXR5IG9yZGVyOiBwcmVzZXJ2ZUVycm9ycyA+IGR1cGxpY2F0ZUVycm9yID4gcGVuZGluZ1ZhbGlkYXRpb25FcnJvcnNcclxuICAgIGNvbnN0IGVycm9yc1RvQXBwbHkgPSBwcmVzZXJ2ZUVycm9ycyB8fCBkdXBsaWNhdGVFcnJvciB8fCB0aGlzLnBlbmRpbmdWYWxpZGF0aW9uRXJyb3JzO1xyXG4gICAgaWYgKGVycm9yc1RvQXBwbHkpIHtcclxuICAgICAgdGhpcy5maWxlVXBsb2FkRm9ybUNvbnRyb2wuc2V0RXJyb3JzKGVycm9yc1RvQXBwbHkpO1xyXG4gICAgICB0aGlzLmZpbGVVcGxvYWRGb3JtQ29udHJvbC5tYXJrQXNUb3VjaGVkKCk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gVXBkYXRlIHRoZSBvcHRpb25zIHZhbHVlIGZvciB0d28td2F5IGJpbmRpbmdcclxuICAgIHRoaXMub3B0aW9ucy52YWx1ZSA9IHZhbHVlO1xyXG4gIH1cclxufSIsIjxkaXYgY2xhc3M9XCJmb3JtLWdyb3VwIGJic2YtY29udHJvbCBiYnNmLWZpbGUtdXBsb2FkXCIgW2Zvcm1Hcm91cF09XCJncm91cFwiPlxyXG4gIDxkaXYgW25nQ2xhc3NdPVwib3B0aW9ucy52aWV3VHlwZSA9PSAxID8gJ2Jic2YtdmVydGljYWwnIDogJ2Jic2YtaG9yaXpvbnRhbCdcIj5cclxuICAgIDwhLS1sYWJlbC0tPlxyXG4gICAgPGxhYmVsIFtoaWRkZW5dPVwib3B0aW9ucy5oaWRlTGFiZWxcIiBjbGFzcz1cImJic2YtbGFiZWwge3sgb3B0aW9ucy5sYWJlbEV4dHJhQ2xhc3NlcyB9fVwiPlxyXG4gICAgICB7eyBvcHRpb25zLmxhYmVsVmFsdWUgfX1cclxuICAgICAgPCEtLUFzdGVyaXNrLS0+XHJcbiAgICAgIDxzcGFuICpuZ0lmPVwiKChvcHRpb25zLnNob3dBc3RlcmlzayAmJiBvcHRpb25zLmlzUmVxdWlyZWQpIHx8IG9wdGlvbnMuaXNSZXF1aXJlZCkgJiYgIW9wdGlvbnMuaXNSZWFkb25seVwiXHJcbiAgICAgICAgY2xhc3M9XCJ0ZXh0LWRhbmdlclwiPio8L3NwYW4+XHJcbiAgICA8L2xhYmVsPlxyXG4gICAgPCEtLUFsbG93IGRyb3Bab25lLS0+XHJcbiAgICA8ZGl2IG5nMkZpbGVEcm9wIGNsYXNzPVwiYmJzZi1pbnB1dC1jb250YWluZXIge3sgb3B0aW9ucy5leHRyYUNsYXNzZXMgfX1cIlxyXG4gICAgICAqbmdJZj1cIm9wdGlvbnMuaXNEcm9wWm9uZSAmJiAhKG9wdGlvbnMuaXNNdWx0aXBsZUZpbGUgPT0gZmFsc2UgJiYgdXBsb2FkZXIucXVldWUubGVuZ3RoID4gMCkgJiYgIW9wdGlvbnMuaXNSZWFkb25seVwiXHJcbiAgICAgIFtuZ0NsYXNzXT1cInsgJ2Fub3RoZXItZmlsZS1vdmVyLWNsYXNzJzogaGFzQW5vdGhlckRyb3Bab25lT3ZlciB9XCIgKG9uRmlsZURyb3ApPVwib25GaWxlQ2hhbmdlKClcIlxyXG4gICAgICAoZmlsZU92ZXIpPVwiZmlsZU92ZXJBbm90aGVyKCRldmVudClcIiBbdXBsb2FkZXJdPVwidXBsb2FkZXJcIiBbYWNjZXB0XT1cImFjY2VwdGVkVHlwZVwiIGlkPVwie3sgb3B0aW9ucy5uYW1lIH19XCJcclxuICAgICAgbXVsdGlwbGU9XCJ7eyBvcHRpb25zLmlzTXVsdGlwbGVGaWxlID8gJ211bHRpcGxlJyA6ICcnIH19XCIgYXJpYS1kZXNjcmliZWRieT1cImVtYWlsLWVycm9yXCIgYXJpYS1pbnZhbGlkPVwidHJ1ZVwiXHJcbiAgICAgIHR5cGU9XCJmaWxlXCIgW2NsYXNzLmlzLWludmFsaWRdPVwiZmlsZVVwbG9hZEZvcm1Db250cm9sLmludmFsaWQgJiYgZmlsZVVwbG9hZEZvcm1Db250cm9sLnRvdWNoZWRcIlxyXG4gICAgICAoY2xpY2spPVwiZmlsZUlucHV0RHJvcFpvbmUuY2xpY2soKVwiPlxyXG4gICAgICA8ZGl2IGNsYXNzPVwiZHJvcHpvbmUtbGFiZWxcIj5cclxuICAgICAgICA8ZGl2IGNsYXNzPVwic3ZnLWFuZC12YWxpZGF0aW9uXCI+XHJcbiAgICAgICAgICA8c3ZnIHhtbG5zPVwiaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmdcIiB3aWR0aD1cIjcwXCIgaGVpZ2h0PVwiNzBcIiB2aWV3Qm94PVwiMCAwIDcwIDcwXCIgZmlsbD1cIm5vbmVcIj5cclxuICAgICAgICAgICAgPHBhdGggb3BhY2l0eT1cIjAuNFwiXHJcbiAgICAgICAgICAgICAgZD1cIk01OC4zMzMgNDguODMzMkM2MS44OTU3IDQ1Ljg5MDggNjQuMTY2MyA0MS40Mzk3IDY0LjE2NjMgMzYuNDU4M0M2NC4xNjYzIDI3LjU5ODggNTYuOTg0MyAyMC40MTY3IDQ4LjEyNDcgMjAuNDE2N0M0Ny40ODc0IDIwLjQxNjcgNDYuODkxMiAyMC4wODQyIDQ2LjU2NzUgMTkuNTM1MUM0Mi43NjQxIDEzLjA4MDggMzUuNzQxNyA4Ljc1IDI3LjcwOCA4Ljc1QzE1LjYyNjggOC43NSA1LjgzMzAxIDE4LjU0MzggNS44MzMwMSAzMC42MjVDNS44MzMwMSAzNi42NTExIDguMjY5NzQgNDIuMTA4MiAxMi4yMTE2IDQ2LjA2NDRcIlxyXG4gICAgICAgICAgICAgIHN0cm9rZT1cIiM0QjU0ODlcIiBzdHJva2Utd2lkdGg9XCIyXCIgc3Ryb2tlLWxpbmVjYXA9XCJyb3VuZFwiIHN0cm9rZS1saW5lam9pbj1cInJvdW5kXCIgLz5cclxuICAgICAgICAgICAgPHBhdGggZD1cIk0yMy4zMzMgNDYuNjY2N0wzNC45OTk3IDM1TTM0Ljk5OTcgMzVMNDYuNjY2MyA0Ni42NjY3TTM0Ljk5OTcgMzVWNjEuMjVcIiBzdHJva2U9XCIjNEI1NDg5XCJcclxuICAgICAgICAgICAgICBzdHJva2Utd2lkdGg9XCIyXCIgc3Ryb2tlLWxpbmVjYXA9XCJyb3VuZFwiIHN0cm9rZS1saW5lam9pbj1cInJvdW5kXCIgLz5cclxuICAgICAgICAgIDwvc3ZnPlxyXG4gICAgICAgICAgPCEtLVZhbGlkYXRpb24gdGV4dC0tPlxyXG4gICAgICAgICAgPGRpdiBjbGFzcz1cImJic2YtdmFsaWRhdGlvbi1tc2cgdmFsaWRhdGlvbi1tc2ctaGVhZGVyIHRleHQtY2VudGVyXCI+XHJcbiAgICAgICAgICAgIHt7IFV0aWxpdHlTZXJ2aWNlLmdldFJlc291cmNlVmFsdWUoJ0RyYWdBbmREcm9wSGVyZScpIH19XHJcbiAgICAgICAgICA8L2Rpdj5cclxuICAgICAgICAgIDxkaXYgY2xhc3M9XCJiYnNmLXZhbGlkYXRpb24tbXNnIHRleHQtY2VudGVyXCIgKm5nSWY9XCJ2YWxpZGF0aW9uTWVzc2FnZVwiIFtpbm5lckhUTUxdPVwidmFsaWRhdGlvbk1lc3NhZ2VcIj48L2Rpdj5cclxuICAgICAgICAgIDxkaXYgY2xhc3M9XCJiYnNmLXZhbGlkYXRpb24tbXNnIG5nLXN0YXItaW5zZXJ0ZWQgdGV4dC1jZW50ZXIgdGV4dC1kYW5nZXJcIlxyXG4gICAgICAgICAgICAqbmdJZj1cInZhbGlkYXRpb25Db3VudE1lc3NhZ2UgJiYgb3B0aW9ucy5pc011bHRpcGxlRmlsZSAmJiBvcHRpb25zLm1heE5vT2ZGaWxlcyA+IDBcIlxyXG4gICAgICAgICAgICBbaW5uZXJIVE1MXT1cInZhbGlkYXRpb25Db3VudE1lc3NhZ2VcIj48L2Rpdj5cclxuICAgICAgICA8L2Rpdj5cclxuICAgICAgPC9kaXY+XHJcbiAgICAgIDxpbnB1dCBuZzJGaWxlU2VsZWN0IFt1cGxvYWRlcl09XCJ1cGxvYWRlclwiIFthY2NlcHRdPVwiYWNjZXB0ZWRUeXBlXCJcclxuICAgICAgICBjbGFzcz1cImZpbGVTZWxlY3RvciBjdXN0b21GaWxlVXBsb2FkUGxhY21lbnQgaGlkZGVuIHYtcmVxdWlyZWQtbXVsdGlwbGVmaWxlcyBkLW5vbmVcIlxyXG4gICAgICAgIG11bHRpcGxlPVwie3sgb3B0aW9ucy5pc011bHRpcGxlRmlsZSA/ICdtdWx0aXBsZScgOiAnJyB9fVwiIG5hbWU9XCJmaWxlXCIgdHlwZT1cImZpbGVcIiB2YWx1ZT1cIlwiIGF1dG9jb21wbGV0ZT1cIm9mZlwiXHJcbiAgICAgICAgKGNoYW5nZSk9XCJvbkZpbGVDaGFuZ2UoKVwiIFtuZ0NsYXNzXT1cIm9wdGlvbnMudmlld1R5cGUgPT0gMSA/ICcnIDogJ2NvbC1tZC05J1wiIGlkPVwie3sgb3B0aW9ucy5uYW1lIH19XCJcclxuICAgICAgICBhcmlhLWRlc2NyaWJlZGJ5PVwiZW1haWwtZXJyb3JcIiBhcmlhLWludmFsaWQ9XCJ0cnVlXCIgI2ZpbGVJbnB1dERyb3Bab25lXHJcbiAgICAgICAgW2NsYXNzLmlzLWludmFsaWRdPVwiZmlsZVVwbG9hZEZvcm1Db250cm9sLmludmFsaWQgJiYgZmlsZVVwbG9hZEZvcm1Db250cm9sLnRvdWNoZWRcIiAvPlxyXG4gICAgPC9kaXY+XHJcbiAgICA8IS0tTm90IGFsbG93ZWQgZHJvcFpvbmUtLT5cclxuICAgIDxkaXYgY2xhc3M9XCJiYnNmLWlucHV0LWNvbnRhaW5lclwiICpuZ0lmPVwiIW9wdGlvbnMuaXNEcm9wWm9uZSAmJiAhaXNIaWRlSW5wdXQoKSAmJiAhb3B0aW9ucy5pc1JlYWRvbmx5XCJcclxuICAgICAgKGNsaWNrKT1cImZpbGVJbnB1dC5jbGljaygpXCI+XHJcbiAgICAgIDxkaXYgY2xhc3M9XCJkcm9wem9uZS1sYWJlbFwiPlxyXG4gICAgICAgIDxkaXYgY2xhc3M9XCJzdmctYW5kLXZhbGlkYXRpb25cIj5cclxuICAgICAgICAgIDxzdmcgeG1sbnM9XCJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2Z1wiIHdpZHRoPVwiNzBcIiBoZWlnaHQ9XCI3MFwiIHZpZXdCb3g9XCIwIDAgNzAgNzBcIiBmaWxsPVwibm9uZVwiPlxyXG4gICAgICAgICAgICA8cGF0aCBvcGFjaXR5PVwiMC40XCJcclxuICAgICAgICAgICAgICBkPVwiTTU4LjMzMyA0OC44MzMyQzYxLjg5NTcgNDUuODkwOCA2NC4xNjYzIDQxLjQzOTcgNjQuMTY2MyAzNi40NTgzQzY0LjE2NjMgMjcuNTk4OCA1Ni45ODQzIDIwLjQxNjcgNDguMTI0NyAyMC40MTY3QzQ3LjQ4NzQgMjAuNDE2NyA0Ni44OTEyIDIwLjA4NDIgNDYuNTY3NSAxOS41MzUxQzQyLjc2NDEgMTMuMDgwOCAzNS43NDE3IDguNzUgMjcuNzA4IDguNzVDMTUuNjI2OCA4Ljc1IDUuODMzMDEgMTguNTQzOCA1LjgzMzAxIDMwLjYyNUM1LjgzMzAxIDM2LjY1MTEgOC4yNjk3NCA0Mi4xMDgyIDEyLjIxMTYgNDYuMDY0NFwiXHJcbiAgICAgICAgICAgICAgc3Ryb2tlPVwiIzRCNTQ4OVwiIHN0cm9rZS13aWR0aD1cIjJcIiBzdHJva2UtbGluZWNhcD1cInJvdW5kXCIgc3Ryb2tlLWxpbmVqb2luPVwicm91bmRcIiAvPlxyXG4gICAgICAgICAgICA8cGF0aCBkPVwiTTIzLjMzMyA0Ni42NjY3TDM0Ljk5OTcgMzVNMzQuOTk5NyAzNUw0Ni42NjYzIDQ2LjY2NjdNMzQuOTk5NyAzNVY2MS4yNVwiIHN0cm9rZT1cIiM0QjU0ODlcIlxyXG4gICAgICAgICAgICAgIHN0cm9rZS13aWR0aD1cIjJcIiBzdHJva2UtbGluZWNhcD1cInJvdW5kXCIgc3Ryb2tlLWxpbmVqb2luPVwicm91bmRcIiAvPlxyXG4gICAgICAgICAgPC9zdmc+XHJcbiAgICAgICAgICA8IS0tVmFsaWRhdGlvbiB0ZXh0LS0+XHJcbiAgICAgICAgICA8ZGl2IGNsYXNzPVwiYmJzZi12YWxpZGF0aW9uLW1zZyB0ZXh0LWNlbnRlclwiPnt7IFV0aWxpdHlTZXJ2aWNlLmdldFJlc291cmNlVmFsdWUoJ1VwbG9hZCcpIH19PC9kaXY+XHJcbiAgICAgICAgICA8ZGl2IGNsYXNzPVwiYmJzZi12YWxpZGF0aW9uLW1zZyB0ZXh0LWNlbnRlclwiICpuZ0lmPVwidmFsaWRhdGlvbk1lc3NhZ2VcIiBbaW5uZXJIVE1MXT1cInZhbGlkYXRpb25NZXNzYWdlXCI+PC9kaXY+XHJcbiAgICAgICAgICA8ZGl2IGNsYXNzPVwiYmJzZi12YWxpZGF0aW9uLW1zZyBuZy1zdGFyLWluc2VydGVkIHRleHQtY2VudGVyIHRleHQtZGFuZ2VyXCJcclxuICAgICAgICAgICAgKm5nSWY9XCJ2YWxpZGF0aW9uQ291bnRNZXNzYWdlICYmIG9wdGlvbnMuaXNNdWx0aXBsZUZpbGUgJiYgb3B0aW9ucy5tYXhOb09mRmlsZXMgPiAwXCJcclxuICAgICAgICAgICAgW2lubmVySFRNTF09XCJ2YWxpZGF0aW9uQ291bnRNZXNzYWdlXCI+PC9kaXY+XHJcbiAgICAgICAgPC9kaXY+XHJcbiAgICAgIDwvZGl2PlxyXG4gICAgICA8aW5wdXQgbmcyRmlsZVNlbGVjdCBbdXBsb2FkZXJdPVwidXBsb2FkZXJcIiBbYWNjZXB0XT1cImFjY2VwdGVkVHlwZVwiXHJcbiAgICAgICAgY2xhc3M9XCJmaWxlU2VsZWN0b3IgY3VzdG9tRmlsZVVwbG9hZFBsYWNtZW50IGhpZGRlbiB2LXJlcXVpcmVkLW11bHRpcGxlZmlsZXMgZC1ub25lXCJcclxuICAgICAgICBtdWx0aXBsZT1cInt7IG9wdGlvbnMuaXNNdWx0aXBsZUZpbGUgPyAnbXVsdGlwbGUnIDogJycgfX1cIiBuYW1lPVwiZmlsZVwiIHR5cGU9XCJmaWxlXCIgdmFsdWU9XCJcIiBhdXRvY29tcGxldGU9XCJvZmZcIlxyXG4gICAgICAgIChjaGFuZ2UpPVwib25GaWxlQ2hhbmdlKClcIiBbbmdDbGFzc109XCJvcHRpb25zLnZpZXdUeXBlID09IDEgPyAnJyA6ICdjb2wtbWQtOSdcIiBpZD1cInt7IG9wdGlvbnMubmFtZSB9fVwiXHJcbiAgICAgICAgYXJpYS1kZXNjcmliZWRieT1cImVtYWlsLWVycm9yXCIgYXJpYS1pbnZhbGlkPVwidHJ1ZVwiICNmaWxlSW5wdXRcclxuICAgICAgICBbY2xhc3MuaXMtaW52YWxpZF09XCJmaWxlVXBsb2FkRm9ybUNvbnRyb2wuaW52YWxpZCAmJiBmaWxlVXBsb2FkRm9ybUNvbnRyb2wudG91Y2hlZFwiIC8+XHJcbiAgICA8L2Rpdj5cclxuICAgIDwhLS0gcmVhZG9ubHkgLS0+XHJcbiAgICA8ZGl2ICpuZ0lmPVwib3B0aW9ucy5pc1JlYWRvbmx5ICYmICFvcHRpb25zLnZhbHVlXCI+XHJcbiAgICAgIDxzcGFuIGNsYXNzPVwicmVhZG9ubHktdmlld1wiPnt7IFV0aWxpdHlTZXJ2aWNlLmdldFJlc291cmNlVmFsdWUoJ05BJykgfX08L3NwYW4+XHJcbiAgICA8L2Rpdj5cclxuICA8L2Rpdj5cclxuICA8IS0taXRlbXMgdXBsb2FkZWQtLT5cclxuICA8ZGl2IGNsYXNzPVwidXBsb2FkZWQtaXRlbXNcIj5cclxuICAgIDxkaXYgY2xhc3M9XCJidG4tZ3JvdXBcIiAqbmdGb3I9XCJsZXQgaXRlbSBvZiB1cGxvYWRlci5xdWV1ZVwiPlxyXG4gICAgICA8bmctY29udGFpbmVyICpuZ0lmPVwiaXRlbT8ucHJvZ3Jlc3MgPT0gMTAwICYmIG9wdGlvbnMuaXNVcGxvYWRGaWxlQXN5bmNcIj5cclxuICAgICAgICA8YSAqbmdJZj1cIml0ZW0/LmZpbGU/LnJhd0ZpbGVbJ3VybCddXCIgaHJlZj1cInt7IGl0ZW0/LmZpbGU/LnJhd0ZpbGVbJ3VybCddIH19XCJcclxuICAgICAgICAgIGNsYXNzPVwiYnRuLWRvd25sb2FkLWZpbGUgYnRuLXNtIGJ0bi1wcm9ncmVzcy11cGxvYWRcIiBkb3dubG9hZD5cclxuICAgICAgICAgIDxzcGFuIGNsYXNzPVwiZmlsZS1uYW1lXCI+e3sgc2FuaXRpemVGaWxlTmFtZShpdGVtPy5maWxlPy5uYW1lIHx8ICcnKSB9fTwvc3Bhbj5cclxuICAgICAgICA8L2E+XHJcbiAgICAgICAgPGEgKm5nSWY9XCJpdGVtPy5maWxlPy5yYXdGaWxlWyd1cmwnXSA9PSBudWxsXCIgY2xhc3M9XCJidG4tZG93bmxvYWQtZmlsZSBidG4tc20gYnRuLXByb2dyZXNzLXVwbG9hZFwiPlxyXG4gICAgICAgICAgPHNwYW4gY2xhc3M9XCJmaWxlLW5hbWVcIj57eyBzYW5pdGl6ZUZpbGVOYW1lKGl0ZW0/LmZpbGU/Lm5hbWUgfHwgJycpIH19PC9zcGFuPlxyXG4gICAgICAgIDwvYT5cclxuICAgICAgICA8YnV0dG9uICpuZ0lmPVwiIW9wdGlvbnMuaXNSZWFkb25seVwiIGNsYXNzPVwiYnRuIGJ0bi1kb3dubG9hZC1maWxlIGJ0bi1zbVwiXHJcbiAgICAgICAgICAoY2xpY2spPVwiaXRlbS5yZW1vdmUoKTsgcmVtb3ZlRnJvbUNvbnRyb2xWYWx1ZShpdGVtKVwiPlxyXG4gICAgICAgICAgPHN2ZyB4bWxucz1cImh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnXCIgd2lkdGg9XCIxNFwiIGhlaWdodD1cIjE0XCIgdmlld0JveD1cIjAgMCAxNCAxNFwiIGZpbGw9XCJub25lXCI+XHJcbiAgICAgICAgICAgIDxwYXRoIG9wYWNpdHk9XCIwLjRcIlxyXG4gICAgICAgICAgICAgIGQ9XCJNOS4zMzMwMSAzLjcwNTg0VjMuMjY2NjNDOS4zMzMwMSAyLjY1MTY2IDkuMzMzMDEgMi4zNDQxOSA5LjIwNTg3IDIuMTA5M0M5LjA5NDA1IDEuOTAyNyA4LjkxNTU1IDEuNzM0NzEgOC42OTYwNCAxLjYyOTQ0QzguNDQ2NDcgMS41MDk3NyA4LjExOTc3IDEuNTA5NzcgNy40NjYzOCAxLjUwOTc3SDYuNTMzMDVDNS44Nzk2NSAxLjUwOTc3IDUuNTUyOTYgMS41MDk3NyA1LjMwMzM5IDEuNjI5NDRDNS4wODM4NyAxLjczNDcxIDQuOTA1MzkgMS45MDI3IDQuNzkzNTQgMi4xMDkzQzQuNjY2MzggMi4zNDQxOSA0LjY2NjM4IDIuNjUxNjYgNC42NjYzOCAzLjI2NjYzVjMuNzA1ODRcIlxyXG4gICAgICAgICAgICAgIHN0cm9rZT1cIiNEODM3MzFcIiBzdHJva2Utd2lkdGg9XCIxLjVcIiBzdHJva2UtbGluZWNhcD1cInJvdW5kXCIgc3Ryb2tlLWxpbmVqb2luPVwicm91bmRcIiAvPlxyXG4gICAgICAgICAgICA8cGF0aFxyXG4gICAgICAgICAgICAgIGQ9XCJNMS43NSAzLjcwNjA1SDEyLjI1TTExLjA4MzQgMy43MDYwNVY5Ljg1NTFDMTEuMDgzNCAxMC43Nzc1IDExLjA4MzQgMTEuMjM4NyAxMC44OTI2IDExLjU5MUMxMC43MjQ4IDExLjkwMSAxMC40NTcxIDEyLjE1MjkgMTAuMTI3OCAxMi4zMTA5QzkuNzUzNDUgMTIuNDkwNCA5LjI2MzQ1IDEyLjQ5MDQgOC4yODMzNCAxMi40OTA0SDUuNzE2NjZDNC43MzY1OCAxMi40OTA0IDQuMjQ2NTMgMTIuNDkwNCAzLjg3MjE4IDEyLjMxMDlDMy41NDI5IDEyLjE1MjkgMy4yNzUxOSAxMS45MDEgMy4xMDc0MSAxMS41OTFDMi45MTY2NiAxMS4yMzg3IDIuOTE2NjYgMTAuNzc3NSAyLjkxNjY2IDkuODU1MVYzLjcwNjA1XCJcclxuICAgICAgICAgICAgICBzdHJva2U9XCIjRDgzNzMxXCIgc3Ryb2tlLXdpZHRoPVwiMS41XCIgc3Ryb2tlLWxpbmVjYXA9XCJyb3VuZFwiIHN0cm9rZS1saW5lam9pbj1cInJvdW5kXCIgLz5cclxuICAgICAgICAgIDwvc3ZnPlxyXG4gICAgICAgIDwvYnV0dG9uPlxyXG4gICAgICA8L25nLWNvbnRhaW5lcj5cclxuICAgICAgPG5nLWNvbnRhaW5lciAqbmdJZj1cIiFvcHRpb25zLmlzVXBsb2FkRmlsZUFzeW5jXCI+XHJcbiAgICAgICAgPGEgaHJlZj1cInt7IGl0ZW0/LmZpbGU/LnJhd0ZpbGVbJ3VybCddIH19XCIgY2xhc3M9XCJidG4gYnRuLWRvd25sb2FkLWZpbGUgYnRuLXNtXCIgZG93bmxvYWQ+XHJcbiAgICAgICAgICA8c3ZnIHdpZHRoPVwiMjRcIiBoZWlnaHQ9XCIyNFwiIHZpZXdCb3g9XCIwIDAgMjQgMjRcIiBmaWxsPVwibm9uZVwiIHhtbG5zPVwiaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmdcIj5cclxuICAgICAgICAgICAgPHBhdGhcclxuICAgICAgICAgICAgICBkPVwiTTIxIDIySDNDMi40IDIyIDIgMjEuNiAyIDIxQzIgMjAuNCAyLjQgMjAgMyAyMEgyMUMyMS42IDIwIDIyIDIwLjQgMjIgMjFDMjIgMjEuNiAyMS42IDIyIDIxIDIyWk0xMyAxMy40VjNDMTMgMi40IDEyLjYgMiAxMiAyQzExLjQgMiAxMSAyLjQgMTEgM1YxMy40SDEzWlwiXHJcbiAgICAgICAgICAgICAgZmlsbD1cImN1cnJlbnRDb2xvclwiPjwvcGF0aD5cclxuICAgICAgICAgICAgPHBhdGggb3BhY2l0eT1cIjAuM1wiIGQ9XCJNNyAxMy40SDE3TDEyLjcgMTcuN0MxMi4zIDE4LjEgMTEuNyAxOC4xIDExLjMgMTcuN0w3IDEzLjRaXCIgZmlsbD1cImN1cnJlbnRDb2xvclwiPlxyXG4gICAgICAgICAgICA8L3BhdGg+XHJcbiAgICAgICAgICA8L3N2Zz5cclxuICAgICAgICAgIDxzcGFuIGNsYXNzPVwiZmlsZS1uYW1lXCI+e3sgc2FuaXRpemVGaWxlTmFtZShpdGVtPy5maWxlPy5uYW1lIHx8ICcnKSB9fTwvc3Bhbj5cclxuICAgICAgICA8L2E+XHJcbiAgICAgICAgPGJ1dHRvbiAqbmdJZj1cIiFvcHRpb25zLmlzUmVhZG9ubHlcIiBjbGFzcz1cImJ0biBidG4tZG93bmxvYWQtZmlsZSBidG4tc20gYnRuLWRhbmdlclwiXHJcbiAgICAgICAgICAoY2xpY2spPVwiaXRlbS5yZW1vdmUoKTsgcmVtb3ZlRnJvbUNvbnRyb2xWYWx1ZShpdGVtKVwiPlxyXG4gICAgICAgICAgPGkgY2xhc3M9XCJmYSBmYS10aW1lcyBweC0wXCI+PC9pPlxyXG4gICAgICAgIDwvYnV0dG9uPlxyXG4gICAgICA8L25nLWNvbnRhaW5lcj5cclxuICAgIDwvZGl2PlxyXG4gIDwvZGl2PlxyXG4gIDwhLS1wcm9ncmVzcyBiYXIgZmlsZSB1cGxvYWQtLT5cclxuICA8ZGl2ICpuZ0Zvcj1cImxldCBpdGVtIG9mIHVwbG9hZGVyLnF1ZXVlXCI+XHJcbiAgICA8ZGl2IGNsYXNzPVwidXBsb2FkLWl0ZW1zXCIgW25nQ2xhc3NdPVwieyAnbXQtNCc6IG9wdGlvbnMuaXNNdWx0aXBsZUZpbGUgPT0gdHJ1ZSB9XCJcclxuICAgICAgKm5nSWY9XCJpdGVtPy5wcm9ncmVzcyA8IDEwMCAmJiBvcHRpb25zLmlzVXBsb2FkRmlsZUFzeW5jXCI+XHJcbiAgICAgIDxkaXYgY2xhc3M9XCJ1cGxvYWQtaXRlbXMtdG9vbGJhclwiPlxyXG4gICAgICAgIDxoND57eyBpdGVtPy5maWxlPy5uYW1lIH19PC9oND5cclxuICAgICAgICA8c3BhbiAoY2xpY2spPVwiaXRlbS5yZW1vdmUoKTsgcmVtb3ZlRnJvbUNvbnRyb2xWYWx1ZShpdGVtKVwiPlxyXG4gICAgICAgICAgPHN2ZyB4bWxucz1cImh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnXCIgd2lkdGg9XCIxOFwiIGhlaWdodD1cIjE4XCIgdmlld0JveD1cIjAgMCAxOCAxOFwiIGZpbGw9XCJub25lXCI+XHJcbiAgICAgICAgICAgIDxnIGNsaXAtcGF0aD1cInVybCgjY2xpcDBfMTMyNF8xMzIxNilcIj5cclxuICAgICAgICAgICAgICA8cGF0aCBvcGFjaXR5PVwiMC40XCJcclxuICAgICAgICAgICAgICAgIGQ9XCJNOSAxNi41QzEzLjE0MjEgMTYuNSAxNi41IDEzLjE0MjEgMTYuNSA5QzE2LjUgNC44NTc4NiAxMy4xNDIxIDEuNSA5IDEuNUM0Ljg1Nzg2IDEuNSAxLjUgNC44NTc4NiAxLjUgOUMxLjUgMTMuMTQyMSA0Ljg1Nzg2IDE2LjUgOSAxNi41WlwiXHJcbiAgICAgICAgICAgICAgICBzdHJva2U9XCIjREJFMUYwXCIgc3Ryb2tlLXdpZHRoPVwiMlwiIHN0cm9rZS1saW5lY2FwPVwicm91bmRcIiBzdHJva2UtbGluZWpvaW49XCJyb3VuZFwiIC8+XHJcbiAgICAgICAgICAgICAgPHBhdGggZD1cIk0xMS4yNSA2Ljc1TDYuNzUgMTEuMjVNNi43NSA2Ljc1TDExLjI1IDExLjI1XCIgc3Ryb2tlPVwiI0RCRTFGMFwiIHN0cm9rZS13aWR0aD1cIjJcIlxyXG4gICAgICAgICAgICAgICAgc3Ryb2tlLWxpbmVjYXA9XCJyb3VuZFwiIHN0cm9rZS1saW5lam9pbj1cInJvdW5kXCIgLz5cclxuICAgICAgICAgICAgPC9nPlxyXG4gICAgICAgICAgICA8ZGVmcz5cclxuICAgICAgICAgICAgICA8Y2xpcFBhdGggaWQ9XCJjbGlwMF8xMzI0XzEzMjE2XCI+XHJcbiAgICAgICAgICAgICAgICA8cmVjdCB3aWR0aD1cIjE4XCIgaGVpZ2h0PVwiMThcIiBmaWxsPVwid2hpdGVcIiAvPlxyXG4gICAgICAgICAgICAgIDwvY2xpcFBhdGg+XHJcbiAgICAgICAgICAgIDwvZGVmcz5cclxuICAgICAgICAgIDwvc3ZnPlxyXG4gICAgICAgIDwvc3Bhbj5cclxuICAgICAgPC9kaXY+XHJcbiAgICAgIDxkaXYgY2xhc3M9XCJwcm9ncmVzc1wiPlxyXG4gICAgICAgIDxkaXYgY2xhc3M9XCJwcm9ncmVzcy1iYXJcIiByb2xlPVwicHJvZ3Jlc3NiYXJcIiBhcmlhLXZhbHVlbm93PVwiNzBcIiBhcmlhLXZhbHVlbWluPVwiMFwiIGFyaWEtdmFsdWVtYXg9XCIxMDBcIlxyXG4gICAgICAgICAgW2NsYXNzLmZpbGUtdXBsb2FkZWRdPVwiaXRlbT8ucHJvZ3Jlc3MgPCAxMDBcIiBbc3R5bGUud2lkdGguJV09XCJpdGVtPy5wcm9ncmVzc1wiICpuZ0lmPVwiaXRlbT8ucHJvZ3Jlc3MgPiAwXCI+XHJcbiAgICAgICAgPC9kaXY+XHJcbiAgICAgIDwvZGl2PlxyXG4gICAgPC9kaXY+XHJcbiAgPC9kaXY+XHJcblxyXG4gIDxkaXYgY2xhc3M9XCJzdWJ0ZXh0LWNvbnRhaW5lclwiICpuZ0lmPVwiIW9wdGlvbnMuaXNSZWFkb25seVwiPlxyXG4gICAgPCEtLSByZXF1aXJlZCB0ZXh0LS0+XHJcbiAgICA8ZGl2IGNsYXNzPVwiYmJzZi12YWxpZGF0aW9uXCIgKm5nSWY9XCJmaWxlVXBsb2FkRm9ybUNvbnRyb2wuaW52YWxpZCAmJiBmaWxlVXBsb2FkRm9ybUNvbnRyb2wudG91Y2hlZFwiPlxyXG4gICAgICB7eyBnZXRFcnJvclZhbGlkYXRpb24oZmlsZVVwbG9hZEZvcm1Db250cm9sLmVycm9ycyB8IGtleXZhbHVlKSB9fVxyXG4gICAgPC9kaXY+XHJcbiAgICA8IS0tIExhYmVsRGVzY3JpcHRpb24tLT5cclxuICAgIDxkaXYgY2xhc3M9XCJiYnNmLWNvbnRyb2wtZGVzY1wiICpuZ0lmPVwib3B0aW9ucy5sYWJlbERlc2NyaXB0aW9uICE9IG51bGxcIj57eyBvcHRpb25zLmxhYmVsRGVzY3JpcHRpb24gfX08L2Rpdj5cclxuICAgIDxkaXYgKm5nSWY9XCIoZ3JvdXAudmFsaWQgJiYgZ3JvdXAuZGlydHkgJiYgZ3JvdXAudG91Y2hlZCkgfHwgKGdyb3VwLnVudG91Y2hlZCAmJiBncm91cC5pbnZhbGlkICYmIGdyb3VwLmRpcnR5KVwiPlxyXG4gICAgICB7eyByZXNldEVycm9yKCkgfX1cclxuICAgIDwvZGl2PlxyXG4gIDwvZGl2PlxyXG48L2Rpdj4iXX0=