@c8y/ngx-components
Version:
Angular modules for Cumulocity IoT applications
111 lines • 20.9 kB
JavaScript
import { Component, EventEmitter, Input, Output, ViewChild } from '@angular/core';
import { isEmpty } from 'lodash-es';
import { DropAreaComponent } from '../drop-area/drop-area.component';
import { ValidationPattern } from '../forms/validation-pattern';
import * as i0 from "@angular/core";
import * as i1 from "@angular/forms";
import * as i2 from "../forms/form-group.component";
import * as i3 from "../forms/required-input-placeholder.directive";
import * as i4 from "@angular/common";
import * as i5 from "../drop-area/drop-area.component";
import * as i6 from "../common/icon.directive";
import * as i7 from "ngx-bootstrap/popover";
import * as i8 from "../i18n/c8y-translate.pipe";
/**
* User can upload a binary directly or use an URL.
*
* ## Usage
*
* ```html
* <div>
* <c8y-file-picker [maxAllowedFiles]="1" (onFilesPicked)="onFile($event)">
* </c8y-file-picker>
* </div>
* ```
*/
export class FilePickerComponent {
constructor() {
this.onFilesPicked = new EventEmitter();
this.maxAllowedFiles = Infinity;
this.uploadChoice = 'uploadBinary';
this.config = { maxlength: 2048 };
this.ValidationPattern = ValidationPattern;
}
/**
* @ignore
*/
ngOnInit() {
if (this.fileBinary) {
this.droppedFiles = [this.fileBinary];
}
}
/**
* Triggered by dropped file in component and pass it into drop-area component.
*/
onFileDropped(droppedFiles) {
this.onFilesPicked.emit({
droppedFiles
});
}
/**
* Triggered when user changes upload choice, from upload url to upload binary.
*/
clearInputFromUrl() {
delete this.fileUrl;
this.fileToSave = {
url: undefined
};
this.onFilesPicked.emit(this.fileToSave);
}
/**
* Triggered when user changes upload choice, to avoid cumulation of droppedFiles.
*/
clearSelectedFiles() {
this.dropArea.onDelete();
this.fileToSave = {
droppedFiles: undefined
};
this.onFilesPicked.emit(this.fileToSave);
}
/**
* Triggered when user puts binary's url to upload.
*/
onFileUrlChange(urlStr) {
this.fileToSave = {
url: urlStr
};
this.onFilesPicked.emit(this.fileToSave);
}
/**
* Checks if there is popover to display.
*/
isPopoverUsed() {
return !isEmpty(this.fileUrlPopover);
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FilePickerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: FilePickerComponent, selector: "c8y-file-picker", inputs: { maxAllowedFiles: "maxAllowedFiles", uploadChoice: "uploadChoice", fileUrl: "fileUrl", fileBinary: "fileBinary", config: "config", filePickerIndex: "filePickerIndex", fileUrlPopover: "fileUrlPopover" }, outputs: { onFilesPicked: "onFilesPicked" }, viewQueries: [{ propertyName: "dropArea", first: true, predicate: DropAreaComponent, descendants: true, static: true }], ngImport: i0, template: "<div class=\"form-group\">\n <label title=\"{{ 'Upload a binary' | translate }}\" class=\"c8y-radio radio-inline\">\n <input\n #radio\n type=\"radio\"\n value=\"uploadBinary\"\n name=\"uploadChoice-{{filePickerIndex}}\"\n [(ngModel)]=\"uploadChoice\"\n (click)=\"clearInputFromUrl()\"\n />\n <span></span>\n <span>{{ 'Upload a binary' | translate }}</span>\n </label>\n <label\n title=\"{{ 'Provide a file path' | translate }}\"\n class=\"c8y-radio radio-inline m-l-8\"\n data-cy=\"file-picker--file-path-input\"\n >\n <input\n #radio\n type=\"radio\"\n value=\"uploadUrl\"\n name=\"uploadChoice-{{filePickerIndex}}\"\n [(ngModel)]=\"uploadChoice\"\n (click)=\"clearSelectedFiles()\"\n />\n <span></span>\n <span>\n {{ 'Provide a file path' | translate }}\n </span>\n <button\n class=\"btn-help\"\n type=\"button\"\n [attr.aria-label]=\"'Help' | translate\"\n popover=\"{{ fileUrlPopover | translate }}\"\n placement=\"top\"\n triggers=\"focus\"\n container=\"body\"\n placement=\"top\"\n *ngIf=\"isPopoverUsed()\"\n ></button>\n </label>\n</div>\n\n<div [hidden]=\"uploadChoice !== 'uploadBinary'\">\n <c8y-form-group class=\"m-0\">\n <c8y-drop-area\n class=\"drop-area-sm\"\n (dropped)=\"onFileDropped($event)\"\n [title]=\"'Drop file or click to browse' | translate\"\n [attr.aria-label]=\"'Drop file or click to browse' | translate\"\n [maxAllowedFiles]=\"maxAllowedFiles\"\n [files]=\"droppedFiles\"\n ></c8y-drop-area>\n </c8y-form-group>\n</div>\n\n<div [hidden]=\"uploadChoice !== 'uploadUrl'\">\n <c8y-form-group class=\"m-0\">\n <div class=\"m-b-4 p-b-8\">\n <div class=\"input-group\">\n <span class=\"input-group-addon\">\n <i c8yIcon=\"globe\"></i>\n </span>\n <input\n type=\"text\"\n class=\"form-control\"\n name=\"fileUrl\"\n data-cy=\"file-picker--fileUrl\"\n [(ngModel)]=\"fileUrl\"\n (ngModelChange)=\"onFileUrlChange($event)\"\n placeholder=\"{{ 'e.g.' | translate }} http://example.com/binary.zip\"\n maxlength=\"{{ config.maxlength }}\"\n required\n [pattern]=\"ValidationPattern.rules.noWhiteSpaceOnly.pattern\"\n />\n </div>\n </div>\n </c8y-form-group>\n</div>\n", dependencies: [{ kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.RadioControlValueAccessor, selector: "input[type=radio][formControlName],input[type=radio][formControl],input[type=radio][ngModel]", inputs: ["name", "formControlName", "value"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i1.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i1.PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i2.FormGroupComponent, selector: "c8y-form-group", inputs: ["hasError", "hasWarning", "hasSuccess", "novalidation", "status"] }, { kind: "directive", type: i3.RequiredInputPlaceholderDirective, selector: "input[required], input[formControlName]" }, { kind: "directive", type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i5.DropAreaComponent, selector: "c8y-drop-area", inputs: ["formControl", "title", "message", "icon", "loadingMessage", "forceHideList", "alwaysShow", "clickToOpen", "loading", "progress", "maxAllowedFiles", "files", "maxFileSizeInMegaBytes", "accept"], outputs: ["dropped"] }, { kind: "directive", type: i6.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i7.PopoverDirective, selector: "[popover]", inputs: ["adaptivePosition", "boundariesElement", "popover", "popoverContext", "popoverTitle", "placement", "outsideClick", "triggers", "container", "containerClass", "isOpen", "delay"], outputs: ["onShown", "onHidden"], exportAs: ["bs-popover"] }, { kind: "pipe", type: i8.C8yTranslatePipe, name: "translate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: FilePickerComponent, decorators: [{
type: Component,
args: [{ selector: 'c8y-file-picker', template: "<div class=\"form-group\">\n <label title=\"{{ 'Upload a binary' | translate }}\" class=\"c8y-radio radio-inline\">\n <input\n #radio\n type=\"radio\"\n value=\"uploadBinary\"\n name=\"uploadChoice-{{filePickerIndex}}\"\n [(ngModel)]=\"uploadChoice\"\n (click)=\"clearInputFromUrl()\"\n />\n <span></span>\n <span>{{ 'Upload a binary' | translate }}</span>\n </label>\n <label\n title=\"{{ 'Provide a file path' | translate }}\"\n class=\"c8y-radio radio-inline m-l-8\"\n data-cy=\"file-picker--file-path-input\"\n >\n <input\n #radio\n type=\"radio\"\n value=\"uploadUrl\"\n name=\"uploadChoice-{{filePickerIndex}}\"\n [(ngModel)]=\"uploadChoice\"\n (click)=\"clearSelectedFiles()\"\n />\n <span></span>\n <span>\n {{ 'Provide a file path' | translate }}\n </span>\n <button\n class=\"btn-help\"\n type=\"button\"\n [attr.aria-label]=\"'Help' | translate\"\n popover=\"{{ fileUrlPopover | translate }}\"\n placement=\"top\"\n triggers=\"focus\"\n container=\"body\"\n placement=\"top\"\n *ngIf=\"isPopoverUsed()\"\n ></button>\n </label>\n</div>\n\n<div [hidden]=\"uploadChoice !== 'uploadBinary'\">\n <c8y-form-group class=\"m-0\">\n <c8y-drop-area\n class=\"drop-area-sm\"\n (dropped)=\"onFileDropped($event)\"\n [title]=\"'Drop file or click to browse' | translate\"\n [attr.aria-label]=\"'Drop file or click to browse' | translate\"\n [maxAllowedFiles]=\"maxAllowedFiles\"\n [files]=\"droppedFiles\"\n ></c8y-drop-area>\n </c8y-form-group>\n</div>\n\n<div [hidden]=\"uploadChoice !== 'uploadUrl'\">\n <c8y-form-group class=\"m-0\">\n <div class=\"m-b-4 p-b-8\">\n <div class=\"input-group\">\n <span class=\"input-group-addon\">\n <i c8yIcon=\"globe\"></i>\n </span>\n <input\n type=\"text\"\n class=\"form-control\"\n name=\"fileUrl\"\n data-cy=\"file-picker--fileUrl\"\n [(ngModel)]=\"fileUrl\"\n (ngModelChange)=\"onFileUrlChange($event)\"\n placeholder=\"{{ 'e.g.' | translate }} http://example.com/binary.zip\"\n maxlength=\"{{ config.maxlength }}\"\n required\n [pattern]=\"ValidationPattern.rules.noWhiteSpaceOnly.pattern\"\n />\n </div>\n </div>\n </c8y-form-group>\n</div>\n" }]
}], propDecorators: { dropArea: [{
type: ViewChild,
args: [DropAreaComponent, { static: true }]
}], onFilesPicked: [{
type: Output
}], maxAllowedFiles: [{
type: Input
}], uploadChoice: [{
type: Input
}], fileUrl: [{
type: Input
}], fileBinary: [{
type: Input
}], config: [{
type: Input
}], filePickerIndex: [{
type: Input
}], fileUrlPopover: [{
type: Input
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmlsZS1waWNrZXIuY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vY29yZS9maWxlLXBpY2tlci9maWxlLXBpY2tlci5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi9jb3JlL2ZpbGUtcGlja2VyL2ZpbGUtcGlja2VyLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQUUsWUFBWSxFQUFFLEtBQUssRUFBVSxNQUFNLEVBQUUsU0FBUyxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQzFGLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFDcEMsT0FBTyxFQUFFLGlCQUFpQixFQUFlLE1BQU0sa0NBQWtDLENBQUM7QUFDbEYsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sNkJBQTZCLENBQUM7Ozs7Ozs7Ozs7QUFJaEU7Ozs7Ozs7Ozs7O0dBV0c7QUFNSCxNQUFNLE9BQU8sbUJBQW1CO0lBSmhDO1FBTVksa0JBQWEsR0FBOEIsSUFBSSxZQUFZLEVBQUUsQ0FBQztRQUMvRCxvQkFBZSxHQUFHLFFBQVEsQ0FBQztRQUMzQixpQkFBWSxHQUFpQyxjQUFjLENBQUM7UUFHNUQsV0FBTSxHQUFxQixFQUFFLFNBQVMsRUFBRSxJQUFJLEVBQUUsQ0FBQztRQVV4RCxzQkFBaUIsR0FBRyxpQkFBaUIsQ0FBQztLQTREdkM7SUF4REM7O09BRUc7SUFDSCxRQUFRO1FBQ04sSUFBSSxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUM7WUFDcEIsSUFBSSxDQUFDLFlBQVksR0FBRyxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQztRQUN4QyxDQUFDO0lBQ0gsQ0FBQztJQUVEOztPQUVHO0lBQ0gsYUFBYSxDQUFDLFlBQTJCO1FBQ3ZDLElBQUksQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDO1lBQ3RCLFlBQVk7U0FDYixDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQ7O09BRUc7SUFDSCxpQkFBaUI7UUFDZixPQUFPLElBQUksQ0FBQyxPQUFPLENBQUM7UUFDcEIsSUFBSSxDQUFDLFVBQVUsR0FBRztZQUNoQixHQUFHLEVBQUUsU0FBUztTQUNmLENBQUM7UUFDRixJQUFJLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUM7SUFDM0MsQ0FBQztJQUVEOztPQUVHO0lBQ0gsa0JBQWtCO1FBQ2hCLElBQUksQ0FBQyxRQUFRLENBQUMsUUFBUSxFQUFFLENBQUM7UUFDekIsSUFBSSxDQUFDLFVBQVUsR0FBRztZQUNoQixZQUFZLEVBQUUsU0FBUztTQUN4QixDQUFDO1FBQ0YsSUFBSSxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFDO0lBQzNDLENBQUM7SUFFRDs7T0FFRztJQUNILGVBQWUsQ0FBQyxNQUFNO1FBQ3BCLElBQUksQ0FBQyxVQUFVLEdBQUc7WUFDaEIsR0FBRyxFQUFFLE1BQU07U0FDWixDQUFDO1FBQ0YsSUFBSSxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFDO0lBQzNDLENBQUM7SUFFRDs7T0FFRztJQUNILGFBQWE7UUFDWCxPQUFPLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxjQUFjLENBQUMsQ0FBQztJQUN2QyxDQUFDOytHQTVFVSxtQkFBbUI7bUdBQW5CLG1CQUFtQixrV0FDbkIsaUJBQWlCLDhEQ3pCOUIsODNFQWdGQTs7NEZEeERhLG1CQUFtQjtrQkFKL0IsU0FBUzsrQkFDRSxpQkFBaUI7OEJBSXFCLFFBQVE7c0JBQXZELFNBQVM7dUJBQUMsaUJBQWlCLEVBQUUsRUFBRSxNQUFNLEVBQUUsSUFBSSxFQUFFO2dCQUNwQyxhQUFhO3NCQUF0QixNQUFNO2dCQUNFLGVBQWU7c0JBQXZCLEtBQUs7Z0JBQ0csWUFBWTtzQkFBcEIsS0FBSztnQkFDRyxPQUFPO3NCQUFmLEtBQUs7Z0JBQ0csVUFBVTtzQkFBbEIsS0FBSztnQkFDRyxNQUFNO3NCQUFkLEtBQUs7Z0JBSUcsZUFBZTtzQkFBdkIsS0FBSztnQkFJRyxjQUFjO3NCQUF0QixLQUFLIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29tcG9uZW50LCBFdmVudEVtaXR0ZXIsIElucHV0LCBPbkluaXQsIE91dHB1dCwgVmlld0NoaWxkIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBpc0VtcHR5IH0gZnJvbSAnbG9kYXNoLWVzJztcbmltcG9ydCB7IERyb3BBcmVhQ29tcG9uZW50LCBEcm9wcGVkRmlsZSB9IGZyb20gJy4uL2Ryb3AtYXJlYS9kcm9wLWFyZWEuY29tcG9uZW50JztcbmltcG9ydCB7IFZhbGlkYXRpb25QYXR0ZXJuIH0gZnJvbSAnLi4vZm9ybXMvdmFsaWRhdGlvbi1wYXR0ZXJuJztcbmltcG9ydCB7IEZpbGVQaWNrZXJDb25maWcgfSBmcm9tICcuL2ZpbGUtcGlja2VyLWNvbmZpZy5tb2RlbCc7XG5pbXBvcnQgeyBQaWNrZWRGaWxlcyB9IGZyb20gJy4vZmlsZS1waWNrZXIubW9kZWwnO1xuXG4vKipcbiAqIFVzZXIgY2FuIHVwbG9hZCBhIGJpbmFyeSBkaXJlY3RseSBvciB1c2UgYW4gVVJMLlxuICpcbiAqICMjIFVzYWdlXG4gKlxuICogYGBgaHRtbFxuICogPGRpdj5cbiAqIDxjOHktZmlsZS1waWNrZXIgW21heEFsbG93ZWRGaWxlc109XCIxXCIgKG9uRmlsZXNQaWNrZWQpPVwib25GaWxlKCRldmVudClcIj5cbiAqIDwvYzh5LWZpbGUtcGlja2VyPlxuICogPC9kaXY+XG4gKiBgYGBcbiAqL1xuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICdjOHktZmlsZS1waWNrZXInLFxuICB0ZW1wbGF0ZVVybDogJy4vZmlsZS1waWNrZXIuY29tcG9uZW50Lmh0bWwnXG59KVxuZXhwb3J0IGNsYXNzIEZpbGVQaWNrZXJDb21wb25lbnQgaW1wbGVtZW50cyBPbkluaXQge1xuICBAVmlld0NoaWxkKERyb3BBcmVhQ29tcG9uZW50LCB7IHN0YXRpYzogdHJ1ZSB9KSBkcm9wQXJlYTogRHJvcEFyZWFDb21wb25lbnQ7XG4gIEBPdXRwdXQoKSBvbkZpbGVzUGlja2VkOiBFdmVudEVtaXR0ZXI8UGlja2VkRmlsZXM+ID0gbmV3IEV2ZW50RW1pdHRlcigpO1xuICBASW5wdXQoKSBtYXhBbGxvd2VkRmlsZXMgPSBJbmZpbml0eTtcbiAgQElucHV0KCkgdXBsb2FkQ2hvaWNlOiAndXBsb2FkQmluYXJ5JyB8ICd1cGxvYWRVcmwnID0gJ3VwbG9hZEJpbmFyeSc7XG4gIEBJbnB1dCgpIGZpbGVVcmw6IHN0cmluZztcbiAgQElucHV0KCkgZmlsZUJpbmFyeTogRHJvcHBlZEZpbGU7XG4gIEBJbnB1dCgpIGNvbmZpZzogRmlsZVBpY2tlckNvbmZpZyA9IHsgbWF4bGVuZ3RoOiAyMDQ4IH07XG4gIC8qKlxuICAgKiBVc2VkIG9ubHkgd2hlbiBkaXNwbGF5aW5nIG11bHRpcGxlIGZpbGUgcGlja2VycyBpbiB0aGUgc2FtZSB2aWV3LlxuICAgKi9cbiAgQElucHV0KCkgZmlsZVBpY2tlckluZGV4OiBudW1iZXI7XG4gIC8qKlxuICAgKiBBZGRpdGlvbmFsIHN0cmluZyB0byBiZSBkaXNwbGF5ZWQgaW4gYSBwb3BvdmVyLlxuICAgKi9cbiAgQElucHV0KCkgZmlsZVVybFBvcG92ZXI6IHN0cmluZztcblxuICBWYWxpZGF0aW9uUGF0dGVybiA9IFZhbGlkYXRpb25QYXR0ZXJuO1xuICBkcm9wcGVkRmlsZXM6IERyb3BwZWRGaWxlW107XG4gIHByaXZhdGUgZmlsZVRvU2F2ZTogUGlja2VkRmlsZXM7XG5cbiAgLyoqXG4gICAqIEBpZ25vcmVcbiAgICovXG4gIG5nT25Jbml0KCk6IHZvaWQge1xuICAgIGlmICh0aGlzLmZpbGVCaW5hcnkpIHtcbiAgICAgIHRoaXMuZHJvcHBlZEZpbGVzID0gW3RoaXMuZmlsZUJpbmFyeV07XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFRyaWdnZXJlZCBieSBkcm9wcGVkIGZpbGUgaW4gY29tcG9uZW50IGFuZCBwYXNzIGl0IGludG8gZHJvcC1hcmVhIGNvbXBvbmVudC5cbiAgICovXG4gIG9uRmlsZURyb3BwZWQoZHJvcHBlZEZpbGVzOiBEcm9wcGVkRmlsZVtdKTogdm9pZCB7XG4gICAgdGhpcy5vbkZpbGVzUGlja2VkLmVtaXQoe1xuICAgICAgZHJvcHBlZEZpbGVzXG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogVHJpZ2dlcmVkIHdoZW4gdXNlciBjaGFuZ2VzIHVwbG9hZCBjaG9pY2UsIGZyb20gdXBsb2FkIHVybCB0byB1cGxvYWQgYmluYXJ5LlxuICAgKi9cbiAgY2xlYXJJbnB1dEZyb21VcmwoKTogdm9pZCB7XG4gICAgZGVsZXRlIHRoaXMuZmlsZVVybDtcbiAgICB0aGlzLmZpbGVUb1NhdmUgPSB7XG4gICAgICB1cmw6IHVuZGVmaW5lZFxuICAgIH07XG4gICAgdGhpcy5vbkZpbGVzUGlja2VkLmVtaXQodGhpcy5maWxlVG9TYXZlKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBUcmlnZ2VyZWQgd2hlbiB1c2VyIGNoYW5nZXMgdXBsb2FkIGNob2ljZSwgdG8gYXZvaWQgY3VtdWxhdGlvbiBvZiBkcm9wcGVkRmlsZXMuXG4gICAqL1xuICBjbGVhclNlbGVjdGVkRmlsZXMoKTogdm9pZCB7XG4gICAgdGhpcy5kcm9wQXJlYS5vbkRlbGV0ZSgpO1xuICAgIHRoaXMuZmlsZVRvU2F2ZSA9IHtcbiAgICAgIGRyb3BwZWRGaWxlczogdW5kZWZpbmVkXG4gICAgfTtcbiAgICB0aGlzLm9uRmlsZXNQaWNrZWQuZW1pdCh0aGlzLmZpbGVUb1NhdmUpO1xuICB9XG5cbiAgLyoqXG4gICAqIFRyaWdnZXJlZCB3aGVuIHVzZXIgcHV0cyBiaW5hcnkncyB1cmwgdG8gdXBsb2FkLlxuICAgKi9cbiAgb25GaWxlVXJsQ2hhbmdlKHVybFN0cik6IHZvaWQge1xuICAgIHRoaXMuZmlsZVRvU2F2ZSA9IHtcbiAgICAgIHVybDogdXJsU3RyXG4gICAgfTtcbiAgICB0aGlzLm9uRmlsZXNQaWNrZWQuZW1pdCh0aGlzLmZpbGVUb1NhdmUpO1xuICB9XG5cbiAgLyoqXG4gICAqIENoZWNrcyBpZiB0aGVyZSBpcyBwb3BvdmVyIHRvIGRpc3BsYXkuXG4gICAqL1xuICBpc1BvcG92ZXJVc2VkKCkge1xuICAgIHJldHVybiAhaXNFbXB0eSh0aGlzLmZpbGVVcmxQb3BvdmVyKTtcbiAgfVxufVxuIiwiPGRpdiBjbGFzcz1cImZvcm0tZ3JvdXBcIj5cbiAgPGxhYmVsIHRpdGxlPVwie3sgJ1VwbG9hZCBhIGJpbmFyeScgfCB0cmFuc2xhdGUgfX1cIiBjbGFzcz1cImM4eS1yYWRpbyByYWRpby1pbmxpbmVcIj5cbiAgICA8aW5wdXRcbiAgICAgICNyYWRpb1xuICAgICAgdHlwZT1cInJhZGlvXCJcbiAgICAgIHZhbHVlPVwidXBsb2FkQmluYXJ5XCJcbiAgICAgIG5hbWU9XCJ1cGxvYWRDaG9pY2Ute3tmaWxlUGlja2VySW5kZXh9fVwiXG4gICAgICBbKG5nTW9kZWwpXT1cInVwbG9hZENob2ljZVwiXG4gICAgICAoY2xpY2spPVwiY2xlYXJJbnB1dEZyb21VcmwoKVwiXG4gICAgLz5cbiAgICA8c3Bhbj48L3NwYW4+XG4gICAgPHNwYW4+e3sgJ1VwbG9hZCBhIGJpbmFyeScgfCB0cmFuc2xhdGUgfX08L3NwYW4+XG4gIDwvbGFiZWw+XG4gIDxsYWJlbFxuICAgIHRpdGxlPVwie3sgJ1Byb3ZpZGUgYSBmaWxlIHBhdGgnIHwgdHJhbnNsYXRlIH19XCJcbiAgICBjbGFzcz1cImM4eS1yYWRpbyByYWRpby1pbmxpbmUgbS1sLThcIlxuICAgIGRhdGEtY3k9XCJmaWxlLXBpY2tlci0tZmlsZS1wYXRoLWlucHV0XCJcbiAgPlxuICAgIDxpbnB1dFxuICAgICAgI3JhZGlvXG4gICAgICB0eXBlPVwicmFkaW9cIlxuICAgICAgdmFsdWU9XCJ1cGxvYWRVcmxcIlxuICAgICAgbmFtZT1cInVwbG9hZENob2ljZS17e2ZpbGVQaWNrZXJJbmRleH19XCJcbiAgICAgIFsobmdNb2RlbCldPVwidXBsb2FkQ2hvaWNlXCJcbiAgICAgIChjbGljayk9XCJjbGVhclNlbGVjdGVkRmlsZXMoKVwiXG4gICAgLz5cbiAgICA8c3Bhbj48L3NwYW4+XG4gICAgPHNwYW4+XG4gICAgICB7eyAnUHJvdmlkZSBhIGZpbGUgcGF0aCcgfCB0cmFuc2xhdGUgfX1cbiAgICA8L3NwYW4+XG4gICAgPGJ1dHRvblxuICAgICAgY2xhc3M9XCJidG4taGVscFwiXG4gICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgIFthdHRyLmFyaWEtbGFiZWxdPVwiJ0hlbHAnIHwgdHJhbnNsYXRlXCJcbiAgICAgIHBvcG92ZXI9XCJ7eyBmaWxlVXJsUG9wb3ZlciB8IHRyYW5zbGF0ZSB9fVwiXG4gICAgICBwbGFjZW1lbnQ9XCJ0b3BcIlxuICAgICAgdHJpZ2dlcnM9XCJmb2N1c1wiXG4gICAgICBjb250YWluZXI9XCJib2R5XCJcbiAgICAgIHBsYWNlbWVudD1cInRvcFwiXG4gICAgICAqbmdJZj1cImlzUG9wb3ZlclVzZWQoKVwiXG4gICAgPjwvYnV0dG9uPlxuICA8L2xhYmVsPlxuPC9kaXY+XG5cbjxkaXYgW2hpZGRlbl09XCJ1cGxvYWRDaG9pY2UgIT09ICd1cGxvYWRCaW5hcnknXCI+XG4gIDxjOHktZm9ybS1ncm91cCBjbGFzcz1cIm0tMFwiPlxuICAgIDxjOHktZHJvcC1hcmVhXG4gICAgICBjbGFzcz1cImRyb3AtYXJlYS1zbVwiXG4gICAgICAoZHJvcHBlZCk9XCJvbkZpbGVEcm9wcGVkKCRldmVudClcIlxuICAgICAgW3RpdGxlXT1cIidEcm9wIGZpbGUgb3IgY2xpY2sgdG8gYnJvd3NlJyB8IHRyYW5zbGF0ZVwiXG4gICAgICBbYXR0ci5hcmlhLWxhYmVsXT1cIidEcm9wIGZpbGUgb3IgY2xpY2sgdG8gYnJvd3NlJyB8IHRyYW5zbGF0ZVwiXG4gICAgICBbbWF4QWxsb3dlZEZpbGVzXT1cIm1heEFsbG93ZWRGaWxlc1wiXG4gICAgICBbZmlsZXNdPVwiZHJvcHBlZEZpbGVzXCJcbiAgICA+PC9jOHktZHJvcC1hcmVhPlxuICA8L2M4eS1mb3JtLWdyb3VwPlxuPC9kaXY+XG5cbjxkaXYgW2hpZGRlbl09XCJ1cGxvYWRDaG9pY2UgIT09ICd1cGxvYWRVcmwnXCI+XG4gIDxjOHktZm9ybS1ncm91cCBjbGFzcz1cIm0tMFwiPlxuICAgIDxkaXYgY2xhc3M9XCJtLWItNCBwLWItOFwiPlxuICAgICAgPGRpdiBjbGFzcz1cImlucHV0LWdyb3VwXCI+XG4gICAgICAgIDxzcGFuIGNsYXNzPVwiaW5wdXQtZ3JvdXAtYWRkb25cIj5cbiAgICAgICAgICA8aSBjOHlJY29uPVwiZ2xvYmVcIj48L2k+XG4gICAgICAgIDwvc3Bhbj5cbiAgICAgICAgPGlucHV0XG4gICAgICAgICAgdHlwZT1cInRleHRcIlxuICAgICAgICAgIGNsYXNzPVwiZm9ybS1jb250cm9sXCJcbiAgICAgICAgICBuYW1lPVwiZmlsZVVybFwiXG4gICAgICAgICAgZGF0YS1jeT1cImZpbGUtcGlja2VyLS1maWxlVXJsXCJcbiAgICAgICAgICBbKG5nTW9kZWwpXT1cImZpbGVVcmxcIlxuICAgICAgICAgIChuZ01vZGVsQ2hhbmdlKT1cIm9uRmlsZVVybENoYW5nZSgkZXZlbnQpXCJcbiAgICAgICAgICBwbGFjZWhvbGRlcj1cInt7ICdlLmcuJyB8IHRyYW5zbGF0ZSB9fSBodHRwOi8vZXhhbXBsZS5jb20vYmluYXJ5LnppcFwiXG4gICAgICAgICAgbWF4bGVuZ3RoPVwie3sgY29uZmlnLm1heGxlbmd0aCB9fVwiXG4gICAgICAgICAgcmVxdWlyZWRcbiAgICAgICAgICBbcGF0dGVybl09XCJWYWxpZGF0aW9uUGF0dGVybi5ydWxlcy5ub1doaXRlU3BhY2VPbmx5LnBhdHRlcm5cIlxuICAgICAgICAvPlxuICAgICAgPC9kaXY+XG4gICAgPC9kaXY+XG4gIDwvYzh5LWZvcm0tZ3JvdXA+XG48L2Rpdj5cbiJdfQ==