UNPKG

@c8y/ngx-components

Version:

Angular modules for Cumulocity IoT applications

142 lines 44.3 kB
import { Component, ViewChild } from '@angular/core'; import { FormGroup } from '@angular/forms'; import { DeviceRegistrationBulkService, FeatureService } from '@c8y/client'; import { C8yJSONSchema, C8yStepper, GainsightService, gettext } from '@c8y/ngx-components'; import { saveAs } from 'file-saver'; import { BsModalRef } from 'ngx-bootstrap/modal'; import { PRODUCT_EXPERIENCE_BASE_REGISTRATION } from '../extensible/base-device-registration.model'; import { RegisterDeviceService } from '../register-device.service'; import { TranslateService } from '@ngx-translate/core'; import * as i0 from "@angular/core"; import * as i1 from "@c8y/ngx-components"; import * as i2 from "@c8y/client"; import * as i3 from "../register-device.service"; import * as i4 from "ngx-bootstrap/modal"; import * as i5 from "@ngx-translate/core"; import * as i6 from "@angular/common"; import * as i7 from "@angular/cdk/stepper"; import * as i8 from "@ngx-formly/core"; const registerDeviceBulkSchema = { $schema: 'https://json-schema.org/draft/2019-09/schema', type: 'object', properties: { csvBulkFile: { type: 'array', title: gettext('CSV file upload'), description: gettext('You can use file upload component to let users send files. This input accepts only a single CSV file.'), contentMediaType: 'csv' } }, required: ['csvBulkFile'], additionalProperties: false }; const simpleCsvHeaders = ['ID', 'PATH']; const csvHeaders = [ 'ID', 'TYPE', 'NAME', 'ICCID', 'IDTYPE', 'PATH', 'SHELL', 'AUTH_TYPE' ]; const fullCsvHeaders = [...csvHeaders, 'CREDENTIALS']; export const ESTCsvHeaders = [...csvHeaders, 'ENROLLMENT_OTP']; export class BulkDeviceRegistrationModalComponent { constructor(jsonschema, deviceRegistrationService, registerDeviceService, bsModalRef, gainsightService, featureService, translateService) { this.jsonschema = jsonschema; this.deviceRegistrationService = deviceRegistrationService; this.registerDeviceService = registerDeviceService; this.bsModalRef = bsModalRef; this.gainsightService = gainsightService; this.featureService = featureService; this.translateService = translateService; this.form = new FormGroup({}); this.model = {}; this.certificateAuthorityFeatureEnabled = this.featureService .detail('certificate-authority') .then(({ data }) => data.active); } ngOnInit() { this.template = [this.jsonschema.toFieldConfig(registerDeviceBulkSchema)]; } upload() { this.pending = true; const file = this.getFile(this.model); this.deviceRegistrationService .create(file) .then(({ res, data }) => { if (res.status < 400) { this.result = data; this.success = data.numberOfFailed === 0 && data.numberOfSuccessful === data.numberOfAll; this.message = this.success ? gettext('Device registration created.') : (this.message = gettext('Device registration failed.')); if (this.success) { this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_BASE_REGISTRATION.EVENT, { result: PRODUCT_EXPERIENCE_BASE_REGISTRATION.RESULT.SUCCESS, component: PRODUCT_EXPERIENCE_BASE_REGISTRATION.COMPONENT.BULK }); } else { this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_BASE_REGISTRATION.EVENT, { result: PRODUCT_EXPERIENCE_BASE_REGISTRATION.RESULT.FAILURE, component: PRODUCT_EXPERIENCE_BASE_REGISTRATION.COMPONENT.BULK }); } } else { this.failedResult = data; this.message = gettext('Device registration failed.'); this.gainsightService.triggerEvent(PRODUCT_EXPERIENCE_BASE_REGISTRATION.EVENT, { result: PRODUCT_EXPERIENCE_BASE_REGISTRATION.RESULT.FAILURE, component: PRODUCT_EXPERIENCE_BASE_REGISTRATION.COMPONENT.BULK }); } this.model = {}; this.pending = false; this.stepper.next(); }) .catch(() => { this.message = gettext('Error occurred while processing the uploaded file.'); this.pending = false; this.stepper.next(); }); } downloadSimple() { return this.download(simpleCsvHeaders, gettext('Simple bulk registration - template.csv')); } downloadFull() { return this.download(fullCsvHeaders, gettext('Full bulk registration - template.csv')); } downloadEst() { return this.download(ESTCsvHeaders, gettext('EST registration - template.csv')); } download(headers, fileName) { const headerRaw = headers.map(header => `"${header}"`).join(';'); const binaryFile = new Blob([headerRaw], { type: 'text/csv' }); saveAs(binaryFile, this.translateService.instant(fileName)); } complete() { this.registerDeviceService.list(); this.bsModalRef.hide(); } cancel() { this.bsModalRef.hide(); } getFile(model) { const csvBulkFile = model?.csvBulkFile; return csvBulkFile ? csvBulkFile[0]?.file : undefined; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: BulkDeviceRegistrationModalComponent, deps: [{ token: i1.C8yJSONSchema }, { token: i2.DeviceRegistrationBulkService }, { token: i3.RegisterDeviceService }, { token: i4.BsModalRef }, { token: i1.GainsightService }, { token: i2.FeatureService }, { token: i5.TranslateService }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: BulkDeviceRegistrationModalComponent, selector: "bulk-device-registration", viewQueries: [{ propertyName: "stepper", first: true, predicate: C8yStepper, descendants: true, static: true }], ngImport: i0, template: "<c8y-modal\n [title]=\"'Bulk device registration' | translate\"\n [headerClasses]=\"'dialog-header'\"\n [customFooter]=\"true\"\n>\n <ng-container c8y-modal-title>\n <i c8yIcon=\"upload\"></i>\n </ng-container>\n\n <c8y-stepper [hideStepProgress]=\"true\" linear id=\"modal-body\">\n <cdk-step>\n <p class=\"modal-subtitle sticky-top\" translate>Register devices in bulk</p>\n\n <c8y-form-group class=\"d-block p-24 p-t-16 p-b-0 m-b-0\">\n <formly-form [form]=\"form\" [fields]=\"template\" [model]=\"model\"></formly-form>\n </c8y-form-group>\n\n <div class=\"p-24 m-t-0 bg-level-1\">\n <div class=\"bg-gray-white separator-bottom p-t-16 p-b-16 p-l-24 p-r-24\">\n <div>\n <p class=\"m-b-8 text-medium\">\n <strong translate>Simple registration</strong>\n </p>\n <small class=\"text-muted\" translate>\n Creates all registration requests at once, then each one needs to go through regular\n acceptance process.\n </small>\n </div>\n <div class=\"m-b-16 m-t-16\">\n <a\n title=\"{{ 'Download template' | translate }}\"\n class=\"btn btn-default btn-sm\"\n target=\"_self\"\n (click)=\"downloadSimple()\"\n >\n <i c8yIcon=\"download\" translate></i>\n {{ 'Download template' | translate }}\n </a>\n </div>\n </div>\n <div class=\"bg-gray-white separator-bottom p-t-16 p-b-16 p-l-24 p-r-24\">\n <div>\n <p class=\"m-b-8 text-medium\">\n <strong translate>Full registration</strong>\n </p>\n <small class=\"text-muted\" translate>\n Creates all device credentials and devices using provided list of property values.\n Devices can start communicating with the platform immediately.\n </small>\n </div>\n <div class=\"m-b-16 m-t-16\">\n <a\n title=\"{{ 'Download template' | translate }}\"\n class=\"btn btn-default btn-sm\"\n target=\"_self\"\n (click)=\"downloadFull()\"\n >\n <i c8yIcon=\"download\" translate></i>\n {{ 'Download template' | translate }}\n </a>\n </div>\n </div>\n <div class=\"bg-gray-white separator-bottom p-t-16 p-b-16 p-l-24 p-r-24\" *ngIf=\"certificateAuthorityFeatureEnabled | async\">\n <div>\n <p class=\"m-b-8 text-medium\">\n <strong translate>Full registration with device certificate creation</strong>\n </p>\n <small class=\"text-muted\" translate>\n Creates device certificates and devices using the provided list of property values. Once the certificates are provisioned, the devices can immediately start communicating with the platform\n </small>\n </div>\n <div class=\"m-b-16 m-t-16\">\n <a\n title=\"{{ 'Download template' | translate }}\"\n class=\"btn btn-default btn-sm\"\n target=\"_self\"\n (click)=\"downloadEst()\"\n >\n <i c8yIcon=\"download\"></i>\n {{ 'Download template' | translate }}\n </a>\n </div>\n </div>\n </div>\n\n <c8y-stepper-buttons\n class=\"sticky-bottom d-block p-t-16 p-b-16 separator-top bg-level-0\"\n [showButtons]=\"{ cancel: true, next: true }\"\n [disabled]=\"form.invalid\"\n [pending]=\"pending\"\n (onCancel)=\"cancel()\"\n (onNext)=\"upload()\"\n [labels]=\"{ next: 'Upload' }\"\n ></c8y-stepper-buttons>\n </cdk-step>\n\n <cdk-step state=\"final\">\n <div class=\"m-24\">\n <div *ngIf=\"success; else warning\">\n <c8y-operation-result\n text=\"{{ message | translate }}\"\n [size]=\"84\"\n [vertical]=\"true\"\n type=\"success\"\n class=\"lead\"\n ></c8y-operation-result>\n </div>\n <ng-template #warning>\n <c8y-operation-result\n text=\"{{ message | translate }}\"\n [size]=\"84\"\n [vertical]=\"true\"\n type=\"error\"\n class=\"lead\"\n ></c8y-operation-result>\n </ng-template>\n <c8y-list-group class=\"separator-top m-t-16\">\n <ng-container *ngIf=\"result; else failedResponse\">\n <c8y-li *ngIf=\"success; else fail\">\n <c8y-li-icon class=\"text-success\" icon=\"check-circle\"></c8y-li-icon>\n <p>{{ 'All devices have been processed.' | translate }}</p>\n <c8y-li-collapse>\n <pre><code>{{ result | json }}</code></pre>\n </c8y-li-collapse>\n </c8y-li>\n <ng-template #fail>\n <c8y-li>\n <c8y-li-icon class=\"text-danger\" icon=\"ban\"></c8y-li-icon>\n <p\n ngNonBindable\n [translateParams]=\"{ count: result?.numberOfFailed, total: result?.numberOfAll }\"\n translate\n >\n Failed to process {{ count }} out of {{ total }}.\n </p>\n <c8y-li-collapse>\n <pre><code>{{ result | json }}</code></pre>\n </c8y-li-collapse>\n </c8y-li>\n </ng-template>\n </ng-container>\n <ng-template #failedResponse>\n <c8y-li>\n <c8y-li-icon class=\"text-danger\" [icon]=\"'ban'\"></c8y-li-icon>\n <small>{{ failedResult?.message | translate }}</small>\n <c8y-li-collapse>\n <pre><code>{{ failedResult | json }}</code></pre>\n </c8y-li-collapse>\n </c8y-li>\n </ng-template>\n </c8y-list-group>\n </div>\n <c8y-stepper-buttons\n class=\"sticky-bottom d-block p-t-16 p-b-16 separator-top bg-level-0\"\n [showButtons]=\"{ next: true }\"\n (onNext)=\"complete()\"\n [labels]=\"{ next: success ? 'Close' : 'Cancel' }\"\n ></c8y-stepper-buttons>\n </cdk-step>\n </c8y-stepper>\n</c8y-modal>\n", dependencies: [{ kind: "directive", type: i1.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i1.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i6.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i1.OperationResultComponent, selector: "c8y-operation-result", inputs: ["text", "vertical", "size", "type"] }, { kind: "component", type: i1.ModalComponent, selector: "c8y-modal", inputs: ["disabled", "close", "dismiss", "title", "body", "customFooter", "headerClasses", "labels"], outputs: ["onDismiss", "onClose"] }, { kind: "component", type: i1.FormGroupComponent, selector: "c8y-form-group", inputs: ["hasError", "hasWarning", "hasSuccess", "novalidation", "status"] }, { kind: "component", type: i1.C8yStepper, selector: "c8y-stepper", inputs: ["disableDefaultIcons", "disableProgressButtons", "customClasses", "hideStepProgress", "useStepLabelsAsTitlesOnly"], outputs: ["onStepChange"] }, { kind: "component", type: i7.CdkStep, selector: "cdk-step", inputs: ["stepControl", "label", "errorMessage", "aria-label", "aria-labelledby", "state", "editable", "optional", "completed", "hasError"], outputs: ["interacted"], exportAs: ["cdkStep"] }, { kind: "component", type: i1.C8yStepperButtons, selector: "c8y-stepper-buttons", inputs: ["labels", "pending", "disabled", "showButtons"], outputs: ["onCancel", "onNext", "onBack", "onCustom"] }, { kind: "component", type: i1.ListGroupComponent, selector: "c8y-list-group" }, { kind: "component", type: i1.ListItemComponent, selector: "c8y-list-item, c8y-li", inputs: ["active", "highlighted", "emptyActions", "dense", "collapsed", "selectable"], outputs: ["collapsedChange"] }, { kind: "component", type: i1.ListItemIconComponent, selector: "c8y-list-item-icon, c8y-li-icon", inputs: ["icon", "status"] }, { kind: "component", type: i1.ListItemCollapseComponent, selector: "c8y-list-item-collapse, c8y-li-collapse", inputs: ["collapseWay"] }, { kind: "component", type: i8.FormlyForm, selector: "formly-form", inputs: ["form", "model", "fields", "options"], outputs: ["modelChange"] }, { kind: "pipe", type: i1.C8yTranslatePipe, name: "translate" }, { kind: "pipe", type: i6.AsyncPipe, name: "async" }, { kind: "pipe", type: i6.JsonPipe, name: "json" }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: BulkDeviceRegistrationModalComponent, decorators: [{ type: Component, args: [{ selector: 'bulk-device-registration', template: "<c8y-modal\n [title]=\"'Bulk device registration' | translate\"\n [headerClasses]=\"'dialog-header'\"\n [customFooter]=\"true\"\n>\n <ng-container c8y-modal-title>\n <i c8yIcon=\"upload\"></i>\n </ng-container>\n\n <c8y-stepper [hideStepProgress]=\"true\" linear id=\"modal-body\">\n <cdk-step>\n <p class=\"modal-subtitle sticky-top\" translate>Register devices in bulk</p>\n\n <c8y-form-group class=\"d-block p-24 p-t-16 p-b-0 m-b-0\">\n <formly-form [form]=\"form\" [fields]=\"template\" [model]=\"model\"></formly-form>\n </c8y-form-group>\n\n <div class=\"p-24 m-t-0 bg-level-1\">\n <div class=\"bg-gray-white separator-bottom p-t-16 p-b-16 p-l-24 p-r-24\">\n <div>\n <p class=\"m-b-8 text-medium\">\n <strong translate>Simple registration</strong>\n </p>\n <small class=\"text-muted\" translate>\n Creates all registration requests at once, then each one needs to go through regular\n acceptance process.\n </small>\n </div>\n <div class=\"m-b-16 m-t-16\">\n <a\n title=\"{{ 'Download template' | translate }}\"\n class=\"btn btn-default btn-sm\"\n target=\"_self\"\n (click)=\"downloadSimple()\"\n >\n <i c8yIcon=\"download\" translate></i>\n {{ 'Download template' | translate }}\n </a>\n </div>\n </div>\n <div class=\"bg-gray-white separator-bottom p-t-16 p-b-16 p-l-24 p-r-24\">\n <div>\n <p class=\"m-b-8 text-medium\">\n <strong translate>Full registration</strong>\n </p>\n <small class=\"text-muted\" translate>\n Creates all device credentials and devices using provided list of property values.\n Devices can start communicating with the platform immediately.\n </small>\n </div>\n <div class=\"m-b-16 m-t-16\">\n <a\n title=\"{{ 'Download template' | translate }}\"\n class=\"btn btn-default btn-sm\"\n target=\"_self\"\n (click)=\"downloadFull()\"\n >\n <i c8yIcon=\"download\" translate></i>\n {{ 'Download template' | translate }}\n </a>\n </div>\n </div>\n <div class=\"bg-gray-white separator-bottom p-t-16 p-b-16 p-l-24 p-r-24\" *ngIf=\"certificateAuthorityFeatureEnabled | async\">\n <div>\n <p class=\"m-b-8 text-medium\">\n <strong translate>Full registration with device certificate creation</strong>\n </p>\n <small class=\"text-muted\" translate>\n Creates device certificates and devices using the provided list of property values. Once the certificates are provisioned, the devices can immediately start communicating with the platform\n </small>\n </div>\n <div class=\"m-b-16 m-t-16\">\n <a\n title=\"{{ 'Download template' | translate }}\"\n class=\"btn btn-default btn-sm\"\n target=\"_self\"\n (click)=\"downloadEst()\"\n >\n <i c8yIcon=\"download\"></i>\n {{ 'Download template' | translate }}\n </a>\n </div>\n </div>\n </div>\n\n <c8y-stepper-buttons\n class=\"sticky-bottom d-block p-t-16 p-b-16 separator-top bg-level-0\"\n [showButtons]=\"{ cancel: true, next: true }\"\n [disabled]=\"form.invalid\"\n [pending]=\"pending\"\n (onCancel)=\"cancel()\"\n (onNext)=\"upload()\"\n [labels]=\"{ next: 'Upload' }\"\n ></c8y-stepper-buttons>\n </cdk-step>\n\n <cdk-step state=\"final\">\n <div class=\"m-24\">\n <div *ngIf=\"success; else warning\">\n <c8y-operation-result\n text=\"{{ message | translate }}\"\n [size]=\"84\"\n [vertical]=\"true\"\n type=\"success\"\n class=\"lead\"\n ></c8y-operation-result>\n </div>\n <ng-template #warning>\n <c8y-operation-result\n text=\"{{ message | translate }}\"\n [size]=\"84\"\n [vertical]=\"true\"\n type=\"error\"\n class=\"lead\"\n ></c8y-operation-result>\n </ng-template>\n <c8y-list-group class=\"separator-top m-t-16\">\n <ng-container *ngIf=\"result; else failedResponse\">\n <c8y-li *ngIf=\"success; else fail\">\n <c8y-li-icon class=\"text-success\" icon=\"check-circle\"></c8y-li-icon>\n <p>{{ 'All devices have been processed.' | translate }}</p>\n <c8y-li-collapse>\n <pre><code>{{ result | json }}</code></pre>\n </c8y-li-collapse>\n </c8y-li>\n <ng-template #fail>\n <c8y-li>\n <c8y-li-icon class=\"text-danger\" icon=\"ban\"></c8y-li-icon>\n <p\n ngNonBindable\n [translateParams]=\"{ count: result?.numberOfFailed, total: result?.numberOfAll }\"\n translate\n >\n Failed to process {{ count }} out of {{ total }}.\n </p>\n <c8y-li-collapse>\n <pre><code>{{ result | json }}</code></pre>\n </c8y-li-collapse>\n </c8y-li>\n </ng-template>\n </ng-container>\n <ng-template #failedResponse>\n <c8y-li>\n <c8y-li-icon class=\"text-danger\" [icon]=\"'ban'\"></c8y-li-icon>\n <small>{{ failedResult?.message | translate }}</small>\n <c8y-li-collapse>\n <pre><code>{{ failedResult | json }}</code></pre>\n </c8y-li-collapse>\n </c8y-li>\n </ng-template>\n </c8y-list-group>\n </div>\n <c8y-stepper-buttons\n class=\"sticky-bottom d-block p-t-16 p-b-16 separator-top bg-level-0\"\n [showButtons]=\"{ next: true }\"\n (onNext)=\"complete()\"\n [labels]=\"{ next: success ? 'Close' : 'Cancel' }\"\n ></c8y-stepper-buttons>\n </cdk-step>\n </c8y-stepper>\n</c8y-modal>\n" }] }], ctorParameters: () => [{ type: i1.C8yJSONSchema }, { type: i2.DeviceRegistrationBulkService }, { type: i3.RegisterDeviceService }, { type: i4.BsModalRef }, { type: i1.GainsightService }, { type: i2.FeatureService }, { type: i5.TranslateService }], propDecorators: { stepper: [{ type: ViewChild, args: [C8yStepper, { static: true }] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYnVsay1kZXZpY2UtcmVnaXN0cmF0aW9uLW1vZGFsLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3JlZ2lzdGVyLWRldmljZS9idWxrL2J1bGstZGV2aWNlLXJlZ2lzdHJhdGlvbi1tb2RhbC5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi9yZWdpc3Rlci1kZXZpY2UvYnVsay9idWxrLWRldmljZS1yZWdpc3RyYXRpb24tbW9kYWwuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFNBQVMsRUFBRSxTQUFTLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDckQsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQzNDLE9BQU8sRUFDTCw2QkFBNkIsRUFDN0IsY0FBYyxFQUVmLE1BQU0sYUFBYSxDQUFDO0FBQ3JCLE9BQU8sRUFBRSxhQUFhLEVBQUUsVUFBVSxFQUFFLGdCQUFnQixFQUFFLE9BQU8sRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBRTNGLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxZQUFZLENBQUM7QUFDcEMsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQ2pELE9BQU8sRUFBRSxvQ0FBb0MsRUFBRSxNQUFNLDhDQUE4QyxDQUFDO0FBRXBHLE9BQU8sRUFBRSxxQkFBcUIsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBQ25FLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLHFCQUFxQixDQUFDOzs7Ozs7Ozs7O0FBRXZELE1BQU0sd0JBQXdCLEdBQVc7SUFDdkMsT0FBTyxFQUFFLDhDQUE4QztJQUN2RCxJQUFJLEVBQUUsUUFBUTtJQUNkLFVBQVUsRUFBRTtRQUNWLFdBQVcsRUFBRTtZQUNYLElBQUksRUFBRSxPQUFPO1lBQ2IsS0FBSyxFQUFFLE9BQU8sQ0FBQyxpQkFBaUIsQ0FBQztZQUNqQyxXQUFXLEVBQUUsT0FB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b0M7a0JBSmhELFNBQVM7K0JBQ0UsMEJBQTBCO3NSQUlLLE9BQU87c0JBQS9DLFNBQVM7dUJBQUMsVUFBVSxFQUFFLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCwgVmlld0NoaWxkIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBGb3JtR3JvdXAgfSBmcm9tICdAYW5ndWxhci9mb3Jtcyc7XG5pbXBvcnQge1xuICBEZXZpY2VSZWdpc3RyYXRpb25CdWxrU2VydmljZSxcbiAgRmVhdHVyZVNlcnZpY2UsXG4gIElEZXZpY2VSZWdpc3RyYXRpb25CdWxrUmVzdWx0XG59IGZyb20gJ0BjOHkvY2xpZW50JztcbmltcG9ydCB7IEM4eUpTT05TY2hlbWEsIEM4eVN0ZXBwZXIsIEdhaW5zaWdodFNlcnZpY2UsIGdldHRleHQgfSBmcm9tICdAYzh5L25neC1jb21wb25lbnRzJztcbmltcG9ydCB7IEZvcm1seUZpZWxkQ29uZmlnIH0gZnJvbSAnQG5neC1mb3JtbHkvY29yZSc7XG5pbXBvcnQgeyBzYXZlQXMgfSBmcm9tICdmaWxlLXNhdmVyJztcbmltcG9ydCB7IEJzTW9kYWxSZWYgfSBmcm9tICduZ3gtYm9vdHN0cmFwL21vZGFsJztcbmltcG9ydCB7IFBST0RVQ1RfRVhQRVJJRU5DRV9CQVNFX1JFR0lTVFJBVElPTiB9IGZyb20gJy4uL2V4dGVuc2libGUvYmFzZS1kZXZpY2UtcmVnaXN0cmF0aW9uLm1vZGVsJztcbmltcG9ydCB7IEJ1bGtGYWlsZWRSZXN1bHQgfSBmcm9tICcuLi9leHRlbnNpYmxlL2J1bGsvZXh0ZW5zaWJsZS1idWxrLWRldmljZS1yZWdpc3RyYXRpb24ubW9kZWwnO1xuaW1wb3J0IHsgUmVnaXN0ZXJEZXZpY2VTZXJ2aWNlIH0gZnJvbSAnLi4vcmVnaXN0ZXItZGV2aWNlLnNlcnZpY2UnO1xuaW1wb3J0IHsgVHJhbnNsYXRlU2VydmljZSB9IGZyb20gJ0BuZ3gtdHJhbnNsYXRlL2NvcmUnO1xuXG5jb25zdCByZWdpc3RlckRldmljZUJ1bGtTY2hlbWE6IG9iamVjdCA9IHtcbiAgJHNjaGVtYTogJ2h0dHBzOi8vanNvbi1zY2hlbWEub3JnL2RyYWZ0LzIwMTktMDkvc2NoZW1hJyxcbiAgdHlwZTogJ29iamVjdCcsXG4gIHByb3BlcnRpZXM6IHtcbiAgICBjc3ZCdWxrRmlsZToge1xuICAgICAgdHlwZTogJ2FycmF5JyxcbiAgICAgIHRpdGxlOiBnZXR0ZXh0KCdDU1YgZmlsZSB1cGxvYWQnKSxcbiAgICAgIGRlc2NyaXB0aW9uOiBnZXR0ZXh0KFxuICAgICAgICAnWW91IGNhbiB1c2UgZmlsZSB1cGxvYWQgY29tcG9uZW50IHRvIGxldCB1c2VycyBzZW5kIGZpbGVzLiBUaGlzIGlucHV0IGFjY2VwdHMgb25seSBhIHNpbmdsZSBDU1YgZmlsZS4nXG4gICAgICApLFxuICAgICAgY29udGVudE1lZGlhVHlwZTogJ2NzdidcbiAgICB9XG4gIH0sXG4gIHJlcXVpcmVkOiBbJ2NzdkJ1bGtGaWxlJ10sXG4gIGFkZGl0aW9uYWxQcm9wZXJ0aWVzOiBmYWxzZVxufTtcblxuY29uc3Qgc2ltcGxlQ3N2SGVhZGVyczogc3RyaW5nW10gPSBbJ0lEJywgJ1BBVEgnXTtcbmNvbnN0IGNzdkhlYWRlcnM6IHN0cmluZ1tdID0gW1xuICAnSUQnLFxuICAnVFlQRScsXG4gICdOQU1FJyxcbiAgJ0lDQ0lEJyxcbiAgJ0lEVFlQRScsXG4gICdQQVRIJyxcbiAgJ1NIRUxMJyxcbiAgJ0FVVEhfVFlQRSdcbl07XG5jb25zdCBmdWxsQ3N2SGVhZGVyczogc3RyaW5nW10gPSBbLi4uY3N2SGVhZGVycywgJ0NSRURFTlRJQUxTJ107XG5leHBvcnQgY29uc3QgRVNUQ3N2SGVhZGVyczogc3RyaW5nW10gPSBbLi4uY3N2SGVhZGVycywgJ0VOUk9MTE1FTlRfT1RQJ107XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ2J1bGstZGV2aWNlLXJlZ2lzdHJhdGlvbicsXG4gIHRlbXBsYXRlVXJsOiAnYnVsay1kZXZpY2UtcmVnaXN0cmF0aW9uLW1vZGFsLmNvbXBvbmVudC5odG1sJ1xufSlcbmV4cG9ydCBjbGFzcyBCdWxrRGV2aWNlUmVnaXN0cmF0aW9uTW9kYWxDb21wb25lbnQge1xuICBAVmlld0NoaWxkKEM4eVN0ZXBwZXIsIHsgc3RhdGljOiB0cnVlIH0pIHN0ZXBwZXI6IEM4eVN0ZXBwZXI7XG4gIG1lc3NhZ2U6IHN0cmluZztcbiAgc3VjY2VzczogYm9vbGVhbjtcbiAgcGVuZGluZzogYm9vbGVhbjtcbiAgcmVzdWx0OiBJRGV2aWNlUmVnaXN0cmF0aW9uQnVsa1Jlc3VsdDtcbiAgZmFpbGVkUmVzdWx0OiBCdWxrRmFpbGVkUmVzdWx0O1xuICBmb3JtID0gbmV3IEZvcm1Hcm91cCh7fSk7XG4gIG1vZGVsID0ge307XG4gIHRlbXBsYXRlOiBGb3JtbHlGaWVsZENvbmZpZ1tdO1xuICBjZXJ0aWZpY2F0ZUF1dGhvcml0eUZlYXR1cmVFbmFibGVkID0gdGhpcy5mZWF0dXJlU2VydmljZVxuICAgIC5kZXRhaWwoJ2NlcnRpZmljYXRlLWF1dGhvcml0eScpXG4gICAgLnRoZW4oKHsgZGF0YSB9KSA9PiBkYXRhLmFjdGl2ZSk7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHJpdmF0ZSBqc29uc2NoZW1hOiBDOHlKU09OU2NoZW1hLFxuICAgIHByaXZhdGUgZGV2aWNlUmVnaXN0cmF0aW9uU2VydmljZTogRGV2aWNlUmVnaXN0cmF0aW9uQnVsa1NlcnZpY2UsXG4gICAgcHJpdmF0ZSByZWdpc3RlckRldmljZVNlcnZpY2U6IFJlZ2lzdGVyRGV2aWNlU2VydmljZSxcbiAgICBwcml2YXRlIGJzTW9kYWxSZWY6IEJzTW9kYWxSZWYsXG4gICAgcHJpdmF0ZSBnYWluc2lnaHRTZXJ2aWNlOiBHYWluc2lnaHRTZXJ2aWNlLFxuICAgIHByaXZhdGUgZmVhdHVyZVNlcnZpY2U6IEZlYXR1cmVTZXJ2aWNlLFxuICAgIHByaXZhdGUgdHJhbnNsYXRlU2VydmljZTogVHJhbnNsYXRlU2VydmljZVxuICApIHt9XG5cbiAgbmdPbkluaXQoKSB7XG4gICAgdGhpcy50ZW1wbGF0ZSA9IFt0aGlzLmpzb25zY2hlbWEudG9GaWVsZENvbmZpZyhyZWdpc3RlckRldmljZUJ1bGtTY2hlbWEpXTtcbiAgfVxuXG4gIHVwbG9hZCgpIHtcbiAgICB0aGlzLnBlbmRpbmcgPSB0cnVlO1xuICAgIGNvbnN0IGZpbGUgPSB0aGlzLmdldEZpbGUodGhpcy5tb2RlbCk7XG4gICAgdGhpcy5kZXZpY2VSZWdpc3RyYXRpb25TZXJ2aWNlXG4gICAgICAuY3JlYXRlKGZpbGUpXG4gICAgICAudGhlbigoeyByZXMsIGRhdGEgfSkgPT4ge1xuICAgICAgICBpZiAocmVzLnN0YXR1cyA8IDQwMCkge1xuICAgICAgICAgIHRoaXMucmVzdWx0ID0gZGF0YTtcbiAgICAgICAgICB0aGlzLnN1Y2Nlc3MgPSBkYXRhLm51bWJlck9mRmFpbGVkID09PSAwICYmIGRhdGEubnVtYmVyT2ZTdWNjZXNzZnVsID09PSBkYXRhLm51bWJlck9mQWxsO1xuICAgICAgICAgIHRoaXMubWVzc2FnZSA9IHRoaXMuc3VjY2Vzc1xuICAgICAgICAgICAgPyBnZXR0ZXh0KCdEZXZpY2UgcmVnaXN0cmF0aW9uIGNyZWF0ZWQuJylcbiAgICAgICAgICAgIDogKHRoaXMubWVzc2FnZSA9IGdldHRleHQoJ0RldmljZSByZWdpc3RyYXRpb24gZmFpbGVkLicpKTtcbiAgICAgICAgICBpZiAodGhpcy5zdWNjZXNzKSB7XG4gICAgICAgICAgICB0aGlzLmdhaW5zaWdodFNlcnZpY2UudHJpZ2dlckV2ZW50KFBST0RVQ1RfRVhQRVJJRU5DRV9CQVNFX1JFR0lTVFJBVElPTi5FVkVOVCwge1xuICAgICAgICAgICAgICByZXN1bHQ6IFBST0RVQ1RfRVhQRVJJRU5DRV9CQVNFX1JFR0lTVFJBVElPTi5SRVNVTFQuU1VDQ0VTUyxcbiAgICAgICAgICAgICAgY29tcG9uZW50OiBQUk9EVUNUX0VYUEVSSUVOQ0VfQkFTRV9SRUdJU1RSQVRJT04uQ09NUE9ORU5ULkJVTEtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLmdhaW5zaWdodFNlcnZpY2UudHJpZ2dlckV2ZW50KFBST0RVQ1RfRVhQRVJJRU5DRV9CQVNFX1JFR0lTVFJBVElPTi5FVkVOVCwge1xuICAgICAgICAgICAgICByZXN1bHQ6IFBST0RVQ1RfRVhQRVJJRU5DRV9CQVNFX1JFR0lTVFJBVElPTi5SRVNVTFQuRkFJTFVSRSxcbiAgICAgICAgICAgICAgY29tcG9uZW50OiBQUk9EVUNUX0VYUEVSSUVOQ0VfQkFTRV9SRUdJU1RSQVRJT04uQ09NUE9ORU5ULkJVTEtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICB0aGlzLmZhaWxlZFJlc3VsdCA9IGRhdGEgYXMgdW5rbm93biBhcyBCdWxrRmFpbGVkUmVzdWx0O1xuICAgICAgICAgIHRoaXMubWVzc2FnZSA9IGdldHRleHQoJ0RldmljZSByZWdpc3RyYXRpb24gZmFpbGVkLicpO1xuICAgICAgICAgIHRoaXMuZ2FpbnNpZ2h0U2VydmljZS50cmlnZ2VyRXZlbnQoUFJPRFVDVF9FWFBFUklFTkNFX0JBU0VfUkVHSVNUUkFUSU9OLkVWRU5ULCB7XG4gICAgICAgICAgICByZXN1bHQ6IFBST0RVQ1RfRVhQRVJJRU5DRV9CQVNFX1JFR0lTVFJBVElPTi5SRVNVTFQuRkFJTFVSRSxcbiAgICAgICAgICAgIGNvbXBvbmVudDogUFJPRFVDVF9FWFBFUklFTkNFX0JBU0VfUkVHSVNUUkFUSU9OLkNPTVBPTkVOVC5CVUxLXG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5tb2RlbCA9IHt9O1xuICAgICAgICB0aGlzLnBlbmRpbmcgPSBmYWxzZTtcbiAgICAgICAgdGhpcy5zdGVwcGVyLm5leHQoKTtcbiAgICAgIH0pXG4gICAgICAuY2F0Y2goKCkgPT4ge1xuICAgICAgICB0aGlzLm1lc3NhZ2UgPSBnZXR0ZXh0KCdFcnJvciBvY2N1cnJlZCB3aGlsZSBwcm9jZXNzaW5nIHRoZSB1cGxvYWRlZCBmaWxlLicpO1xuICAgICAgICB0aGlzLnBlbmRpbmcgPSBmYWxzZTtcbiAgICAgICAgdGhpcy5zdGVwcGVyLm5leHQoKTtcbiAgICAgIH0pO1xuICB9XG5cbiAgZG93bmxvYWRTaW1wbGUoKSB7XG4gICAgcmV0dXJuIHRoaXMuZG93bmxvYWQoc2ltcGxlQ3N2SGVhZGVycywgZ2V0dGV4dCgnU2ltcGxlIGJ1bGsgcmVnaXN0cmF0aW9uIC0gdGVtcGxhdGUuY3N2JykpO1xuICB9XG5cbiAgZG93bmxvYWRGdWxsKCkge1xuICAgIHJldHVybiB0aGlzLmRvd25sb2FkKGZ1bGxDc3ZIZWFkZXJzLCBnZXR0ZXh0KCdGdWxsIGJ1bGsgcmVnaXN0cmF0aW9uIC0gdGVtcGxhdGUuY3N2JykpO1xuICB9XG5cbiAgZG93bmxvYWRFc3QoKSB7XG4gICAgcmV0dXJuIHRoaXMuZG93bmxvYWQoRVNUQ3N2SGVhZGVycywgZ2V0dGV4dCgnRVNUIHJlZ2lzdHJhdGlvbiAtIHRlbXBsYXRlLmNzdicpKTtcbiAgfVxuXG4gIGRvd25sb2FkKGhlYWRlcnM6IHN0cmluZ1tdLCBmaWxlTmFtZTogc3RyaW5nKSB7XG4gICAgY29uc3QgaGVhZGVyUmF3ID0gaGVhZGVycy5tYXAoaGVhZGVyID0+IGBcIiR7aGVhZGVyfVwiYCkuam9pbignOycpO1xuICAgIGNvbnN0IGJpbmFyeUZpbGUgPSBuZXcgQmxvYihbaGVhZGVyUmF3XSwgeyB0eXBlOiAndGV4dC9jc3YnIH0pO1xuICAgIHNhdmVBcyhiaW5hcnlGaWxlLCB0aGlzLnRyYW5zbGF0ZVNlcnZpY2UuaW5zdGFudChmaWxlTmFtZSkpO1xuICB9XG5cbiAgY29tcGxldGUoKSB7XG4gICAgdGhpcy5yZWdpc3RlckRldmljZVNlcnZpY2UubGlzdCgpO1xuICAgIHRoaXMuYnNNb2RhbFJlZi5oaWRlKCk7XG4gIH1cblxuICBjYW5jZWwoKSB7XG4gICAgdGhpcy5ic01vZGFsUmVmLmhpZGUoKTtcbiAgfVxuXG4gIHByaXZhdGUgZ2V0RmlsZShtb2RlbCk6IEZpbGUge1xuICAgIGNvbnN0IGNzdkJ1bGtGaWxlID0gKG1vZGVsIGFzIGFueSk/LmNzdkJ1bGtGaWxlO1xuICAgIHJldHVybiBjc3ZCdWxrRmlsZSA/IGNzdkJ1bGtGaWxlWzBdPy5maWxlIDogdW5kZWZpbmVkO1xuICB9XG59XG4iLCI8Yzh5LW1vZGFsXG4gIFt0aXRsZV09XCInQnVsayBkZXZpY2UgcmVnaXN0cmF0aW9uJyB8IHRyYW5zbGF0ZVwiXG4gIFtoZWFkZXJDbGFzc2VzXT1cIidkaWFsb2ctaGVhZGVyJ1wiXG4gIFtjdXN0b21Gb290ZXJdPVwidHJ1ZVwiXG4+XG4gIDxuZy1jb250YWluZXIgYzh5LW1vZGFsLXRpdGxlPlxuICAgIDxpIGM4eUljb249XCJ1cGxvYWRcIj48L2k+XG4gIDwvbmctY29udGFpbmVyPlxuXG4gIDxjOHktc3RlcHBlciBbaGlkZVN0ZXBQcm9ncmVzc109XCJ0cnVlXCIgbGluZWFyIGlkPVwibW9kYWwtYm9keVwiPlxuICAgIDxjZGstc3RlcD5cbiAgICAgIDxwIGNsYXNzPVwibW9kYWwtc3VidGl0bGUgc3RpY2t5LXRvcFwiIHRyYW5zbGF0ZT5SZWdpc3RlciBkZXZpY2VzIGluIGJ1bGs8L3A+XG5cbiAgICAgIDxjOHktZm9ybS1ncm91cCBjbGFzcz1cImQtYmxvY2sgcC0yNCBwLXQtMTYgcC1iLTAgbS1iLTBcIj5cbiAgICAgICAgPGZvcm1seS1mb3JtIFtmb3JtXT1cImZvcm1cIiBbZmllbGRzXT1cInRlbXBsYXRlXCIgW21vZGVsXT1cIm1vZGVsXCI+PC9mb3JtbHktZm9ybT5cbiAgICAgIDwvYzh5LWZvcm0tZ3JvdXA+XG5cbiAgICAgIDxkaXYgY2xhc3M9XCJwLTI0IG0tdC0wIGJnLWxldmVsLTFcIj5cbiAgICAgICAgICA8ZGl2IGNsYXNzPVwiYmctZ3JheS13aGl0ZSBzZXBhcmF0b3ItYm90dG9tIHAtdC0xNiBwLWItMTYgcC1sLTI0IHAtci0yNFwiPlxuICAgICAgICAgICAgPGRpdj5cbiAgICAgICAgICAgICAgPHAgY2xhc3M9XCJtLWItOCB0ZXh0LW1lZGl1bVwiPlxuICAgICAgICAgICAgICAgIDxzdHJvbmcgdHJhbnNsYXRlPlNpbXBsZSByZWdpc3RyYXRpb248L3N0cm9uZz5cbiAgICAgICAgICAgICAgPC9wPlxuICAgICAgICAgICAgICA8c21hbGwgY2xhc3M9XCJ0ZXh0LW11dGVkXCIgdHJhbnNsYXRlPlxuICAgICAgICAgICAgICAgIENyZWF0ZXMgYWxsIHJlZ2lzdHJhdGlvbiByZXF1ZXN0cyBhdCBvbmNlLCB0aGVuIGVhY2ggb25lIG5lZWRzIHRvIGdvIHRocm91Z2ggcmVndWxhclxuICAgICAgICAgICAgICAgIGFjY2VwdGFuY2UgcHJvY2Vzcy5cbiAgICAgICAgICAgICAgPC9zbWFsbD5cbiAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgPGRpdiBjbGFzcz1cIm0tYi0xNiBtLXQtMTZcIj5cbiAgICAgICAgICAgICAgPGFcbiAgICAgICAgICAgICAgICB0aXRsZT1cInt7ICdEb3dubG9hZCB0ZW1wbGF0ZScgfCB0cmFuc2xhdGUgfX1cIlxuICAgICAgICAgICAgICAgIGNsYXNzPVwiYnRuIGJ0bi1kZWZhdWx0IGJ0bi1zbVwiXG4gICAgICAgICAgICAgICAgdGFyZ2V0PVwiX3NlbGZcIlxuICAgICAgICAgICAgICAgIChjbGljayk9XCJkb3dubG9hZFNpbXBsZSgpXCJcbiAgICAgICAgICAgICAgPlxuICAgICAgICAgICAgICAgIDxpIGM4eUljb249XCJkb3dubG9hZFwiIHRyYW5zbGF0ZT48L2k+XG4gICAgICAgICAgICAgICAge3sgJ0Rvd25sb2FkIHRlbXBsYXRlJyB8IHRyYW5zbGF0ZSB9fVxuICAgICAgICAgICAgICA8L2E+XG4gICAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICA8ZGl2IGNsYXNzPVwiYmctZ3JheS13aGl0ZSBzZXBhcmF0b3ItYm90dG9tIHAtdC0xNiBwLWItMTYgcC1sLTI0IHAtci0yNFwiPlxuICAgICAgICAgICAgPGRpdj5cbiAgICAgICAgICAgICAgPHAgY2xhc3M9XCJtLWItOCB0ZXh0LW1lZGl1bVwiPlxuICAgICAgICAgICAgICAgIDxzdHJvbmcgdHJhbnNsYXRlPkZ1bGwgcmVnaXN0cmF0aW9uPC9zdHJvbmc+XG4gICAgICAgICAgICAgIDwvcD5cbiAgICAgICAgICAgICAgPHNtYWxsIGNsYXNzPVwidGV4dC1tdXRlZFwiIHRyYW5zbGF0ZT5cbiAgICAgICAgICAgICAgICBDcmVhdGVzIGFsbCBkZXZpY2UgY3JlZGVudGlhbHMgYW5kIGRldmljZXMgdXNpbmcgcHJvdmlkZWQgbGlzdCBvZiBwcm9wZXJ0eSB2YWx1ZXMuXG4gICAgICAgICAgICAgICAgRGV2aWNlcyBjYW4gc3RhcnQgY29tbXVuaWNhdGluZyB3aXRoIHRoZSBwbGF0Zm9ybSBpbW1lZGlhdGVseS5cbiAgICAgICAgICAgICAgPC9zbWFsbD5cbiAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICAgICAgPGRpdiBjbGFzcz1cIm0tYi0xNiBtLXQtMTZcIj5cbiAgICAgICAgICAgICAgPGFcbiAgICAgICAgICAgICAgICB0aXRsZT1cInt7ICdEb3dubG9hZCB0ZW1wbGF0ZScgfCB0cmFuc2xhdGUgfX1cIlxuICAgICAgICAgICAgICAgIGNsYXNzPVwiYnRuIGJ0bi1kZWZhdWx0IGJ0bi1zbVwiXG4gICAgICAgICAgICAgICAgdGFyZ2V0PVwiX3NlbGZcIlxuICAgICAgICAgICAgICAgIChjbGljayk9XCJkb3dubG9hZEZ1bGwoKVwiXG4gICAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgICA8aSBjOHlJY29uPVwiZG93bmxvYWRcIiB0cmFuc2xhdGU+PC9pPlxuICAgICAgICAgICAgICAgIHt7ICdEb3dubG9hZCB0ZW1wbGF0ZScgfCB0cmFuc2xhdGUgfX1cbiAgICAgICAgICAgICAgPC9hPlxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgPGRpdiBjbGFzcz1cImJnLWdyYXktd2hpdGUgc2VwYXJhdG9yLWJvdHRvbSBwLXQtMTYgcC1iLTE2IHAtbC0yNCBwLXItMjRcIiAqbmdJZj1cImNlcnRpZmljYXRlQXV0aG9yaXR5RmVhdHVyZUVuYWJsZWQgfCBhc3luY1wiPlxuICAgICAgICAgICAgPGRpdj5cbiAgICAgICAgICAgICAgPHAgY2xhc3M9XCJtLWItOCB0ZXh0LW1lZGl1bVwiPlxuICAgICAgICAgICAgICAgIDxzdHJvbmcgdHJhbnNsYXRlPkZ1bGwgcmVnaXN0cmF0aW9uIHdpdGggZGV2aWNlIGNlcnRpZmljYXRlIGNyZWF0aW9uPC9zdHJvbmc+XG4gICAgICAgICAgICAgIDwvcD5cbiAgICAgICAgICAgICAgPHNtYWxsIGNsYXNzPVwidGV4dC1tdXRlZFwiIHRyYW5zbGF0ZT5cbiAgICAgICAgICAgICAgICBDcmVhdGVzIGRldmljZSBjZXJ0aWZpY2F0ZXMgYW5kIGRldmljZXMgdXNpbmcgdGhlIHByb3ZpZGVkIGxpc3Qgb2YgcHJvcGVydHkgdmFsdWVzLiBPbmNlIHRoZSBjZXJ0aWZpY2F0ZXMgYXJlIHByb3Zpc2lvbmVkLCB0aGUgZGV2aWNlcyBjYW4gaW1tZWRpYXRlbHkgc3RhcnQgY29tbXVuaWNhdGluZyB3aXRoIHRoZSBwbGF0Zm9ybVxuICAgICAgICAgICAgICA8L3NtYWxsPlxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwibS1iLTE2IG0tdC0xNlwiPlxuICAgICAgICAgICAgICA8YVxuICAgICAgICAgICAgICAgIHRpdGxlPVwie3sgJ0Rvd25sb2FkIHRlbXBsYXRlJyB8IHRyYW5zbGF0ZSB9fVwiXG4gICAgICAgICAgICAgICAgY2xhc3M9XCJidG4gYnRuLWRlZmF1bHQgYnRuLXNtXCJcbiAgICAgICAgICAgICAgICB0YXJnZXQ9XCJfc2VsZlwiXG4gICAgICAgICAgICAgICAgKGNsaWNrKT1cImRvd25sb2FkRXN0KClcIlxuICAgICAgICAgICAgICA+XG4gICAgICAgICAgICAgICAgPGkgYzh5SWNvbj1cImRvd25sb2FkXCI+PC9pPlxuICAgICAgICAgICAgICAgIHt7ICdEb3dubG9hZCB0ZW1wbGF0ZScgfCB0cmFuc2xhdGUgfX1cbiAgICAgICAgICAgICAgPC9hPlxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgPC9kaXY+XG4gICAgICA8L2Rpdj5cblxuICAgICAgPGM4eS1zdGVwcGVyLWJ1dHRvbnNcbiAgICAgICAgY2xhc3M9XCJzdGlja3ktYm90dG9tIGQtYmxvY2sgcC10LTE2IHAtYi0xNiBzZXBhcmF0b3ItdG9wIGJnLWxldmVsLTBcIlxuICAgICAgICBbc2hvd0J1dHRvbnNdPVwieyBjYW5jZWw6IHRydWUsIG5leHQ6IHRydWUgfVwiXG4gICAgICAgIFtkaXNhYmxlZF09XCJmb3JtLmludmFsaWRcIlxuICAgICAgICBbcGVuZGluZ109XCJwZW5kaW5nXCJcbiAgICAgICAgKG9uQ2FuY2VsKT1cImNhbmNlbCgpXCJcbiAgICAgICAgKG9uTmV4dCk9XCJ1cGxvYWQoKVwiXG4gICAgICAgIFtsYWJlbHNdPVwieyBuZXh0OiAnVXBsb2FkJyB9XCJcbiAgICAgID48L2M4eS1zdGVwcGVyLWJ1dHRvbnM+XG4gICAgPC9jZGstc3RlcD5cblxuICAgIDxjZGstc3RlcCBzdGF0ZT1cImZpbmFsXCI+XG4gICAgICA8ZGl2IGNsYXNzPVwibS0yNFwiPlxuICAgICAgICA8ZGl2ICpuZ0lmPVwic3VjY2VzczsgZWxzZSB3YXJuaW5nXCI+XG4gICAgICAgICAgPGM4eS1vcGVyYXRpb24tcmVzdWx0XG4gICAgICAgICAgICB0ZXh0PVwie3sgbWVzc2FnZSB8IHRyYW5zbGF0ZSB9fVwiXG4gICAgICAgICAgICBbc2l6ZV09XCI4NFwiXG4gICAgICAgICAgICBbdmVydGljYWxdPVwidHJ1ZVwiXG4gICAgICAgICAgICB0eXBlPVwic3VjY2Vzc1wiXG4gICAgICAgICAgICBjbGFzcz1cImxlYWRcIlxuICAgICAgICAgID48L2M4eS1vcGVyYXRpb24tcmVzdWx0PlxuICAgICAgICA8L2Rpdj5cbiAgICAgICAgPG5nLXRlbXBsYXRlICN3YXJuaW5nPlxuICAgICAgICAgIDxjOHktb3BlcmF0aW9uLXJlc3VsdFxuICAgICAgICAgICAgdGV4dD1cInt7IG1lc3NhZ2UgfCB0cmFuc2xhdGUgfX1cIlxuICAgICAgICAgICAgW3NpemVdPVwiODRcIlxuICAgICAgICAgICAgW3ZlcnRpY2FsXT1cInRydWVcIlxuICAgICAgICAgICAgdHlwZT1cImVycm9yXCJcbiAgICAgICAgICAgIGNsYXNzPVwibGVhZFwiXG4gICAgICAgICAgPjwvYzh5LW9wZXJhdGlvbi1yZXN1bHQ+XG4gICAgICAgIDwvbmctdGVtcGxhdGU+XG4gICAgICAgIDxjOHktbGlzdC1ncm91cCBjbGFzcz1cInNlcGFyYXRvci10b3AgbS10LTE2XCI+XG4gICAgICAgICAgPG5nLWNvbnRhaW5lciAqbmdJZj1cInJlc3VsdDsgZWxzZSBmYWlsZWRSZXNwb25zZVwiPlxuICAgICAgICAgICAgPGM4eS1saSAqbmdJZj1cInN1Y2Nlc3M7IGVsc2UgZmFpbFwiPlxuICAgICAgICAgICAgICA8Yzh5LWxpLWljb24gY2xhc3M9XCJ0ZXh0LXN1Y2Nlc3NcIiBpY29uPVwiY2hlY2stY2lyY2xlXCI+PC9jOHktbGktaWNvbj5cbiAgICAgICAgICAgICAgPHA+e3sgJ0FsbCBkZXZpY2VzIGhhdmUgYmVlbiBwcm9jZXNzZWQuJyB8IHRyYW5zbGF0ZSB9fTwvcD5cbiAgICAgICAgICAgICAgPGM4eS1saS1jb2xsYXBzZT5cbiAgICAgICAgICAgICAgICA8cHJlPjxjb2RlPnt7IHJlc3VsdCB8IGpzb24gfX08L2NvZGU+PC9wcmU+XG4gICAgICAgICAgICAgIDwvYzh5LWxpLWNvbGxhcHNlPlxuICAgICAgICAgICAgPC9jOHktbGk+XG4gICAgICAgICAgICA8bmctdGVtcGxhdGUgI2ZhaWw+XG4gICAgICAgICAgICAgIDxjOHktbGk+XG4gICAgICAgICAgICAgICAgPGM4eS1saS1pY29uIGNsYXNzPVwidGV4dC1kYW5nZXJcIiBpY29uPVwiYmFuXCI+PC9jOHktbGktaWNvbj5cbiAgICAgICAgICAgICAgICA8cFxuICAgICAgICAgICAgICAgICAgbmdOb25CaW5kYWJsZVxuICAgICAgICAgICAgICAgICAgW3RyYW5zbGF0ZVBhcmFtc109XCJ7IGNvdW50OiByZXN1bHQ/Lm51bWJlck9mRmFpbGVkLCB0b3RhbDogcmVzdWx0Py5udW1iZXJPZkFsbCB9XCJcbiAgICAgICAgICAgICAgICAgIHRyYW5zbGF0ZVxuICAgICAgICAgICAgICAgID5cbiAgICAgICAgICAgICAgICAgIEZhaWxlZCB0byBwcm9jZXNzIHt7IGNvdW50IH19IG91dCBvZiB7eyB0b3RhbCB9fS5cbiAgICAgICAgICAgICAgICA8L3A+XG4gICAgICAgICAgICAgICAgPGM4eS1saS1jb2xsYXBzZT5cbiAgICAgICAgICAgICAgICAgIDxwcmU+PGNvZGU+e3sgcmVzdWx0IHwganNvbiB9fTwvY29kZT48L3ByZT5cbiAgICAgICAgICAgICAgICA8L2M4eS1saS1jb2xsYXBzZT5cbiAgICAgICAgICAgICAgPC9jOHktbGk+XG4gICAgICAgICAgICA8L25nLXRlbXBsYXRlPlxuICAgICAgICAgIDwvbmctY29udGFpbmVyPlxuICAgICAgICAgIDxuZy10ZW1wbGF0ZSAjZmFpbGVkUmVzcG9uc2U+XG4gICAgICAgICAgICA8Yzh5LWxpPlxuICAgICAgICAgICAgICA8Yzh5LWxpLWljb24gY2xhc3M9XCJ0ZXh0LWRhbmdlclwiIFtpY29uXT1cIidiYW4nXCI+PC9jOHktbGktaWNvbj5cbiAgICAgICAgICAgICAgPHNtYWxsPnt7IGZhaWxlZFJlc3VsdD8ubWVzc2FnZSB8IHRyYW5zbGF0ZSB9fTwvc21hbGw+XG4gICAgICAgICAgICAgIDxjOHktbGktY29sbGFwc2U+XG4gICAgICAgICAgICAgICAgPHByZT48Y29kZT57eyBmYWlsZWRSZXN1bHQgfCBqc29uIH19PC9jb2RlPjwvcHJlPlxuICAgICAgICAgICAgICA8L2M4eS1saS1jb2xsYXBzZT5cbiAgICAgICAgICAgIDwvYzh5LWxpPlxuICAgICAgICAgIDwvbmctdGVtcGxhdGU+XG4gICAgICAgIDwvYzh5LWxpc3QtZ3JvdXA+XG4gICAgICA8L2Rpdj5cbiAgICAgIDxjOHktc3RlcHBlci1idXR0b25zXG4gICAgICAgIGNsYXNzPVwic3RpY2t5LWJvdHRvbSBkLWJsb2NrIHAtdC0xNiBwLWItMTYgc2VwYXJhdG9yLXRvcCBiZy1sZXZlbC0wXCJcbiAgICAgICAgW3Nob3dCdXR0b25zXT1cInsgbmV4dDogdHJ1ZSB9XCJcbiAgICAgICAgKG9uTmV4dCk9XCJjb21wbGV0ZSgpXCJcbiAgICAgICAgW2xhYmVsc109XCJ7IG5leHQ6IHN1Y2Nlc3MgPyAnQ2xvc2UnIDogJ0NhbmNlbCcgfVwiXG4gICAgICA+PC9jOHktc3RlcHBlci1idXR0b25zPlxuICAgIDwvY2RrLXN0ZXA+XG4gIDwvYzh5LXN0ZXBwZXI+XG48L2M4eS1tb2RhbD5cbiJdfQ==