UNPKG

@c8y/ngx-components

Version:

Angular modules for Cumulocity IoT applications

219 lines 43.1 kB
import { Component } from '@angular/core'; import { FormGroup } from '@angular/forms'; import { GainsightService, gettext } from '@c8y/ngx-components'; import { TranslateService } from '@ngx-translate/core'; import { cloneDeep, uniq } from 'lodash-es'; import { BsModalRef } from 'ngx-bootstrap/modal'; import { BehaviorSubject, defer, forkJoin, from, of, Subject, throwError } from 'rxjs'; import { catchError, map, mergeMap, shareReplay, switchMap, takeUntil } from 'rxjs/operators'; import { PRODUCT_EXPERIENCE_SIGFOX_REGISTRATION } from './sigfox-device-registration.model'; import { SigfoxErrorName, SigfoxProviderService } from './sigfox-provider.service'; import * as i0 from "@angular/core"; import * as i1 from "ngx-bootstrap/modal"; import * as i2 from "./sigfox-provider.service"; import * as i3 from "@ngx-translate/core"; import * as i4 from "@c8y/ngx-components"; import * as i5 from "@angular/common"; import * as i6 from "@angular/cdk/stepper"; import * as i7 from "@ngx-formly/core"; export class SigfoxDeviceRegistrationComponent { constructor(bsModalRef, sigfoxService, translateService, gainsightService) { this.bsModalRef = bsModalRef; this.sigfoxService = sigfoxService; this.translateService = translateService; this.gainsightService = gainsightService; this.PAGING = { withTotalPages: true, pageSize: 10 }; this.form = new FormGroup({}); this.model = {}; this.protocols$ = this.getProtocols$(); this.connections$ = this.getConnections$(); this.unsubscribe$ = new Subject(); this.load$ = this.connections$.pipe(catchError((error) => of(error)), switchMap(connections => { if (connections instanceof Error && connections.name === SigfoxErrorName.NoConnectivitySettingsError) { return of([connections]); } return forkJoin([ of(connections), this.protocols$.pipe(catchError((error) => of(error))) ]); }), map(results => { return results.filter(result => { return result instanceof Error; }); }), switchMap(errors => { return errors.length === 0 ? of([]) : throwError(errors); })); this.fields = [ { key: 'id', type: 'string', templateOptions: { placeholder: 'FED987', label: gettext('ID'), required: true, pattern: '(0x){0,1}[0-9A-F]+(h){0,1}' }, validation: { messages: { pattern: gettext('Must be a valid hexadecimal number.') } } }, { key: 'pac', type: 'string', templateOptions: { placeholder: 'FEDCBA9876543210', label: gettext('PAC'), required: true, pattern: '^([a-fA-F0-9]{16})$' }, validation: { messages: { pattern: gettext('Must be a valid 16 digit hexadecimal number.') } } }, { key: 'connection', type: 'typeahead', templateOptions: { label: gettext('Connection'), required: true, c8yForOptions: this.connections$, displayProperty: 'name', valueProperties: ['name'] } }, { key: 'contract', type: 'typeahead', templateOptions: { label: gettext('Contract'), required: true, placeholder: 'Free contract_25', displayProperty: 'name', valueProperties: ['id'], description: gettext('Only active contracts with free slots are displayed.') }, hooks: { onInit: field => { const connectionControl = field.form.get('connection'); connectionControl.valueChanges .pipe(takeUntil(this.unsubscribe$), mergeMap(({ name }) => this.getContracts$(name))) .subscribe(profiles => { field.templateOptions.c8yForOptions = of(profiles); field.formControl.setValue(null); }, error => { field.form.get('contract').setErrors({ contract: true }); field.validators.contract.message = error.message; }); } }, validators: { contract: { expression: (control) => { return control.status === 'VALID'; }, message: () => '' } } }, { key: 'deviceType', type: 'typeahead', templateOptions: { label: gettext('Device protocol'), required: true, c8yForOptions: this.protocols$, displayProperty: 'name', valueProperties: ['id', 'name'] } }, { key: 'productCertificate', type: 'string', templateOptions: { placeholder: 'P_001F_EDCB_01', label: gettext('Product certificate key'), pattern: 'P_[0-9A-F]{4}_[0-9A-F]{4}_[0-9A-F]{2}', description: gettext('If no product certificate key is specified, the device is considered a prototype.') }, validation: { messages: { pattern: (_error, _field) => this.translateService.instant(gettext('Must be a valid product certificate key, for example, {{ example }}'), { example: 'P_001F_EDCB_01' }) } } } ]; this.registrationStepLabels = { next: gettext('Register') }; this.finalStepLabels = { back: gettext('Close') }; this.state = 'loadPending'; this.errors$ = new BehaviorSubject([]); this.errorMessages$ = this.errors$.pipe(map(errors => errors.map(error => error.message)), map(messages => uniq(messages))); this.load$.subscribe(() => { this.state = 'loadSuccess'; }, errors => { this.state = 'loadError'; this.errors$.next(errors); }); } async create(event) { this.state = 'registrationPending'; const sigfoxDevice = this.getSigfoxDeviceToSend(); try { await this.sigfoxService.createDevice(sigfoxDevice); this.state = 'registrationSuccess'; this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_SIGFOX_REGISTRATION.EVENT, { result: PRODUCT_EXPERIENCE_SIGFOX_REGISTRATION.RESULT.SUCCESS, component: PRODUCT_EXPERIENCE_SIGFOX_REGISTRATION.COMPONENT }); } catch (error) { this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_SIGFOX_REGISTRATION.EVENT, { result: PRODUCT_EXPERIENCE_SIGFOX_REGISTRATION.RESULT.FAILURE, component: PRODUCT_EXPERIENCE_SIGFOX_REGISTRATION.COMPONENT }); this.state = 'registrationError'; this.errors$.next([error]); } event.stepper.next(); } getSigfoxDeviceToSend() { const sigfoxDevice = cloneDeep(this.model); sigfoxDevice.lnsConnectionName = this.model.connection.name; sigfoxDevice.contractId = this.model.contract.id; sigfoxDevice.prototype = !sigfoxDevice.productCertificate; delete sigfoxDevice.contract; delete sigfoxDevice.connection; return sigfoxDevice; } getContracts$(name) { return defer(() => from(this.sigfoxService.getContracts(name))).pipe(shareReplay(1)); } getProtocols$() { return defer(() => from(this.sigfoxService.getAvailableProtocols())).pipe(shareReplay(1)); } getConnections$() { return defer(() => from(this.sigfoxService.getConnections())).pipe(shareReplay(1)); } ngOnDestroy() { this.unsubscribe$.next(); this.unsubscribe$.complete(); } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SigfoxDeviceRegistrationComponent, deps: [{ token: i1.BsModalRef }, { token: i2.SigfoxProviderService }, { token: i3.TranslateService }, { token: i4.GainsightService }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: SigfoxDeviceRegistrationComponent, selector: "c8y-sigfox-device-registration", ngImport: i0, template: "<c8y-modal\n [title]=\"'Sigfox registration' | translate\"\n [headerClasses]=\"'dialog-header'\"\n [customFooter]=\"true\"\n>\n <ng-container c8y-modal-title>\n <span [c8yIcon]=\"'c8y-device-connect'\"></span>\n </ng-container>\n <ng-container *ngIf=\"state === 'loadPending'; else registrationForm\">\n <div class=\"p-16 text-center\">\n <c8y-loading></c8y-loading>\n </div>\n </ng-container>\n\n <ng-template #registrationForm>\n <c8y-stepper\n [hideStepProgress]=\"true\"\n linear\n c8y-modal-body\n *ngIf=\"(errorMessages$ | async).length === 0; else errorMessagesPresent\"\n >\n <cdk-step [stepControl]=\"form\">\n <div class=\"p-b-16\">\n <p class=\"modal-subtitle sticky-top\">\n {{ 'Register a single Sigfox device' | translate }}\n </p>\n <formly-form\n class=\"d-block p-l-24 p-r-24 p-t-16\"\n [form]=\"form\"\n [fields]=\"fields\"\n [model]=\"model\"\n ></formly-form>\n </div>\n <c8y-stepper-buttons\n class=\"modal-footer d-block sticky-bottom separator-top bg-component\"\n [labels]=\"registrationStepLabels\"\n (onNext)=\"create($event)\"\n (onCancel)=\"bsModalRef.hide()\"\n [showButtons]=\"{ cancel: true, next: true }\"\n [pending]=\"state === 'registrationPending'\"\n [disabled]=\"!form.valid\"\n ></c8y-stepper-buttons>\n </cdk-step>\n <cdk-step state=\"final\">\n <div\n class=\"p-16 text-center\"\n *ngIf=\"state === 'registrationPending'\"\n >\n <c8y-loading></c8y-loading>\n </div>\n <div class=\"m-24\">\n <c8y-operation-result\n class=\"lead m-b-0\"\n type=\"success\"\n *ngIf=\"state === 'registrationSuccess'\"\n text=\"{{ 'Device registered' | translate }}\"\n [size]=\"84\"\n [vertical]=\"true\"\n ></c8y-operation-result>\n </div>\n\n <c8y-stepper-buttons\n class=\"sticky-bottom d-block p-t-16 p-b-16 separator-top bg-component\"\n (onCustom)=\"bsModalRef.hide()\"\n [showButtons]=\"{ custom: true }\"\n [labels]=\"finalStepLabels\"\n ></c8y-stepper-buttons>\n </cdk-step>\n </c8y-stepper>\n </ng-template>\n\n <ng-template #errorMessagesPresent>\n <div class=\"m-24\">\n <c8y-operation-result\n class=\"lead\"\n type=\"error\"\n *ngIf=\"state === 'registrationError'\"\n text=\"{{ 'Failed to register' | translate }}\"\n [size]=\"84\"\n [vertical]=\"true\"\n ></c8y-operation-result>\n <div\n class=\"m-b-8\"\n *ngFor=\"let msg of errorMessages$ | async\"\n data-cy=\"sigfox-device-registration.component--registration-error\"\n [ngClass]=\"{\n 'text-center': state === 'registrationError',\n 'alert alert-danger': state === 'loadError'\n }\"\n >\n <span [innerHTML]=\"msg | translate\"></span>\n </div>\n </div>\n\n <div class=\"modal-footer\">\n <button\n class=\"btn btn-default\"\n title=\"{{ 'Close' | translate }}\"\n type=\"button\"\n (click)=\"bsModalRef.hide()\"\n >\n {{ 'Close' | translate }}\n </button>\n </div>\n </ng-template>\n</c8y-modal>\n", dependencies: [{ kind: "directive", type: i4.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i5.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i5.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i4.LoadingComponent, selector: "c8y-loading", inputs: ["layout", "progress", "message"] }, { kind: "component", type: i4.OperationResultComponent, selector: "c8y-operation-result", inputs: ["text", "vertical", "size", "type"] }, { kind: "component", type: i4.ModalComponent, selector: "c8y-modal", inputs: ["disabled", "close", "dismiss", "title", "body", "customFooter", "headerClasses", "labels"], outputs: ["onDismiss", "onClose"] }, { kind: "component", type: i4.C8yStepper, selector: "c8y-stepper", inputs: ["disableDefaultIcons", "disableProgressButtons", "customClasses", "hideStepProgress", "useStepLabelsAsTitlesOnly"], outputs: ["onStepChange"] }, { kind: "component", type: i6.CdkStep, selector: "cdk-step", inputs: ["stepControl", "label", "errorMessage", "aria-label", "aria-labelledby", "state", "editable", "optional", "completed", "hasError"], outputs: ["interacted"], exportAs: ["cdkStep"] }, { kind: "component", type: i4.C8yStepperButtons, selector: "c8y-stepper-buttons", inputs: ["labels", "pending", "disabled", "showButtons"], outputs: ["onCancel", "onNext", "onBack", "onCustom"] }, { kind: "component", type: i7.FormlyForm, selector: "formly-form", inputs: ["form", "model", "fields", "options"], outputs: ["modelChange"] }, { kind: "pipe", type: i4.C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: i5.AsyncPipe, name: "async" }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: SigfoxDeviceRegistrationComponent, decorators: [{ type: Component, args: [{ selector: 'c8y-sigfox-device-registration', template: "<c8y-modal\n [title]=\"'Sigfox registration' | translate\"\n [headerClasses]=\"'dialog-header'\"\n [customFooter]=\"true\"\n>\n <ng-container c8y-modal-title>\n <span [c8yIcon]=\"'c8y-device-connect'\"></span>\n </ng-container>\n <ng-container *ngIf=\"state === 'loadPending'; else registrationForm\">\n <div class=\"p-16 text-center\">\n <c8y-loading></c8y-loading>\n </div>\n </ng-container>\n\n <ng-template #registrationForm>\n <c8y-stepper\n [hideStepProgress]=\"true\"\n linear\n c8y-modal-body\n *ngIf=\"(errorMessages$ | async).length === 0; else errorMessagesPresent\"\n >\n <cdk-step [stepControl]=\"form\">\n <div class=\"p-b-16\">\n <p class=\"modal-subtitle sticky-top\">\n {{ 'Register a single Sigfox device' | translate }}\n </p>\n <formly-form\n class=\"d-block p-l-24 p-r-24 p-t-16\"\n [form]=\"form\"\n [fields]=\"fields\"\n [model]=\"model\"\n ></formly-form>\n </div>\n <c8y-stepper-buttons\n class=\"modal-footer d-block sticky-bottom separator-top bg-component\"\n [labels]=\"registrationStepLabels\"\n (onNext)=\"create($event)\"\n (onCancel)=\"bsModalRef.hide()\"\n [showButtons]=\"{ cancel: true, next: true }\"\n [pending]=\"state === 'registrationPending'\"\n [disabled]=\"!form.valid\"\n ></c8y-stepper-buttons>\n </cdk-step>\n <cdk-step state=\"final\">\n <div\n class=\"p-16 text-center\"\n *ngIf=\"state === 'registrationPending'\"\n >\n <c8y-loading></c8y-loading>\n </div>\n <div class=\"m-24\">\n <c8y-operation-result\n class=\"lead m-b-0\"\n type=\"success\"\n *ngIf=\"state === 'registrationSuccess'\"\n text=\"{{ 'Device registered' | translate }}\"\n [size]=\"84\"\n [vertical]=\"true\"\n ></c8y-operation-result>\n </div>\n\n <c8y-stepper-buttons\n class=\"sticky-bottom d-block p-t-16 p-b-16 separator-top bg-component\"\n (onCustom)=\"bsModalRef.hide()\"\n [showButtons]=\"{ custom: true }\"\n [labels]=\"finalStepLabels\"\n ></c8y-stepper-buttons>\n </cdk-step>\n </c8y-stepper>\n </ng-template>\n\n <ng-template #errorMessagesPresent>\n <div class=\"m-24\">\n <c8y-operation-result\n class=\"lead\"\n type=\"error\"\n *ngIf=\"state === 'registrationError'\"\n text=\"{{ 'Failed to register' | translate }}\"\n [size]=\"84\"\n [vertical]=\"true\"\n ></c8y-operation-result>\n <div\n class=\"m-b-8\"\n *ngFor=\"let msg of errorMessages$ | async\"\n data-cy=\"sigfox-device-registration.component--registration-error\"\n [ngClass]=\"{\n 'text-center': state === 'registrationError',\n 'alert alert-danger': state === 'loadError'\n }\"\n >\n <span [innerHTML]=\"msg | translate\"></span>\n </div>\n </div>\n\n <div class=\"modal-footer\">\n <button\n class=\"btn btn-default\"\n title=\"{{ 'Close' | translate }}\"\n type=\"button\"\n (click)=\"bsModalRef.hide()\"\n >\n {{ 'Close' | translate }}\n </button>\n </div>\n </ng-template>\n</c8y-modal>\n" }] }], ctorParameters: () => [{ type: i1.BsModalRef }, { type: i2.SigfoxProviderService }, { type: i3.TranslateService }, { type: i4.GainsightService }] }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2lnZm94LWRldmljZS1yZWdpc3RyYXRpb24uY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc2lnZm94LWRldmljZS1yZWdpc3RyYXRpb24vc2lnZm94LWRldmljZS1yZWdpc3RyYXRpb24uY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vc2lnZm94LWRldmljZS1yZWdpc3RyYXRpb24vc2lnZm94LWRldmljZS1yZWdpc3RyYXRpb24uY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUMxQyxPQUFPLEVBQW1CLFNBQVMsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQzVELE9BQU8sRUFBYyxnQkFBZ0IsRUFBRSxPQUFPLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUU1RSxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUN2RCxPQUFPLEVBQUUsU0FBUyxFQUFFLElBQUksRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUM1QyxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDakQsT0FBTyxFQUFFLGVBQWUsRUFBRSxLQUFLLEVBQUUsUUFBUSxFQUFFLElBQUksRUFBRSxFQUFFLEVBQUUsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUN2RixPQUFPLEVBQUUsVUFBVSxFQUFFLEdBQUcsRUFBRSxRQUFRLEVBQUUsV0FBVyxFQUFFLFNBQVMsRUFBRSxTQUFTLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUM5RixPQUFPLEVBR0wsc0NBQXNDLEVBQ3ZDLE1BQU0sb0NBQW9DLENBQUM7QUFDNUMsT0FBTyxFQUFFLGVBQWUsRUFBRSxxQkFBcUIsRUFBRSxNQUFNLDJCQUEyQixDQUFDOzs7Ozs7Ozs7QUFjbkYsTUFBTSxPQUFPLGlDQUFpQztJQXNLNUMsWUFDUyxVQUFzQixFQUNyQixh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T0FBTyxLQUFLLENBQUMsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDdkYsQ0FBQztJQUVELGFBQWE7UUFDWCxPQUFPLEtBQUssQ0FBQyxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxxQkFBcUIsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDNUYsQ0FBQztJQUVELGVBQWU7UUFDYixPQUFPLEtBQUssQ0FBQyxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxjQUFjLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3JGLENBQUM7SUFFRCxXQUFXO1FBQ1QsSUFBSSxDQUFDLFlBQVksQ0FBQyxJQUFJLEVBQUUsQ0FBQztRQUN6QixJQUFJLENBQUMsWUFBWSxDQUFDLFFBQVEsRUFBRSxDQUFDO0lBQy9CLENBQUM7K0dBdE9VLGlDQUFpQzttR0FBakMsaUNBQWlDLHNFQzdCOUMsMDJHQTBHQTs7NEZEN0VhLGlDQUFpQztrQkFKN0MsU0FBUzsrQkFDRSxnQ0FBZ0MiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDZGtTdGVwIH0gZnJvbSAnQGFuZ3VsYXIvY2RrL3N0ZXBwZXInO1xuaW1wb3J0IHsgQ29tcG9uZW50IH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBBYnN0cmFjdENvbnRyb2wsIEZvcm1Hcm91cCB9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcbmltcG9ydCB7IEM4eVN0ZXBwZXIsIEdhaW5zaWdodFNlcnZpY2UsIGdldHRleHQgfSBmcm9tICdAYzh5L25neC1jb21wb25lbnRzJztcbmltcG9ydCB7IEZvcm1seUZpZWxkQ29uZmlnIH0gZnJvbSAnQG5neC1mb3JtbHkvY29yZSc7XG5pbXBvcnQgeyBUcmFuc2xhdGVTZXJ2aWNlIH0gZnJvbSAnQG5neC10cmFuc2xhdGUvY29yZSc7XG5pbXBvcnQgeyBjbG9uZURlZXAsIHVuaXEgfSBmcm9tICdsb2Rhc2gtZXMnO1xuaW1wb3J0IHsgQnNNb2RhbFJlZiB9IGZyb20gJ25neC1ib290c3RyYXAvbW9kYWwnO1xuaW1wb3J0IHsgQmVoYXZpb3JTdWJqZWN0LCBkZWZlciwgZm9ya0pvaW4sIGZyb20sIG9mLCBTdWJqZWN0LCB0aHJvd0Vycm9yIH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyBjYXRjaEVycm9yLCBtYXAsIG1lcmdlTWFwLCBzaGFyZVJlcGxheSwgc3dpdGNoTWFwLCB0YWtlVW50aWwgfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5pbXBvcnQge1xuICBTaWdmb3hEZXZpY2UsXG4gIFNpZ2ZveERldmljZUZvcm1seSxcbiAgUFJPRFVDVF9FWFBFUklFTkNFX1NJR0ZPWF9SRUdJU1RSQVRJT05cbn0gZnJvbSAnLi9zaWdmb3gtZGV2aWNlLXJlZ2lzdHJhdGlvbi5tb2RlbCc7XG5pbXBvcnQgeyBTaWdmb3hFcnJvck5hbWUsIFNpZ2ZveFByb3ZpZGVyU2VydmljZSB9IGZyb20gJy4vc2lnZm94LXByb3ZpZGVyLnNlcnZpY2UnO1xuXG50eXBlIFNpZ2ZveFN0YXRlID1cbiAgfCAnbG9hZFBlbmRpbmcnXG4gIHwgJ2xvYWRTdWNjZXNzJ1xuICB8ICdsb2FkRXJyb3InXG4gIHwgJ3JlZ2lzdHJhdGlvblBlbmRpbmcnXG4gIHwgJ3JlZ2lzdHJhdGlvblN1Y2Nlc3MnXG4gIHwgJ3JlZ2lzdHJhdGlvbkVycm9yJztcblxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnYzh5LXNpZ2ZveC1kZXZpY2UtcmVnaXN0cmF0aW9uJyxcbiAgdGVtcGxhdGVVcmw6ICdzaWdmb3gtZGV2aWNlLXJlZ2lzdHJhdGlvbi5jb21wb25lbnQuaHRtbCdcbn0pXG5leHBvcnQgY2xhc3MgU2lnZm94RGV2aWNlUmVnaXN0cmF0aW9uQ29tcG9uZW50IHtcbiAgc3RlcHBlcjogQzh5U3RlcHBlcjtcbiAgcmVhZG9ubHkgUEFHSU5HOiBvYmplY3QgPSB7XG4gICAgd2l0aFRvdGFsUGFnZXM6IHRydWUsXG4gICAgcGFnZVNpemU6IDEwXG4gIH07XG5cbiAgZm9ybSA9IG5ldyBGb3JtR3JvdXAoe30pO1xuICBtb2RlbDogU2lnZm94RGV2aWNlRm9ybWx5ID0ge30gYXMgYW55O1xuICBwcm90b2NvbHMkID0gdGhpcy5nZXRQcm90b2NvbHMkKCk7XG4gIGNvbm5lY3Rpb25zJCA9IHRoaXMuZ2V0Q29ubmVjdGlvbnMkKCk7XG4gIHVuc3Vic2NyaWJlJDogU3ViamVjdDx2b2lkPiA9IG5ldyBTdWJqZWN0KCk7XG5cbiAgbG9hZCQgPSB0aGlzLmNvbm5lY3Rpb25zJC5waXBlKFxuICAgIGNhdGNoRXJyb3IoKGVycm9yOiBFcnJvcikgPT4gb2YoZXJyb3IpKSxcbiAgICBzd2l0Y2hNYXAoY29ubmVjdGlvbnMgPT4ge1xuICAgICAgaWYgKFxuICAgICAgICBjb25uZWN0aW9ucyBpbnN0YW5jZW9mIEVycm9yICYmXG4gICAgICAgIGNvbm5lY3Rpb25zLm5hbWUgPT09IFNpZ2ZveEVycm9yTmFtZS5Ob0Nvbm5lY3Rpdml0eVNldHRpbmdzRXJyb3JcbiAgICAgICkge1xuICAgICAgICByZXR1cm4gb2YoW2Nvbm5lY3Rpb25zXSk7XG4gICAgICB9XG4gICAgICByZXR1cm4gZm9ya0pvaW4oW1xuICAgICAgICBvZihjb25uZWN0aW9ucyksXG4gICAgICAgIHRoaXMucHJvdG9jb2xzJC5waXBlKGNhdGNoRXJyb3IoKGVycm9yOiBFcnJvcikgPT4gb2YoZXJyb3IpKSlcbiAgICAgIF0pO1xuICAgIH0pLFxuICAgIG1hcChyZXN1bHRzID0+IHtcbiAgICAgIHJldHVybiByZXN1bHRzLmZpbHRlcihyZXN1bHQgPT4ge1xuICAgICAgICByZXR1cm4gcmVzdWx0IGluc3RhbmNlb2YgRXJyb3I7XG4gICAgICB9KTtcbiAgICB9KSxcbiAgICBzd2l0Y2hNYXAoZXJyb3JzID0+IHtcbiAgICAgIHJldHVybiBlcnJvcnMubGVuZ3RoID09PSAwID8gb2YoW10pIDogdGhyb3dFcnJvcihlcnJvcnMpO1xuICAgIH0pXG4gICk7XG5cbiAgZmllbGRzOiBGb3JtbHlGaWVsZENvbmZpZ1tdID0gW1xuICAgIHtcbiAgICAgIGtleTogJ2lkJyxcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgdGVtcGxhdGVPcHRpb25zOiB7XG4gICAgICAgIHBsYWNlaG9sZGVyOiAnRkVEOTg3JyxcbiAgICAgICAgbGFiZWw6IGdldHRleHQoJ0lEJyksXG4gICAgICAgIHJlcXVpcmVkOiB0cnVlLFxuICAgICAgICBwYXR0ZXJuOiAnKDB4KXswLDF9WzAtOUEtRl0rKGgpezAsMX0nXG4gICAgICB9LFxuICAgICAgdmFsaWRhdGlvbjoge1xuICAgICAgICBtZXNzYWdlczoge1xuICAgICAgICAgIHBhdHRlcm46IGdldHRleHQoJ011c3QgYmUgYSB2YWxpZCBoZXhhZGVjaW1hbCBudW1iZXIuJylcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0sXG4gICAge1xuICAgICAga2V5OiAncGFjJyxcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgdGVtcGxhdGVPcHRpb25zOiB7XG4gICAgICAgIHBsYWNlaG9sZGVyOiAnRkVEQ0JBOTg3NjU0MzIxMCcsXG4gICAgICAgIGxhYmVsOiBnZXR0ZXh0KCdQQUMnKSxcbiAgICAgICAgcmVxdWlyZWQ6IHRydWUsXG4gICAgICAgIHBhdHRlcm46ICdeKFthLWZBLUYwLTldezE2fSkkJ1xuICAgICAgfSxcbiAgICAgIHZhbGlkYXRpb246IHtcbiAgICAgICAgbWVzc2FnZXM6IHtcbiAgICAgICAgICBwYXR0ZXJuOiBnZXR0ZXh0KCdNdXN0IGJlIGEgdmFsaWQgMTYgZGlnaXQgaGV4YWRlY2ltYWwgbnVtYmVyLicpXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9LFxuICAgIHtcbiAgICAgIGtleTogJ2Nvbm5lY3Rpb24nLFxuICAgICAgdHlwZTogJ3R5cGVhaGVhZCcsXG4gICAgICB0ZW1wbGF0ZU9wdGlvbnM6IHtcbiAgICAgICAgbGFiZWw6IGdldHRleHQoJ0Nvbm5lY3Rpb24nKSxcbiAgICAgICAgcmVxdWlyZWQ6IHRydWUsXG4gICAgICAgIGM4eUZvck9wdGlvbnM6IHRoaXMuY29ubmVjdGlvbnMkLFxuICAgICAgICBkaXNwbGF5UHJvcGVydHk6ICduYW1lJyxcbiAgICAgICAgdmFsdWVQcm9wZXJ0aWVzOiBbJ25hbWUnXVxuICAgICAgfVxuICAgIH0sXG4gICAge1xuICAgICAga2V5OiAnY29udHJhY3QnLFxuICAgICAgdHlwZTogJ3R5cGVhaGVhZCcsXG4gICAgICB0ZW1wbGF0ZU9wdGlvbnM6IHtcbiAgICAgICAgbGFiZWw6IGdldHRleHQoJ0NvbnRyYWN0JyksXG4gICAgICAgIHJlcXVpcmVkOiB0cnVlLFxuICAgICAgICBwbGFjZWhvbGRlcjogJ0ZyZWUgY29udHJhY3RfMjUnLFxuICAgICAgICBkaXNwbGF5UHJvcGVydHk6ICduYW1lJyxcbiAgICAgICAgdmFsdWVQcm9wZXJ0aWVzOiBbJ2lkJ10sXG4gICAgICAgIGRlc2NyaXB0aW9uOiBnZXR0ZXh0KCdPbmx5IGFjdGl2ZSBjb250cmFjdHMgd2l0aCBmcmVlIHNsb3RzIGFyZSBkaXNwbGF5ZWQuJylcbiAgICAgIH0sXG4gICAgICBob29rczoge1xuICAgICAgICBvbkluaXQ6IGZpZWxkID0+IHtcbiAgICAgICAgICBjb25zdCBjb25uZWN0aW9uQ29udHJvbCA9IGZpZWxkLmZvcm0uZ2V0KCdjb25uZWN0aW9uJyk7XG4gICAgICAgICAgY29ubmVjdGlvbkNvbnRyb2wudmFsdWVDaGFuZ2VzXG4gICAgICAgICAgICAucGlwZShcbiAgICAgICAgICAgICAgdGFrZVVudGlsKHRoaXMudW5zdWJzY3JpYmUkKSxcbiAgICAgICAgICAgICAgbWVyZ2VNYXAoKHsgbmFtZSB9KSA9PiB0aGlzLmdldENvbnRyYWN0cyQobmFtZSkpXG4gICAgICAgICAgICApXG4gICAgICAgICAgICAuc3Vic2NyaWJlKFxuICAgICAgICAgICAgICBwcm9maWxlcyA9PiB7XG4gICAgICAgICAgICAgICAgZmllbGQudGVtcGxhdGVPcHRpb25zLmM4eUZvck9wdGlvbnMgPSBvZihwcm9maWxlcyk7XG4gICAgICAgICAgICAgICAgZmllbGQuZm9ybUNvbnRyb2wuc2V0VmFsdWUobnVsbCk7XG4gICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgIGVycm9yID0+IHtcbiAgICAgICAgICAgICAgICBmaWVsZC5mb3JtLmdldCgnY29udHJhY3QnKS5zZXRFcnJvcnMoeyBjb250cmFjdDogdHJ1ZSB9KTtcbiAgICAgICAgICAgICAgICBmaWVsZC52YWxpZGF0b3JzLmNvbnRyYWN0Lm1lc3NhZ2UgPSBlcnJvci5tZXNzYWdlO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICB9LFxuICAgICAgdmFsaWRhdG9yczoge1xuICAgICAgICBjb250cmFjdDoge1xuICAgICAgICAgIGV4cHJlc3Npb246IChjb250cm9sOiBBYnN0cmFjdENvbnRyb2wpID0+IHtcbiAgICAgICAgICAgIHJldHVybiBjb250cm9sLnN0YXR1cyA9PT0gJ1ZBTElEJztcbiAgICAgICAgICB9LFxuICAgICAgICAgIG1lc3NhZ2U6ICgpID0+ICcnXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9LFxuICAgIHtcbiAgICAgIGtleTogJ2RldmljZVR5cGUnLFxuICAgICAgdHlwZTogJ3R5cGVhaGVhZCcsXG4gICAgICB0ZW1wbGF0ZU9wdGlvbnM6IHtcbiAgICAgICAgbGFiZWw6IGdldHRleHQoJ0RldmljZSBwcm90b2NvbCcpLFxuICAgICAgICByZXF1aXJlZDogdHJ1ZSxcbiAgICAgICAgYzh5Rm9yT3B0aW9uczogdGhpcy5wcm90b2NvbHMkLFxuICAgICAgICBkaXNwbGF5UHJvcGVydHk6ICduYW1lJyxcbiAgICAgICAgdmFsdWVQcm9wZXJ0aWVzOiBbJ2lkJywgJ25hbWUnXVxuICAgICAgfVxuICAgIH0sXG4gICAge1xuICAgICAga2V5OiAncHJvZHVjdENlcnRpZmljYXRlJyxcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgdGVtcGxhdGVPcHRpb25zOiB7XG4gICAgICAgIHBsYWNlaG9sZGVyOiAnUF8wMDFGX0VEQ0JfMDEnLFxuICAgICAgICBsYWJlbDogZ2V0dGV4dCgnUHJvZHVjdCBjZXJ0aWZpY2F0ZSBrZXknKSxcbiAgICAgICAgcGF0dGVybjogJ1BfWzAtOUEtRl17NH1fWzAtOUEtRl17NH1fWzAtOUEtRl17Mn0nLFxuICAgICAgICBkZXNjcmlwdGlvbjogZ2V0dGV4dChcbiAgICAgICAgICAnSWYgbm8gcHJvZHVjdCBjZXJ0aWZpY2F0ZSBrZXkgaXMgc3BlY2lmaWVkLCB0aGUgZGV2aWNlIGlzIGNvbnNpZGVyZWQgYSBwcm90b3R5cGUuJ1xuICAgICAgICApXG4gICAgICB9LFxuICAgICAgdmFsaWRhdGlvbjoge1xuICAgICAgICBtZXNzYWdlczoge1xuICAgICAgICAgIHBhdHRlcm46IChfZXJyb3IsIF9maWVsZDogRm9ybWx5RmllbGRDb25maWcpID0+XG4gICAgICAgICAgICB0aGlzLnRyYW5zbGF0ZVNlcnZpY2UuaW5zdGFudChcbiAgICAgICAgICAgICAgZ2V0dGV4dCgnTXVzdCBiZSBhIHZhbGlkIHByb2R1Y3QgY2VydGlmaWNhdGUga2V5LCBmb3IgZXhhbXBsZSwge3sgZXhhbXBsZSB9fScpLFxuICAgICAgICAgICAgICB7IGV4YW1wbGU6ICdQXzAwMUZfRURDQl8wMScgfVxuICAgICAgICAgICAgKVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICBdO1xuXG4gIHJlZ2lzdHJhdGlvblN0ZXBMYWJlbHMgPSB7XG4gICAgbmV4dDogZ2V0dGV4dCgnUmVnaXN0ZXInKVxuICB9O1xuICBmaW5hbFN0ZXBMYWJlbHMgPSB7XG4gICAgYmFjazogZ2V0dGV4dCgnQ2xvc2UnKVxuICB9O1xuXG4gIHN0YXRlOiBTaWdmb3hTdGF0ZSA9ICdsb2FkUGVuZGluZyc7XG4gIGVycm9ycyQgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PEVycm9yW10+KFtdKTtcbiAgZXJyb3JNZXNzYWdlcyQgPSB0aGlzLmVycm9ycyQucGlwZShcbiAgICBtYXAoZXJyb3JzID0+IGVycm9ycy5tYXAoZXJyb3IgPT4gZXJyb3IubWVzc2FnZSkpLFxuICAgIG1hcChtZXNzYWdlcyA9PiB1bmlxKG1lc3NhZ2VzKSlcbiAgKTtcbiAgY29uc3RydWN0b3IoXG4gICAgcHVibGljIGJzTW9kYWxSZWY6IEJzTW9kYWxSZWYsXG4gICAgcHJpdmF0ZSBzaWdmb3hTZXJ2aWNlOiBTaWdmb3hQcm92aWRlclNlcnZpY2UsXG4gICAgcHJpdmF0ZSB0cmFuc2xhdGVTZXJ2aWNlOiBUcmFuc2xhdGVTZXJ2aWNlLFxuICAgIHByaXZhdGUgZ2FpbnNpZ2h0U2VydmljZTogR2FpbnNpZ2h0U2VydmljZVxuICApIHtcbiAgICB0aGlzLmxvYWQkLnN1YnNjcmliZShcbiAgICAgICgpID0+IHtcbiAgICAgICAgdGhpcy5zdGF0ZSA9ICdsb2FkU3VjY2Vzcyc7XG4gICAgICB9LFxuICAgICAgZXJyb3JzID0+IHtcbiAgICAgICAgdGhpcy5zdGF0ZSA9ICdsb2FkRXJyb3InO1xuICAgICAgICB0aGlzLmVycm9ycyQubmV4dChlcnJvcnMpO1xuICAgICAgfVxuICAgICk7XG4gIH1cblxuICBhc3luYyBjcmVhdGUoZXZlbnQ6IHsgc3RlcHBlcjogQzh5U3RlcHBlcjsgc3RlcDogQ2RrU3RlcCB9KSB7XG4gICAgdGhpcy5zdGF0ZSA9ICdyZWdpc3RyYXRpb25QZW5kaW5nJztcbiAgICBjb25zdCBzaWdmb3hEZXZpY2UgPSB0aGlzLmdldFNpZ2ZveERldmljZVRvU2VuZCgpO1xuICAgIHRyeSB7XG4gICAgICBhd2FpdCB0aGlzLnNpZ2ZveFNlcnZpY2UuY3JlYXRlRGV2aWNlKHNpZ2ZveERldmljZSk7XG4gICAgICB0aGlzLnN0YXRlID0gJ3JlZ2lzdHJhdGlvblN1Y2Nlc3MnO1xuICAgICAgdGhpcy5nYWluc2lnaHRTZXJ2aWNlLnRyaWdnZXJFdmVudChQUk9EVUNUX0VYUEVSSUVOQ0VfU0lHRk9YX1JFR0lTVFJBVElPTi5FVkVOVCwge1xuICAgICAgICByZXN1bHQ6IFBST0RVQ1RfRVhQRVJJRU5DRV9TSUdGT1hfUkVHSVNUUkFUSU9OLlJFU1VMVC5TVUNDRVNTLFxuICAgICAgICBjb21wb25lbnQ6IFBST0RVQ1RfRVhQRVJJRU5DRV9TSUdGT1hfUkVHSVNUUkFUSU9OLkNPTVBPTkVOVFxuICAgICAgfSk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIHRoaXMuZ2FpbnNpZ2h0U2VydmljZS50cmlnZ2VyRXZlbnQoUFJPRFVDVF9FWFBFUklFTkNFX1NJR0ZPWF9SRUdJU1RSQVRJT04uRVZFTlQsIHtcbiAgICAgICAgcmVzdWx0OiBQUk9EVUNUX0VYUEVSSUVOQ0VfU0lHRk9YX1JFR0lTVFJBVElPTi5SRVNVTFQuRkFJTFVSRSxcbiAgICAgICAgY29tcG9uZW50OiBQUk9EVUNUX0VYUEVSSUVOQ0VfU0lHRk9YX1JFR0lTVFJBVElPTi5DT01QT05FTlRcbiAgICAgIH0pO1xuICAgICAgdGhpcy5zdGF0ZSA9ICdyZWdpc3RyYXRpb25FcnJvcic7XG4gICAgICB0aGlzLmVycm9ycyQubmV4dChbZXJyb3JdKTtcbiAgICB9XG5cbiAgICBldmVudC5zdGVwcGVyLm5leHQoKTtcbiAgfVxuXG4gIGdldFNpZ2ZveERldmljZVRvU2VuZCgpIHtcbiAgICBjb25zdCBzaWdmb3hEZXZpY2U6IFNpZ2ZveERldmljZSA9IGNsb25lRGVlcCh0aGlzLm1vZGVsKTtcbiAgICBzaWdmb3hEZXZpY2UubG5zQ29ubmVjdGlvbk5hbWUgPSB0aGlzLm1vZGVsLmNvbm5lY3Rpb24ubmFtZTtcbiAgICBzaWdmb3hEZXZpY2UuY29udHJhY3RJZCA9IHRoaXMubW9kZWwuY29udHJhY3QuaWQ7XG4gICAgc2lnZm94RGV2aWNlLnByb3RvdHlwZSA9ICFzaWdmb3hEZXZpY2UucHJvZHVjdENlcnRpZmljYXRlO1xuICAgIGRlbGV0ZSAoc2lnZm94RGV2aWNlIGFzIGFueSkuY29udHJhY3Q7XG4gICAgZGVsZXRlIChzaWdmb3hEZXZpY2UgYXMgYW55KS5jb25uZWN0aW9uO1xuICAgIHJldHVybiBzaWdmb3hEZXZpY2U7XG4gIH1cblxuICBnZXRDb250cmFjdHMkKG5hbWUpIHtcbiAgICByZXR1cm4gZGVmZXIoKCkgPT4gZnJvbSh0aGlzLnNpZ2ZveFNlcnZpY2UuZ2V0Q29udHJhY3RzKG5hbWUpKSkucGlwZShzaGFyZVJlcGxheSgxKSk7XG4gIH1cblxuICBnZXRQcm90b2NvbHMkKCkge1xuICAgIHJldHVybiBkZWZlcigoKSA9PiBmcm9tKHRoaXMuc2lnZm94U2VydmljZS5nZXRBdmFpbGFibGVQcm90b2NvbHMoKSkpLnBpcGUoc2hhcmVSZXBsYXkoMSkpO1xuICB9XG5cbiAgZ2V0Q29ubmVjdGlvbnMkKCkge1xuICAgIHJldHVybiBkZWZlcigoKSA9PiBmcm9tKHRoaXMuc2lnZm94U2VydmljZS5nZXRDb25uZWN0aW9ucygpKSkucGlwZShzaGFyZVJlcGxheSgxKSk7XG4gIH1cblxuICBuZ09uRGVzdHJveSgpOiB2b2lkIHtcbiAgICB0aGlzLnVuc3Vic2NyaWJlJC5uZXh0KCk7XG4gICAgdGhpcy51bnN1YnNjcmliZSQuY29tcGxldGUoKTtcbiAgfVxufVxuIiwiPGM4eS1tb2RhbFxuICBbdGl0bGVdPVwiJ1NpZ2ZveCByZWdpc3RyYXRpb24nIHwgdHJhbnNsYXRlXCJcbiAgW2hlYWRlckNsYXNzZXNdPVwiJ2RpYWxvZy1oZWFkZXInXCJcbiAgW2N1c3RvbUZvb3Rlcl09XCJ0cnVlXCJcbj5cbiAgPG5nLWNvbnRhaW5lciBjOHktbW9kYWwtdGl0bGU+XG4gICAgPHNwYW4gW2M4eUljb25dPVwiJ2M4eS1kZXZpY2UtY29ubmVjdCdcIj48L3NwYW4+XG4gIDwvbmctY29udGFpbmVyPlxuICA8bmctY29udGFpbmVyICpuZ0lmPVwic3RhdGUgPT09ICdsb2FkUGVuZGluZyc7IGVsc2UgcmVnaXN0cmF0aW9uRm9ybVwiPlxuICAgIDxkaXYgY2xhc3M9XCJwLTE2IHRleHQtY2VudGVyXCI+XG4gICAgICA8Yzh5LWxvYWRpbmc+PC9jOHktbG9hZGluZz5cbiAgICA8L2Rpdj5cbiAgPC9uZy1jb250YWluZXI+XG5cbiAgPG5nLXRlbXBsYXRlICNyZWdpc3RyYXRpb25Gb3JtPlxuICAgIDxjOHktc3RlcHBlclxuICAgICAgW2hpZGVTdGVwUHJvZ3Jlc3NdPVwidHJ1ZVwiXG4gICAgICBsaW5lYXJcbiAgICAgIGM4eS1tb2RhbC1ib2R5XG4gICAgICAqbmdJZj1cIihlcnJvck1lc3NhZ2VzJCB8IGFzeW5jKS5sZW5ndGggPT09IDA7IGVsc2UgZXJyb3JNZXNzYWdlc1ByZXNlbnRcIlxuICAgID5cbiAgICAgIDxjZGstc3RlcCBbc3RlcENvbnRyb2xdPVwiZm9ybVwiPlxuICAgICAgICA8ZGl2IGNsYXNzPVwicC1iLTE2XCI+XG4gICAgICAgICAgPHAgY2xhc3M9XCJtb2RhbC1zdWJ0aXRsZSBzdGlja3ktdG9wXCI+XG4gICAgICAgICAgICB7eyAnUmVnaXN0ZXIgYSBzaW5nbGUgU2lnZm94IGRldmljZScgfCB0cmFuc2xhdGUgfX1cbiAgICAgICAgICA8L3A+XG4gICAgICAgICAgPGZvcm1seS1mb3JtXG4gICAgICAgICAgICBjbGFzcz1cImQtYmxvY2sgcC1sLTI0IHAtci0yNCBwLXQtMTZcIlxuICAgICAgICAgICAgW2Zvcm1dPVwiZm9ybVwiXG4gICAgICAgICAgICBbZmllbGRzXT1cImZpZWxkc1wiXG4gICAgICAgICAgICBbbW9kZWxdPVwibW9kZWxcIlxuICAgICAgICAgID48L2Zvcm1seS1mb3JtPlxuICAgICAgICA8L2Rpdj5cbiAgICAgICAgPGM4eS1zdGVwcGVyLWJ1dHRvbnNcbiAgICAgICAgICBjbGFzcz1cIm1vZGFsLWZvb3RlciBkLWJsb2NrIHN0aWNreS1ib3R0b20gc2VwYXJhdG9yLXRvcCBiZy1jb21wb25lbnRcIlxuICAgICAgICAgIFtsYWJlbHNdPVwicmVnaXN0cmF0aW9uU3RlcExhYmVsc1wiXG4gICAgICAgICAgKG9uTmV4dCk9XCJjcmVhdGUoJGV2ZW50KVwiXG4gICAgICAgICAgKG9uQ2FuY2VsKT1cImJzTW9kYWxSZWYuaGlkZSgpXCJcbiAgICAgICAgICBbc2hvd0J1dHRvbnNdPVwieyBjYW5jZWw6IHRydWUsIG5leHQ6IHRydWUgfVwiXG4gICAgICAgICAgW3BlbmRpbmddPVwic3RhdGUgPT09ICdyZWdpc3RyYXRpb25QZW5kaW5nJ1wiXG4gICAgICAgICAgW2Rpc2FibGVkXT1cIiFmb3JtLnZhbGlkXCJcbiAgICAgICAgPjwvYzh5LXN0ZXBwZXItYnV0dG9ucz5cbiAgICAgIDwvY2RrLXN0ZXA+XG4gICAgICA8Y2RrLXN0ZXAgc3RhdGU9XCJmaW5hbFwiPlxuICAgICAgICA8ZGl2XG4gICAgICAgICAgY2xhc3M9XCJwLTE2IHRleHQtY2VudGVyXCJcbiAgICAgICAgICAqbmdJZj1cInN0YXRlID09PSAncmVnaXN0cmF0aW9uUGVuZGluZydcIlxuICAgICAgICA+XG4gICAgICAgICAgPGM4eS1sb2FkaW5nPjwvYzh5LWxvYWRpbmc+XG4gICAgICAgIDwvZGl2PlxuICAgICAgICA8ZGl2IGNsYXNzPVwibS0yNFwiPlxuICAgICAgICAgIDxjOHktb3BlcmF0aW9uLXJlc3VsdFxuICAgICAgICAgICAgY2xhc3M9XCJsZWFkIG0tYi0wXCJcbiAgICAgICAgICAgIHR5cGU9XCJzdWNjZXNzXCJcbiAgICAgICAgICAgICpuZ0lmPVwic3RhdGUgPT09ICdyZWdpc3RyYXRpb25TdWNjZXNzJ1wiXG4gICAgICAgICAgICB0ZXh0PVwie3sgJ0RldmljZSByZWdpc3RlcmVkJyB8IHRyYW5zbGF0ZSB9fVwiXG4gICAgICAgICAgICBbc2l6ZV09XCI4NFwiXG4gICAgICAgICAgICBbdmVydGljYWxdPVwidHJ1ZVwiXG4gICAgICAgICAgPjwvYzh5LW9wZXJhdGlvbi1yZXN1bHQ+XG4gICAgICAgIDwvZGl2PlxuXG4gICAgICAgIDxjOHktc3RlcHBlci1idXR0b25zXG4gICAgICAgICAgY2xhc3M9XCJzdGlja3ktYm90dG9tIGQtYmxvY2sgcC10LTE2IHAtYi0xNiBzZXBhcmF0b3ItdG9wIGJnLWNvbXBvbmVudFwiXG4gICAgICAgICAgKG9uQ3VzdG9tKT1cImJzTW9kYWxSZWYuaGlkZSgpXCJcbiAgICAgICAgICBbc2hvd0J1dHRvbnNdPVwieyBjdXN0b206IHRydWUgfVwiXG4gICAgICAgICAgW2xhYmVsc109XCJmaW5hbFN0ZXBMYWJlbHNcIlxuICAgICAgICA+PC9jOHktc3RlcHBlci1idXR0b25zPlxuICAgICAgPC9jZGstc3RlcD5cbiAgICA8L2M4eS1zdGVwcGVyPlxuICA8L25nLXRlbXBsYXRlPlxuXG4gIDxuZy10ZW1wbGF0ZSAjZXJyb3JNZXNzYWdlc1ByZXNlbnQ+XG4gICAgPGRpdiBjbGFzcz1cIm0tMjRcIj5cbiAgICAgIDxjOHktb3BlcmF0aW9uLXJlc3VsdFxuICAgICAgICBjbGFzcz1cImxlYWRcIlxuICAgICAgICB0eXBlPVwiZXJyb3JcIlxuICAgICAgICAqbmdJZj1cInN0YXRlID09PSAncmVnaXN0cmF0aW9uRXJyb3InXCJcbiAgICAgICAgdGV4dD1cInt7ICdGYWlsZWQgdG8gcmVnaXN0ZXInIHwgdHJhbnNsYXRlIH19XCJcbiAgICAgICAgW3NpemVdPVwiODRcIlxuICAgICAgICBbdmVydGljYWxdPVwidHJ1ZVwiXG4gICAgICA+PC9jOHktb3BlcmF0aW9uLXJlc3VsdD5cbiAgICAgIDxkaXZcbiAgICAgICAgY2xhc3M9XCJtLWItOFwiXG4gICAgICAgICpuZ0Zvcj1cImxldCBtc2cgb2YgZXJyb3JNZXNzYWdlcyQgfCBhc3luY1wiXG4gICAgICAgIGRhdGEtY3k9XCJzaWdmb3gtZGV2aWNlLXJlZ2lzdHJhdGlvbi5jb21wb25lbnQtLXJlZ2lzdHJhdGlvbi1lcnJvclwiXG4gICAgICAgIFtuZ0NsYXNzXT1cIntcbiAgICAgICAgICAndGV4dC1jZW50ZXInOiBzdGF0ZSA9PT0gJ3JlZ2lzdHJhdGlvbkVycm9yJyxcbiAgICAgICAgICAnYWxlcnQgYWxlcnQtZGFuZ2VyJzogc3RhdGUgPT09ICdsb2FkRXJyb3InXG4gICAgICAgIH1cIlxuICAgICAgPlxuICAgICAgICA8c3BhbiBbaW5uZXJIVE1MXT1cIm1zZyB8IHRyYW5zbGF0ZVwiPjwvc3Bhbj5cbiAgICAgIDwvZGl2PlxuICAgIDwvZGl2PlxuXG4gICAgPGRpdiBjbGFzcz1cIm1vZGFsLWZvb3RlclwiPlxuICAgICAgPGJ1dHRvblxuICAgICAgICBjbGFzcz1cImJ0biBidG4tZGVmYXVsdFwiXG4gICAgICAgIHRpdGxlPVwie3sgJ0Nsb3NlJyB8IHRyYW5zbGF0ZSB9fVwiXG4gICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICAoY2xpY2spPVwiYnNNb2RhbFJlZi5oaWRlKClcIlxuICAgICAgPlxuICAgICAgICB7eyAnQ2xvc2UnIHwgdHJhbnNsYXRlIH19XG4gICAgICA8L2J1dHRvbj5cbiAgICA8L2Rpdj5cbiAgPC9uZy10ZW1wbGF0ZT5cbjwvYzh5LW1vZGFsPlxuIl19