UNPKG

kwikui

Version:

KwikID's UI Component Library in Angular

323 lines 60.2 kB
import { Component, EventEmitter, forwardRef, Input, Output, ViewChild } from "@angular/core"; import { FormControl, FormGroup, NG_VALUE_ACCESSOR } from "@angular/forms"; import { TUI_SANITIZER } from "@taiga-ui/core"; import { NgDompurifySanitizer } from "@tinkoff/ng-dompurify"; import { isNotEmptyValue } from "kwikid-toolkit"; import { Subscription } from "rxjs"; import { distinctUntilChanged } from "rxjs/operators"; import { throwErrorMessage } from "../../../../helpers/kwikui.common.helpers"; import { DEFAULT_VALUES, VALIDATE_KEY_VALUES } from "./input-files.constants"; import { EKwikUIInputFileState } from "./input-files.definitions"; import { isValidKeyValue } from "./input-files.validation"; import * as i0 from "@angular/core"; import * as i1 from "@taiga-ui/core"; import * as i2 from "@taiga-ui/kit"; import * as i3 from "@taiga-ui/kit/components/files"; import * as i4 from "../../button/button.component"; import * as i5 from "@angular/forms"; import * as i6 from "@angular/common"; export class KwikUIInputFilesComponent { constructor() { this.accept = DEFAULT_VALUES.accept; this.class = DEFAULT_VALUES.class; this.disabled = DEFAULT_VALUES.disabled; this.files = []; this.formControl = new FormControl({}); this.formControlName = DEFAULT_VALUES.formControlName; this.icon = DEFAULT_VALUES.icon; this.id = DEFAULT_VALUES.id; this.label = DEFAULT_VALUES.label; this.link = DEFAULT_VALUES.link; this.maxFileSize = DEFAULT_VALUES.maxFileSize; this.multiple = DEFAULT_VALUES.multiple; this.setFileTypesToForm = DEFAULT_VALUES.setFileTypesToForm; this.showAddedFiles = DEFAULT_VALUES.showAddedFiles; this.size = DEFAULT_VALUES.size; this.styles = DEFAULT_VALUES.styles; this.validators = { required: true }; this.variant = DEFAULT_VALUES.variant; this.showViewButton = DEFAULT_VALUES.showViewButton; this.getKeyValue = new EventEmitter(); this.getRemovedFile = new EventEmitter(); this.getViewButtonClick = new EventEmitter(); this.formGroup = new FormGroup({}); this.openDropdown = false; this.normalFiles = []; this.errorFiles = []; this.loadingFiles = []; this.deletedFiles = []; this.subscriptions = new Subscription(); } ngOnInit() { this.formGroup.addControl(this.formControlName, this.formControl); this.validators = Object.assign({}, this.validators); this.disabled = this.disabled; this.setDisabled(); this.files = this.filterDuplicates(this.files); this.loadFiles(this.files); this.subscriptions.add(this.formGroup.controls[this.formControlName].valueChanges .pipe(distinctUntilChanged()) // makes sure the value has actually changed. .subscribe((value) => { this.handleInputValueChange(value); })); } ngOnChanges(changes) { const verifyChange = (key) => { return changes.hasOwnProperty(key) && !changes[key].firstChange; }; for (const change of Object.entries(changes)) { const key = change[0]; const value = change[1].currentValue; this.validateInputProperty(key, value); } if (verifyChange("formControl")) { this.formControl = changes.formControl.currentValue; } if (verifyChange("styles")) { this.styles = changes.styles.currentValue; } if (verifyChange("class")) { this.class = changes.class.currentValue; } if (verifyChange("multiple")) { this.multiple = changes.multiple.currentValue; } if (verifyChange("accept")) { this.accept = changes.accept.currentValue; } if (verifyChange("label")) { this.label = changes.label.currentValue; } if (verifyChange("link")) { this.link = changes.link.currentValue; } if (verifyChange("icon")) { this.icon = changes.icon.currentValue; } if (verifyChange("size")) { this.size = changes.size.currentValue; } if (verifyChange("setFileTypesToForm")) { this.setFileTypesToForm = changes.setFileTypesToForm.currentValue; } if (verifyChange("files")) { this.files = changes.files.currentValue; this.files = this.filterDuplicates(this.files); this.loadFiles(this.files); } if (verifyChange("maxFileSize")) { this.maxFileSize = changes.maxFileSize.currentValue; } if (verifyChange("disabled")) { this.disabled = changes.disabled.currentValue; this.setDisabled(); } } ngOnDestroy() { this.subscriptions.unsubscribe(); // ensure when component is destroyed the subscription is also and not left open. } validateInputProperty(key, value) { if (VALIDATE_KEY_VALUES[key] && !isValidKeyValue(key, value)) { this[key] = DEFAULT_VALUES[key]; throwErrorMessage("kwikui-input-files", this.id, key, value, DEFAULT_VALUES[key]); } } loadFiles(files) { this.normalFiles = files.filter((file) => file.state === EKwikUIInputFileState.NORMAL); this.errorFiles = files.filter((file) => file.state === EKwikUIInputFileState.ERROR); this.loadingFiles = files.filter((file) => file.state === EKwikUIInputFileState.LOADING); this.deletedFiles = files.filter((file) => file.state === EKwikUIInputFileState.DELETED); const setFiles = [ ...(this.setFileTypesToForm.includes(EKwikUIInputFileState.NORMAL) ? this.normalFiles : []), ...(this.setFileTypesToForm.includes(EKwikUIInputFileState.ERROR) ? this.errorFiles : []), ...(this.setFileTypesToForm.includes(EKwikUIInputFileState.LOADING) ? this.loadingFiles : []), ...(this.setFileTypesToForm.includes(EKwikUIInputFileState.DELETED) ? this.deletedFiles : []) ]; this.formControl.setValue(setFiles, { emitEvent: false }); } filterDuplicates(files) { const uniqueFiles = []; files.forEach((file) => { const isDuplicate = uniqueFiles.some((existingFile) => existingFile.name === file.name && existingFile.size === file.size); if (!isDuplicate) { uniqueFiles.push(file); } }); return uniqueFiles; } filterUnique(arr1, arr2) { const uniqueElements = []; arr2.forEach((element) => { if (!arr1.includes(element)) { uniqueElements.push(element); } }); return uniqueElements; } /** * @description Handles setting up of error and focus on the input field is it is invalid */ setDisabled() { if (this.formGroup.controls[this.formControlName] !== undefined) { if (this.disabled === true) { this.formGroup.controls[this.formControlName].disable({ emitEvent: false }); } else { this.formGroup.controls[this.formControlName].enable({ emitEvent: false }); } } } handleOnClickOpenFileManager() { if (isNotEmptyValue(this.nativeFilePicker)) { this.nativeFilePicker.nativeElement.click(); } } handleOnInputFileChange(e) { const files = []; for (const file of e.target.files) { files.push(file); } this.formGroup.patchValue({ [this.formControlName]: this.multiple ? files : files[0] }, { emitEvent: true }); } /** * @description Handles firing of 2 events on (keyup) event * * @param value */ handleInputValueChange(value) { if (Array.isArray(value)) { value = this.filterUnique(this.files, value); } else { value = this.filterUnique(this.files, [value]); } this.emitEvent(this.getKeyValue, { key: this.formControlName, value }); } emitEvent(event, data) { event.emit(data); } removeFile(file) { const files = this.files.filter((f) => { return !(file.name === f.name && file.size === f.size); }); this.emitEvent(this.getRemovedFile, { key: this.formControlName, value: file, files }); } fileClick(file) { const files = this.files.filter((f) => { return !(file.name === f.name && file.size === f.size); }); this.emitEvent(this.getViewButtonClick, { key: this.formControlName, value: file, files }); } /** Method Implementations for Abstract Control */ writeValue(value) { } registerOnChange(fn) { } registerOnTouched(fn) { } setDisabledState(isDisabled) { } } /** @nocollapse */ KwikUIInputFilesComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: KwikUIInputFilesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); /** @nocollapse */ KwikUIInputFilesComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "12.2.17", type: KwikUIInputFilesComponent, selector: "kwikui-input-files", inputs: { accept: "accept", class: "class", disabled: "disabled", files: "files", formControl: "formControl", formControlName: "formControlName", icon: "icon", id: "id", label: "label", link: "link", maxFileSize: "maxFileSize", multiple: "multiple", setFileTypesToForm: "setFileTypesToForm", showAddedFiles: "showAddedFiles", size: "size", styles: "styles", validators: "validators", variant: "variant", showViewButton: "showViewButton" }, outputs: { getKeyValue: "getKeyValue", getRemovedFile: "getRemovedFile", getViewButtonClick: "getViewButtonClick" }, providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef((() => KwikUIInputFilesComponent)), multi: true }, { provide: TUI_SANITIZER, useClass: NgDompurifySanitizer } ], viewQueries: [{ propertyName: "nativeFilePicker", first: true, predicate: ["nativeFilePicker"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div\n [formGroup]=\"formGroup\"\n id=\"input-files-container\"\n [class.small]=\"size === 's'\"\n [class.medium]=\"size === 'm'\"\n [class.large]=\"size === 'l'\"\n>\n <input\n *ngIf=\"variant === 'native'\"\n type=\"file\"\n id=\"input-files-native\"\n [class.control]=\"true\"\n [class.small]=\"size === 's'\"\n [class.medium]=\"size === 'm'\"\n [class.large]=\"size === 'l'\"\n [style]=\"styles\"\n [class]=\"class\"\n [multiple]=\"multiple\"\n [accept]=\"accept\"\n #nativeFilePicker\n (change)=\"handleOnInputFileChange($event)\"\n (click)=\"$event.target.value = null\"\n style=\"\n visibility: hidden;\n position: absolute;\n top: -10000px;\n left: -10000px;\n \"\n />\n <button\n id=\"input-files-native\"\n *ngIf=\"variant === 'native'\"\n [class.small]=\"size === 's'\"\n [class.medium]=\"size === 'm'\"\n [class.large]=\"size === 'l'\"\n [style]=\"styles\"\n [class]=\"class\"\n (click)=\"handleOnClickOpenFileManager()\"\n >\n <ng-container *ngIf=\"size === 's'\">\n <div class=\"content small\">\n <tui-svg [src]=\"icon\"></tui-svg>\n </div>\n </ng-container>\n <ng-container *ngIf=\"size === 'm'\">\n <div class=\"content medium\">\n <div class=\"input-file-dropzone-label\"> {{ link }}</div>\n </div>\n </ng-container>\n <ng-container *ngIf=\"size === 'l'\">\n <div class=\"content large\">\n <tui-marker-icon\n mode=\"link\"\n [src]=\"icon\"\n ></tui-marker-icon>\n <div class=\"input-file-dropzone-label\"> {{ link }}{{ label }} </div>\n </div>\n </ng-container>\n </button>\n\n <tui-input-files\n id=\"input-files\"\n *ngIf=\"variant === 'taigaui'\"\n [class.control]=\"true\"\n [class.small]=\"size === 's'\"\n [class.medium]=\"size === 'm'\"\n [class.large]=\"size === 'l'\"\n [style]=\"styles\"\n [class]=\"class\"\n [formControl]=\"formControl\"\n [multiple]=\"multiple\"\n [accept]=\"accept\"\n [label]=\"label\"\n [link]=\"link\"\n [maxFileSize]=\"maxFileSize\"\n >\n <ng-template let-dragged>\n <div\n *ngIf=\"false; else base\"\n class=\"content\"\n ></div>\n <ng-template #base>\n <ng-container *ngIf=\"size === 's'\">\n <div class=\"content small\">\n <tui-svg [src]=\"icon\"></tui-svg>\n </div>\n </ng-container>\n <ng-container *ngIf=\"size === 'm'\">\n <div class=\"content medium\">\n <a tuiLink>{{ link }}</a>\n </div>\n </ng-container>\n <ng-container *ngIf=\"size === 'l'\">\n <div class=\"content large\">\n <tui-marker-icon\n mode=\"link\"\n [src]=\"icon\"\n ></tui-marker-icon>\n <div>\n <a tuiLink>{{ link }}</a>\n {{ label }}\n </div>\n </div>\n </ng-container>\n </ng-template>\n </ng-template>\n </tui-input-files>\n\n <button\n *ngIf=\"files.length > 0 && size === 's' && showAddedFiles\"\n tuiButton\n id=\"view-added-files-btn\"\n appearance=\"flat\"\n nativeId=\"view-added-files-btn\"\n shape=\"square\"\n size=\"m\"\n [tuiDropdown]=\"addedFiles\"\n [tuiDropdownManual]=\"openDropdown\"\n (click)=\"openDropdown = !openDropdown\"\n >\n {{ files.length }}\n </button>\n\n <ng-container *ngIf=\"files.length > 0 && size !== 's' && showAddedFiles\">\n <ng-container\n *ngTemplateOutlet=\"addedFiles; context: { files: files }\"\n ></ng-container>\n </ng-container>\n\n <div\n *ngIf=\"files.length === 0 && size !== 's' && showAddedFiles\"\n id=\"no-files-added\"\n [class.small]=\"size === 's'\"\n [class.medium]=\"size === 'm'\"\n [class.large]=\"size === 'l'\"\n >\n {{ size !== \"s\" ? \"No Files Added\" : \"0\" }}\n </div>\n</div>\n\n<ng-template\n #addedFiles\n let-files=\"files\"\n>\n <div\n id=\"files-added\"\n [class.small]=\"size === 's'\"\n [class.medium]=\"size === 'm'\"\n [class.large]=\"size === 'l'\"\n >\n <tui-files [max]=\"2\">\n <ng-container\n class=\"file-parent\"\n *ngFor=\"let file of normalFiles\"\n >\n <tui-file\n [showDelete]=\"file?.showDelete ?? true\"\n [file]=\"file\"\n state=\"normal\"\n showSize=\"true\"\n size=\"l\"\n (removed)=\"removeFile(file)\"\n >\n <kwikui-button\n *ngIf=\"showViewButton\"\n class=\"view-button-underline\"\n [pseudoHover]=\"showViewButton?.viewButtonPseudoHover\"\n appearance=\"flat\"\n size=\"s\"\n style=\"--tui-padding: 0px\"\n [label]=\"showViewButton?.label\"\n (click)=\"fileClick(file)\"\n ></kwikui-button>\n </tui-file>\n </ng-container>\n\n <ng-container\n class=\"file-parent\"\n *ngFor=\"let file of errorFiles\"\n >\n <tui-file\n [showDelete]=\"file?.showDelete ?? true\"\n [file]=\"file\"\n state=\"error\"\n showSize=\"true\"\n size=\"l\"\n (removed)=\"removeFile(file)\"\n >\n <kwikui-button\n *ngIf=\"showViewButton\"\n class=\"view-button-underline\"\n [pseudoHover]=\"showViewButton?.viewButtonPseudoHover\"\n appearance=\"flat\"\n size=\"s\"\n style=\"--tui-padding: 0px\"\n [label]=\"showViewButton?.label\"\n (click)=\"fileClick(file)\"\n ></kwikui-button>\n </tui-file>\n </ng-container>\n\n <ng-container\n class=\"file-parent\"\n *ngFor=\"let file of loadingFiles\"\n >\n <tui-file\n [showDelete]=\"file?.showDelete ?? true\"\n [file]=\"file\"\n state=\"loading\"\n showSize=\"true\"\n size=\"l\"\n >\n <kwikui-button\n *ngIf=\"showViewButton\"\n class=\"view-button-underline\"\n [pseudoHover]=\"showViewButton?.viewButtonPseudoHover\"\n appearance=\"flat\"\n size=\"s\"\n style=\"--tui-padding: 0px\"\n [label]=\"showViewButton?.label\"\n (click)=\"fileClick(file)\"\n ></kwikui-button>\n </tui-file>\n </ng-container>\n\n <ng-container\n class=\"file-parent\"\n *ngFor=\"let file of deletedFiles\"\n >\n <tui-file\n [showDelete]=\"file?.showDelete ?? true\"\n [file]=\"file\"\n state=\"deleted\"\n showSize=\"true\"\n size=\"l\"\n >\n <kwikui-button\n *ngIf=\"showViewButton\"\n class=\"view-button-underline\"\n [pseudoHover]=\"showViewButton?.viewButtonPseudoHover\"\n appearance=\"flat\"\n size=\"s\"\n style=\"--tui-padding: 0px\"\n [label]=\"showViewButton?.label\"\n (click)=\"fileClick(file)\"\n ></kwikui-button>\n </tui-file>\n </ng-container>\n </tui-files>\n </div>\n</ng-template>\n", styles: ["#input-files-container.small{height:100%;border-radius:50%;width:100%;display:flex;flex-direction:row;align-items:stretch;justify-content:space-between}#input-files-native{width:100%;height:100%;min-height:auto;cursor:pointer}#input-files-native.small{height:100%;border-radius:50%;width:unset;border:1px dashed var(--tui-primary);background-color:transparent;outline:none;aspect-ratio:1/1}#input-files-native.medium{border:1px dashed var(--tui-primary);background-color:transparent;outline:none;width:100%;border-radius:.5rem;padding:1rem;font-size:.9rem}#input-files-native.large{border:1px dashed var(--tui-primary);background-color:transparent;outline:none;width:100%;border-radius:.5rem;padding:1rem;font-size:.9rem}#input-files-native .input-file-dropzone-label{color:var(--tui-text-02)}#input-files{width:100%;height:100%;min-height:auto;cursor:pointer}#input-files.small{height:100%;border-radius:50%;width:unset;border:1px dashed var(--tui-primary);background-color:transparent;outline:none;aspect-ratio:1/1}#view-added-files-btn{border-radius:50%;width:-moz-fit-content;width:fit-content;height:100%;aspect-ratio:1/1}.content{display:flex;flex-direction:column;align-items:center;justify-content:center;grid-gap:1rem;gap:1rem}.file-parent{pointer-events:none}#files-added{overflow:auto;cursor:pointer}#files-added.medium{margin-top:1rem}#files-added.large{margin-top:1rem}#no-files-added{width:100%;height:100%;border:1px solid var(--tui-base-03);border-radius:var(--tui-radius-m);overflow:hidden;padding:1rem;display:flex;flex-direction:row;align-content:center;justify-content:center;align-items:center}#no-files-added.small{border-radius:50%;width:-moz-fit-content;width:fit-content;height:100%;aspect-ratio:1/1;border:none}#no-files-added.medium{margin-top:1rem}#no-files-added.large{margin-top:1rem}.view-file-btn{background:var(--tui-primary);text-align:center;color:var(--tui-primary-text)}\n"], components: [{ type: i1.TuiSvgComponent, selector: "tui-svg", inputs: ["src"] }, { type: i2.TuiMarkerIconComponent, selector: "tui-marker-icon, a[tuiMarkerIcon], button[tuiMarkerIcon]", inputs: ["mode", "size", "src"] }, { type: i2.TuiInputFilesComponent, selector: "tui-input-files", inputs: ["link", "label", "accept", "multiple", "size", "maxFileSize"], outputs: ["reject"] }, { type: i1.TuiButtonComponent, selector: "button[tuiButton], button[tuiIconButton], a[tuiButton], a[tuiIconButton]", inputs: ["appearance", "disabled", "icon", "iconRight", "shape", "showLoader", "size"] }, { type: i3.TuiFilesComponent, selector: "tui-files", inputs: ["max", "expanded"], outputs: ["expandedChange"] }, { type: i3.TuiFileComponent, selector: "tui-file", inputs: ["file", "state", "size", "showDelete", "showSize", "leftContent"], outputs: ["removed"] }, { type: i4.KwikUIButtonComponent, selector: "kwikui-button", inputs: ["appearance", "class", "disabled", "icon", "iconRight", "id", "label", "shape", "showLoader", "size", "styles", "type", "pseudoHover"], outputs: ["onClick"] }], directives: [{ type: i5.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i5.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i6.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i5.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i5.FormControlDirective, selector: "[formControl]", inputs: ["disabled", "formControl", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { type: i1.TuiDropdownDirective, selector: "[tuiDropdown]:not(ng-container)", inputs: ["tuiDropdown"], exportAs: ["tuiDropdown"] }, { type: i1.TuiDropdownDriverDirective, selector: "[tuiDropdown]" }, { type: i1.TuiDropdownPositionDirective, selector: "[tuiDropdown]" }, { type: i1.TuiDropdownManualDirective, selector: "[tuiDropdown][tuiDropdownManual]", inputs: ["tuiDropdownManual"] }, { type: i6.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet"] }, { type: i6.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }] }); i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "12.2.17", ngImport: i0, type: KwikUIInputFilesComponent, decorators: [{ type: Component, args: [{ selector: "kwikui-input-files", templateUrl: "./input-files.component.html", styleUrls: ["./input-files.component.scss"], providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef((() => KwikUIInputFilesComponent)), multi: true }, { provide: TUI_SANITIZER, useClass: NgDompurifySanitizer } ] }] }], ctorParameters: function () { return []; }, propDecorators: { accept: [{ type: Input }], class: [{ type: Input }], disabled: [{ type: Input }], files: [{ type: Input }], formControl: [{ type: Input }], formControlName: [{ type: Input }], icon: [{ type: Input }], id: [{ type: Input }], label: [{ type: Input }], link: [{ type: Input }], maxFileSize: [{ type: Input }], multiple: [{ type: Input }], setFileTypesToForm: [{ type: Input }], showAddedFiles: [{ type: Input }], size: [{ type: Input }], styles: [{ type: Input }], validators: [{ type: Input }], variant: [{ type: Input }], showViewButton: [{ type: Input }], getKeyValue: [{ type: Output }], getRemovedFile: [{ type: Output }], getViewButtonClick: [{ type: Output }], nativeFilePicker: [{ type: ViewChild, args: ["nativeFilePicker"] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5wdXQtZmlsZXMuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMva3dpa3VpL3NyYy9saWIvY29tcG9uZW50cy9jb3JlL2lucHV0cy9pbnB1dC1maWxlcy9pbnB1dC1maWxlcy5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9rd2lrdWkvc3JjL2xpYi9jb21wb25lbnRzL2NvcmUvaW5wdXRzL2lucHV0LWZpbGVzL2lucHV0LWZpbGVzLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFDTCxTQUFTLEVBRVQsWUFBWSxFQUNaLFVBQVUsRUFDVixLQUFLLEVBR0wsTUFBTSxFQUVOLFNBQVMsRUFDVixNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBRUwsV0FBVyxFQUNYLFNBQVMsRUFDVCxpQkFBaUIsRUFDbEIsTUFBTSxnQkFBZ0IsQ0FBQztBQUN4QixPQUFPLEVBQUUsYUFBYSxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDL0MsT0FBTyxFQUFFLG9CQUFvQixFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFDN0QsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQ2pELE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDcEMsT0FBTyxFQUFFLG9CQUFvQixFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDdEQsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sMkNBQTJDLENBQUM7QUFDOUUsT0FBTyxFQUFFLGNBQWMsRUFBRSxtQkFBbUIsRUFBRSxNQUFNLHlCQUF5QixDQUFDO0FBQzlFLE9BQU8sRUFBRSxxQkFBcUIsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBQ2xFLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQzs7Ozs7Ozs7QUFrQjNELE1BQU0s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M0MsU0FBUyxFQUFFO3dCQUNUOzRCQUNFLE9BQU8sRUFBRSxpQkFBaUI7NEJBQzFCLFdBQVcsRUFBRSxVQUFVLEVBQUMsR0FBRyxFQUFFLDBCQUEwQixFQUFDOzRCQUN4RCxLQUFLLEVBQUUsSUFBSTt5QkFDWjt3QkFDRDs0QkFDRSxPQUFPLEVBQUUsYUFBYTs0QkFDdEIsUUFBUSxFQUFFLG9CQUFvQjt5QkFDL0I7cUJBQ0Y7aUJBQ0Y7MEVBR1UsTUFBTTtzQkFBZCxLQUFLO2dCQUVHLEtBQUs7c0JBQWIsS0FBSztnQkFFRyxRQUFRO3NCQUFoQixLQUFLO2dCQUVHLEtBQUs7c0JBQWIsS0FBSztnQkFFRyxXQUFXO3NCQUFuQixLQUFLO2dCQUVHLGVBQWU7c0JBQXZCLEtBQUs7Z0JBRUcsSUFBSTtzQkFBWixLQUFLO2dCQUVHLEVBQUU7c0JBQVYsS0FBSztnQkFFRyxLQUFLO3NCQUFiLEtBQUs7Z0JBRUcsSUFBSTtzQkFBWixLQUFLO2dCQUVHLFdBQVc7c0JBQW5CLEtBQUs7Z0JBRUcsUUFBUTtzQkFBaEIsS0FBSztnQkFFRyxrQkFBa0I7c0JBQTFCLEtBQUs7Z0JBRUcsY0FBYztzQkFBdEIsS0FBSztnQkFFRyxJQUFJO3NCQUFaLEtBQUs7Z0JBRUcsTUFBTTtzQkFBZCxLQUFLO2dCQUVHLFVBQVU7c0JBQWxCLEtBQUs7Z0JBRUcsT0FBTztzQkFBZixLQUFLO2dCQUVHLGNBQWM7c0JBQXRCLEtBQUs7Z0JBRUksV0FBVztzQkFBcEIsTUFBTTtnQkFFRyxjQUFjO3NCQUF2QixNQUFNO2dCQUVHLGtCQUFrQjtzQkFBM0IsTUFBTTtnQkFFd0IsZ0JBQWdCO3NCQUE5QyxTQUFTO3VCQUFDLGtCQUFrQiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIENvbXBvbmVudCxcbiAgRWxlbWVudFJlZixcbiAgRXZlbnRFbWl0dGVyLFxuICBmb3J3YXJkUmVmLFxuICBJbnB1dCxcbiAgT25DaGFuZ2VzLFxuICBPbkluaXQsXG4gIE91dHB1dCxcbiAgU2ltcGxlQ2hhbmdlcyxcbiAgVmlld0NoaWxkXG59IGZyb20gXCJAYW5ndWxhci9jb3JlXCI7XG5pbXBvcnQge1xuICBDb250cm9sVmFsdWVBY2Nlc3NvcixcbiAgRm9ybUNvbnRyb2wsXG4gIEZvcm1Hcm91cCxcbiAgTkdfVkFMVUVfQUNDRVNTT1Jcbn0gZnJvbSBcIkBhbmd1bGFyL2Zvcm1zXCI7XG5pbXBvcnQgeyBUVUlfU0FOSVRJWkVSIH0gZnJvbSBcIkB0YWlnYS11aS9jb3JlXCI7XG5pbXBvcnQgeyBOZ0RvbXB1cmlmeVNhbml0aXplciB9IGZyb20gXCJAdGlua29mZi9uZy1kb21wdXJpZnlcIjtcbmltcG9ydCB7IGlzTm90RW1wdHlWYWx1ZSB9IGZyb20gXCJrd2lraWQtdG9vbGtpdFwiO1xuaW1wb3J0IHsgU3Vic2NyaXB0aW9uIH0gZnJvbSBcInJ4anNcIjtcbmltcG9ydCB7IGRpc3RpbmN0VW50aWxDaGFuZ2VkIH0gZnJvbSBcInJ4anMvb3BlcmF0b3JzXCI7XG5pbXBvcnQgeyB0aHJvd0Vycm9yTWVzc2FnZSB9IGZyb20gXCIuLi8uLi8uLi8uLi9oZWxwZXJzL2t3aWt1aS5jb21tb24uaGVscGVyc1wiO1xuaW1wb3J0IHsgREVGQVVMVF9WQUxVRVMsIFZBTElEQVRFX0tFWV9WQUxVRVMgfSBmcm9tIFwiLi9pbnB1dC1maWxlcy5jb25zdGFudHNcIjtcbmltcG9ydCB7IEVLd2lrVUlJbnB1dEZpbGVTdGF0ZSB9IGZyb20gXCIuL2lucHV0LWZpbGVzLmRlZmluaXRpb25zXCI7XG5pbXBvcnQgeyBpc1ZhbGlkS2V5VmFsdWUgfSBmcm9tIFwiLi9pbnB1dC1maWxlcy52YWxpZGF0aW9uXCI7XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogXCJrd2lrdWktaW5wdXQtZmlsZXNcIixcbiAgdGVtcGxhdGVVcmw6IFwiLi9pbnB1dC1maWxlcy5jb21wb25lbnQuaHRtbFwiLFxuICBzdHlsZVVybHM6IFtcIi4vaW5wdXQtZmlsZXMuY29tcG9uZW50LnNjc3NcIl0sXG4gIHByb3ZpZGVyczogW1xuICAgIHtcbiAgICAgIHByb3ZpZGU6IE5HX1ZBTFVFX0FDQ0VTU09SLFxuICAgICAgdXNlRXhpc3Rpbmc6IGZvcndhcmRSZWYoKCkgPT4gS3dpa1VJSW5wdXRGaWxlc0NvbXBvbmVudCksXG4gICAgICBtdWx0aTogdHJ1ZVxuICAgIH0sXG4gICAge1xuICAgICAgcHJvdmlkZTogVFVJX1NBTklUSVpFUixcbiAgICAgIHVzZUNsYXNzOiBOZ0RvbXB1cmlmeVNhbml0aXplclxuICAgIH1cbiAgXVxufSlcbmV4cG9ydCBjbGFzcyBLd2lrVUlJbnB1dEZpbGVzQ29tcG9uZW50XG4gIGltcGxlbWVudHMgT25Jbml0LCBPbkNoYW5nZXMsIENvbnRyb2xWYWx1ZUFjY2Vzc29yIHtcbiAgQElucHV0KCkgYWNjZXB0OiBzdHJpbmcgPSBERUZBVUxUX1ZBTFVFUy5hY2NlcHQ7XG5cbiAgQElucHV0KCkgY2xhc3M6IHN0cmluZyA9IERFRkFVTFRfVkFMVUVTLmNsYXNzO1xuXG4gIEBJbnB1dCgpIGRpc2FibGVkOiBib29sZWFuID0gREVGQVVMVF9WQUxVRVMuZGlzYWJsZWQ7XG5cbiAgQElucHV0KCkgZmlsZXM6IGFueVtdID0gW107XG5cbiAgQElucHV0KCkgZm9ybUNvbnRyb2w6IEZvcm1Db250cm9sID0gbmV3IEZvcm1Db250cm9sKHt9KTtcblxuICBASW5wdXQoKSBmb3JtQ29udHJvbE5hbWU6IHN0cmluZyA9IERFRkFVTFRfVkFMVUVTLmZvcm1Db250cm9sTmFtZTtcblxuICBASW5wdXQoKSBpY29uOiBzdHJpbmcgPSBERUZBVUxUX1ZBTFVFUy5pY29uO1xuXG4gIEBJbnB1dCgpIGlkOiBzdHJpbmcgPSBERUZBVUxUX1ZBTFVFUy5pZDtcblxuICBASW5wdXQoKSBsYWJlbDogc3RyaW5nID0gREVGQVVMVF9WQUxVRVMubGFiZWw7XG5cbiAgQElucHV0KCkgbGluazogc3RyaW5nID0gREVGQVVMVF9WQUxVRVMubGluaztcblxuICBASW5wdXQoKSBtYXhGaWxlU2l6ZTogbnVtYmVyID0gREVGQVVMVF9WQUxVRVMubWF4RmlsZVNpemU7XG5cbiAgQElucHV0KCkgbXVsdGlwbGU6IGJvb2xlYW4gPSBERUZBVUxUX1ZBTFVFUy5tdWx0aXBsZTtcblxuICBASW5wdXQoKSBzZXRGaWxlVHlwZXNUb0Zvcm06IHN0cmluZ1tdID0gREVGQVVMVF9WQUxVRVMuc2V0RmlsZVR5cGVzVG9Gb3JtO1xuXG4gIEBJbnB1dCgpIHNob3dBZGRlZEZpbGVzOiBib29sZWFuID0gREVGQVVMVF9WQUxVRVMuc2hvd0FkZGVkRmlsZXM7XG5cbiAgQElucHV0KCkgc2l6ZTogc3RyaW5nID0gREVGQVVMVF9WQUxVRVMuc2l6ZTtcblxuICBASW5wdXQoKSBzdHlsZXM6IHN0cmluZyA9IERFRkFVTFRfVkFMVUVTLnN0eWxlcztcblxuICBASW5wdXQoKSB2YWxpZGF0b3JzID0geyByZXF1aXJlZDogdHJ1ZSB9O1xuXG4gIEBJbnB1dCgpIHZhcmlhbnQgPSBERUZBVUxUX1ZBTFVFUy52YXJpYW50O1xuXG4gIEBJbnB1dCgpIHNob3dWaWV3QnV0dG9uOiBhbnkgPSBERUZBVUxUX1ZBTFVFUy5zaG93Vmlld0J1dHRvbjtcblxuICBAT3V0cHV0KCkgZ2V0S2V5VmFsdWU6IEV2ZW50RW1pdHRlcjxhbnk+ID0gbmV3IEV2ZW50RW1pdHRlcjxhbnk+KCk7XG5cbiAgQE91dHB1dCgpIGdldFJlbW92ZWRGaWxlOiBFdmVudEVtaXR0ZXI8YW55PiA9IG5ldyBFdmVudEVtaXR0ZXI8YW55PigpO1xuXG4gIEBPdXRwdXQoKSBnZXRWaWV3QnV0dG9uQ2xpY2s6IEV2ZW50RW1pdHRlcjxhbnk+ID0gbmV3IEV2ZW50RW1pdHRlcjxhbnk+KCk7XG5cbiAgQFZpZXdDaGlsZChcIm5hdGl2ZUZpbGVQaWNrZXJcIikgbmF0aXZlRmlsZVBpY2tlcjogRWxlbWVudFJlZjtcblxuICBmb3JtR3JvdXA6IEZvcm1Hcm91cCA9IG5ldyBGb3JtR3JvdXAoe30pO1xuXG4gIG9wZW5Ecm9wZG93biA9IGZhbHNlO1xuXG4gIG5vcm1hbEZpbGVzOiBhbnlbXSA9IFtdO1xuXG4gIGVycm9yRmlsZXM6IGFueVtdID0gW107XG5cbiAgbG9hZGluZ0ZpbGVzOiBhbnlbXSA9IFtdO1xuXG4gIGRlbGV0ZWRGaWxlczogYW55W10gPSBbXTtcblxuICBzdWJzY3JpcHRpb25zID0gbmV3IFN1YnNjcmlwdGlvbigpO1xuXG4gIGNvbnN0cnVjdG9yKCkge31cblxuICBuZ09uSW5pdCgpOiB2b2lkIHtcbiAgICB0aGlzLmZvcm1Hcm91cC5hZGRDb250cm9sKHRoaXMuZm9ybUNvbnRyb2xOYW1lLCB0aGlzLmZvcm1Db250cm9sKTtcbiAgICB0aGlzLnZhbGlkYXRvcnMgPSB7IC4uLnRoaXMudmFsaWRhdG9ycyB9O1xuICAgIHRoaXMuZGlzYWJsZWQgPSB0aGlzLmRpc2FibGVkO1xuICAgIHRoaXMuc2V0RGlzYWJsZWQoKTtcblxuICAgIHRoaXMuZmlsZXMgPSB0aGlzLmZpbHRlckR1cGxpY2F0ZXModGhpcy5maWxlcyk7XG4gICAgdGhpcy5sb2FkRmlsZXModGhpcy5maWxlcyk7XG5cbiAgICB0aGlzLnN1YnNjcmlwdGlvbnMuYWRkKFxuICAgICAgdGhpcy5mb3JtR3JvdXAuY29udHJvbHNbdGhpcy5mb3JtQ29udHJvbE5hbWVdLnZhbHVlQ2hhbmdlc1xuICAgICAgICAucGlwZShkaXN0aW5jdFVudGlsQ2hhbmdlZCgpKSAvLyBtYWtlcyBzdXJlIHRoZSB2YWx1ZSBoYXMgYWN0dWFsbHkgY2hhbmdlZC5cbiAgICAgICAgLnN1YnNjcmliZSgodmFsdWUpID0+IHtcbiAgICAgICAgICB0aGlzLmhhbmRsZUlucHV0VmFsdWVDaGFuZ2UodmFsdWUpO1xuICAgICAgICB9KVxuICAgICk7XG4gIH1cblxuICBuZ09uQ2hhbmdlcyhjaGFuZ2VzOiBTaW1wbGVDaGFuZ2VzKSB7XG4gICAgY29uc3QgdmVyaWZ5Q2hhbmdlID0gKGtleTogc3RyaW5nKSA9PiB7XG4gICAgICByZXR1cm4gY2hhbmdlcy5oYXNPd25Qcm9wZXJ0eShrZXkpICYmICFjaGFuZ2VzW2tleV0uZmlyc3RDaGFuZ2U7XG4gICAgfTtcblxuICAgIGZvciAoY29uc3QgY2hhbmdlIG9mIE9iamVjdC5lbnRyaWVzKGNoYW5nZXMpKSB7XG4gICAgICBjb25zdCBrZXk6IHN0cmluZyA9IGNoYW5nZVswXTtcbiAgICAgIGNvbnN0IHZhbHVlOiBhbnkgPSBjaGFuZ2VbMV0uY3VycmVudFZhbHVlO1xuICAgICAgdGhpcy52YWxpZGF0ZUlucHV0UHJvcGVydHkoa2V5LCB2YWx1ZSk7XG4gICAgfVxuXG4gICAgaWYgKHZlcmlmeUNoYW5nZShcImZvcm1Db250cm9sXCIpKSB7XG4gICAgICB0aGlzLmZvcm1Db250cm9sID0gY2hhbmdlcy5mb3JtQ29udHJvbC5jdXJyZW50VmFsdWU7XG4gICAgfVxuICAgIGlmICh2ZXJpZnlDaGFuZ2UoXCJzdHlsZXNcIikpIHtcbiAgICAgIHRoaXMuc3R5bGVzID0gY2hhbmdlcy5zdHlsZXMuY3VycmVudFZhbHVlO1xuICAgIH1cbiAgICBpZiAodmVyaWZ5Q2hhbmdlKFwiY2xhc3NcIikpIHtcbiAgICAgIHRoaXMuY2xhc3MgPSBjaGFuZ2VzLmNsYXNzLmN1cnJlbnRWYWx1ZTtcbiAgICB9XG4gICAgaWYgKHZlcmlmeUNoYW5nZShcIm11bHRpcGxlXCIpKSB7XG4gICAgICB0aGlzLm11bHRpcGxlID0gY2hhbmdlcy5tdWx0aXBsZS5jdXJyZW50VmFsdWU7XG4gICAgfVxuICAgIGlmICh2ZXJpZnlDaGFuZ2UoXCJhY2NlcHRcIikpIHtcbiAgICAgIHRoaXMuYWNjZXB0ID0gY2hhbmdlcy5hY2NlcHQuY3VycmVudFZhbHVlO1xuICAgIH1cbiAgICBpZiAodmVyaWZ5Q2hhbmdlKFwibGFiZWxcIikpIHtcbiAgICAgIHRoaXMubGFiZWwgPSBjaGFuZ2VzLmxhYmVsLmN1cnJlbnRWYWx1ZTtcbiAgICB9XG4gICAgaWYgKHZlcmlmeUNoYW5nZShcImxpbmtcIikpIHtcbiAgICAgIHRoaXMubGluayA9IGNoYW5nZXMubGluay5jdXJyZW50VmFsdWU7XG4gICAgfVxuICAgIGlmICh2ZXJpZnlDaGFuZ2UoXCJpY29uXCIpKSB7XG4gICAgICB0aGlzLmljb24gPSBjaGFuZ2VzLmljb24uY3VycmVudFZhbHVlO1xuICAgIH1cbiAgICBpZiAodmVyaWZ5Q2hhbmdlKFwic2l6ZVwiKSkge1xuICAgICAgdGhpcy5zaXplID0gY2hhbmdlcy5zaXplLmN1cnJlbnRWYWx1ZTtcbiAgICB9XG4gICAgaWYgKHZlcmlmeUNoYW5nZShcInNldEZpbGVUeXBlc1RvRm9ybVwiKSkge1xuICAgICAgdGhpcy5zZXRGaWxlVHlwZXNUb0Zvcm0gPSBjaGFuZ2VzLnNldEZpbGVUeXBlc1RvRm9ybS5jdXJyZW50VmFsdWU7XG4gICAgfVxuICAgIGlmICh2ZXJpZnlDaGFuZ2UoXCJmaWxlc1wiKSkge1xuICAgICAgdGhpcy5maWxlcyA9IGNoYW5nZXMuZmlsZXMuY3VycmVudFZhbHVlO1xuXG4gICAgICB0aGlzLmZpbGVzID0gdGhpcy5maWx0ZXJEdXBsaWNhdGVzKHRoaXMuZmlsZXMpO1xuICAgICAgdGhpcy5sb2FkRmlsZXModGhpcy5maWxlcyk7XG4gICAgfVxuICAgIGlmICh2ZXJpZnlDaGFuZ2UoXCJtYXhGaWxlU2l6ZVwiKSkge1xuICAgICAgdGhpcy5tYXhGaWxlU2l6ZSA9IGNoYW5nZXMubWF4RmlsZVNpemUuY3VycmVudFZhbHVlO1xuICAgIH1cbiAgICBpZiAodmVyaWZ5Q2hhbmdlKFwiZGlzYWJsZWRcIikpIHtcbiAgICAgIHRoaXMuZGlzYWJsZWQgPSBjaGFuZ2VzLmRpc2FibGVkLmN1cnJlbnRWYWx1ZTtcblxuICAgICAgdGhpcy5zZXREaXNhYmxlZCgpO1xuICAgIH1cbiAgfVxuXG4gIG5nT25EZXN0cm95KCk6IHZvaWQge1xuICAgIHRoaXMuc3Vic2NyaXB0aW9ucy51bnN1YnNjcmliZSgpO1xuICAgIC8vIGVuc3VyZSB3aGVuIGNvbXBvbmVudCBpcyBkZXN0cm95ZWQgdGhlIHN1YnNjcmlwdGlvbiBpcyBhbHNvIGFuZCBub3QgbGVmdCBvcGVuLlxuICB9XG5cbiAgcHJpdmF0ZSB2YWxpZGF0ZUlucHV0UHJvcGVydHkoa2V5OiBzdHJpbmcsIHZhbHVlOiBhbnkpOiB2b2lkIHtcbiAgICBpZiAoVkFMSURBVEVfS0VZX1ZBTFVFU1trZXldICYmICFpc1ZhbGlkS2V5VmFsdWUoa2V5LCB2YWx1ZSkpIHtcbiAgICAgIHRoaXNba2V5XSA9IERFRkFVTFRfVkFMVUVTW2tleV07XG4gICAgICB0aHJvd0Vycm9yTWVzc2FnZShcbiAgICAgICAgXCJrd2lrdWktaW5wdXQtZmlsZXNcIixcbiAgICAgICAgdGhpcy5pZCxcbiAgICAgICAga2V5LFxuICAgICAgICB2YWx1ZSxcbiAgICAgICAgREVGQVVMVF9WQUxVRVNba2V5XVxuICAgICAgKTtcbiAgICB9XG4gIH1cblxuICBsb2FkRmlsZXMoZmlsZXM6IGFueVtdKSB7XG4gICAgdGhpcy5ub3JtYWxGaWxlcyA9IGZpbGVzLmZpbHRlcihcbiAgICAgIChmaWxlOiBhbnkpID0+IGZpbGUuc3RhdGUgPT09IEVLd2lrVUlJbnB1dEZpbGVTdGF0ZS5OT1JNQUxcbiAgICApO1xuICAgIHRoaXMuZXJyb3JGaWxlcyA9IGZpbGVzLmZpbHRlcihcbiAgICAgIChmaWxlOiBhbnkpID0+IGZpbGUuc3RhdGUgPT09IEVLd2lrVUlJbnB1dEZpbGVTdGF0ZS5FUlJPUlxuICAgICk7XG4gICAgdGhpcy5sb2FkaW5nRmlsZXMgPSBmaWxlcy5maWx0ZXIoXG4gICAgICAoZmlsZTogYW55KSA9PiBmaWxlLnN0YXRlID09PSBFS3dpa1VJSW5wdXRGaWxlU3RhdGUuTE9BRElOR1xuICAgICk7XG4gICAgdGhpcy5kZWxldGVkRmlsZXMgPSBmaWxlcy5maWx0ZXIoXG4gICAgICAoZmlsZTogYW55KSA9PiBmaWxlLnN0YXRlID09PSBFS3dpa1VJSW5wdXRGaWxlU3RhdGUuREVMRVRFRFxuICAgICk7XG5cbiAgICBjb25zdCBzZXRGaWxlcyA9IFtcbiAgICAgIC4uLih0aGlzLnNldEZpbGVUeXBlc1RvRm9ybS5pbmNsdWRlcyhFS3dpa1VJSW5wdXRGaWxlU3RhdGUuTk9STUFMKVxuICAgICAgICA/IHRoaXMubm9ybWFsRmlsZXNcbiAgICAgICAgOiBbXSksXG4gICAgICAuLi4odGhpcy5zZXRGaWxlVHlwZXNUb0Zvcm0uaW5jbHVkZXMoRUt3aWtVSUlucHV0RmlsZVN0YXRlLkVSUk9SKVxuICAgICAgICA/IHRoaXMuZXJyb3JGaWxlc1xuICAgICAgICA6IFtdKSxcbiAgICAgIC4uLih0aGlzLnNldEZpbGVUeXBlc1RvRm9ybS5pbmNsdWRlcyhFS3dpa1VJSW5wdXRGaWxlU3RhdGUuTE9BRElORylcbiAgICAgICAgPyB0aGlzLmxvYWRpbmdGaWxlc1xuICAgICAgICA6IFtdKSxcbiAgICAgIC4uLih0aGlzLnNldEZpbGVUeXBlc1RvRm9ybS5pbmNsdWRlcyhFS3dpa1VJSW5wdXRGaWxlU3RhdGUuREVMRVRFRClcbiAgICAgICAgPyB0aGlzLmRlbGV0ZWRGaWxlc1xuICAgICAgICA6IFtdKVxuICAgIF07XG5cbiAgICB0aGlzLmZvcm1Db250cm9sLnNldFZhbHVlKHNldEZpbGVzLCB7IGVtaXRFdmVudDogZmFsc2UgfSk7XG4gIH1cblxuICBmaWx0ZXJEdXBsaWNhdGVzKGZpbGVzOiBhbnlbXSk6IGFueVtdIHtcbiAgICBjb25zdCB1bmlxdWVGaWxlczogYW55W10gPSBbXTtcblxuICAgIGZpbGVzLmZvckVhY2goKGZpbGUpID0+IHtcbiAgICAgIGNvbnN0IGlzRHVwbGljYXRlID0gdW5pcXVlRmlsZXMuc29tZShcbiAgICAgICAgKGV4aXN0aW5nRmlsZSkgPT5cbiAgICAgICAgICBleGlzdGluZ0ZpbGUubmFtZSA9PT0gZmlsZS5uYW1lICYmIGV4aXN0aW5nRmlsZS5zaXplID09PSBmaWxlLnNpemVcbiAgICAgICk7XG5cbiAgICAgIGlmICghaXNEdXBsaWNhdGUpIHtcbiAgICAgICAgdW5pcXVlRmlsZXMucHVzaChmaWxlKTtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIHJldHVybiB1bmlxdWVGaWxlcztcbiAgfVxuXG4gIGZpbHRlclVuaXF1ZShhcnIxOiBhbnlbXSwgYXJyMjogYW55W10pOiBhbnlbXSB7XG4gICAgY29uc3QgdW5pcXVlRWxlbWVudHM6IGFueVtdID0gW107XG5cbiAgICBhcnIyLmZvckVhY2goKGVsZW1lbnQpID0+IHtcbiAgICAgIGlmICghYXJyMS5pbmNsdWRlcyhlbGVtZW50KSkge1xuICAgICAgICB1bmlxdWVFbGVtZW50cy5wdXNoKGVsZW1lbnQpO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgcmV0dXJuIHVuaXF1ZUVsZW1lbnRzO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBIYW5kbGVzIHNldHRpbmcgdXAgb2YgZXJyb3IgYW5kIGZvY3VzIG9uIHRoZSBpbnB1dCBmaWVsZCBpcyBpdCBpcyBpbnZhbGlkXG4gICAqL1xuICBzZXREaXNhYmxlZCgpIHtcbiAgICBpZiAodGhpcy5mb3JtR3JvdXAuY29udHJvbHNbdGhpcy5mb3JtQ29udHJvbE5hbWVdICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIGlmICh0aGlzLmRpc2FibGVkID09PSB0cnVlKSB7XG4gICAgICAgIHRoaXMuZm9ybUdyb3VwLmNvbnRyb2xzW3RoaXMuZm9ybUNvbnRyb2xOYW1lXS5kaXNhYmxlKHtcbiAgICAgICAgICBlbWl0RXZlbnQ6IGZhbHNlXG4gICAgICAgIH0pO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy5mb3JtR3JvdXAuY29udHJvbHNbdGhpcy5mb3JtQ29udHJvbE5hbWVdLmVuYWJsZSh7XG4gICAgICAgICAgZW1pdEV2ZW50OiBmYWxzZVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBoYW5kbGVPbkNsaWNrT3BlbkZpbGVNYW5hZ2VyKCkge1xuICAgIGlmIChpc05vdEVtcHR5VmFsdWUodGhpcy5uYXRpdmVGaWxlUGlja2VyKSkge1xuICAgICAgdGhpcy5uYXRpdmVGaWxlUGlja2VyLm5hdGl2ZUVsZW1lbnQuY2xpY2soKTtcbiAgICB9XG4gIH1cblxuICBoYW5kbGVPbklucHV0RmlsZUNoYW5nZShlOiBhbnkpIHtcbiAgICBjb25zdCBmaWxlcyA9IFtdO1xuXG4gICAgZm9yIChjb25zdCBmaWxlIG9mIGUudGFyZ2V0LmZpbGVzKSB7XG4gICAgICBmaWxlcy5wdXNoKGZpbGUpO1xuICAgIH1cblxuICAgIHRoaXMuZm9ybUdyb3VwLnBhdGNoVmFsdWUoXG4gICAgICB7XG4gICAgICAgIFt0aGlzLmZvcm1Db250cm9sTmFtZV06IHRoaXMubXVsdGlwbGUgPyBmaWxlcyA6IGZpbGVzWzBdXG4gICAgICB9LFxuICAgICAge1xuICAgICAgICBlbWl0RXZlbnQ6IHRydWVcbiAgICAgIH1cbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIEBkZXNjcmlwdGlvbiBIYW5kbGVzIGZpcmluZyBvZiAyIGV2ZW50cyBvbiAoa2V5dXApIGV2ZW50XG4gICAqXG4gICAqIEBwYXJhbSB2YWx1ZVxuICAgKi9cbiAgaGFuZGxlSW5wdXRWYWx1ZUNoYW5nZSh2YWx1ZTogYW55KSB7XG4gICAgaWYgKEFycmF5LmlzQXJyYXkodmFsdWUpKSB7XG4gICAgICB2YWx1ZSA9IHRoaXMuZmlsdGVyVW5pcXVlKHRoaXMuZmlsZXMsIHZhbHVlKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdmFsdWUgPSB0aGlzLmZpbHRlclVuaXF1ZSh0aGlzLmZpbGVzLCBbdmFsdWVdKTtcbiAgICB9XG5cbiAgICB0aGlzLmVtaXRFdmVudCh0aGlzLmdldEtleVZhbHVlLCB7XG4gICAgICBrZXk6IHRoaXMuZm9ybUNvbnRyb2xOYW1lLFxuICAgICAgdmFsdWVcbiAgICB9KTtcbiAgfVxuXG4gIGVtaXRFdmVudChldmVudDogYW55LCBkYXRhOiBhbnkpIHtcbiAgICBldmVudC5lbWl0KGRhdGEpO1xuICB9XG5cbiAgcmVtb3ZlRmlsZShmaWxlOiBhbnkpIHtcbiAgICBjb25zdCBmaWxlcyA9IHRoaXMuZmlsZXMuZmlsdGVyKChmOiBhbnkpID0+IHtcbiAgICAgIHJldHVybiAhKGZpbGUubmFtZSA9PT0gZi5uYW1lICYmIGZpbGUuc2l6ZSA9PT0gZi5zaXplKTtcbiAgICB9KTtcblxuICAgIHRoaXMuZW1pdEV2ZW50KHRoaXMuZ2V0UmVtb3ZlZEZpbGUsIHtcbiAgICAgIGtleTogdGhpcy5mb3JtQ29udHJvbE5hbWUsXG4gICAgICB2YWx1ZTogZmlsZSxcbiAgICAgIGZpbGVzXG4gICAgfSk7XG4gIH1cblxuICBmaWxlQ2xpY2soZmlsZTogYW55KSB7XG4gICAgY29uc3QgZmlsZXMgPSB0aGlzLmZpbGVzLmZpbHRlcigoZjogYW55KSA9PiB7XG4gICAgICByZXR1cm4gIShmaWxlLm5hbWUgPT09IGYubmFtZSAmJiBmaWxlLnNpemUgPT09