@bnsights/bbsf-controls 1.0.176 → 1.0.178

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.
@@ -0,0 +1,1094 @@
1
+ import { Component, Input, Optional, ViewChild, Output, EventEmitter } from '@angular/core';
2
+ import { FormControl, Validators } from '@angular/forms';
3
+ import { FileUploader } from 'ng2-file-upload';
4
+ import { FileUploadModel } from '../../Shared/Models/FileUploadModel';
5
+ import { MultipleFileUploadModel } from '../../Shared/Models/MultipleFileUploadModel';
6
+ import { HttpEventType } from '@angular/common/http';
7
+ import { Subscription } from 'rxjs';
8
+ import * as i0 from "@angular/core";
9
+ import * as i1 from "@angular/forms";
10
+ import * as i2 from "../../Shared/services/ControlUtility";
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";
16
+ export class FileUploadComponent {
17
+ static { this.controlContainerStatic = null; }
18
+ constructor(controlContainer, multipleFileUploadControlHost, controlUtility, utilityService, controlValidationService, globalSettings, fileUploadService) {
19
+ this.controlContainer = controlContainer;
20
+ this.multipleFileUploadControlHost = multipleFileUploadControlHost;
21
+ this.controlUtility = controlUtility;
22
+ this.utilityService = utilityService;
23
+ this.controlValidationService = controlValidationService;
24
+ this.globalSettings = globalSettings;
25
+ 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
+ this.OnChange = new EventEmitter();
34
+ this.isUploadComplete = new EventEmitter();
35
+ this.validationMessage = '';
36
+ this.validationCountMessage = '';
37
+ this.hasAnotherDropZoneOver = false;
38
+ this.acceptedType = '';
39
+ this.acceptedTypeArray = [];
40
+ this.toolTipTypeArray = [];
41
+ this.markAllAsTouched = false;
42
+ this.validationRules = [];
43
+ this.validationRulesAsync = [];
44
+ this.file = null;
45
+ this.deletedFiles = [];
46
+ this.subscriptions = new Subscription();
47
+ this.resetError = () => {
48
+ this.controlValidationService.removeGlobalError();
49
+ };
50
+ this.removeRequiredValidation = () => {
51
+ this.controlUtility.removeRequiredValidation(this.fileUploadFormControl, this.validationRules, this.options);
52
+ };
53
+ this.addRequiredValidation = () => {
54
+ this.controlUtility.addRequiredValidation(this.fileUploadFormControl, this.validationRules, this.options);
55
+ };
56
+ this.removeCustomValidation = (customValidation) => {
57
+ this.controlUtility.removeCustomValidation(this.fileUploadFormControl, this.validationRules, customValidation);
58
+ };
59
+ this.addCustomValidation = (customValidation) => {
60
+ this.controlUtility.addCustomValidation(this.fileUploadFormControl, this.validationRules, customValidation);
61
+ };
62
+ this.isValid = () => {
63
+ this.controlUtility.isValid(this.fileUploadFormControl);
64
+ return this.fileUploadFormControl.valid;
65
+ };
66
+ FileUploadComponent.controlContainerStatic = this.controlContainer;
67
+ this.initializeUploader();
68
+ }
69
+ initializeUploader() {
70
+ this.uploader = new FileUploader({
71
+ disableMultipart: false
72
+ });
73
+ }
74
+ 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
+ this.fileUploadModel = new FileUploadModel();
85
+ this.multipleFileUploadModel = new MultipleFileUploadModel();
86
+ }
87
+ setViewType() {
88
+ if (!this.options.viewType) {
89
+ 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;
104
+ });
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;
124
+ }
125
+ 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);
179
+ }
180
+ else {
181
+ // Single MIME type
182
+ allMimeTypes.push(fileType);
183
+ }
184
+ }
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);
198
+ }
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(', ')})`);
237
+ }
238
+ if (this.options.fileMaxSizeInMB > 0) {
239
+ messages.push(`${this.utilityService.getResourceValue('FileMaxSizeInMB')}${this.options.fileMaxSizeInMB}`);
240
+ }
241
+ if (this.options.minNoOfFiles > 0) {
242
+ messages.push(`${this.utilityService.getResourceValue('MinFileCountValidationKey')}${this.options.minNoOfFiles}`);
243
+ }
244
+ if (this.options.maxNoOfFiles > 0) {
245
+ messages.push(`${this.utilityService.getResourceValue('MaxFileCountValidationKey')}${this.options.maxNoOfFiles}`);
246
+ }
247
+ this.validationMessage = messages.join(' <br/> ');
248
+ }
249
+ setupFormControl() {
250
+ this.group.addControl(this.options.name, new FormControl(''));
251
+ 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);
261
+ }
262
+ }
263
+ if (this.options.isRequired) {
264
+ this.validationRules.push(Validators.required);
265
+ }
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
+ this.fileUploadFormControl.setValidators(this.validationRules);
274
+ if (this.validationRulesAsync.length > 0) {
275
+ this.fileUploadFormControl.setAsyncValidators(this.validationRulesAsync);
276
+ }
277
+ if (this.options.isDisabled) {
278
+ this.fileUploadFormControl.disable();
279
+ }
280
+ }
281
+ setupSubscriptions() {
282
+ this.multipleFileUploadControlHost.ngSubmit.subscribe(() => {
283
+ this.group.markAllAsTouched();
284
+ this.markAllAsTouched = true;
285
+ });
286
+ }
287
+ 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);
298
+ }
299
+ }
300
+ }
301
+ showGlobalError() {
302
+ this.controlUtility.showGlobalError();
303
+ }
304
+ getErrorValidation(errorList) {
305
+ if (this.markAllAsTouched && this.group.invalid) {
306
+ this.showGlobalError();
307
+ this.markAllAsTouched = false;
308
+ }
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);
317
+ }
318
+ fileOverAnother(event) {
319
+ this.hasAnotherDropZoneOver = !!event;
320
+ }
321
+ isHideInput() {
322
+ 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);
381
+ }
382
+ }
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);
430
+ }
431
+ }
432
+ }
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;
440
+ }
441
+ }
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;
450
+ }
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;
462
+ }
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);
477
+ }
478
+ else {
479
+ this.fileUploadFormControl.setErrors(currentErrors);
480
+ }
481
+ }
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;
490
+ }
491
+ }
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;
517
+ }
518
+ }
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
+ }
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);
590
+ }
591
+ }
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);
603
+ }
604
+ else if (event.type === HttpEventType.Response) {
605
+ this.handleUploadComplete(element, event, filesArray);
606
+ }
607
+ },
608
+ error: (error) => {
609
+ console.error('Upload failed:', error);
610
+ // Handle upload error - you can add custom error handling here
611
+ }
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();
666
+ }
667
+ finally {
668
+ // Clean up reader
669
+ readerRef.onload = null;
670
+ readerRef.onerror = null;
671
+ readerRef.onabort = null;
672
+ }
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);
865
+ }
866
+ }
867
+ convertSizeToMB(size) {
868
+ if (size === 0) {
869
+ return 0;
870
+ }
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;
918
+ }
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);
925
+ }
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);
1014
+ }
1015
+ }
1016
+ }
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 = [];
1046
+ }
1047
+ }
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
+ });
1063
+ }
1064
+ }
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');
1072
+ }
1073
+ }
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" }] }); }
1076
+ }
1077
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: FileUploadComponent, decorators: [{
1078
+ 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>" }]
1080
+ }], ctorParameters: () => [{ type: i1.ControlContainer, decorators: [{
1081
+ type: Optional
1082
+ }] }, { type: i1.FormGroupDirective }, { type: i2.ControlUtility }, { type: i3.UtilityService }, { type: i3.ControlValidationService }, { type: i4.GlobalSettings }, { type: i5.FileUploadService }], propDecorators: { fileInput: [{
1083
+ type: ViewChild,
1084
+ args: ['fileInput', { static: false }]
1085
+ }], group: [{
1086
+ type: Input
1087
+ }], options: [{
1088
+ type: Input
1089
+ }], OnChange: [{
1090
+ type: Output
1091
+ }], isUploadComplete: [{
1092
+ type: Output
1093
+ }] } });
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==