UNPKG

@c8y/ngx-components

Version:

Angular modules for Cumulocity IoT applications

136 lines 28.9 kB
import { Component, Input } from '@angular/core'; import { AlertService, C8yValidators, CoreModule, gettext } from '@c8y/ngx-components'; import { FormBuilder, NgForm, ReactiveFormsModule, Validators } from '@angular/forms'; import { MarkdownWidgetService } from '../markdown-widget.service'; import * as i0 from "@angular/core"; import * as i1 from "@angular/forms"; import * as i2 from "@c8y/ngx-components"; import * as i3 from "../markdown-widget.service"; import * as i4 from "@angular/common"; export class MarkdownWidgetConfigComponent { constructor(formBuilder, form, alert, markdownService) { this.formBuilder = formBuilder; this.form = form; this.alert = alert; this.markdownService = markdownService; this.uploadChoice = 'uploadUrl'; this.loading = false; } async onBeforeSave(config) { if (this.formGroup.invalid) { return false; } if (this.uploadChoice === 'uploadUrl') { Object.assign(config, { contentUrl: this.formGroup.value.contentUrl, markdownBinaryId: null }); return true; } const fileFromForm = this.getFileFromFormValue(this.formGroup.value); if (fileFromForm && fileFromForm !== this.fileFromConfig) { try { const markdownBinaryId = await this.markdownService.uploadFile(fileFromForm); Object.assign(config, { markdownBinaryId, contentUrl: null }); return true; } catch (e) { this.alert.danger(gettext('Unable to upload Markdown file.'), e?.data); return false; } } if (!fileFromForm) { Object.assign(config, { contentUrl: '/readme.md', markdownBinaryId: null }); } return true; } async ngOnInit() { this.initForm(); if (this.config.markdownBinaryId) { this.uploadChoice = 'uploadBinary'; this.fileFromConfig = await this.markdownService.getFile(this.config.markdownBinaryId); this.formGroup.patchValue({ droppedFile: [{ file: this.fileFromConfig, name: this.fileFromConfig.name }] }); } } onChange(value) { this.uploadChoice = value; this.formGroup.controls['uploadChoice'].patchValue(value); } getFileFromFormValue(formValue) { const binary = formValue?.droppedFile || []; return binary[0]?.file || null; } initForm() { this.formGroup = this.formBuilder.group({ contentUrl: ['', [Validators.maxLength(2000)]], droppedFile: [ null, [ Validators.minLength(1), Validators.maxLength(1), C8yValidators.filesValidator({ maximumFileSizeInKb: 1000 }) ] ], uploadChoice: [this.config.markdownBinaryId ? 'uploadBinary' : 'uploadUrl', []] }, { validators: this.requireEitherBinaryOrUrl() }); this.form.form.addControl('config', this.formGroup); this.formGroup.patchValue(this.config); } requireEitherBinaryOrUrl() { return (control) => { const url = control.get(`contentUrl`); const uploadBinary = control.get(`droppedFile`); const urlDefined = url && url.value !== undefined && url.value !== null; const uploadBinaryDefined = uploadBinary && uploadBinary.value !== undefined && uploadBinary.value !== null; const errors = {}; if (this.uploadChoice === 'uploadBinary' && !uploadBinaryDefined) { // sets error const error = { required: true }; uploadBinary.setErrors(Object.assign({}, uploadBinary.errors || {}, error)); Object.assign(errors, error); } else { // remove previous error this.removeErrors(uploadBinary, ['required']); } if (this.uploadChoice === 'uploadUrl' && (!urlDefined || url.value === '')) { // sets error const error = { required: true }; url.setErrors(Object.assign({}, url.errors || {}, error)); Object.assign(errors, error); } else { // remove previous error this.removeErrors(url, ['required']); } return Object.keys(errors).length ? errors : null; }; } removeErrors(control, errors) { if (!control || !control.errors) { return false; } let removedError = false; for (const error of errors) { if (control.errors[error]) { removedError = true; delete control.errors[error]; } } if (removedError) { control.setErrors(Object.keys(control.errors).length ? Object.assign({}, control.errors) : null); } return removedError; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MarkdownWidgetConfigComponent, deps: [{ token: i1.FormBuilder }, { token: i1.NgForm }, { token: i2.AlertService }, { token: i3.MarkdownWidgetService }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: MarkdownWidgetConfigComponent, isStandalone: true, selector: "c8y-markdown-widget-config", inputs: { config: "config" }, ngImport: i0, template: "<form [formGroup]=\"formGroup\" class=\"p-l-24 p-r-24 p-t-16\">\n <div class=\"form-group\">\n <label title=\"{{ 'Upload a binary' | translate }}\" class=\"c8y-radio radio-inline\">\n <input\n #radio\n formControlName=\"uploadChoice\"\n type=\"radio\"\n value=\"uploadBinary\"\n name=\"uploadChoice\"\n (change)=\"onChange($event.target.value)\"\n />\n <span></span>\n <span>{{ 'Upload a binary' | translate }}</span>\n </label>\n <label title=\"{{ 'Provide a file path' | translate }}\" class=\"c8y-radio radio-inline m-l-8\">\n <input\n #radio\n formControlName=\"uploadChoice\"\n type=\"radio\"\n value=\"uploadUrl\"\n name=\"uploadChoice\"\n (change)=\"onChange($event.target.value)\"\n />\n <span></span>\n <span>\n {{ 'Provide a file path' | translate }}\n </span>\n </label>\n </div>\n\n <ng-container [ngSwitch]=\"uploadChoice\">\n <div *ngSwitchCase=\"'uploadBinary'\">\n <c8y-form-group class=\"m-0\">\n <c8y-drop-area\n formControlName=\"droppedFile\"\n class=\"drop-area-sm\"\n [title]=\"'Drop file or click to browse' | translate\"\n [maxAllowedFiles]=\"1\"\n [accept]=\"'md'\"\n ></c8y-drop-area>\n </c8y-form-group>\n </div>\n <div *ngSwitchCase=\"'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 formControlName=\"contentUrl\"\n placeholder=\"{{ 'e.g.' | translate }} http://example.com/binary.zip\"\n />\n </div>\n </div>\n </c8y-form-group>\n </div>\n </ng-container>\n</form>\n", dependencies: [{ kind: "ngmodule", type: CoreModule }, { kind: "directive", type: i2.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "pipe", type: i2.C8yTranslatePipe, name: "translate" }, { kind: "directive", type: i4.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i4.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "component", type: i2.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: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { 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.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "component", type: i2.FormGroupComponent, selector: "c8y-form-group", inputs: ["hasError", "hasWarning", "hasSuccess", "novalidation", "status"] }, { kind: "directive", type: i2.RequiredInputPlaceholderDirective, selector: "input[required], input[formControlName]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: ReactiveFormsModule }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: MarkdownWidgetConfigComponent, decorators: [{ type: Component, args: [{ selector: 'c8y-markdown-widget-config', standalone: true, imports: [CoreModule, ReactiveFormsModule], template: "<form [formGroup]=\"formGroup\" class=\"p-l-24 p-r-24 p-t-16\">\n <div class=\"form-group\">\n <label title=\"{{ 'Upload a binary' | translate }}\" class=\"c8y-radio radio-inline\">\n <input\n #radio\n formControlName=\"uploadChoice\"\n type=\"radio\"\n value=\"uploadBinary\"\n name=\"uploadChoice\"\n (change)=\"onChange($event.target.value)\"\n />\n <span></span>\n <span>{{ 'Upload a binary' | translate }}</span>\n </label>\n <label title=\"{{ 'Provide a file path' | translate }}\" class=\"c8y-radio radio-inline m-l-8\">\n <input\n #radio\n formControlName=\"uploadChoice\"\n type=\"radio\"\n value=\"uploadUrl\"\n name=\"uploadChoice\"\n (change)=\"onChange($event.target.value)\"\n />\n <span></span>\n <span>\n {{ 'Provide a file path' | translate }}\n </span>\n </label>\n </div>\n\n <ng-container [ngSwitch]=\"uploadChoice\">\n <div *ngSwitchCase=\"'uploadBinary'\">\n <c8y-form-group class=\"m-0\">\n <c8y-drop-area\n formControlName=\"droppedFile\"\n class=\"drop-area-sm\"\n [title]=\"'Drop file or click to browse' | translate\"\n [maxAllowedFiles]=\"1\"\n [accept]=\"'md'\"\n ></c8y-drop-area>\n </c8y-form-group>\n </div>\n <div *ngSwitchCase=\"'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 formControlName=\"contentUrl\"\n placeholder=\"{{ 'e.g.' | translate }} http://example.com/binary.zip\"\n />\n </div>\n </div>\n </c8y-form-group>\n </div>\n </ng-container>\n</form>\n" }] }], ctorParameters: () => [{ type: i1.FormBuilder }, { type: i1.NgForm }, { type: i2.AlertService }, { type: i3.MarkdownWidgetService }], propDecorators: { config: [{ type: Input }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWFya2Rvd24td2lkZ2V0LWNvbmZpZy5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi93aWRnZXRzL2ltcGxlbWVudGF0aW9ucy9tYXJrZG93bi9tYXJrZG93bi13aWRnZXQtY29uZmlnL21hcmtkb3duLXdpZGdldC1jb25maWcuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vLi4vd2lkZ2V0cy9pbXBsZW1lbnRhdGlvbnMvbWFya2Rvd24vbWFya2Rvd24td2lkZ2V0LWNvbmZpZy9tYXJrZG93bi13aWRnZXQtY29uZmlnLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQUUsS0FBSyxFQUFVLE1BQU0sZUFBZSxDQUFDO0FBQ3pELE9BQU8sRUFDTCxZQUFZLEVBQ1osYUFBYSxFQUNiLFVBQVUsRUFDVixPQUFPLEVBRVIsTUFBTSxxQkFBcUIsQ0FBQztBQUM3QixPQUFPLEVBRUwsV0FBVyxFQUVYLE1BQU0sRUFDTixtQkFBbUIsRUFHbkIsVUFBVSxFQUNYLE1BQU0sZ0JBQWdCLENBQUM7QUFFeEIsT0FBTyxFQUFFLHFCQUFxQixFQUFFLE1BQU0sNEJBQTRCLENBQUM7Ozs7OztBQVFuRSxNQUFNLE9BQU8sNkJBQTZCO0lBT3hDLFlBQ1UsV0FBd0IsRUFDeEIsSUFBWSxFQUNaLEtBQW1CLEVBQ25CLGVBQXNDO1FBSHRDLGdCQUFXLEdBQVgsV0FBVyxDQUFhO1FBQ3hCLFNBQUksR0FBSixJQUFJLENBQVE7UUFDWixVQUFLLEdBQUwsS0FBSyxDQUFjO1FBQ25CLG9CQUFlLEdBQWYsZUFBZSxDQUF1QjtRQVBoRCxpQkFBWSxHQUFpQyxXQUFXLENBQUM7UUFDekQsWUFBTyxHQUFHLEtBQUssQ0FBQztJQU9iLENBQUM7SUFFSixLQUFLLENBQUMsWUFBWSxDQUFDLE1BQTZCO1FBQzlDLElBQUksSUFBSSxDQUFDLFNBQVMsQ0FBQyxPQUFPLEVBQUUs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QyxPQUFPLENBQUMsTUFBTSxFQUFFLENBQUM7WUFDaEMsT0FBTyxLQUFLLENBQUM7UUFDZixDQUFDO1FBQ0QsSUFBSSxZQUFZLEdBQUcsS0FBSyxDQUFDO1FBQ3pCLEtBQUssTUFBTSxLQUFLLElBQUksTUFBTSxFQUFFLENBQUM7WUFDM0IsSUFBSSxPQUFPLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUM7Z0JBQzFCLFlBQVksR0FBRyxJQUFJLENBQUM7Z0JBQ3BCLE9BQU8sT0FBTyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQztZQUMvQixDQUFDO1FBQ0gsQ0FBQztRQUNELElBQUksWUFBWSxFQUFFLENBQUM7WUFDakIsT0FBTyxDQUFDLFNBQVMsQ0FDZixNQUFNLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsRUFBRSxFQUFFLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUM5RSxDQUFDO1FBQ0osQ0FBQztRQUNELE9BQU8sWUFBWSxDQUFDO0lBQ3RCLENBQUM7K0dBdElVLDZCQUE2QjttR0FBN0IsNkJBQTZCLG9IQzNCMUMsZzdEQTZEQSwyQ0RwQ1ksVUFBVSwwakVBQUUsbUJBQW1COzs0RkFFOUIsNkJBQTZCO2tCQU56QyxTQUFTOytCQUNFLDRCQUE0QixjQUUxQixJQUFJLFdBQ1AsQ0FBQyxVQUFVLEVBQUUsbUJBQW1CLENBQUM7b0tBR2pDLE1BQU07c0JBQWQsS0FBSyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCwgSW5wdXQsIE9uSW5pdCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHtcbiAgQWxlcnRTZXJ2aWNlLFxuICBDOHlWYWxpZGF0b3JzLFxuICBDb3JlTW9kdWxlLFxuICBnZXR0ZXh0LFxuICBPbkJlZm9yZVNhdmVcbn0gZnJvbSAnQGM4eS9uZ3gtY29tcG9uZW50cyc7XG5pbXBvcnQge1xuICBBYnN0cmFjdENvbnRyb2wsXG4gIEZvcm1CdWlsZGVyLFxuICBGb3JtR3JvdXAsXG4gIE5nRm9ybSxcbiAgUmVhY3RpdmVGb3Jtc01vZHVsZSxcbiAgVmFsaWRhdGlvbkVycm9ycyxcbiAgVmFsaWRhdG9yRm4sXG4gIFZhbGlkYXRvcnNcbn0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xuaW1wb3J0IHsgTWFya2Rvd25XaWRnZXRDb25maWcgfSBmcm9tICcuLi9tYXJrZG93bi13aWRnZXQubW9kZWwnO1xuaW1wb3J0IHsgTWFya2Rvd25XaWRnZXRTZXJ2aWNlIH0gZnJvbSAnLi4vbWFya2Rvd24td2lkZ2V0LnNlcnZpY2UnO1xuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICdjOHktbWFya2Rvd24td2lkZ2V0LWNvbmZpZycsXG4gIHRlbXBsYXRlVXJsOiAnLi9tYXJrZG93bi13aWRnZXQtY29uZmlnLmNvbXBvbmVudC5odG1sJyxcbiAgc3RhbmRhbG9uZTogdHJ1ZSxcbiAgaW1wb3J0czogW0NvcmVNb2R1bGUsIFJlYWN0aXZlRm9ybXNNb2R1bGVdXG59KVxuZXhwb3J0IGNsYXNzIE1hcmtkb3duV2lkZ2V0Q29uZmlnQ29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0LCBPbkJlZm9yZVNhdmUge1xuICBASW5wdXQoKSBjb25maWc6IE1hcmtkb3duV2lkZ2V0Q29uZmlnO1xuICBmb3JtR3JvdXA6IEZvcm1Hcm91cDtcbiAgZmlsZUZyb21Db25maWc6IEZpbGU7XG4gIHVwbG9hZENob2ljZTogJ3VwbG9hZEJpbmFyeScgfCAndXBsb2FkVXJsJyA9ICd1cGxvYWRVcmwnO1xuICBsb2FkaW5nID0gZmFsc2U7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSBmb3JtQnVpbGRlcjogRm9ybUJ1aWxkZXIsXG4gICAgcHJpdmF0ZSBmb3JtOiBOZ0Zvcm0sXG4gICAgcHJpdmF0ZSBhbGVydDogQWxlcnRTZXJ2aWNlLFxuICAgIHByaXZhdGUgbWFya2Rvd25TZXJ2aWNlOiBNYXJrZG93bldpZGdldFNlcnZpY2VcbiAgKSB7fVxuXG4gIGFzeW5jIG9uQmVmb3JlU2F2ZShjb25maWc/OiBNYXJrZG93bldpZGdldENvbmZpZyk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICAgIGlmICh0aGlzLmZvcm1Hcm91cC5pbnZhbGlkKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIGlmICh0aGlzLnVwbG9hZENob2ljZSA9PT0gJ3VwbG9hZFVybCcpIHtcbiAgICAgIE9iamVjdC5hc3NpZ24oY29uZmlnLCB7XG4gICAgICAgIGNvbnRlbnRVcmw6IHRoaXMuZm9ybUdyb3VwLnZhbHVlLmNvbnRlbnRVcmwsXG4gICAgICAgIG1hcmtkb3duQmluYXJ5SWQ6IG51bGxcbiAgICAgIH0pO1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICAgIGNvbnN0IGZpbGVGcm9tRm9ybSA9IHRoaXMuZ2V0RmlsZUZyb21Gb3JtVmFsdWUodGhpcy5mb3JtR3JvdXAudmFsdWUpO1xuICAgIGlmIChmaWxlRnJvbUZvcm0gJiYgZmlsZUZyb21Gb3JtICE9PSB0aGlzLmZpbGVGcm9tQ29uZmlnKSB7XG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCBtYXJrZG93bkJpbmFyeUlkID0gYXdhaXQgdGhpcy5tYXJrZG93blNlcnZpY2UudXBsb2FkRmlsZShmaWxlRnJvbUZvcm0pO1xuICAgICAgICBPYmplY3QuYXNzaWduKGNvbmZpZywgeyBtYXJrZG93bkJpbmFyeUlkLCBjb250ZW50VXJsOiBudWxsIH0pO1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgdGhpcy5hbGVydC5kYW5nZXIoZ2V0dGV4dCgnVW5hYmxlIHRvIHVwbG9hZCBNYXJrZG93biBmaWxlLicpLCBlPy5kYXRhKTtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgfVxuICAgIH1cbiAgICBpZiAoIWZpbGVGcm9tRm9ybSkge1xuICAgICAgT2JqZWN0LmFzc2lnbihjb25maWcsIHsgY29udGVudFVybDogJy9yZWFkbWUubWQnLCBtYXJrZG93bkJpbmFyeUlkOiBudWxsIH0pO1xuICAgIH1cbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIGFzeW5jIG5nT25Jbml0KCkge1xuICAgIHRoaXMuaW5pdEZvcm0oKTtcbiAgICBpZiAodGhpcy5jb25maWcubWFya2Rvd25CaW5hcnlJZCkge1xuICAgICAgdGhpcy51cGxvYWRDaG9pY2UgPSAndXBsb2FkQmluYXJ5JztcbiAgICAgIHRoaXMuZmlsZUZyb21Db25maWcgPSBhd2FpdCB0aGlzLm1hcmtkb3duU2VydmljZS5nZXRGaWxlKHRoaXMuY29uZmlnLm1hcmtkb3duQmluYXJ5SWQpO1xuICAgICAgdGhpcy5mb3JtR3JvdXAucGF0Y2hWYWx1ZSh7XG4gICAgICAgIGRyb3BwZWRGaWxlOiBbeyBmaWxlOiB0aGlzLmZpbGVGcm9tQ29uZmlnLCBuYW1lOiB0aGlzLmZpbGVGcm9tQ29uZmlnLm5hbWUgfV1cbiAgICAgIH0pO1xuICAgIH1cbiAgfVxuXG4gIG9uQ2hhbmdlKHZhbHVlOiAndXBsb2FkQmluYXJ5JyB8ICd1cGxvYWRVcmwnKSB7XG4gICAgdGhpcy51cGxvYWRDaG9pY2UgPSB2YWx1ZTtcbiAgICB0aGlzLmZvcm1Hcm91cC5jb250cm9sc1sndXBsb2FkQ2hvaWNlJ10ucGF0Y2hWYWx1ZSh2YWx1ZSk7XG4gIH1cblxuICBwcml2YXRlIGdldEZpbGVGcm9tRm9ybVZhbHVlKGZvcm1WYWx1ZTogYW55KTogRmlsZSB8IG51bGwge1xuICAgIGNvbnN0IGJpbmFyeTogYW55W10gPSBmb3JtVmFsdWU/LmRyb3BwZWRGaWxlIHx8IFtdO1xuICAgIHJldHVybiBiaW5hcnlbMF0/LmZpbGUgfHwgbnVsbDtcbiAgfVxuXG4gIHByaXZhdGUgaW5pdEZvcm0oKTogdm9pZCB7XG4gICAgdGhpcy5mb3JtR3JvdXAgPSB0aGlzLmZvcm1CdWlsZGVyLmdyb3VwKFxuICAgICAge1xuICAgICAgICBjb250ZW50VXJsOiBbJycsIFtWYWxpZGF0b3JzLm1heExlbmd0aCgyMDAwKV1dLFxuICAgICAgICBkcm9wcGVkRmlsZTogW1xuICAgICAgICAgIG51bGwsXG4gICAgICAgICAgW1xuICAgICAgICAgICAgVmFsaWRhdG9ycy5taW5MZW5ndGgoMSksXG4gICAgICAgICAgICBWYWxpZGF0b3JzLm1heExlbmd0aCgxKSxcbiAgICAgICAgICAgIEM4eVZhbGlkYXRvcnMuZmlsZXNWYWxpZGF0b3IoeyBtYXhpbXVtRmlsZVNpemVJbktiOiAxMDAwIH0pXG4gICAgICAgICAgXVxuICAgICAgICBdLFxuICAgICAgICB1cGxvYWRDaG9pY2U6IFt0aGlzLmNvbmZpZy5tYXJrZG93bkJpbmFyeUlkID8gJ3VwbG9hZEJpbmFyeScgOiAndXBsb2FkVXJsJywgW11dXG4gICAgICB9LFxuICAgICAgeyB2YWxpZGF0b3JzOiB0aGlzLnJlcXVpcmVFaXRoZXJCaW5hcnlPclVybCgpIH1cbiAgICApO1xuICAgIHRoaXMuZm9ybS5mb3JtLmFkZENvbnRyb2woJ2NvbmZpZycsIHRoaXMuZm9ybUdyb3VwKTtcbiAgICB0aGlzLmZvcm1Hcm91cC5wYXRjaFZhbHVlKHRoaXMuY29uZmlnKTtcbiAgfVxuXG4gIHByaXZhdGUgcmVxdWlyZUVpdGhlckJpbmFyeU9yVXJsKCk6IFZhbGlkYXRvckZuIHtcbiAgICByZXR1cm4gKGNvbnRyb2w6IEFic3RyYWN0Q29udHJvbCk6IFZhbGlkYXRpb25FcnJvcnMgfCBudWxsID0+IHtcbiAgICAgIGNvbnN0IHVybCA9IGNvbnRyb2wuZ2V0KGBjb250ZW50VXJsYCk7XG4gICAgICBjb25zdCB1cGxvYWRCaW5hcnkgPSBjb250cm9sLmdldChgZHJvcHBlZEZpbGVgKTtcblxuICAgICAgY29uc3QgdXJsRGVmaW5lZCA9IHVybCAmJiB1cmwudmFsdWUgIT09IHVuZGVmaW5lZCAmJiB1cmwudmFsdWUgIT09IG51bGw7XG4gICAgICBjb25zdCB1cGxvYWRCaW5hcnlEZWZpbmVkID1cbiAgICAgICAgdXBsb2FkQmluYXJ5ICYmIHVwbG9hZEJpbmFyeS52YWx1ZSAhPT0gdW5kZWZpbmVkICYmIHVwbG9hZEJpbmFyeS52YWx1ZSAhPT0gbnVsbDtcblxuICAgICAgY29uc3QgZXJyb3JzID0ge307XG4gICAgICBpZiAodGhpcy51cGxvYWRDaG9pY2UgPT09ICd1cGxvYWRCaW5hcnknICYmICF1cGxvYWRCaW5hcnlEZWZpbmVkKSB7XG4gICAgICAgIC8vIHNldHMgZXJyb3JcbiAgICAgICAgY29uc3QgZXJyb3IgPSB7IHJlcXVpcmVkOiB0cnVlIH07XG4gICAgICAgIHVwbG9hZEJpbmFyeS5zZXRFcnJvcnMoT2JqZWN0LmFzc2lnbih7fSwgdXBsb2FkQmluYXJ5LmVycm9ycyB8fCB7fSwgZXJyb3IpKTtcbiAgICAgICAgT2JqZWN0LmFzc2lnbihlcnJvcnMsIGVycm9yKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIHJlbW92ZSBwcmV2aW91cyBlcnJvclxuICAgICAgICB0aGlzLnJlbW92ZUVycm9ycyh1cGxvYWRCaW5hcnksIFsncmVxdWlyZWQnXSk7XG4gICAgICB9XG5cbiAgICAgIGlmICh0aGlzLnVwbG9hZENob2ljZSA9PT0gJ3VwbG9hZFVybCcgJiYgKCF1cmxEZWZpbmVkIHx8IHVybC52YWx1ZSA9PT0gJycpKSB7XG4gICAgICAgIC8vIHNldHMgZXJyb3JcbiAgICAgICAgY29uc3QgZXJyb3IgPSB7IHJlcXVpcmVkOiB0cnVlIH07XG4gICAgICAgIHVybC5zZXRFcnJvcnMoT2JqZWN0LmFzc2lnbih7fSwgdXJsLmVycm9ycyB8fCB7fSwgZXJyb3IpKTtcbiAgICAgICAgT2JqZWN0LmFzc2lnbihlcnJvcnMsIGVycm9yKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIHJlbW92ZSBwcmV2aW91cyBlcnJvclxuICAgICAgICB0aGlzLnJlbW92ZUVycm9ycyh1cmwsIFsncmVxdWlyZWQnXSk7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBPYmplY3Qua2V5cyhlcnJvcnMpLmxlbmd0aCA/IGVycm9ycyA6IG51bGw7XG4gICAgfTtcbiAgfVxuXG4gIHByaXZhdGUgcmVtb3ZlRXJyb3JzKGNvbnRyb2w6IEFic3RyYWN0Q29udHJvbCwgZXJyb3JzOiBzdHJpbmdbXSk6IGJvb2xlYW4ge1xuICAgIGlmICghY29udHJvbCB8fCAhY29udHJvbC5lcnJvcnMpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgbGV0IHJlbW92ZWRFcnJvciA9IGZhbHNlO1xuICAgIGZvciAoY29uc3QgZXJyb3Igb2YgZXJyb3JzKSB7XG4gICAgICBpZiAoY29udHJvbC5lcnJvcnNbZXJyb3JdKSB7XG4gICAgICAgIHJlbW92ZWRFcnJvciA9IHRydWU7XG4gICAgICAgIGRlbGV0ZSBjb250cm9sLmVycm9yc1tlcnJvcl07XG4gICAgICB9XG4gICAgfVxuICAgIGlmIChyZW1vdmVkRXJyb3IpIHtcbiAgICAgIGNvbnRyb2wuc2V0RXJyb3JzKFxuICAgICAgICBPYmplY3Qua2V5cyhjb250cm9sLmVycm9ycykubGVuZ3RoID8gT2JqZWN0LmFzc2lnbih7fSwgY29udHJvbC5lcnJvcnMpIDogbnVsbFxuICAgICAgKTtcbiAgICB9XG4gICAgcmV0dXJuIHJlbW92ZWRFcnJvcjtcbiAgfVxufVxuIiwiPGZvcm0gW2Zvcm1Hcm91cF09XCJmb3JtR3JvdXBcIiBjbGFzcz1cInAtbC0yNCBwLXItMjQgcC10LTE2XCI+XG4gIDxkaXYgY2xhc3M9XCJmb3JtLWdyb3VwXCI+XG4gICAgPGxhYmVsIHRpdGxlPVwie3sgJ1VwbG9hZCBhIGJpbmFyeScgfCB0cmFuc2xhdGUgfX1cIiBjbGFzcz1cImM4eS1yYWRpbyByYWRpby1pbmxpbmVcIj5cbiAgICAgIDxpbnB1dFxuICAgICAgICAjcmFkaW9cbiAgICAgICAgZm9ybUNvbnRyb2xOYW1lPVwidXBsb2FkQ2hvaWNlXCJcbiAgICAgICAgdHlwZT1cInJhZGlvXCJcbiAgICAgICAgdmFsdWU9XCJ1cGxvYWRCaW5hcnlcIlxuICAgICAgICBuYW1lPVwidXBsb2FkQ2hvaWNlXCJcbiAgICAgICAgKGNoYW5nZSk9XCJvbkNoYW5nZSgkZXZlbnQudGFyZ2V0LnZhbHVlKVwiXG4gICAgICAvPlxuICAgICAgPHNwYW4+PC9zcGFuPlxuICAgICAgPHNwYW4+e3sgJ1VwbG9hZCBhIGJpbmFyeScgfCB0cmFuc2xhdGUgfX08L3NwYW4+XG4gICAgPC9sYWJlbD5cbiAgICA8bGFiZWwgdGl0bGU9XCJ7eyAnUHJvdmlkZSBhIGZpbGUgcGF0aCcgfCB0cmFuc2xhdGUgfX1cIiBjbGFzcz1cImM4eS1yYWRpbyByYWRpby1pbmxpbmUgbS1sLThcIj5cbiAgICAgIDxpbnB1dFxuICAgICAgICAjcmFkaW9cbiAgICAgICAgZm9ybUNvbnRyb2xOYW1lPVwidXBsb2FkQ2hvaWNlXCJcbiAgICAgICAgdHlwZT1cInJhZGlvXCJcbiAgICAgICAgdmFsdWU9XCJ1cGxvYWRVcmxcIlxuICAgICAgICBuYW1lPVwidXBsb2FkQ2hvaWNlXCJcbiAgICAgICAgKGNoYW5nZSk9XCJvbkNoYW5nZSgkZXZlbnQudGFyZ2V0LnZhbHVlKVwiXG4gICAgICAvPlxuICAgICAgPHNwYW4+PC9zcGFuPlxuICAgICAgPHNwYW4+XG4gICAgICAgIHt7ICdQcm92aWRlIGEgZmlsZSBwYXRoJyB8IHRyYW5zbGF0ZSB9fVxuICAgICAgPC9zcGFuPlxuICAgIDwvbGFiZWw+XG4gIDwvZGl2PlxuXG4gIDxuZy1jb250YWluZXIgW25nU3dpdGNoXT1cInVwbG9hZENob2ljZVwiPlxuICAgIDxkaXYgKm5nU3dpdGNoQ2FzZT1cIid1cGxvYWRCaW5hcnknXCI+XG4gICAgICA8Yzh5LWZvcm0tZ3JvdXAgY2xhc3M9XCJtLTBcIj5cbiAgICAgICAgPGM4eS1kcm9wLWFyZWFcbiAgICAgICAgICBmb3JtQ29udHJvbE5hbWU9XCJkcm9wcGVkRmlsZVwiXG4gICAgICAgICAgY2xhc3M9XCJkcm9wLWFyZWEtc21cIlxuICAgICAgICAgIFt0aXRsZV09XCInRHJvcCBmaWxlIG9yIGNsaWNrIHRvIGJyb3dzZScgfCB0cmFuc2xhdGVcIlxuICAgICAgICAgIFttYXhBbGxvd2VkRmlsZXNdPVwiMVwiXG4gICAgICAgICAgW2FjY2VwdF09XCInbWQnXCJcbiAgICAgICAgPjwvYzh5LWRyb3AtYXJlYT5cbiAgICAgIDwvYzh5LWZvcm0tZ3JvdXA+XG4gICAgPC9kaXY+XG4gICAgPGRpdiAqbmdTd2l0Y2hDYXNlPVwiJ3VwbG9hZFVybCdcIj5cbiAgICAgIDxjOHktZm9ybS1ncm91cCBjbGFzcz1cIm0tMFwiPlxuICAgICAgICA8ZGl2IGNsYXNzPVwibS1iLTQgcC1iLThcIj5cbiAgICAgICAgICA8ZGl2IGNsYXNzPVwiaW5wdXQtZ3JvdXBcIj5cbiAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwiaW5wdXQtZ3JvdXAtYWRkb25cIj5cbiAgICAgICAgICAgICAgPGkgYzh5SWNvbj1cImdsb2JlXCI+PC9pPlxuICAgICAgICAgICAgPC9zcGFuPlxuICAgICAgICAgICAgPGlucHV0XG4gICAgICAgICAgICAgIHR5cGU9XCJ0ZXh0XCJcbiAgICAgICAgICAgICAgY2xhc3M9XCJmb3JtLWNvbnRyb2xcIlxuICAgICAgICAgICAgICBmb3JtQ29udHJvbE5hbWU9XCJjb250ZW50VXJsXCJcbiAgICAgICAgICAgICAgcGxhY2Vob2xkZXI9XCJ7eyAnZS5nLicgfCB0cmFuc2xhdGUgfX0gaHR0cDovL2V4YW1wbGUuY29tL2JpbmFyeS56aXBcIlxuICAgICAgICAgICAgLz5cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgPC9kaXY+XG4gICAgICA8L2M4eS1mb3JtLWdyb3VwPlxuICAgIDwvZGl2PlxuICA8L25nLWNvbnRhaW5lcj5cbjwvZm9ybT5cbiJdfQ==