kwikui
Version:
KwikID's UI Component Library in Angular
323 lines • 60.2 kB
JavaScript
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