UNPKG

@c8y/ngx-components

Version:

Angular modules for Cumulocity IoT applications

138 lines 41.7 kB
import { Component, EventEmitter, Output, ViewChild } from '@angular/core'; import { NgForm } from '@angular/forms'; import { AlertService, gettext, ValidationPattern } from '@c8y/ngx-components'; import { PRODUCT_EXPERIENCE_REPOSITORY_SHARED, RepositoryService, RepositoryType } from '@c8y/ngx-components/repository/shared'; import { assign, get, isUndefined } from 'lodash-es'; import { BsModalRef } from 'ngx-bootstrap/modal'; import { BehaviorSubject, from } from 'rxjs'; import { debounceTime, distinctUntilChanged, 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"; import * as i6 from "ngx-bootstrap/popover"; export class AddFirmwareModalComponent { constructor(modal, repositoryService, alert) { this.modal = modal; this.repositoryService = repositoryService; this.alert = alert; this.PRODUCT_EXPERIENCE = PRODUCT_EXPERIENCE_REPOSITORY_SHARED; this.saved = new EventEmitter(); this.onInput = new BehaviorSubject(''); this.model = { selected: undefined, version: undefined, description: undefined, deviceType: undefined, binary: { file: undefined, url: undefined } }; this.saving = false; this.firmwarePreselected = false; 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.ValidationPattern = ValidationPattern; } ngOnInit() { this.setInitialState(); this.loadFirmwares(); } setInitialState() { if (this.model.selected) { this.firmwarePreselected = true; } } loadFirmwares() { this.inputSubscription$ = this.onInput .pipe(tap(() => { if (!this.firmwarePreselected) { this.model.description = null; if (this.form) { this.form.form.get('description').reset(); } } }), debounceTime(300), distinctUntilChanged(), switchMap(searchStr => this.getFirmwareResult(searchStr))) .subscribe(result => { this.firmwaresResult = result; }); } getFirmwareResult(searchStr) { return from(this.repositoryService.listRepositoryEntries(RepositoryType.FIRMWARE, { partialName: searchStr, skipLegacy: true })); } async save() { this.saving = true; this.repositoryService .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 added.'); this.alert.success(msg); } cancel() { this.modal.hide(); this.saved.complete(); } ngOnDestroy() { this.inputSubscription$.unsubscribe(); } 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 }; } } onFirmwareSelect(firmware) { assign(this.model, { selected: firmware, description: firmware.description, deviceType: get(firmware, 'c8y_Filter.type') }); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AddFirmwareModalComponent, 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: AddFirmwareModalComponent, selector: "c8y-add-firmware-software-modal", outputs: { saved: "saved" }, viewQueries: [{ propertyName: "form", first: true, predicate: ["firmwareForm"], descendants: true }], ngImport: i0, template: "<div class=\"viewport-modal\">\n <div class=\"modal-header dialog-header\">\n <i [c8yIcon]=\"'c8y-firmware'\"></i>\n <div class=\"modal-title\" translate id=\"addFirmwareModalTitle\">Add firmware</div>\n </div>\n <div class=\"p-16 text-center separator-bottom\" *ngIf=\"!firmwarePreselected\">\n <p class=\"text-medium text-16 m-0\" translate>Select or create new firmware</p>\n </div>\n <form\n class=\"d-contents\"\n autocomplete=\"off\"\n #firmwareForm=\"ngForm\"\n (ngSubmit)=\"firmwareForm.form.valid && save()\"\n >\n <div class=\"modal-inner-scroll\">\n <div class=\"modal-body\" id=\"addFirmwareModalDescription\">\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 data-cy=\"add-firmware-modal--input-name\"\n (onSearch)=\"onInput.next($event)\"\n [required]=\"true\"\n >\n <c8y-li\n *c8yFor=\"\n let firmware of firmwaresResult;\n loadMore: 'auto';\n notFound: notFoundTemplate\n \"\n class=\"p-l-8 p-r-8 c8y-list__item--link\"\n (click)=\"onFirmwareSelect(firmware)\"\n [active]=\"model.selected === firmware\"\n >\n <c8y-highlight\n [text]=\"firmware.name || '--'\"\n [pattern]=\"onInput | async\"\n ></c8y-highlight>\n </c8y-li>\n <ng-template #notFoundTemplate>\n <c8y-li class=\"bg-level-2 p-8\" *ngIf=\"(onInput | async)?.length > 0\">\n <span translate>No match found.</span>\n <button\n class=\"btn btn-primary btn-xs m-l-8\"\n type=\"button\"\n title=\"{{ 'Add new`firmware`' | translate }}\"\n translate\n >\n Add new`firmware`\n </button>\n </c8y-li>\n </ng-template>\n </c8y-typeahead>\n </c8y-form-group>\n\n <c8y-form-group>\n <label for=\"firmwareDescription\" translate>Description</label>\n <input\n id=\"firmwareDescription\"\n data-cy=\"add-firmware-modal--input-description\"\n class=\"form-control\"\n autocomplete=\"off\"\n name=\"description\"\n [(ngModel)]=\"model.description\"\n placeholder=\"{{ 'e.g. Firmware for hardware revision B' | translate }}\"\n [disabled]=\"model.selected?.id\"\n [required]=\"true\"\n [pattern]=\"ValidationPattern.rules.noWhiteSpaceOnly.pattern\"\n />\n </c8y-form-group>\n\n <c8y-form-group>\n <label class=\"control-label\" for=\"firmwareDeviceTypeFilter\">\n {{ 'Device type filter' | translate }}\n <button\n class=\"btn-help\"\n type=\"button\"\n [attr.aria-label]=\"'Help' | translate\"\n popover=\"{{\n 'If the filter is set, the firmware will show up for installation only for devices of that type. If no filter is set, it will be available for all devices.'\n | translate\n }}\"\n triggers=\"focus\"\n placement=\"right\"\n container=\"body\"\n ></button>\n </label>\n <input\n id=\"firmwareDeviceTypeFilter\"\n data-cy=\"add-firmware-modal--firmwareDeviceTypeFilter\"\n class=\"form-control\"\n name=\"firmwareDeviceTypeFilter\"\n [(ngModel)]=\"model.deviceType\"\n placeholder=\"{{ 'e.g.' | translate }} c8y_Linux\"\n [disabled]=\"model.selected?.id\"\n [pattern]=\"ValidationPattern.rules.noWhiteSpaceOnly.pattern\"\n />\n </c8y-form-group>\n </div>\n\n <c8y-form-group>\n <label for=\"firmwareVersion\" translate>Version</label>\n <input\n id=\"firmwareVersion\"\n data-cy=\"add-firmware-modal--firmwareVersion\"\n class=\"form-control\"\n autocomplete=\"off\"\n name=\"version\"\n [(ngModel)]=\"model.version\"\n placeholder=\"{{ 'e.g.' | translate }} 1.0.0\"\n [required]=\"true\"\n [pattern]=\"ValidationPattern.rules.noWhiteSpaceOnly.pattern\"\n />\n </c8y-form-group>\n\n <c8y-form-group>\n <div class=\"legend form-block m-t-40\" translate>Firmware 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 class=\"btn btn-default\"\n type=\"button\"\n title=\"{{ 'Cancel' | translate }}\"\n data-cy=\"add-firmware-modal--cancel-btn\"\n (click)=\"cancel()\"\n [disabled]=\"saving\"\n translate\n >\n Cancel\n </button>\n\n <button\n class=\"btn btn-primary\"\n type=\"submit\"\n title=\"{{ 'Add firmware' | translate }}\"\n [ngClass]=\"{ 'btn-pending': saving }\"\n [disabled]=\"\n !firmwareForm.form.valid ||\n firmwareForm.form.pristine ||\n saving ||\n (!model.binary?.url && !model.binary?.file)\n \"\n [actionName]=\"PRODUCT_EXPERIENCE.FIRMWARE.EVENTS.REPOSITORY\"\n [actionData]=\"{\n component: PRODUCT_EXPERIENCE.FIRMWARE.COMPONENTS.ADD_FIRMWARE_MODAL,\n result:\n firmwarePreselected || model.selected?.id\n ? PRODUCT_EXPERIENCE.FIRMWARE.RESULTS.ADD_FIRMWARE_VERSION\n : PRODUCT_EXPERIENCE.FIRMWARE.RESULTS.ADD_FIRMWARE\n }\"\n translate\n c8yProductExperience\n >\n Add firmware\n </button>\n </div>\n </form>\n</div>\n", dependencies: [{ kind: "directive", type: i4.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { 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.PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }, { 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.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: "directive", type: i6.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: i4.AsyncPipe, name: "async" }, { kind: "pipe", type: i3.C8yTranslatePipe, name: "translate" }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: AddFirmwareModalComponent, decorators: [{ type: Component, args: [{ selector: 'c8y-add-firmware-software-modal', template: "<div class=\"viewport-modal\">\n <div class=\"modal-header dialog-header\">\n <i [c8yIcon]=\"'c8y-firmware'\"></i>\n <div class=\"modal-title\" translate id=\"addFirmwareModalTitle\">Add firmware</div>\n </div>\n <div class=\"p-16 text-center separator-bottom\" *ngIf=\"!firmwarePreselected\">\n <p class=\"text-medium text-16 m-0\" translate>Select or create new firmware</p>\n </div>\n <form\n class=\"d-contents\"\n autocomplete=\"off\"\n #firmwareForm=\"ngForm\"\n (ngSubmit)=\"firmwareForm.form.valid && save()\"\n >\n <div class=\"modal-inner-scroll\">\n <div class=\"modal-body\" id=\"addFirmwareModalDescription\">\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 data-cy=\"add-firmware-modal--input-name\"\n (onSearch)=\"onInput.next($event)\"\n [required]=\"true\"\n >\n <c8y-li\n *c8yFor=\"\n let firmware of firmwaresResult;\n loadMore: 'auto';\n notFound: notFoundTemplate\n \"\n class=\"p-l-8 p-r-8 c8y-list__item--link\"\n (click)=\"onFirmwareSelect(firmware)\"\n [active]=\"model.selected === firmware\"\n >\n <c8y-highlight\n [text]=\"firmware.name || '--'\"\n [pattern]=\"onInput | async\"\n ></c8y-highlight>\n </c8y-li>\n <ng-template #notFoundTemplate>\n <c8y-li class=\"bg-level-2 p-8\" *ngIf=\"(onInput | async)?.length > 0\">\n <span translate>No match found.</span>\n <button\n class=\"btn btn-primary btn-xs m-l-8\"\n type=\"button\"\n title=\"{{ 'Add new`firmware`' | translate }}\"\n translate\n >\n Add new`firmware`\n </button>\n </c8y-li>\n </ng-template>\n </c8y-typeahead>\n </c8y-form-group>\n\n <c8y-form-group>\n <label for=\"firmwareDescription\" translate>Description</label>\n <input\n id=\"firmwareDescription\"\n data-cy=\"add-firmware-modal--input-description\"\n class=\"form-control\"\n autocomplete=\"off\"\n name=\"description\"\n [(ngModel)]=\"model.description\"\n placeholder=\"{{ 'e.g. Firmware for hardware revision B' | translate }}\"\n [disabled]=\"model.selected?.id\"\n [required]=\"true\"\n [pattern]=\"ValidationPattern.rules.noWhiteSpaceOnly.pattern\"\n />\n </c8y-form-group>\n\n <c8y-form-group>\n <label class=\"control-label\" for=\"firmwareDeviceTypeFilter\">\n {{ 'Device type filter' | translate }}\n <button\n class=\"btn-help\"\n type=\"button\"\n [attr.aria-label]=\"'Help' | translate\"\n popover=\"{{\n 'If the filter is set, the firmware will show up for installation only for devices of that type. If no filter is set, it will be available for all devices.'\n | translate\n }}\"\n triggers=\"focus\"\n placement=\"right\"\n container=\"body\"\n ></button>\n </label>\n <input\n id=\"firmwareDeviceTypeFilter\"\n data-cy=\"add-firmware-modal--firmwareDeviceTypeFilter\"\n class=\"form-control\"\n name=\"firmwareDeviceTypeFilter\"\n [(ngModel)]=\"model.deviceType\"\n placeholder=\"{{ 'e.g.' | translate }} c8y_Linux\"\n [disabled]=\"model.selected?.id\"\n [pattern]=\"ValidationPattern.rules.noWhiteSpaceOnly.pattern\"\n />\n </c8y-form-group>\n </div>\n\n <c8y-form-group>\n <label for=\"firmwareVersion\" translate>Version</label>\n <input\n id=\"firmwareVersion\"\n data-cy=\"add-firmware-modal--firmwareVersion\"\n class=\"form-control\"\n autocomplete=\"off\"\n name=\"version\"\n [(ngModel)]=\"model.version\"\n placeholder=\"{{ 'e.g.' | translate }} 1.0.0\"\n [required]=\"true\"\n [pattern]=\"ValidationPattern.rules.noWhiteSpaceOnly.pattern\"\n />\n </c8y-form-group>\n\n <c8y-form-group>\n <div class=\"legend form-block m-t-40\" translate>Firmware 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 class=\"btn btn-default\"\n type=\"button\"\n title=\"{{ 'Cancel' | translate }}\"\n data-cy=\"add-firmware-modal--cancel-btn\"\n (click)=\"cancel()\"\n [disabled]=\"saving\"\n translate\n >\n Cancel\n </button>\n\n <button\n class=\"btn btn-primary\"\n type=\"submit\"\n title=\"{{ 'Add firmware' | translate }}\"\n [ngClass]=\"{ 'btn-pending': saving }\"\n [disabled]=\"\n !firmwareForm.form.valid ||\n firmwareForm.form.pristine ||\n saving ||\n (!model.binary?.url && !model.binary?.file)\n \"\n [actionName]=\"PRODUCT_EXPERIENCE.FIRMWARE.EVENTS.REPOSITORY\"\n [actionData]=\"{\n component: PRODUCT_EXPERIENCE.FIRMWARE.COMPONENTS.ADD_FIRMWARE_MODAL,\n result:\n firmwarePreselected || model.selected?.id\n ? PRODUCT_EXPERIENCE.FIRMWARE.RESULTS.ADD_FIRMWARE_VERSION\n : PRODUCT_EXPERIENCE.FIRMWARE.RESULTS.ADD_FIRMWARE\n }\"\n translate\n c8yProductExperience\n >\n Add firmware\n </button>\n </div>\n </form>\n</div>\n" }] }], ctorParameters: () => [{ type: i1.BsModalRef }, { type: i2.RepositoryService }, { type: i3.AlertService }], propDecorators: { form: [{ type: ViewChild, args: ['firmwareForm', { static: false }] }], saved: [{ type: Output }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWRkLWZpcm13YXJlLW1vZGFsLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3JlcG9zaXRvcnkvZmlybXdhcmUvbGlzdC9hZGQtZmlybXdhcmUtbW9kYWwuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vLi4vcmVwb3NpdG9yeS9maXJtd2FyZS9saXN0L2FkZC1maXJtd2FyZS1tb2RhbC5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFFLFlBQVksRUFBRSxNQUFNLEVBQUUsU0FBUyxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQzNFLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUV4QyxPQUFPLEVBQUUsWUFBWSxFQUFFLE9BQU8sRUFBZSxpQkFBaUIsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQzVGLE9BQU8sRUFFTCxvQ0FBb0MsRUFFcEMsaUJBQWlCLEVBQ2pCLGNBQWMsRUFDZixNQUFNLHVDQUF1QyxDQUFDO0FBQy9DLE9BQU8sRUFBRSxNQUFNLEVBQUUsR0FBRyxFQUFFLFdBQVcsRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUNyRCxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDakQsT0FBTyxFQUFFLGVBQWUsRUFBRSxJQUFJLEVBQWdCLE1BQU0sTUFBTSxDQUFDO0FBQzNELE9BQU8sRUFBRSxZQUFZLEVBQUUsb0JBQW9CLEVBQUUsU0FBUyxFQUFFLEdBQUcsRUFBRSxNQUFNLGdCQUFnQixDQUFDOzs7Ozs7OztBQU1wRixNQUFNLE9BQU8seUJBQXlCO0lBMkJwQyxZQUNVLEtBQWlCLEVBQ2pCLGlCQUFvQyxFQUNwQyxLQUFtQjtRQUZuQixVQUFLLEdBQUwsS0FBSyxDQUFZO1FBQ2pCLHNCQUFpQixHQUFqQixpQkFBaUIsQ0FBbUI7UUFDcEMsVUFBSyxHQUFMLEtBQUssQ0FBYztRQTdCN0IsdUJB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QUUsR0FBRyxDQUFDLFFBQVEsRUFBRSxpQkFBaUIsQ0FBQztTQUM3QyxDQUFDLENBQUM7SUFDTCxDQUFDOytHQWpJVSx5QkFBeUI7bUdBQXpCLHlCQUF5QiwwTUNwQnRDLG0wTUF3S0E7OzRGRHBKYSx5QkFBeUI7a0JBSnJDLFNBQVM7K0JBQ0UsaUNBQWlDOzBJQUtHLElBQUk7c0JBQWpELFNBQVM7dUJBQUMsY0FBYyxFQUFFLEVBQUUsTUFBTSxFQUFFLEtBQUssRUFBRTtnQkFDbEMsS0FBSztzQkFBZCxNQUFNIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29tcG9uZW50LCBFdmVudEVtaXR0ZXIsIE91dHB1dCwgVmlld0NoaWxkIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBOZ0Zvcm0gfSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XG5pbXBvcnQgeyBJTWFuYWdlZE9iamVjdCB9IGZyb20gJ0BjOHkvY2xpZW50JztcbmltcG9ydCB7IEFsZXJ0U2VydmljZSwgZ2V0dGV4dCwgUGlja2VkRmlsZXMsIFZhbGlkYXRpb25QYXR0ZXJuIH0gZnJvbSAnQGM4eS9uZ3gtY29tcG9uZW50cyc7XG5pbXBvcnQge1xuICBNb2RhbE1vZGVsLFxuICBQUk9EVUNUX0VYUEVSSUVOQ0VfUkVQT1NJVE9SWV9TSEFSRUQsXG4gIFJlcG9zaXRvcnlDYXRlZ29yeSxcbiAgUmVwb3NpdG9yeVNlcnZpY2UsXG4gIFJlcG9zaXRvcnlUeXBlXG59IGZyb20gJ0BjOHkvbmd4LWNvbXBvbmVudHMvcmVwb3NpdG9yeS9zaGFyZWQnO1xuaW1wb3J0IHsgYXNzaWduLCBnZXQsIGlzVW5kZWZpbmVkIH0gZnJvbSAnbG9kYXNoLWVzJztcbmltcG9ydCB7IEJzTW9kYWxSZWYgfSBmcm9tICduZ3gtYm9vdHN0cmFwL21vZGFsJztcbmltcG9ydCB7IEJlaGF2aW9yU3ViamVjdCwgZnJvbSwgU3Vic2NyaXB0aW9uIH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyBkZWJvdW5jZVRpbWUsIGRpc3RpbmN0VW50aWxDaGFuZ2VkLCBzd2l0Y2hNYXAsIHRhcCB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcblxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnYzh5LWFkZC1maXJtd2FyZS1zb2Z0d2FyZS1tb2RhbCcsXG4gIHRlbXBsYXRlVXJsOiAnYWRkLWZpcm13YXJlLW1vZGFsLmNvbXBvbmVudC5odG1sJ1xufSlcbmV4cG9ydCBjbGFzcyBBZGRGaXJtd2FyZU1vZGFsQ29tcG9uZW50IHtcbiAgUFJPRFVDVF9FWFBFUklFTkNFID0gUFJPRFVDVF9FWFBFUklFTkNFX1JFUE9TSVRPUllfU0hBUkVEO1xuICBAVmlld0NoaWxkKCdmaXJtd2FyZUZvcm0nLCB7IHN0YXRpYzogZmFsc2UgfSkgZm9ybTogTmdGb3JtO1xuICBAT3V0cHV0KCkgc2F2ZWQ6IEV2ZW50RW1pdHRlcjxSZXBvc2l0b3J5Q2F0ZWdvcnk+ID0gbmV3IEV2ZW50RW1pdHRlcjxSZXBvc2l0b3J5Q2F0ZWdvcnk+KCk7XG4gIG9uSW5wdXQ6IEJlaGF2aW9yU3ViamVjdDxzdHJpbmc+ID0gbmV3IEJlaGF2aW9yU3ViamVjdDxzdHJpbmc+KCcnKTtcbiAgbW9kZWw6IE1vZGFsTW9kZWwgPSB7XG4gICAgc2VsZWN0ZWQ6IHVuZGVmaW5lZCxcbiAgICB2ZXJzaW9uOiB1bmRlZmluZWQsXG4gICAgZGVzY3JpcHRpb246IHVuZGVmaW5lZCxcbiAgICBkZXZpY2VUeXBlOiB1bmRlZmluZWQsXG4gICAgYmluYXJ5OiB7XG4gICAgICBmaWxlOiB1bmRlZmluZWQsXG4gICAgICB1cmw6IHVuZGVmaW5lZFxuICAgIH1cbiAgfTtcbiAgZmlybXdhcmVzUmVzdWx0O1xuICBzYXZpbmcgPSBmYWxzZTtcbiAgZmlybXdhcmVQcmVzZWxlY3RlZCA9IGZhbHNlO1xuICB0ZXh0Rm9yRmlybXdhcmVVcmxQb3BvdmVyOiBzdHJpbmcgPVxuICAgIGdldHRleHQoYFBhdGggZm9yIGJpbmFyaWVzIGNhbiB2YXJ5IGRlcGVuZGluZyBvbiBkZXZpY2UgYWdlbnQgaW1wbGVtZW50YXRpb24sIGZvciBleGFtcGxlOlxuICAgIC9maXJtd2FyZS9iaW5hcmllcy9maXJtd2FyZTEuYmluXG4gICAgaHR0cHM6Ly9maXJtd2FyZS9iaW5hcnkvMTIzXG4gICAgZnRwOi8vZmlybXdhcmUvYmluYXJ5LzEyMy50YXIuZ3pcbiAgYCk7XG4gIFZhbGlkYXRpb25QYXR0ZXJuID0gVmFsaWRhdGlvblBhdHRlcm47XG4gIHByaXZhdGUgaW5wdXRTdWJzY3JpcHRpb24kOiBTdWJzY3JpcHRpb247XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSBtb2RhbDogQnNNb2RhbFJlZixcbiAgICBwcml2YXRlIHJlcG9zaXRvcnlTZXJ2aWNlOiBSZXBvc2l0b3J5U2VydmljZSxcbiAgICBwcml2YXRlIGFsZXJ0OiBBbGVydFNlcnZpY2VcbiAgKSB7fVxuXG4gIG5nT25Jbml0KCkge1xuICAgIHRoaXMuc2V0SW5pdGlhbFN0YXRlKCk7XG4gICAgdGhpcy5sb2FkRmlybXdhcmVzKCk7XG4gIH1cblxuICBzZXRJbml0aWFsU3RhdGUoKSB7XG4gICAgaWYgKHRoaXMubW9kZWwuc2VsZWN0ZWQpIHtcbiAgICAgIHRoaXMuZmlybXdhcmVQcmVzZWxlY3RlZCA9IHRydWU7XG4gICAgfVxuICB9XG5cbiAgbG9hZEZpcm13YXJlcygpIHtcbiAgICB0aGlzLmlucHV0U3Vic2NyaXB0aW9uJCA9IHRoaXMub25JbnB1dFxuICAgICAgLnBpcGUoXG4gICAgICAgIHRhcCgoKSA9PiB7XG4gICAgICAgICAgaWYgKCF0aGlzLmZpcm13YXJlUHJlc2VsZWN0ZWQpIHtcbiAgICAgICAgICAgIHRoaXMubW9kZWwuZGVzY3JpcHRpb24gPSBudWxsO1xuICAgICAgICAgICAgaWYgKHRoaXMuZm9ybSkge1xuICAgICAgICAgICAgICB0aGlzLmZvcm0uZm9ybS5nZXQoJ2Rlc2NyaXB0aW9uJykucmVzZXQoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0pLFxuICAgICAgICBkZWJvdW5jZVRpbWUoMzAwKSxcbiAgICAgICAgZGlzdGluY3RVbnRpbENoYW5nZWQoKSxcbiAgICAgICAgc3dpdGNoTWFwKHNlYXJjaFN0ciA9PiB0aGlzLmdldEZpcm13YXJlUmVzdWx0KHNlYXJjaFN0cikpXG4gICAgICApXG4gICAgICAuc3Vic2NyaWJlKHJlc3VsdCA9PiB7XG4gICAgICAgIHRoaXMuZmlybXdhcmVzUmVzdWx0ID0gcmVzdWx0O1xuICAgICAgfSk7XG4gIH1cblxuICBnZXRGaXJtd2FyZVJlc3VsdChzZWFyY2hTdHI6IHN0cmluZykge1xuICAgIHJldHVybiBmcm9tKFxuICAgICAgdGhpcy5yZXBvc2l0b3J5U2VydmljZS5saXN0UmVwb3NpdG9yeUVudHJpZXMoUmVwb3NpdG9yeVR5cGUuRklSTVdBUkUsIHtcbiAgICAgICAgcGFydGlhbE5hbWU6IHNlYXJjaFN0cixcbiAgICAgICAgc2tpcExlZ2FjeTogdHJ1ZVxuICAgICAgfSlcbiAgICApO1xuICB9XG5cbiAgYXN5bmMgc2F2ZSgpIHtcbiAgICB0aGlzLnNhdmluZyA9IHRydWU7XG4gICAgdGhpcy5yZXBvc2l0b3J5U2VydmljZVxuICAgICAgLmNyZWF0ZSh0aGlzLm1vZGVsLCBSZXBvc2l0b3J5VHlwZS5GSVJNV0FSRSlcbiAgICAgIC50aGVuKHNhdmVkRmlybXdhcmUgPT4ge1xuICAgICAgICB0aGlzLnN1Y2Nlc3NNc2coKTtcbiAgICAgICAgdGhpcy5zYXZpbmcgPSBmYWxzZTtcbiAgICAgICAgdGhpcy5zYXZlZC5uZXh0KHNhdmVkRmlybXdhcmUpO1xuICAgICAgICB0aGlzLmNhbmNlbCgpO1xuICAgICAgfSlcbiAgICAgIC5jYXRjaChlID0+IHtcbiAgICAgICAgdGhpcy5zYXZpbmcgPSBmYWxzZTtcbiAgICAgICAgdGhpcy5zYXZlZC5lcnJvcihlKTtcbiAgICAgICAgdGhpcy5jYW5jZWwoKTtcbiAgICAgIH0pO1xuICB9XG5cbiAgc3VjY2Vzc01zZygpIHtcbiAgICBjb25zdCBtc2cgPSBnZXR0ZXh0KCdGaXJtd2FyZSBhZGRlZC4nKTtcbiAgICB0aGlzLmFsZXJ0LnN1Y2Nlc3MobXNnKTtcbiAgfVxuXG4gIGNhbmNlbCgpIHtcbiAgICB0aGlzLm1vZGFsLmhpZGUoKTtcbiAgICB0aGlzLnNhdmVkLmNvbXBsZXRlKCk7XG4gIH1cblxuICBuZ09uRGVzdHJveSgpIHtcbiAgICB0aGlzLmlucHV0U3Vic2NyaXB0aW9uJC51bnN1YnNjcmliZSgpO1xuICB9XG5cbiAgb25GaWxlKGRyb3BwZWQ6IFBpY2tlZEZpbGVzKSB7XG4gICAgaWYgKCFpc1VuZGVmaW5lZChkcm9wcGVkLnVybCkpIHtcbiAgICAgIHRoaXMubW9kZWwuYmluYXJ5ID0ge1xuICAgICAgICB1cmw6IGRyb3BwZWQudXJsXG4gICAgICB9O1xuICAgICAgcmV0dXJuO1xuICAgIH0gZWxzZSBpZiAoZHJvcHBlZC5kcm9wcGVkRmlsZXMpIHtcbiAgICAgIHRoaXMubW9kZWwuYmluYXJ5ID0ge1xuICAgICAgICBmaWxlOiBkcm9wcGVkLmRyb3BwZWRGaWxlc1swXS5maWxlXG4gICAgICB9O1xuICAgICAgcmV0dXJuO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLm1vZGVsLmJpbmFyeSA9IHtcbiAgICAgICAgZmlsZTogdW5kZWZpbmVkLFxuICAgICAgICB1cmw6IHVuZGVmaW5lZFxuICAgICAgfTtcbiAgICB9XG4gIH1cblxuICBvbkZpcm13YXJlU2VsZWN0KGZpcm13YXJlOiBJTWFuYWdlZE9iamVjdCkge1xuICAgIGFzc2lnbih0aGlzLm1vZGVsLCB7XG4gICAgICBzZWxlY3RlZDogZmlybXdhcmUsXG4gICAgICBkZXNjcmlwdGlvbjogZmlybXdhcmUuZGVzY3JpcHRpb24sXG4gICAgICBkZXZpY2VUeXBlOiBnZXQoZmlybXdhcmUsICdjOHlfRmlsdGVyLnR5cGUnKVxuICAgIH0pO1xuICB9XG59XG4iLCI8ZGl2IGNsYXNzPVwidmlld3BvcnQtbW9kYWxcIj5cbiAgPGRpdiBjbGFzcz1cIm1vZGFsLWhlYWRlciBkaWFsb2ctaGVhZGVyXCI+XG4gICAgPGkgW2M4eUljb25dPVwiJ2M4eS1maXJtd2FyZSdcIj48L2k+XG4gICAgPGRpdiBjbGFzcz1cIm1vZGFsLXRpdGxlXCIgdHJhbnNsYXRlIGlkPVwiYWRkRmlybXdhcmVNb2RhbFRpdGxlXCI+QWRkIGZpcm13YXJlPC9kaXY+XG4gIDwvZGl2PlxuICA8ZGl2IGNsYXNzPVwicC0xNiB0ZXh0LWNlbnRlciBzZXBhcmF0b3ItYm90dG9tXCIgKm5nSWY9XCIhZmlybXdhcmVQcmVzZWxlY3RlZFwiPlxuICAgIDxwIGNsYXNzPVwidGV4dC1tZWRpdW0gdGV4dC0xNiBtLTBcIiB0cmFuc2xhdGU+U2VsZWN0IG9yIGNyZWF0ZSBuZXcgZmlybXdhcmU8L3A+XG4gIDwvZGl2PlxuICA8Zm9ybVxuICAgIGNsYXNzPVwiZC1jb250ZW50c1wiXG4gICAgYXV0b2NvbXBsZXRlPVwib2ZmXCJcbiAgICAjZmlybXdhcmVGb3JtPVwibmdGb3JtXCJcbiAgICAobmdTdWJtaXQpPVwiZmlybXdhcmVGb3JtLmZvcm0udmFsaWQgJiYgc2F2ZSgpXCJcbiAgPlxuICAgIDxkaXYgY2xhc3M9XCJtb2RhbC1pbm5lci1zY3JvbGxcIj5cbiAgICAgIDxkaXYgY2xhc3M9XCJtb2RhbC1ib2R5XCIgaWQ9XCJhZGRGaXJtd2FyZU1vZGFsRGVzY3JpcHRpb25cIj5cbiAgICAgICAgPGRpdiBbaGlkZGVuXT1cImZpcm13YXJlUHJlc2VsZWN0ZWRcIj5cbiAgICAgICAgICA8Yzh5LWZvcm0tZ3JvdXA+XG4gICAgICAgICAgICA8bGFiZWwgZm9yPVwiZmlybXdhcmVOYW1lXCIgdHJhbnNsYXRlPkZpcm13YXJlPC9sYWJlbD5cbiAgICAgICAgICAgIDxjOHktdHlwZWFoZWFkXG4gICAgICAgICAgICAgIFsobmdNb2RlbCldPVwibW9kZWwuc2VsZWN0ZWRcIlxuICAgICAgICAgICAgICBuYW1lPVwiZmlybXdhcmVOYW1lXCJcbiAgICAgICAgICAgICAgcGxhY2Vob2xkZXI9XCJ7eyAnU2VsZWN0IG9yIGVudGVyJyB8IHRyYW5zbGF0ZSB9fVwiXG4gICAgICAgICAgICAgIGRhdGEtY3k9XCJhZGQtZmlybXdhcmUtbW9kYWwtLWlucHV0LW5hbWVcIlxuICAgICAgICAgICAgICAob25TZWFyY2gpPVwib25JbnB1dC5uZXh0KCRldmVudClcIlxuICAgICAgICAgICAgICBbcmVxdWlyZWRdPVwidHJ1ZVwiXG4gICAgICAgICAgICA+XG4gICAgICAgICAgICAgIDxjOHktbGlcbiAgICAgICAgICAgICAgICAqYzh5Rm9yPVwiXG4gICAgICAgICAgICAgICAgICBsZXQgZmlybXdhcmUgb2YgZmlybXdhcmVzUmVzdWx0O1xuICAgICAgICAgICAgICAgICAgbG9hZE1vcmU6ICdhdXRvJztcbiAgICAgICAgICAgICAgICAgIG5vdEZvdW5kOiBub3RGb3VuZFRlbXBsYXRlXG4gICAgICAgICAgICAgICAgXCJcbiAgICAgICAgICAgICAgICBjbGFzcz1cInAtbC04IHAtci04IGM4eS1saXN0X19pdGVtLS1saW5rXCJcbiAgICAgICAgICAgICAgICAoY2xpY2spPVwib25GaXJtd2FyZVNlbGVjdChmaXJtd2FyZSlcIlxuICAgICAgICAgICAgICAgIFthY3RpdmVdPVwibW9kZWwuc2VsZWN0ZWQgPT09IGZpcm13YXJlXCJcbiAgICAgICAgICAgICAgPlxuICAgICAgICAgICAgICAgIDxjOHktaGlnaGxpZ2h0XG4gICAgICAgICAgICAgICAgICBbdGV4dF09XCJmaXJtd2FyZS5uYW1lIHx8ICctLSdcIlxuICAgICAgICAgICAgICAgICAgW3BhdHRlcm5dPVwib25JbnB1dCB8IGFzeW5jXCJcbiAgICAgICAgICAgICAgICA+PC9jOHktaGlnaGxpZ2h0PlxuICAgICAgICAgICAgICA8L2M4eS1saT5cbiAgICAgICAgICAgICAgPG5nLXRlbXBsYXRlICNub3RGb3VuZFRlbXBsYXRlPlxuICAgICAgICAgICAgICAgIDxjOHktbGkgY2xhc3M9XCJiZy1sZXZlbC0yIHAtOFwiICpuZ0lmPVwiKG9uSW5wdXQgfCBhc3luYyk/Lmxlbmd0aCA+IDBcIj5cbiAgICAgICAgICAgICAgICAgIDxzcGFuIHRyYW5zbGF0ZT5ObyBtYXRjaCBmb3VuZC48L3NwYW4+XG4gICAgICAgICAgICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgICAgICAgICAgIGNsYXNzPVwiYnRuIGJ0bi1wcmltYXJ5IGJ0bi14cyBtLWwtOFwiXG4gICAgICAgICAgICAgICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICAgICAgICAgICAgICB0aXRsZT1cInt7ICdBZGQgbmV3YGZpcm13YXJlYCcgfCB0cmFuc2xhdGUgfX1cIlxuICAgICAgICAgICAgICAgICAgICB0cmFuc2xhdGVcbiAgICAgICAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgICAgICAgQWRkIG5ld2BmaXJtd2FyZWBcbiAgICAgICAgICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICAgICAgICAgIDwvYzh5LWxpPlxuICAgICAgICAgICAgICA8L25nLXRlbXBsYXRlPlxuICAgICAgICAgICAgPC9jOHktdHlwZWFoZWFkPlxuICAgICAgICAgIDwvYzh5LWZvcm0tZ3JvdXA+XG5cbiAgICAgICAgICA8Yzh5LWZvcm0tZ3JvdXA+XG4gICAgICAgICAgICA8bGFiZWwgZm9yPVwiZmlybXdhcmVEZXNjcmlwdGlvblwiIHRyYW5zbGF0ZT5EZXNjcmlwdGlvbjwvbGFiZWw+XG4gICAgICAgICAgICA8aW5wdXRcbiAgICAgICAgICAgICAgaWQ9XCJmaXJtd2FyZURlc2NyaXB0aW9uXCJcbiAgICAgICAgICAgICAgZGF0YS1jeT1cImFkZC1maXJtd2FyZS1tb2RhbC0taW5wdXQtZGVzY3JpcHRpb25cIlxuICAgICAgICAgICAgICBjbGFzcz1cImZvcm0tY29udHJvbFwiXG4gICAgICAgICAgICAgIGF1dG9jb21wbGV0ZT1cIm9mZlwiXG4gICAgICAgICAgICAgIG5hbWU9XCJkZXNjcmlwdGlvblwiXG4gICAgICAgICAgICAgIFsobmdNb2RlbCldPVwibW9kZWwuZGVzY3JpcHRpb25cIlxuICAgICAgICAgICAgICBwbGFjZWhvbGRlcj1cInt7ICdlLmcuIEZpcm13YXJlIGZvciBoYXJkd2FyZSByZXZpc2lvbiBCJyB8IHRyYW5zbGF0ZSB9fVwiXG4gICAgICAgICAgICAgIFtkaXNhYmxlZF09XCJtb2RlbC5zZWxlY3RlZD8uaWRcIlxuICAgICAgICAgICAgICBbcmVxdWlyZWRdPVwidHJ1ZVwiXG4gICAgICAgICAgICAgIFtwYXR0ZXJuXT1cIlZhbGlkYXRpb25QYXR0ZXJuLnJ1bGVzLm5vV2hpdGVTcGFjZU9ubHkucGF0dGVyblwiXG4gICAgICAgICAgICAvPlxuICAgICAgICAgIDwvYzh5LWZvcm0tZ3JvdXA+XG5cbiAgICAgICAgICA8Yzh5LWZvcm0tZ3JvdXA+XG4gICAgICAgICAgICA8bGFiZWwgY2xhc3M9XCJjb250cm9sLWxhYmVsXCIgZm9yPVwiZmlybXdhcmVEZXZpY2VUeXBlRmlsdGVyXCI+XG4gICAgICAgICAgICAgIHt7ICdEZXZpY2UgdHlwZSBmaWx0ZXInIHwgdHJhbnNsYXRlIH19XG4gICAgICAgICAgICAgIDxidXR0b25cbiAgICAgICAgICAgICAgICBjbGFzcz1cImJ0bi1oZWxwXCJcbiAgICAgICAgICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgICAgICAgICBbYXR0ci5hcmlhLWxhYmVsXT1cIidIZWxwJyB8IHRyYW5zbGF0ZVwiXG4gICAgICAgICAgICAgICAgcG9wb3Zlcj1cInt7XG4gICAgICAgICAgICAgICAgICAnSWYgdGhlIGZpbHRlciBpcyBzZXQsIHRoZSBmaXJtd2FyZSB3aWxsIHNob3cgdXAgZm9yIGluc3RhbGxhdGlvbiBvbmx5IGZvciBkZXZpY2VzIG9mIHRoYXQgdHlwZS4gSWYgbm8gZmlsdGVyIGlzIHNldCwgaXQgd2lsbCBiZSBhdmFpbGFibGUgZm9yIGFsbCBkZXZpY2VzLidcbiAgICAgICAgICAgICAgICAgICAgfCB0cmFuc2xhdGVcbiAgICAgICAgICAgICAgICB9fVwiXG4gICAgICAgICAgICAgICAgdHJpZ2dlcnM9XCJmb2N1c1wiXG4gICAgICAgICAgICAgICAgcGxhY2VtZW50PVwicmlnaHRcIlxuICAgICAgICAgICAgICAgIGNvbnRhaW5lcj1cImJvZHlcIlxuICAgICAgICAgICAgICA+PC9idXR0b24+XG4gICAgICAgICAgICA8L2xhYmVsPlxuICAgICAgICAgICAgPGlucHV0XG4gICAgICAgICAgICAgIGlkPVwiZmlybXdhcmVEZXZpY2VUeXBlRmlsdGVyXCJcbiAgICAgICAgICAgICAgZGF0YS1jeT1cImFkZC1maXJtd2FyZS1tb2RhbC0tZmlybXdhcmVEZXZpY2VUeXBlRmlsdGVyXCJcbiAgICAgICAgICAgICAgY2xhc3M9XCJmb3JtLWNvbnRyb2xcIlxuICAgICAgICAgICAgICBuYW1lPVwiZmlybXdhcmVEZXZpY2VUeXBlRmlsdGVyXCJcbiAgICAgICAgICAgICAgWyhuZ01vZGVsKV09XCJtb2RlbC5kZXZpY2VUeXBlXCJcbiAgICAgICAgICAgICAgcGxhY2Vob2xkZXI9XCJ7eyAnZS5nLicgfCB0cmFuc2xhdGUgfX0gYzh5X0xpbnV4XCJcbiAgICAgICAgICAgICAgW2Rpc2FibGVkXT1cIm1vZGVsLnNlbGVjdGVkPy5pZFwiXG4gICAgICAgICAgICAgIFtwYXR0ZXJuXT1cIlZhbGlkYXRpb25QYXR0ZXJuLnJ1bGVzLm5vV2hpdGVTcGFjZU9ubHkucGF0dGVyblwiXG4gICAgICAgICAgICAvPlxuICAgICAgICAgIDwvYzh5LWZvcm0tZ3JvdXA+XG4gICAgICAgIDwvZGl2PlxuXG4gICAgICAgIDxjOHktZm9ybS1ncm91cD5cbiAgICAgICAgICA8bGFiZWwgZm9yPVwiZmlybXdhcmVWZXJzaW9uXCIgdHJhbnNsYXRlPlZlcnNpb248L2xhYmVsPlxuICAgICAgICAgIDxpbnB1dFxuICAgICAgICAgICAgaWQ9XCJmaXJtd2FyZVZlcnNpb25cIlxuICAgICAgICAgICAgZGF0YS1jeT1cImFkZC1maXJtd2FyZS1tb2RhbC0tZmlybXdhcmVWZXJzaW9uXCJcbiAgICAgICAgICAgIGNsYXNzPVwiZm9ybS1jb250cm9sXCJcbiAgICAgICAgICAgIGF1dG9jb21wbGV0ZT1cIm9mZlwiXG4gICAgICAgICAgICBuYW1lPVwidmVyc2lvblwiXG4gICAgICAgICAgICBbKG5nTW9kZWwpXT1cIm1vZGVsLnZlcnNpb25cIlxuICAgICAgICAgICAgcGxhY2Vob2xkZXI9XCJ7eyAnZS5nLicgfCB0cmFuc2xhdGUgfX0gMS4wLjBcIlxuICAgICAgICAgICAgW3JlcXVpcmVkXT1cInRydWVcIlxuICAgICAgICAgICAgW3BhdHRlcm5dPVwiVmFsaWRhdGlvblBhdHRlcm4ucnVsZXMubm9XaGl0ZVNwYWNlT25seS5wYXR0ZXJuXCJcbiAgICAgICAgICAvPlxuICAgICAgICA8L2M4eS1mb3JtLWdyb3VwPlxuXG4gICAgICAgIDxjOHktZm9ybS1ncm91cD5cbiAgICAgICAgICA8ZGl2IGNsYXNzPVwibGVnZW5kIGZvcm0tYmxvY2sgbS10LTQwXCIgdHJhbnNsYXRlPkZpcm13YXJlIGZpbGU8L2Rpdj5cbiAgICAgICAgICA8Yzh5LWZpbGUtcGlja2VyXG4gICAgICAgICAgICBbbWF4QWxsb3dlZEZpbGVzXT1cIjFcIlxuICAgICAgICAgICAgKG9uRmlsZXNQaWNrZWQpPVwib25GaWxlKCRldmVudClcIlxuICAgICAgICAgICAgW2ZpbGVVcmxQb3BvdmVyXT1cInRleHRGb3JGaXJtd2FyZVVybFBvcG92ZXJcIlxuICAgICAgICAgID48L2M4eS1maWxlLXBpY2tlcj5cbiAgICAgICAgPC9jOHktZm9ybS1ncm91cD5cbiAgICAgIDwvZGl2PlxuICAgIDwvZGl2PlxuICAgIDxkaXYgY2xhc3M9XCJtb2RhbC1mb290ZXJcIj5cbiAgICAgIDxidXR0b25cbiAgICAgICAgY2xhc3M9XCJidG4gYnRuLWRlZmF1bHRcIlxuICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgdGl0bGU9XCJ7eyAnQ2FuY2VsJyB8IHRyYW5zbGF0ZSB9fVwiXG4gICAgICAgIGRhdGEtY3k9XCJhZGQtZmlybXdhcmUtbW9kYWwtLWNhbmNlbC1idG5cIlxuICAgICAgICAoY2xpY2spPVwiY2FuY2VsKClcIlxuICAgICAgICBbZGlzYWJsZWRdPVwic2F2aW5nXCJcbiAgICAgICAgdHJhbnNsYXRlXG4gICAgICA+XG4gICAgICAgIENhbmNlbFxuICAgICAgPC9idXR0b24+XG5cbiAgICAgIDxidXR0b25cbiAgICAgICAgY2xhc3M9XCJidG4gYnRuLXByaW1hcnlcIlxuICAgICAgICB0eXBlPVwic3VibWl0XCJcbiAgICAgICAgdGl0bGU9XCJ7eyAnQWRkIGZpcm13YXJlJyB8IHRyYW5zbGF0ZSB9fVwiXG4gICAgICAgIFtuZ0NsYXNzXT1cInsgJ2J0bi1wZW5kaW5nJzogc2F2aW5nIH1cIlxuICAgICAgICBbZGlzYWJsZWRdPVwiXG4gICAgICAgICAgIWZpcm13YXJlRm9ybS5mb3JtLnZhbGlkIHx8XG4gICAgICAgICAgZmlybXdhcmVGb3JtLmZvcm0ucHJpc3RpbmUgfHxcbiAgICAgICAgICBzYXZpbmcgfHxcbiAgICAgICAgICAoIW1vZGVsLmJpbmFyeT8udXJsICYmICFtb2RlbC5iaW5hcnk/LmZpbGUpXG4gICAgICAgIFwiXG4gICAgICAgIFthY3Rpb25OYW1lXT1cIlBST0RVQ1RfRVhQRVJJRU5DRS5GSVJNV0FSRS5FVkVOVFMuUkVQT1NJVE9SWVwiXG4gICAgICAgIFthY3Rpb25EYXRhXT1cIntcbiAgICAgICAgICBjb21wb25lbnQ6IFBST0RVQ1RfRVhQRVJJRU5DRS5GSVJNV0FSRS5DT01QT05FTlRTLkFERF9GSVJNV0FSRV9NT0RBTCxcbiAgICAgICAgICByZXN1bHQ6XG4gICAgICAgICAgICBmaXJtd2FyZVByZXNlbGVjdGVkIHx8IG1vZGVsLnNlbGVjdGVkPy5pZFxuICAgICAgICAgICAgICA/IFBST0RVQ1RfRVhQRVJJRU5DRS5GSVJNV0FSRS5SRVNVTFRTLkFERF9GSVJNV0FSRV9WRVJTSU9OXG4gICAgICAgICAgICAgIDogUFJPRFVDVF9FWFBFUklFTkNFLkZJUk1XQVJFLlJFU1VMVFMuQUREX0ZJUk1XQVJFXG4gICAgICAgIH1cIlxuICAgICAgICB0cmFuc2xhdGVcbiAgICAgICAgYzh5UHJvZHVjdEV4cGVyaWVuY2VcbiAgICAgID5cbiAgICAgICAgQWRkIGZpcm13YXJlXG4gICAgICA8L2J1dHRvbj5cbiAgICA8L2Rpdj5cbiAgPC9mb3JtPlxuPC9kaXY+XG4iXX0=