@c8y/ngx-components
Version:
Angular modules for Cumulocity IoT applications
125 lines • 39.7 kB
JavaScript
import { Component, EventEmitter, Output, ViewChild } from '@angular/core';
import { NgForm } from '@angular/forms';
import { AlertService, gettext } from '@c8y/ngx-components';
import { PRODUCT_EXPERIENCE_REPOSITORY_SHARED, RepositoryService, RepositoryType } from '@c8y/ngx-components/repository/shared';
import { isUndefined } from 'lodash-es';
import { BsDropdownDirective } from 'ngx-bootstrap/dropdown';
import { BsModalRef } from 'ngx-bootstrap/modal';
import { BehaviorSubject, from, merge, of, pipe } from 'rxjs';
import { debounceTime, distinctUntilChanged, map, shareReplay, switchMap, tap } from 'rxjs/operators';
import * as i0 from "@angular/core";
import * as i1 from "ngx-bootstrap/modal";
import * as i2 from "@c8y/ngx-components/repository/shared";
import * as i3 from "@c8y/ngx-components";
import * as i4 from "@angular/common";
import * as i5 from "@angular/forms";
export class AddFirmwarePatchModalComponent {
constructor(modal, repository, alert) {
this.modal = modal;
this.repository = repository;
this.alert = alert;
this.PRODUCT_EXPERIENCE = PRODUCT_EXPERIENCE_REPOSITORY_SHARED;
this.saved = new EventEmitter();
this.textForFirmwareUrlPopover = gettext(`Path for binaries can vary depending on device agent implementation, for example:
/firmware/binaries/firmware1.bin
https://firmware/binary/123
ftp://firmware/binary/123.tar.gz
`);
this.model = {
selected: undefined,
dependency: null,
patchVersion: undefined,
binary: {
file: undefined,
url: undefined
}
};
this.firmwareInput$ = new BehaviorSubject('');
this.firmwares$ = this.firmwareInput$.pipe(debounceTime(300), distinctUntilChanged(), switchMap(searchStr => from(this.repository.listRepositoryEntries(RepositoryType.FIRMWARE, {
partialName: searchStr,
skipLegacy: true
}))), shareReplay(1));
this.firmwareSelected$ = new BehaviorSubject(null);
this.patchDependencyInput$ = new BehaviorSubject('');
this.saving = false;
this.firmwarePreselected = false;
this.baseVersions$ = merge(this.firmwareInput$.pipe(tap(() => {
this.model.dependency = null;
if (this.form) {
this.form.form.get('patchDependency').reset();
}
}), switchMap(() => of(null))), this.firmwareSelected$).pipe(switchMap(selectedFirmware => selectedFirmware ? this.repository.listBaseVersions(selectedFirmware) : of(null)), shareReplay(1));
this.baseVersionsFilterPipe = pipe(switchMap((data) => this.patchDependencyInput$.pipe(map(partialVersion => data.filter((mo) => {
const version = mo.c8y_Firmware.version?.toLowerCase();
return (partialVersion.length === 0 || version?.indexOf(partialVersion.toLowerCase()) > -1);
})))));
}
async ngOnInit() {
this.setInitialState();
}
setInitialState() {
if (this.model.selected) {
this.firmwarePreselected = true;
this.firmwareSelected$.next(this.model.selected);
}
}
async save() {
this.saving = true;
this.repository
.create(this.model, RepositoryType.FIRMWARE)
.then(savedFirmware => {
this.successMsg();
this.saving = false;
this.saved.next(savedFirmware);
this.cancel();
})
.catch(e => {
this.saving = false;
this.saved.error(e);
this.cancel();
});
}
successMsg() {
const msg = gettext('Firmware patch added.');
this.alert.success(msg);
}
cancel() {
this.modal.hide();
this.saved.complete();
}
onFile(dropped) {
if (!isUndefined(dropped.url)) {
this.model.binary = {
url: dropped.url
};
return;
}
else if (dropped.droppedFiles) {
this.model.binary = {
file: dropped.droppedFiles[0].file
};
return;
}
else {
this.model.binary = {
file: undefined,
url: undefined
};
}
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AddFirmwarePatchModalComponent, deps: [{ token: i1.BsModalRef }, { token: i2.RepositoryService }, { token: i3.AlertService }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: AddFirmwarePatchModalComponent, selector: "c8y-add-firmware-patch-modal.component", outputs: { saved: "saved" }, viewQueries: [{ propertyName: "dropdown", first: true, predicate: ["dropdown"], descendants: true }, { propertyName: "form", first: true, predicate: ["firmwarePatchForm"], descendants: true }], ngImport: i0, template: "<div class=\"viewport-modal\">\n <div class=\"modal-header dialog-header\">\n <i [c8yIcon]=\"'c8y-firmware'\"></i>\n <h4 translate id=\"addFirmwarePatchModalTitle\">Add firmware patch</h4>\n </div>\n <div class=\"p-16 text-center separator-bottom\" id=\"addFirmwarePatchModalDescription\">\n <p class=\"text-medium text-16 m-0\" translate>Select a firmware version</p>\n </div>\n\n <form\n class=\"d-contents\"\n autocomplete=\"off\"\n #firmwarePatchForm=\"ngForm\"\n (ngSubmit)=\"firmwarePatchForm.form.valid && save()\"\n >\n <div class=\"modal-inner-scroll\">\n <div class=\"modal-body\">\n <div [hidden]=\"firmwarePreselected\">\n <c8y-form-group>\n <label for=\"firmwareName\" translate>Firmware</label>\n <c8y-typeahead\n [ngModel]=\"model.selected\"\n name=\"firmwareName\"\n placeholder=\"{{ 'Select or enter' | translate }}\"\n (onSearch)=\"firmwareInput$.next($event)\"\n [allowFreeEntries]=\"false\"\n [required]=\"true\"\n >\n <c8y-li\n *c8yFor=\"let firmware of firmwares$ | async; loadMore: 'auto'\"\n class=\"p-l-8 p-r-8 c8y-list__item--link\"\n (click)=\"model.selected = firmware; firmwareSelected$.next(firmware)\"\n [active]=\"model.selected === firmware\"\n >\n <c8y-highlight\n [text]=\"firmware.name || '--'\"\n [pattern]=\"firmwareInput$ | async\"\n ></c8y-highlight>\n </c8y-li>\n </c8y-typeahead>\n <c8y-messages>\n <c8y-message\n name=\"notExisting\"\n [text]=\"'Select one of the existing firmwares.' | translate\"\n ></c8y-message>\n </c8y-messages>\n </c8y-form-group>\n </div>\n\n <c8y-form-group>\n <label for=\"patchDependency\" class=\"m-r-8\" translate>Version</label>\n <c8y-typeahead\n [ngModel]=\"model.dependency\"\n name=\"patchDependency\"\n data-cy=\"add-firmware-patch-modal--patchDependency\"\n placeholder=\"{{ 'Select or enter' | translate }}\"\n (onSearch)=\"patchDependencyInput$.next($event)\"\n [displayProperty]=\"'c8y_Firmware.version'\"\n [allowFreeEntries]=\"false\"\n [disabled]=\"\n (baseVersions$ | async) === null || (baseVersions$ | async)?.data.length === 0\n \"\n [required]=\"true\"\n >\n <c8y-li\n *c8yFor=\"\n let baseVersion of baseVersions$;\n loadMore: 'auto';\n pipe: baseVersionsFilterPipe\n \"\n class=\"p-l-8 p-r-8 c8y-list__item--link\"\n (click)=\"model.dependency = baseVersion\"\n [active]=\"model.dependency === baseVersion\"\n >\n <c8y-highlight\n [text]=\"baseVersion.c8y_Firmware.version || '--'\"\n [pattern]=\"patchDependencyInput$ | async\"\n ></c8y-highlight>\n </c8y-li>\n </c8y-typeahead>\n <c8y-messages>\n <c8y-message\n name=\"notExisting\"\n [text]=\"'Select one of the existing versions.' | translate\"\n ></c8y-message>\n </c8y-messages>\n </c8y-form-group>\n\n <c8y-form-group>\n <label for=\"patchVersion\" translate>Patch</label>\n <input\n id=\"patchVersion\"\n class=\"form-control\"\n autocomplete=\"off\"\n name=\"patchVersion\"\n data-cy=\"add-firmware-patch-modal--patchVersion\"\n [(ngModel)]=\"model.patchVersion\"\n placeholder=\"{{ 'e.g.' | translate }} 1.0.0\"\n required\n />\n </c8y-form-group>\n\n <c8y-form-group>\n <div class=\"legend form-block m-t-40\" translate>Patch file</div>\n <c8y-file-picker\n [maxAllowedFiles]=\"1\"\n (onFilesPicked)=\"onFile($event)\"\n [fileUrlPopover]=\"textForFirmwareUrlPopover\"\n ></c8y-file-picker>\n </c8y-form-group>\n </div>\n </div>\n <div class=\"modal-footer\">\n <button\n title=\"{{ 'Cancel' | translate }}\"\n data-cy=\"add-firmware-patch-modal--cancel-btn\"\n class=\"btn btn-default\"\n type=\"button\"\n (click)=\"cancel()\"\n [disabled]=\"saving\"\n translate\n >\n Cancel\n </button>\n <button\n title=\"{{ 'Add firmware patch' | translate }}\"\n class=\"btn btn-primary\"\n type=\"submit\"\n [ngClass]=\"{ 'btn-pending': saving }\"\n [disabled]=\"\n !firmwarePatchForm.form.valid ||\n firmwarePatchForm.form.pristine ||\n (!model.binary?.url && !model.binary?.file) ||\n saving\n \"\n translate\n c8yProductExperience\n [actionName]=\"PRODUCT_EXPERIENCE.FIRMWARE.EVENTS.REPOSITORY\"\n [actionData]=\"{\n component: PRODUCT_EXPERIENCE.FIRMWARE.COMPONENTS.ADD_FIRMWAR_PATCH_MODAL,\n result: PRODUCT_EXPERIENCE.FIRMWARE.RESULTS.ADD_FIRMWARE_PATCH\n }\"\n >\n Add firmware patch\n </button>\n </div>\n </form>\n</div>\n", dependencies: [{ kind: "directive", type: i4.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i3.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i3.ForOfDirective, selector: "[c8yFor]", inputs: ["c8yForOf", "c8yForLoadMore", "c8yForPipe", "c8yForNotFound", "c8yForMaxIterations", "c8yForLoadingTemplate", "c8yForLoadNextLabel", "c8yForLoadingLabel", "c8yForRealtime", "c8yForRealtimeOptions", "c8yForComparator", "c8yForEnableVirtualScroll", "c8yForVirtualScrollElementSize", "c8yForVirtualScrollStrategy", "c8yForVirtualScrollContainerHeight"], outputs: ["c8yForCount", "c8yForChange", "c8yForLoadMoreComponent"] }, { kind: "component", type: i3.HighlightComponent, selector: "c8y-highlight", inputs: ["pattern", "text", "elementClass", "shouldTrimPattern"] }, { kind: "component", type: i3.TypeaheadComponent, selector: "c8y-typeahead", inputs: ["required", "maxlength", "disabled", "allowFreeEntries", "placeholder", "displayProperty", "icon", "name", "autoClose", "hideNew", "container", "selected", "highlightFirstItem"], outputs: ["onSearch", "onIconClick"] }, { kind: "directive", type: i5.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i5.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: i5.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i5.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i5.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i5.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i5.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: i3.FormGroupComponent, selector: "c8y-form-group", inputs: ["hasError", "hasWarning", "hasSuccess", "novalidation", "status"] }, { kind: "directive", type: i3.MessageDirective, selector: "c8y-message", inputs: ["name", "text"] }, { kind: "component", type: i3.MessagesComponent, selector: "c8y-messages", inputs: ["show", "defaults", "helpMessage"] }, { kind: "directive", type: i3.RequiredInputPlaceholderDirective, selector: "input[required], input[formControlName]" }, { kind: "component", type: i3.ListItemComponent, selector: "c8y-list-item, c8y-li", inputs: ["active", "highlighted", "emptyActions", "dense", "collapsed", "selectable"], outputs: ["collapsedChange"] }, { kind: "component", type: i3.FilePickerComponent, selector: "c8y-file-picker", inputs: ["maxAllowedFiles", "uploadChoice", "fileUrl", "fileBinary", "config", "filePickerIndex", "fileUrlPopover"], outputs: ["onFilesPicked"] }, { kind: "directive", type: i3.ProductExperienceDirective, selector: "[c8yProductExperience]", inputs: ["actionName", "actionData", "inherit", "suppressDataOverriding"] }, { kind: "pipe", type: i4.AsyncPipe, name: "async" }, { kind: "pipe", type: i3.C8yTranslatePipe, name: "translate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AddFirmwarePatchModalComponent, decorators: [{
type: Component,
args: [{ selector: 'c8y-add-firmware-patch-modal.component', template: "<div class=\"viewport-modal\">\n <div class=\"modal-header dialog-header\">\n <i [c8yIcon]=\"'c8y-firmware'\"></i>\n <h4 translate id=\"addFirmwarePatchModalTitle\">Add firmware patch</h4>\n </div>\n <div class=\"p-16 text-center separator-bottom\" id=\"addFirmwarePatchModalDescription\">\n <p class=\"text-medium text-16 m-0\" translate>Select a firmware version</p>\n </div>\n\n <form\n class=\"d-contents\"\n autocomplete=\"off\"\n #firmwarePatchForm=\"ngForm\"\n (ngSubmit)=\"firmwarePatchForm.form.valid && save()\"\n >\n <div class=\"modal-inner-scroll\">\n <div class=\"modal-body\">\n <div [hidden]=\"firmwarePreselected\">\n <c8y-form-group>\n <label for=\"firmwareName\" translate>Firmware</label>\n <c8y-typeahead\n [ngModel]=\"model.selected\"\n name=\"firmwareName\"\n placeholder=\"{{ 'Select or enter' | translate }}\"\n (onSearch)=\"firmwareInput$.next($event)\"\n [allowFreeEntries]=\"false\"\n [required]=\"true\"\n >\n <c8y-li\n *c8yFor=\"let firmware of firmwares$ | async; loadMore: 'auto'\"\n class=\"p-l-8 p-r-8 c8y-list__item--link\"\n (click)=\"model.selected = firmware; firmwareSelected$.next(firmware)\"\n [active]=\"model.selected === firmware\"\n >\n <c8y-highlight\n [text]=\"firmware.name || '--'\"\n [pattern]=\"firmwareInput$ | async\"\n ></c8y-highlight>\n </c8y-li>\n </c8y-typeahead>\n <c8y-messages>\n <c8y-message\n name=\"notExisting\"\n [text]=\"'Select one of the existing firmwares.' | translate\"\n ></c8y-message>\n </c8y-messages>\n </c8y-form-group>\n </div>\n\n <c8y-form-group>\n <label for=\"patchDependency\" class=\"m-r-8\" translate>Version</label>\n <c8y-typeahead\n [ngModel]=\"model.dependency\"\n name=\"patchDependency\"\n data-cy=\"add-firmware-patch-modal--patchDependency\"\n placeholder=\"{{ 'Select or enter' | translate }}\"\n (onSearch)=\"patchDependencyInput$.next($event)\"\n [displayProperty]=\"'c8y_Firmware.version'\"\n [allowFreeEntries]=\"false\"\n [disabled]=\"\n (baseVersions$ | async) === null || (baseVersions$ | async)?.data.length === 0\n \"\n [required]=\"true\"\n >\n <c8y-li\n *c8yFor=\"\n let baseVersion of baseVersions$;\n loadMore: 'auto';\n pipe: baseVersionsFilterPipe\n \"\n class=\"p-l-8 p-r-8 c8y-list__item--link\"\n (click)=\"model.dependency = baseVersion\"\n [active]=\"model.dependency === baseVersion\"\n >\n <c8y-highlight\n [text]=\"baseVersion.c8y_Firmware.version || '--'\"\n [pattern]=\"patchDependencyInput$ | async\"\n ></c8y-highlight>\n </c8y-li>\n </c8y-typeahead>\n <c8y-messages>\n <c8y-message\n name=\"notExisting\"\n [text]=\"'Select one of the existing versions.' | translate\"\n ></c8y-message>\n </c8y-messages>\n </c8y-form-group>\n\n <c8y-form-group>\n <label for=\"patchVersion\" translate>Patch</label>\n <input\n id=\"patchVersion\"\n class=\"form-control\"\n autocomplete=\"off\"\n name=\"patchVersion\"\n data-cy=\"add-firmware-patch-modal--patchVersion\"\n [(ngModel)]=\"model.patchVersion\"\n placeholder=\"{{ 'e.g.' | translate }} 1.0.0\"\n required\n />\n </c8y-form-group>\n\n <c8y-form-group>\n <div class=\"legend form-block m-t-40\" translate>Patch file</div>\n <c8y-file-picker\n [maxAllowedFiles]=\"1\"\n (onFilesPicked)=\"onFile($event)\"\n [fileUrlPopover]=\"textForFirmwareUrlPopover\"\n ></c8y-file-picker>\n </c8y-form-group>\n </div>\n </div>\n <div class=\"modal-footer\">\n <button\n title=\"{{ 'Cancel' | translate }}\"\n data-cy=\"add-firmware-patch-modal--cancel-btn\"\n class=\"btn btn-default\"\n type=\"button\"\n (click)=\"cancel()\"\n [disabled]=\"saving\"\n translate\n >\n Cancel\n </button>\n <button\n title=\"{{ 'Add firmware patch' | translate }}\"\n class=\"btn btn-primary\"\n type=\"submit\"\n [ngClass]=\"{ 'btn-pending': saving }\"\n [disabled]=\"\n !firmwarePatchForm.form.valid ||\n firmwarePatchForm.form.pristine ||\n (!model.binary?.url && !model.binary?.file) ||\n saving\n \"\n translate\n c8yProductExperience\n [actionName]=\"PRODUCT_EXPERIENCE.FIRMWARE.EVENTS.REPOSITORY\"\n [actionData]=\"{\n component: PRODUCT_EXPERIENCE.FIRMWARE.COMPONENTS.ADD_FIRMWAR_PATCH_MODAL,\n result: PRODUCT_EXPERIENCE.FIRMWARE.RESULTS.ADD_FIRMWARE_PATCH\n }\"\n >\n Add firmware patch\n </button>\n </div>\n </form>\n</div>\n" }]
}], ctorParameters: () => [{ type: i1.BsModalRef }, { type: i2.RepositoryService }, { type: i3.AlertService }], propDecorators: { saved: [{
type: Output
}], dropdown: [{
type: ViewChild,
args: ['dropdown', { static: false }]
}], form: [{
type: ViewChild,
args: ['firmwarePatchForm', { static: false }]
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWRkLWZpcm13YXJlLXBhdGNoLW1vZGFsLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3JlcG9zaXRvcnkvZmlybXdhcmUvbGlzdC9hZGQtZmlybXdhcmUtcGF0Y2gtbW9kYWwuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vcmVwb3NpdG9yeS9maXJtd2FyZS9saXN0L2FkZC1maXJtd2FyZS1wYXRjaC1tb2RhbC5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFFLFlBQVksRUFBRSxNQUFNLEVBQUUsU0FBUyxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQzNFLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUV4QyxPQUFPLEVBQUUsWUFBWSxFQUFFLE9BQU8sRUFBZSxNQUFNLHFCQUFxQixDQUFDO0FBQ3pFLE9BQU8sRUFFTCxvQ0FBb0MsRUFFcEMsaUJBQWlCLEVBQ2pCLGNBQWMsRUFDZixNQUFNLHVDQUF1QyxDQUFDO0FBQy9DLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFDeEMsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDN0QsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQ2pELE9BQU8sRUFBRSxlQUFlLEVBQUUsSUFBSSxFQUFFLEtBQUssRUFBYyxFQUFFLEVBQUUsSUFBSSxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQzFFLE9BQU8sRUFDTCxZQUFZLEVBQ1osb0JBQW9CLEVBQ3BCLEdBQUcsRUFDSCxXQUFXLEVBQ1gsU0FBUyxFQUNULEdBQUcsRUFDSixNQUFNLGdCQUFnQixDQUFDOzs7Ozs7O0FBTXhCLE1BQU0sT0FBTyw4QkFBOEI7SUEwRXpDLFlBQ1UsS0FBaUIsRUFDakIsVUFBNkIsRUFDN0IsS0FBbUI7UUFGbkIsVUFBSyxHQUFM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QyxRQUFRLEVBQUUsQ0FBQztJQUN4QixDQUFDO0lBRUQsTUFBTSxDQUFDLE9BQW9CO1FBQ3pCLElBQUksQ0FBQyxXQUFXLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7WUFDOUIsSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLEdBQUc7Z0JBQ2xCLEdBQUcsRUFBRSxPQUFPLENBQUMsR0FBRzthQUNqQixDQUFDO1lBQ0YsT0FBTztRQUNULENBQUM7YUFBTSxJQUFJLE9BQU8sQ0FBQyxZQUFZLEVBQUUsQ0FBQztZQUNoQyxJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sR0FBRztnQkFDbEIsSUFBSSxFQUFFLE9BQU8sQ0FBQyxZQUFZLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSTthQUNuQyxDQUFDO1lBQ0YsT0FBTztRQUNULENBQUM7YUFBTSxDQUFDO1lBQ04sSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLEdBQUc7Z0JBQ2xCLElBQUksRUFBRSxTQUFTO2dCQUNmLEdBQUcsRUFBRSxTQUFTO2FBQ2YsQ0FBQztRQUNKLENBQUM7SUFDSCxDQUFDOytHQXZJVSw4QkFBOEI7bUdBQTlCLDhCQUE4Qiw2U0M1QjNDLCsyS0FvSkE7OzRGRHhIYSw4QkFBOEI7a0JBSjFDLFNBQVM7K0JBQ0Usd0NBQXdDOzBJQUt4QyxLQUFLO3NCQUFkLE1BQU07Z0JBRW1DLFFBQVE7c0JBQWpELFNBQVM7dUJBQUMsVUFBVSxFQUFFLEVBQUUsTUFBTSxFQUFFLEtBQUssRUFBRTtnQkFDVyxJQUFJO3NCQUF0RCxTQUFTO3VCQUFDLG1CQUFtQixFQUFFLEVBQUUsTUFBTSxFQUFFLEtBQUssRUFBRSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCwgRXZlbnRFbWl0dGVyLCBPdXRwdXQsIFZpZXdDaGlsZCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgTmdGb3JtIH0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xuaW1wb3J0IHsgSU1hbmFnZWRPYmplY3QsIElSZXN1bHRMaXN0IH0gZnJvbSAnQGM4eS9jbGllbnQnO1xuaW1wb3J0IHsgQWxlcnRTZXJ2aWNlLCBnZXR0ZXh0LCBQaWNrZWRGaWxlcyB9IGZyb20gJ0BjOHkvbmd4LWNvbXBvbmVudHMnO1xuaW1wb3J0IHtcbiAgTW9kYWxNb2RlbCxcbiAgUFJPRFVDVF9FWFBFUklFTkNFX1JFUE9TSVRPUllfU0hBUkVELFxuICBSZXBvc2l0b3J5Q2F0ZWdvcnksXG4gIFJlcG9zaXRvcnlTZXJ2aWNlLFxuICBSZXBvc2l0b3J5VHlwZVxufSBmcm9tICdAYzh5L25neC1jb21wb25lbnRzL3JlcG9zaXRvcnkvc2hhcmVkJztcbmltcG9ydCB7IGlzVW5kZWZpbmVkIH0gZnJvbSAnbG9kYXNoLWVzJztcbmltcG9ydCB7IEJzRHJvcGRvd25EaXJlY3RpdmUgfSBmcm9tICduZ3gtYm9vdHN0cmFwL2Ryb3Bkb3duJztcbmltcG9ydCB7IEJzTW9kYWxSZWYgfSBmcm9tICduZ3gtYm9vdHN0cmFwL21vZGFsJztcbmltcG9ydCB7IEJlaGF2aW9yU3ViamVjdCwgZnJvbSwgbWVyZ2UsIE9ic2VydmFibGUsIG9mLCBwaXBlIH0gZnJvbSAncnhqcyc7XG5pbXBvcnQge1xuICBkZWJvdW5jZVRpbWUsXG4gIGRpc3RpbmN0VW50aWxDaGFuZ2VkLFxuICBtYXAsXG4gIHNoYXJlUmVwbGF5LFxuICBzd2l0Y2hNYXAsXG4gIHRhcFxufSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ2M4eS1hZGQtZmlybXdhcmUtcGF0Y2gtbW9kYWwuY29tcG9uZW50JyxcbiAgdGVtcGxhdGVVcmw6ICdhZGQtZmlybXdhcmUtcGF0Y2gtbW9kYWwuY29tcG9uZW50Lmh0bWwnXG59KVxuZXhwb3J0IGNsYXNzIEFkZEZpcm13YXJlUGF0Y2hNb2RhbENvbXBvbmVudCB7XG4gIFBST0RVQ1RfRVhQRVJJRU5DRSA9IFBST0RVQ1RfRVhQRVJJRU5DRV9SRVBPU0lUT1JZX1NIQVJFRDtcbiAgQE91dHB1dCgpIHNhdmVkOiBFdmVudEVtaXR0ZXI8UmVwb3NpdG9yeUNhdGVnb3J5PiA9IG5ldyBFdmVudEVtaXR0ZXI8UmVwb3NpdG9yeUNhdGVnb3J5PigpO1xuXG4gIEBWaWV3Q2hpbGQoJ2Ryb3Bkb3duJywgeyBzdGF0aWM6IGZhbHNlIH0pIGRyb3Bkb3duOiBCc0Ryb3Bkb3duRGlyZWN0aXZlO1xuICBAVmlld0NoaWxkKCdmaXJtd2FyZVBhdGNoRm9ybScsIHsgc3RhdGljOiBmYWxzZSB9KSBmb3JtOiBOZ0Zvcm07XG4gIHRleHRGb3JGaXJtd2FyZVVybFBvcG92ZXI6IHN0cmluZyA9XG4gICAgZ2V0dGV4dChgUGF0aCBmb3IgYmluYXJpZXMgY2FuIHZhcnkgZGVwZW5kaW5nIG9uIGRldmljZSBhZ2VudCBpbXBsZW1lbnRhdGlvbiwgZm9yIGV4YW1wbGU6XG4gICAgL2Zpcm13YXJlL2JpbmFyaWVzL2Zpcm13YXJlMS5iaW5cbiAgICBodHRwczovL2Zpcm13YXJlL2JpbmFyeS8xMjNcbiAgICBmdHA6Ly9maXJtd2FyZS9iaW5hcnkvMTIzLnRhci5nelxuICBgKTtcblxuICBtb2RlbDogTW9kYWxNb2RlbCA9IHtcbiAgICBzZWxlY3RlZDogdW5kZWZpbmVkLFxuICAgIGRlcGVuZGVuY3k6IG51bGwsXG4gICAgcGF0Y2hWZXJzaW9uOiB1bmRlZmluZWQsXG4gICAgYmluYXJ5OiB7XG4gICAgICBmaWxlOiB1bmRlZmluZWQsXG4gICAgICB1cmw6IHVuZGVmaW5lZFxuICAgIH1cbiAgfTtcblxuICBmaXJtd2FyZUlucHV0JCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8c3RyaW5nPignJyk7XG4gIGZpcm13YXJlcyQ6IE9ic2VydmFibGU8SVJlc3VsdExpc3Q8SU1hbmFnZWRPYmplY3Q+PiA9IHRoaXMuZmlybXdhcmVJbnB1dCQucGlwZShcbiAgICBkZWJvdW5jZVRpbWUoMzAwKSxcbiAgICBkaXN0aW5jdFVudGlsQ2hhbmdlZCgpLFxuICAgIHN3aXRjaE1hcChzZWFyY2hTdHIgPT5cbiAgICAgIGZyb20oXG4gICAgICAgIHRoaXMucmVwb3NpdG9yeS5saXN0UmVwb3NpdG9yeUVudHJpZXMoUmVwb3NpdG9yeVR5cGUuRklSTVdBUkUsIHtcbiAgICAgICAgICBwYXJ0aWFsTmFtZTogc2VhcmNoU3RyLFxuICAgICAgICAgIHNraXBMZWdhY3k6IHRydWVcbiAgICAgICAgfSlcbiAgICAgIClcbiAgICApLFxuICAgIHNoYXJlUmVwbGF5KDEpXG4gICk7XG4gIGZpcm13YXJlU2VsZWN0ZWQkID0gbmV3IEJlaGF2aW9yU3ViamVjdDxQYXJ0aWFsPFJlcG9zaXRvcnlDYXRlZ29yeT4+KG51bGwpO1xuICBwYXRjaERlcGVuZGVuY3lJbnB1dCQgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PHN0cmluZz4oJycpO1xuXG4gIHNhdmluZyA9IGZhbHNlO1xuICBmaXJtd2FyZVByZXNlbGVjdGVkID0gZmFsc2U7XG4gIGJhc2VWZXJzaW9ucyQ6IE9ic2VydmFibGU8SVJlc3VsdExpc3Q8SU1hbmFnZWRPYmplY3Q+PiA9IG1lcmdlKFxuICAgIHRoaXMuZmlybXdhcmVJbnB1dCQucGlwZShcbiAgICAgIHRhcCgoKSA9PiB7XG4gICAgICAgIHRoaXMubW9kZWwuZGVwZW5kZW5jeSA9IG51bGw7XG4gICAgICAgIGlmICh0aGlzLmZvcm0pIHtcbiAgICAgICAgICB0aGlzLmZvcm0uZm9ybS5nZXQoJ3BhdGNoRGVwZW5kZW5jeScpLnJlc2V0KCk7XG4gICAgICAgIH1cbiAgICAgIH0pLFxuICAgICAgc3dpdGNoTWFwKCgpID0+IG9mKG51bGwpKVxuICAgICksXG4gICAgdGhpcy5maXJtd2FyZVNlbGVjdGVkJFxuICApLnBpcGUoXG4gICAgc3dpdGNoTWFwKHNlbGVjdGVkRmlybXdhcmUgPT5cbiAgICAgIHNlbGVjdGVkRmlybXdhcmUgPyB0aGlzLnJlcG9zaXRvcnkubGlzdEJhc2VWZXJzaW9ucyhzZWxlY3RlZEZpcm13YXJlKSA6IG9mKG51bGwpXG4gICAgKSxcbiAgICBzaGFyZVJlcGxheSgxKVxuICApO1xuICBiYXNlVmVyc2lvbnNGaWx0ZXJQaXBlID0gcGlwZShcbiAgICBzd2l0Y2hNYXAoKGRhdGE6IFtdKSA9PlxuICAgICAgdGhpcy5wYXRjaERlcGVuZGVuY3lJbnB1dCQucGlwZShcbiAgICAgICAgbWFwKHBhcnRpYWxWZXJzaW9uID0+XG4gICAgICAgICAgZGF0YS5maWx0ZXIoKG1vOiBhbnkpID0+IHtcbiAgICAgICAgICAgIGNvbnN0IHZlcnNpb24gPSBtby5jOHlfRmlybXdhcmUudmVyc2lvbj8udG9Mb3dlckNhc2UoKTtcbiAgICAgICAgICAgIHJldHVybiAoXG4gICAgICAgICAgICAgIHBhcnRpYWxWZXJzaW9uLmxlbmd0aCA9PT0gMCB8fCB2ZXJzaW9uPy5pbmRleE9mKHBhcnRpYWxWZXJzaW9uLnRvTG93ZXJDYXNlKCkpID4gLTFcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfSlcbiAgICAgICAgKVxuICAgICAgKVxuICAgIClcbiAgKTtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIG1vZGFsOiBCc01vZGFsUmVmLFxuICAgIHByaXZhdGUgcmVwb3NpdG9yeTogUmVwb3NpdG9yeVNlcnZpY2UsXG4gICAgcHJpdmF0ZSBhbGVydDogQWxlcnRTZXJ2aWNlXG4gICkge31cblxuICBhc3luYyBuZ09uSW5pdCgpIHtcbiAgICB0aGlzLnNldEluaXRpYWxTdGF0ZSgpO1xuICB9XG5cbiAgc2V0SW5pdGlhbFN0YXRlKCkge1xuICAgIGlmICh0aGlzLm1vZGVsLnNlbGVjdGVkKSB7XG4gICAgICB0aGlzLmZpcm13YXJlUHJlc2VsZWN0ZWQgPSB0cnVlO1xuICAgICAgdGhpcy5maXJtd2FyZVNlbGVjdGVkJC5uZXh0KHRoaXMubW9kZWwuc2VsZWN0ZWQpO1xuICAgIH1cbiAgfVxuXG4gIGFzeW5jIHNhdmUoKSB7XG4gICAgdGhpcy5zYXZpbmcgPSB0cnVlO1xuICAgIHRoaXMucmVwb3NpdG9yeVxuICAgICAgLmNyZWF0ZSh0aGlzLm1vZGVsLCBSZXBvc2l0b3J5VHlwZS5GSVJNV0FSRSlcbiAgICAgIC50aGVuKHNhdmVkRmlybXdhcmUgPT4ge1xuICAgICAgICB0aGlzLnN1Y2Nlc3NNc2coKTtcbiAgICAgICAgdGhpcy5zYXZpbmcgPSBmYWxzZTtcbiAgICAgICAgdGhpcy5zYXZlZC5uZXh0KHNhdmVkRmlybXdhcmUpO1xuICAgICAgICB0aGlzLmNhbmNlbCgpO1xuICAgICAgfSlcbiAgICAgIC5jYXRjaChlID0+IHtcbiAgICAgICAgdGhpcy5zYXZpbmcgPSBmYWxzZTtcbiAgICAgICAgdGhpcy5zYXZlZC5lcnJvcihlKTtcbiAgICAgICAgdGhpcy5jYW5jZWwoKTtcbiAgICAgIH0pO1xuICB9XG5cbiAgc3VjY2Vzc01zZygpIHtcbiAgICBjb25zdCBtc2cgPSBnZXR0ZXh0KCdGaXJtd2FyZSBwYXRjaCBhZGRlZC4nKTtcbiAgICB0aGlzLmFsZXJ0LnN1Y2Nlc3MobXNnKTtcbiAgfVxuXG4gIGNhbmNlbCgpIHtcbiAgICB0aGlzLm1vZGFsLmhpZGUoKTtcbiAgICB0aGlzLnNhdmVkLmNvbXBsZXRlKCk7XG4gIH1cblxuICBvbkZpbGUoZHJvcHBlZDogUGlja2VkRmlsZXMpIHtcbiAgICBpZiAoIWlzVW5kZWZpbmVkKGRyb3BwZWQudXJsKSkge1xuICAgICAgdGhpcy5tb2RlbC5iaW5hcnkgPSB7XG4gICAgICAgIHVybDogZHJvcHBlZC51cmxcbiAgICAgIH07XG4gICAgICByZXR1cm47XG4gICAgfSBlbHNlIGlmIChkcm9wcGVkLmRyb3BwZWRGaWxlcykge1xuICAgICAgdGhpcy5tb2RlbC5iaW5hcnkgPSB7XG4gICAgICAgIGZpbGU6IGRyb3BwZWQuZHJvcHBlZEZpbGVzWzBdLmZpbGVcbiAgICAgIH07XG4gICAgICByZXR1cm47XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMubW9kZWwuYmluYXJ5ID0ge1xuICAgICAgICBmaWxlOiB1bmRlZmluZWQsXG4gICAgICAgIHVybDogdW5kZWZpbmVkXG4gICAgICB9O1xuICAgIH1cbiAgfVxufVxuIiwiPGRpdiBjbGFzcz1cInZpZXdwb3J0LW1vZGFsXCI+XG4gIDxkaXYgY2xhc3M9XCJtb2RhbC1oZWFkZXIgZGlhbG9nLWhlYWRlclwiPlxuICAgIDxpIFtjOHlJY29uXT1cIidjOHktZmlybXdhcmUnXCI+PC9pPlxuICAgIDxoNCB0cmFuc2xhdGUgaWQ9XCJhZGRGaXJtd2FyZVBhdGNoTW9kYWxUaXRsZVwiPkFkZCBmaXJtd2FyZSBwYXRjaDwvaDQ+XG4gIDwvZGl2PlxuICA8ZGl2IGNsYXNzPVwicC0xNiB0ZXh0LWNlbnRlciBzZXBhcmF0b3ItYm90dG9tXCIgaWQ9XCJhZGRGaXJtd2FyZVBhdGNoTW9kYWxEZXNjcmlwdGlvblwiPlxuICAgIDxwIGNsYXNzPVwidGV4dC1tZWRpdW0gdGV4dC0xNiBtLTBcIiB0cmFuc2xhdGU+U2VsZWN0IGEgZmlybXdhcmUgdmVyc2lvbjwvcD5cbiAgPC9kaXY+XG5cbiAgPGZvcm1cbiAgICBjbGFzcz1cImQtY29udGVudHNcIlxuICAgIGF1dG9jb21wbGV0ZT1cIm9mZlwiXG4gICAgI2Zpcm13YXJlUGF0Y2hGb3JtPVwibmdGb3JtXCJcbiAgICAobmdTdWJtaXQpPVwiZmlybXdhcmVQYXRjaEZvcm0uZm9ybS52YWxpZCAmJiBzYXZlKClcIlxuICA+XG4gICAgPGRpdiBjbGFzcz1cIm1vZGFsLWlubmVyLXNjcm9sbFwiPlxuICAgICAgPGRpdiBjbGFzcz1cIm1vZGFsLWJvZHlcIj5cbiAgICAgICAgPGRpdiBbaGlkZGVuXT1cImZpcm13YXJlUHJlc2VsZWN0ZWRcIj5cbiAgICAgICAgICA8Yzh5LWZvcm0tZ3JvdXA+XG4gICAgICAgICAgICA8bGFiZWwgZm9yPVwiZmlybXdhcmVOYW1lXCIgdHJhbnNsYXRlPkZpcm13YXJlPC9sYWJlbD5cbiAgICAgICAgICAgIDxjOHktdHlwZWFoZWFkXG4gICAgICAgICAgICAgIFtuZ01vZGVsXT1cIm1vZGVsLnNlbGVjdGVkXCJcbiAgICAgICAgICAgICAgbmFtZT1cImZpcm13YXJlTmFtZVwiXG4gICAgICAgICAgICAgIHBsYWNlaG9sZGVyPVwie3sgJ1NlbGVjdCBvciBlbnRlcicgfCB0cmFuc2xhdGUgfX1cIlxuICAgICAgICAgICAgICAob25TZWFyY2gpPVwiZmlybXdhcmVJbnB1dCQubmV4dCgkZXZlbnQpXCJcbiAgICAgICAgICAgICAgW2FsbG93RnJlZUVudHJpZXNdPVwiZmFsc2VcIlxuICAgICAgICAgICAgICBbcmVxdWlyZWRdPVwidHJ1ZVwiXG4gICAgICAgICAgICA+XG4gICAgICAgICAgICAgIDxjOHktbGlcbiAgICAgICAgICAgICAgICAqYzh5Rm9yPVwibGV0IGZpcm13YXJlIG9mIGZpcm13YXJlcyQgfCBhc3luYzsgbG9hZE1vcmU6ICdhdXRvJ1wiXG4gICAgICAgICAgICAgICAgY2xhc3M9XCJwLWwtOCBwLXItOCBjOHktbGlzdF9faXRlbS0tbGlua1wiXG4gICAgICAgICAgICAgICAgKGNsaWNrKT1cIm1vZGVsLnNlbGVjdGVkID0gZmlybXdhcmU7IGZpcm13YXJlU2VsZWN0ZWQkLm5leHQoZmlybXdhcmUpXCJcbiAgICAgICAgICAgICAgICBbYWN0aXZlXT1cIm1vZGVsLnNlbGVjdGVkID09PSBmaXJtd2FyZVwiXG4gICAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgICA8Yzh5LWhpZ2hsaWdodFxuICAgICAgICAgICAgICAgICAgW3RleHRdPVwiZmlybXdhcmUubmFtZSB8fCAnLS0nXCJcbiAgICAgICAgICAgICAgICAgIFtwYXR0ZXJuXT1cImZpcm13YXJlSW5wdXQkIHwgYXN5bmNcIlxuICAgICAgICAgICAgICAgID48L2M4eS1oaWdobGlnaHQ+XG4gICAgICAgICAgICAgIDwvYzh5LWxpPlxuICAgICAgICAgICAgPC9jOHktdHlwZWFoZWFkPlxuICAgICAgICAgICAgPGM4eS1tZXNzYWdlcz5cbiAgICAgICAgICAgICAgPGM4eS1tZXNzYWdlXG4gICAgICAgICAgICAgICAgbmFtZT1cIm5vdEV4aXN0aW5nXCJcbiAgICAgICAgICAgICAgICBbdGV4dF09XCInU2VsZWN0IG9uZSBvZiB0aGUgZXhpc3RpbmcgZmlybXdhcmVzLicgfCB0cmFuc2xhdGVcIlxuICAgICAgICAgICAgICA+PC9jOHktbWVzc2FnZT5cbiAgICAgICAgICAgIDwvYzh5LW1lc3NhZ2VzPlxuICAgICAgICAgIDwvYzh5LWZvcm0tZ3JvdXA+XG4gICAgICAgIDwvZGl2PlxuXG4gICAgICAgIDxjOHktZm9ybS1ncm91cD5cbiAgICAgICAgICA8bGFiZWwgZm9yPVwicGF0Y2hEZXBlbmRlbmN5XCIgY2xhc3M9XCJtLXItOFwiIHRyYW5zbGF0ZT5WZXJzaW9uPC9sYWJlbD5cbiAgICAgICAgICA8Yzh5LXR5cGVhaGVhZFxuICAgICAgICAgICAgW25nTW9kZWxdPVwibW9kZWwuZGVwZW5kZW5jeVwiXG4gICAgICAgICAgICBuYW1lPVwicGF0Y2hEZXBlbmRlbmN5XCJcbiAgICAgICAgICAgIGRhdGEtY3k9XCJhZGQtZmlybXdhcmUtcGF0Y2gtbW9kYWwtLXBhdGNoRGVwZW5kZW5jeVwiXG4gICAgICAgICAgICBwbGFjZWhvbGRlcj1cInt7ICdTZWxlY3Qgb3IgZW50ZXInIHwgdHJhbnNsYXRlIH19XCJcbiAgICAgICAgICAgIChvblNlYXJjaCk9XCJwYXRjaERlcGVuZGVuY3lJbnB1dCQubmV4dCgkZXZlbnQpXCJcbiAgICAgICAgICAgIFtkaXNwbGF5UHJvcGVydHldPVwiJ2M4eV9GaXJtd2FyZS52ZXJzaW9uJ1wiXG4gICAgICAgICAgICBbYWxsb3dGcmVlRW50cmllc109XCJmYWxzZVwiXG4gICAgICAgICAgICBbZGlzYWJsZWRdPVwiXG4gICAgICAgICAgICAgIChiYXNlVmVyc2lvbnMkIHwgYXN5bmMpID09PSBudWxsIHx8IChiYXNlVmVyc2lvbnMkIHwgYXN5bmMpPy5kYXRhLmxlbmd0aCA9PT0gMFxuICAgICAgICAgICAgXCJcbiAgICAgICAgICAgIFtyZXF1aXJlZF09XCJ0cnVlXCJcbiAgICAgICAgICA+XG4gICAgICAgICAgICA8Yzh5LWxpXG4gICAgICAgICAgICAgICpjOHlGb3I9XCJcbiAgICAgICAgICAgICAgICBsZXQgYmFzZVZlcnNpb24gb2YgYmFzZVZlcnNpb25zJDtcbiAgICAgICAgICAgICAgICBsb2FkTW9yZTogJ2F1dG8nO1xuICAgICAgICAgICAgICAgIHBpcGU6IGJhc2VWZXJzaW9uc0ZpbHRlclBpcGVcbiAgICAgICAgICAgICAgXCJcbiAgICAgICAgICAgICAgY2xhc3M9XCJwLWwtOCBwLXItOCBjOHktbGlzdF9faXRlbS0tbGlua1wiXG4gICAgICAgICAgICAgIChjbGljayk9XCJtb2RlbC5kZXBlbmRlbmN5ID0gYmFzZVZlcnNpb25cIlxuICAgICAgICAgICAgICBbYWN0aXZlXT1cIm1vZGVsLmRlcGVuZGVuY3kgPT09IGJhc2VWZXJzaW9uXCJcbiAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgPGM4eS1oaWdobGlnaHRcbiAgICAgICAgICAgICAgICBbdGV4dF09XCJiYXNlVmVyc2lvbi5jOHlfRmlybXdhcmUudmVyc2lvbiB8fCAnLS0nXCJcbiAgICAgICAgICAgICAgICBbcGF0dGVybl09XCJwYXRjaERlcGVuZGVuY3lJbnB1dCQgfCBhc3luY1wiXG4gICAgICAgICAgICAgID48L2M4eS1oaWdobGlnaHQ+XG4gICAgICAgICAgICA8L2M4eS1saT5cbiAgICAgICAgICA8L2M4eS10eXBlYWhlYWQ+XG4gICAgICAgICAgPGM4eS1tZXNzYWdlcz5cbiAgICAgICAgICAgIDxjOHktbWVzc2FnZVxuICAgICAgICAgICAgICBuYW1lPVwibm90RXhpc3RpbmdcIlxuICAgICAgICAgICAgICBbdGV4dF09XCInU2VsZWN0IG9uZSBvZiB0aGUgZXhpc3RpbmcgdmVyc2lvbnMuJyB8IHRyYW5zbGF0ZVwiXG4gICAgICAgICAgICA+PC9jOHktbWVzc2FnZT5cbiAgICAgICAgICA8L2M4eS1tZXNzYWdlcz5cbiAgICAgICAgPC9jOHktZm9ybS1ncm91cD5cblxuICAgICAgICA8Yzh5LWZvcm0tZ3JvdXA+XG4gICAgICAgICAgPGxhYmVsIGZvcj1cInBhdGNoVmVyc2lvblwiIHRyYW5zbGF0ZT5QYXRjaDwvbGFiZWw+XG4gICAgICAgICAgPGlucHV0XG4gICAgICAgICAgICBpZD1cInBhdGNoVmVyc2lvblwiXG4gICAgICAgICAgICBjbGFzcz1cImZvcm0tY29udHJvbFwiXG4gICAgICAgICAgICBhdXRvY29tcGxldGU9XCJvZmZcIlxuICAgICAgICAgICAgbmFtZT1cInBhdGNoVmVyc2lvblwiXG4gICAgICAgICAgICBkYXRhLWN5PVwiYWRkLWZpcm13YXJlLXBhdGNoLW1vZGFsLS1wYXRjaFZlcnNpb25cIlxuICAgICAgICAgICAgWyhuZ01vZGVsKV09XCJtb2RlbC5wYXRjaFZlcnNpb25cIlxuICAgICAgICAgICAgcGxhY2Vob2xkZXI9XCJ7eyAnZS5nLicgfCB0cmFuc2xhdGUgfX0gMS4wLjBcIlxuICAgICAgICAgICAgcmVxdWlyZWRcbiAgICAgICAgICAvPlxuICAgICAgICA8L2M4eS1mb3JtLWdyb3VwPlxuXG4gICAgICAgIDxjOHktZm9ybS1ncm91cD5cbiAgICAgICAgICA8ZGl2IGNsYXNzPVwibGVnZW5kIGZvcm0tYmxvY2sgbS10LTQwXCIgdHJhbnNsYXRlPlBhdGNoIGZpbGU8L2Rpdj5cbiAgICAgICAgICA8Yzh5LWZpbGUtcGlja2VyXG4gICAgICAgICAgICBbbWF4QWxsb3dlZEZpbGVzXT1cIjFcIlxuICAgICAgICAgICAgKG9uRmlsZXNQaWNrZWQpPVwib25GaWxlKCRldmVudClcIlxuICAgICAgICAgICAgW2ZpbGVVcmxQb3BvdmVyXT1cInRleHRGb3JGaXJtd2FyZVVybFBvcG92ZXJcIlxuICAgICAgICAgID48L2M4eS1maWxlLXBpY2tlcj5cbiAgICAgICAgPC9jOHktZm9ybS1ncm91cD5cbiAgICAgIDwvZGl2PlxuICAgIDwvZGl2PlxuICAgIDxkaXYgY2xhc3M9XCJtb2RhbC1mb290ZXJcIj5cbiAgICAgIDxidXR0b25cbiAgICAgICAgdGl0bGU9XCJ7eyAnQ2FuY2VsJyB8IHRyYW5zbGF0ZSB9fVwiXG4gICAgICAgIGRhdGEtY3k9XCJhZGQtZmlybXdhcmUtcGF0Y2gtbW9kYWwtLWNhbmNlbC1idG5cIlxuICAgICAgICBjbGFzcz1cImJ0biBidG4tZGVmYXVsdFwiXG4gICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICAoY2xpY2spPVwiY2FuY2VsKClcIlxuICAgICAgICBbZGlzYWJsZWRdPVwic2F2aW5nXCJcbiAgICAgICAgdHJhbnNsYXRlXG4gICAgICA+XG4gICAgICAgIENhbmNlbFxuICAgICAgPC9idXR0b24+XG4gICAgICA8YnV0dG9uXG4gICAgICAgIHRpdGxlPVwie3sgJ0FkZCBmaXJtd2FyZSBwYXRjaCcgfCB0cmFuc2xhdGUgfX1cIlxuICAgICAgICBjbGFzcz1cImJ0biBidG4tcHJpbWFyeVwiXG4gICAgICAgIHR5cGU9XCJzdWJtaXRcIlxuICAgICAgICBbbmdDbGFzc109XCJ7ICdidG4tcGVuZGluZyc6IHNhdmluZyB9XCJcbiAgICAgICAgW2Rpc2FibGVkXT1cIlxuICAgICAgICAgICFmaXJtd2FyZVBhdGNoRm9ybS5mb3JtLnZhbGlkIHx8XG4gICAgICAgICAgZmlybXdhcmVQYXRjaEZvcm0uZm9ybS5wcmlzdGluZSB8fFxuICAgICAgICAgICghbW9kZWwuYmluYXJ5Py51cmwgJiYgIW1vZGVsLmJpbmFyeT8uZmlsZSkgfHxcbiAgICAgICAgICBzYXZpbmdcbiAgICAgICAgXCJcbiAgICAgICAgdHJhbnNsYXRlXG4gICAgICAgIGM4eVByb2R1Y3RFeHBlcmllbmNlXG4gICAgICAgIFthY3Rpb25OYW1lXT1cIlBST0RVQ1RfRVhQRVJJRU5DRS5GSVJNV0FSRS5FVkVOVFMuUkVQT1NJVE9SWVwiXG4gICAgICAgIFthY3Rpb25EYXRhXT1cIntcbiAgICAgICAgICBjb21wb25lbnQ6IFBST0RVQ1RfRVhQRVJJRU5DRS5GSVJNV0FSRS5DT01QT05FTlRTLkFERF9GSVJNV0FSX1BBVENIX01PREFMLFxuICAgICAgICAgIHJlc3VsdDogUFJPRFVDVF9FWFBFUklFTkNFLkZJUk1XQVJFLlJFU1VMVFMuQUREX0ZJUk1XQVJFX1BBVENIXG4gICAgICAgIH1cIlxuICAgICAgPlxuICAgICAgICBBZGQgZmlybXdhcmUgcGF0Y2hcbiAgICAgIDwvYnV0dG9uPlxuICAgIDwvZGl2PlxuICA8L2Zvcm0+XG48L2Rpdj5cbiJdfQ==