UNPKG

@c8y/ngx-components

Version:

Angular modules for Cumulocity IoT applications

136 lines 43.4 kB
import { Component, DestroyRef, forwardRef, inject } from '@angular/core'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { ActivatedRoute } from '@angular/router'; import { AlertService, gettext, ManagedObjectRealtimeService, OperationRealtimeService, PRODUCT_EXPERIENCE_EVENT_SOURCE } from '@c8y/ngx-components'; import { has, pickBy } from 'lodash-es'; import { BehaviorSubject, combineLatest, pipe } from 'rxjs'; import { filter, map, switchMap, tap } from 'rxjs/operators'; import { PRODUCT_EXPERIENCE_DEVICE_PROFILE } from '../device-profile.model'; import { DeviceProfileService } from '../device-profile.service'; import * as i0 from "@angular/core"; import * as i1 from "@c8y/ngx-components"; import * as i2 from "../device-profile.service"; import * as i3 from "@angular/router"; import * as i4 from "@angular/common"; import * as i5 from "@angular/forms"; import * as i6 from "@c8y/ngx-components/operations/operation-details"; import * as i7 from "./device-tab-profile-detail.component"; export class DeviceTabProfileComponent { constructor(deviceRealtime, deviceProfileService, route, operationRealtime, alertService) { this.deviceRealtime = deviceRealtime; this.deviceProfileService = deviceProfileService; this.route = route; this.operationRealtime = operationRealtime; this.alertService = alertService; this.PRODUCT_EXPERIENCE = PRODUCT_EXPERIENCE_DEVICE_PROFILE; this.firmwareItems = []; this.softwareItems = []; this.configurationItems = []; this.pattern$ = new BehaviorSubject(''); this.reload$ = new BehaviorSubject(true); this.productExperienceEvent = { eventName: PRODUCT_EXPERIENCE_DEVICE_PROFILE.EVENTS.DEVICE_TAB, data: { component: PRODUCT_EXPERIENCE_DEVICE_PROFILE.COMPONENTS.DEVICE_TAB_PROFILE } }; this.destroyRef = inject(DestroyRef); this.device = this.route.snapshot.parent.data.contextData; } async ngOnInit() { this.getDeviceProfilesAndUpdateProfileItems(); this.subscribeToManagedObjects(); const supportedSoftwareTypes = new Set(this.device.c8y_SupportedSoftwareTypes); const isSubset = (profileTypes) => { return profileTypes.every(type => supportedSoftwareTypes.has(type)); }; this.filterPipe = pipe(map(data => { if (supportedSoftwareTypes.size) { return data.filter(mo => isSubset(this.deviceProfileService.getSoftwareTypes(mo))); } else { return data; } })); } async getDeviceProfilesAndUpdateProfileItems() { this.deviceProfiles$ = combineLatest([this.reload$.pipe(filter(Boolean)), this.pattern$]).pipe(switchMap(([_, name]) => this.deviceProfileService.getDeviceProfilesByDevice(this.device, name)), tap(async (profiles) => { if (this.device.c8y_Profile) { const profileId = this.device.c8y_Profile.profileId; this.selectedProfile = profiles.data.find(mo => mo.id === profileId); } this.updateProfileItems(this.device, this.selectedProfile); this.operation = await this.deviceProfileService.getProfileOperation(this.device.id); this.subscribeToOperations(); }), tap(() => this.reload$.next(false)), takeUntilDestroyed(this.destroyRef)); } selectProfile(mo) { this.selectedProfile = this.toProfileForDevice(mo); this.updateProfileItems(this.device, this.selectedProfile); } async createOperation() { this.operation = await this.deviceProfileService.createProfileOperation(this.device, this.selectedProfile); } updateProfileItems(device, profile) { this.firmwareItems = this.deviceProfileService.getFirmwareItems(device, profile); this.softwareItems = this.deviceProfileService.getSoftwareItems(device, profile); this.configurationItems = this.deviceProfileService.getConfigurationItems(device, profile); } subscribeToManagedObjects() { this.deviceRealtime .onUpdate$(this.device.id) .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe((managedObject) => { this.updateProfileItems(managedObject, this.selectedProfile); }); this.deviceRealtime .onDelete$(this.device.id) .pipe(takeUntilDestroyed(this.destroyRef)) .subscribe(() => { this.alertService.danger(gettext('This device has just been deleted. You will be redirected to "All devices" page now.')); window.location.href = '#/device'; }); } subscribeToOperations() { this.operationRealtime .onAll$(this.device.id) .pipe(map(({ data }) => data), filter(operation => operation.c8y_DeviceProfile), takeUntilDestroyed(this.destroyRef)) .subscribe(operation => { this.operation = operation; }); } toProfileForDevice(profile) { if (Array.from(profile?.c8y_DeviceProfile?.software || []).length === 0 || has(this.device, 'c8y_SupportedSoftwareTypes')) { return profile; } else { return { ...profile, c8y_DeviceProfile: { ...profile.c8y_DeviceProfile, software: profile.c8y_DeviceProfile.software.map(sw => pickBy(sw, (_, key) => key !== 'softwareType')) } }; } } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DeviceTabProfileComponent, deps: [{ token: i1.ManagedObjectRealtimeService }, { token: i2.DeviceProfileService }, { token: i3.ActivatedRoute }, { token: i1.OperationRealtimeService }, { token: i1.AlertService }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: DeviceTabProfileComponent, selector: "c8y-device-tab-profile", providers: [ ManagedObjectRealtimeService, { provide: PRODUCT_EXPERIENCE_EVENT_SOURCE, useExisting: forwardRef(() => DeviceTabProfileComponent) } ], ngImport: i0, template: "<c8y-action-bar-item [placement]=\"'right'\">\n <button\n class=\"btn btn-link\"\n title=\"{{ 'Reload' | translate }}\"\n type=\"button\"\n (click)=\"reload$.next(true)\"\n >\n <i\n c8yIcon=\"refresh\"\n [ngClass]=\"{ 'icon-spin': reload$.value }\"\n ></i>\n {{ 'Reload' | translate }}\n </button>\n</c8y-action-bar-item>\n<c8y-action-bar-item [placement]=\"'right'\">\n <c8y-realtime-btn [service]=\"deviceRealtime\"></c8y-realtime-btn>\n</c8y-action-bar-item>\n\n<div class=\"card card--grid--fullpage card--grid--fullpage card--grid grid__row--2-10--md\">\n <div class=\"card--grid grid__col--6-6--md\">\n <!-- AVAILABLE PROFILES -->\n <div class=\"bg-level-0\">\n <div class=\"card-header separator\">\n <div\n class=\"card-title\"\n translate\n >\n Device profile\n </div>\n </div>\n <div class=\"p-16\">\n <form #deviceProfileForm=\"ngForm\">\n <div class=\"input-group\">\n <c8y-typeahead\n class=\"flex-grow\"\n placeholder=\"{{ 'Select device profile' | translate }}\"\n name=\"selectProfile\"\n data-cy=\"device-tab-profile--select-device-profile\"\n [(ngModel)]=\"selectedProfile\"\n (onSearch)=\"pattern$.next($event)\"\n [allowFreeEntries]=\"false\"\n >\n <c8y-li\n class=\"p-l-8 p-r-8 c8y-list__item--link\"\n *c8yFor=\"let profile of deviceProfiles$; pipe: filterPipe\"\n (click)=\"selectProfile(profile); pattern$.next('')\"\n >\n <c8y-highlight\n [text]=\"profile.name || '&#45;&#45;'\"\n [pattern]=\"pattern$.value\"\n ></c8y-highlight>\n </c8y-li>\n </c8y-typeahead>\n <div class=\"input-group-btn\">\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Assign device profile' | translate }}\"\n type=\"button\"\n (click)=\"createOperation()\"\n data-cy=\"device-tab-profile--Assign-device-profile-button\"\n [disabled]=\"!selectedProfile?.id\"\n c8yProductExperience\n inherit\n [actionData]=\"{ action: PRODUCT_EXPERIENCE.ACTIONS.ASSIGN_DEVICE_PROFILE }\"\n >\n <span>{{ 'Assign device profile' | translate }}</span>\n </button>\n </div>\n </div>\n </form>\n </div>\n </div>\n\n <!-- INSTALL PROFILE OPERATION -->\n <div class=\"bg-level-1\">\n <div class=\"card-header separator\">\n <div\n class=\"card-title\"\n translate\n >\n Currently installed\n </div>\n </div>\n <div class=\"card-block\">\n <c8y-operation-details\n [operation]=\"operation\"\n c8yProductExperience\n inherit\n suppressDataOverriding\n ></c8y-operation-details>\n </div>\n </div>\n </div>\n <div class=\"card--grid__inner-scroll d-col no-align-items\">\n <div class=\"d-contents\">\n <!-- FIRMWARE -->\n <c8y-device-tab-profile-detail\n class=\"d-contents\"\n [sectionIcon]=\"'c8y-firmware'\"\n [sectionTitle]=\"'Firmware' | translate\"\n [emptyStateText]=\"'No firmware to display.' | translate\"\n [emptyStateDetails]=\"'No firmware assigned.' | translate\"\n [isProfileSelected]=\"!!selectedProfile\"\n [items]=\"firmwareItems\"\n [isEmpty]=\"!selectedProfile?.c8y_DeviceProfile?.firmware?.name\"\n ></c8y-device-tab-profile-detail>\n </div>\n <div class=\"d-contents\">\n <!-- SOFTWARE -->\n <c8y-device-tab-profile-detail\n class=\"d-contents\"\n [sectionIcon]=\"'c8y-tools'\"\n [sectionTitle]=\"'Software' | translate\"\n [emptyStateText]=\"'No software to display.' | translate\"\n [emptyStateDetails]=\"'No software assigned.' | translate\"\n [isProfileSelected]=\"!!selectedProfile\"\n [items]=\"softwareItems\"\n [isEmpty]=\"\n !selectedProfile?.c8y_DeviceProfile?.software ||\n selectedProfile?.c8y_DeviceProfile?.software?.length === 0\n \"\n ></c8y-device-tab-profile-detail>\n </div>\n <div class=\"d-contents\">\n <!-- CONFIGURATION -->\n <c8y-device-tab-profile-detail\n class=\"d-contents\"\n [sectionIcon]=\"'gears'\"\n [sectionTitle]=\"'Configuration' | translate\"\n [emptyStateText]=\"'No configuration to display' | translate\"\n [emptyStateDetails]=\"'No configuration assigned' | translate\"\n [isProfileSelected]=\"!!selectedProfile\"\n [items]=\"configurationItems\"\n [isEmpty]=\"\n !selectedProfile?.c8y_DeviceProfile?.configuration ||\n selectedProfile?.c8y_DeviceProfile?.configuration?.length === 0\n \"\n ></c8y-device-tab-profile-detail>\n </div>\n <!-- fill in the remanining vertical space when empty -->\n <div class=\"card--grid grid__col--6-6--md flex-grow\">\n <div class=\"bg-level-0\"></div>\n <div class=\"bg-level-1\"></div>\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "component", type: i1.ActionBarItemComponent, selector: "c8y-action-bar-item", inputs: ["placement", "priority", "itemClass", "injector", "groupId", "inGroupPriority"] }, { kind: "directive", type: i1.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i1.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i4.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.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: i1.HighlightComponent, selector: "c8y-highlight", inputs: ["pattern", "text", "elementClass", "shouldTrimPattern"] }, { kind: "component", type: i1.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.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i5.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { 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: i1.ListItemComponent, selector: "c8y-list-item, c8y-li", inputs: ["active", "highlighted", "emptyActions", "dense", "collapsed", "selectable"], outputs: ["collapsedChange"] }, { kind: "directive", type: i1.ProductExperienceDirective, selector: "[c8yProductExperience]", inputs: ["actionName", "actionData", "inherit", "suppressDataOverriding"] }, { kind: "component", type: i1.RealtimeButtonComponent, selector: "c8y-realtime-btn", inputs: ["service", "label", "title", "disabled"], outputs: ["onToggle"] }, { kind: "component", type: i6.OperationDetailsComponent, selector: "c8y-operation-details", inputs: ["operation"] }, { kind: "component", type: i7.DeviceTabProfileDetailComponent, selector: "c8y-device-tab-profile-detail", inputs: ["sectionTitle", "sectionIcon", "emptyStateText", "emptyStateDetails", "isProfileSelected", "isEmpty", "items", "showTextLabel"] }, { kind: "pipe", type: i1.C8yTranslatePipe, name: "translate" }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DeviceTabProfileComponent, decorators: [{ type: Component, args: [{ selector: 'c8y-device-tab-profile', providers: [ ManagedObjectRealtimeService, { provide: PRODUCT_EXPERIENCE_EVENT_SOURCE, useExisting: forwardRef(() => DeviceTabProfileComponent) } ], template: "<c8y-action-bar-item [placement]=\"'right'\">\n <button\n class=\"btn btn-link\"\n title=\"{{ 'Reload' | translate }}\"\n type=\"button\"\n (click)=\"reload$.next(true)\"\n >\n <i\n c8yIcon=\"refresh\"\n [ngClass]=\"{ 'icon-spin': reload$.value }\"\n ></i>\n {{ 'Reload' | translate }}\n </button>\n</c8y-action-bar-item>\n<c8y-action-bar-item [placement]=\"'right'\">\n <c8y-realtime-btn [service]=\"deviceRealtime\"></c8y-realtime-btn>\n</c8y-action-bar-item>\n\n<div class=\"card card--grid--fullpage card--grid--fullpage card--grid grid__row--2-10--md\">\n <div class=\"card--grid grid__col--6-6--md\">\n <!-- AVAILABLE PROFILES -->\n <div class=\"bg-level-0\">\n <div class=\"card-header separator\">\n <div\n class=\"card-title\"\n translate\n >\n Device profile\n </div>\n </div>\n <div class=\"p-16\">\n <form #deviceProfileForm=\"ngForm\">\n <div class=\"input-group\">\n <c8y-typeahead\n class=\"flex-grow\"\n placeholder=\"{{ 'Select device profile' | translate }}\"\n name=\"selectProfile\"\n data-cy=\"device-tab-profile--select-device-profile\"\n [(ngModel)]=\"selectedProfile\"\n (onSearch)=\"pattern$.next($event)\"\n [allowFreeEntries]=\"false\"\n >\n <c8y-li\n class=\"p-l-8 p-r-8 c8y-list__item--link\"\n *c8yFor=\"let profile of deviceProfiles$; pipe: filterPipe\"\n (click)=\"selectProfile(profile); pattern$.next('')\"\n >\n <c8y-highlight\n [text]=\"profile.name || '&#45;&#45;'\"\n [pattern]=\"pattern$.value\"\n ></c8y-highlight>\n </c8y-li>\n </c8y-typeahead>\n <div class=\"input-group-btn\">\n <button\n class=\"btn btn-primary\"\n title=\"{{ 'Assign device profile' | translate }}\"\n type=\"button\"\n (click)=\"createOperation()\"\n data-cy=\"device-tab-profile--Assign-device-profile-button\"\n [disabled]=\"!selectedProfile?.id\"\n c8yProductExperience\n inherit\n [actionData]=\"{ action: PRODUCT_EXPERIENCE.ACTIONS.ASSIGN_DEVICE_PROFILE }\"\n >\n <span>{{ 'Assign device profile' | translate }}</span>\n </button>\n </div>\n </div>\n </form>\n </div>\n </div>\n\n <!-- INSTALL PROFILE OPERATION -->\n <div class=\"bg-level-1\">\n <div class=\"card-header separator\">\n <div\n class=\"card-title\"\n translate\n >\n Currently installed\n </div>\n </div>\n <div class=\"card-block\">\n <c8y-operation-details\n [operation]=\"operation\"\n c8yProductExperience\n inherit\n suppressDataOverriding\n ></c8y-operation-details>\n </div>\n </div>\n </div>\n <div class=\"card--grid__inner-scroll d-col no-align-items\">\n <div class=\"d-contents\">\n <!-- FIRMWARE -->\n <c8y-device-tab-profile-detail\n class=\"d-contents\"\n [sectionIcon]=\"'c8y-firmware'\"\n [sectionTitle]=\"'Firmware' | translate\"\n [emptyStateText]=\"'No firmware to display.' | translate\"\n [emptyStateDetails]=\"'No firmware assigned.' | translate\"\n [isProfileSelected]=\"!!selectedProfile\"\n [items]=\"firmwareItems\"\n [isEmpty]=\"!selectedProfile?.c8y_DeviceProfile?.firmware?.name\"\n ></c8y-device-tab-profile-detail>\n </div>\n <div class=\"d-contents\">\n <!-- SOFTWARE -->\n <c8y-device-tab-profile-detail\n class=\"d-contents\"\n [sectionIcon]=\"'c8y-tools'\"\n [sectionTitle]=\"'Software' | translate\"\n [emptyStateText]=\"'No software to display.' | translate\"\n [emptyStateDetails]=\"'No software assigned.' | translate\"\n [isProfileSelected]=\"!!selectedProfile\"\n [items]=\"softwareItems\"\n [isEmpty]=\"\n !selectedProfile?.c8y_DeviceProfile?.software ||\n selectedProfile?.c8y_DeviceProfile?.software?.length === 0\n \"\n ></c8y-device-tab-profile-detail>\n </div>\n <div class=\"d-contents\">\n <!-- CONFIGURATION -->\n <c8y-device-tab-profile-detail\n class=\"d-contents\"\n [sectionIcon]=\"'gears'\"\n [sectionTitle]=\"'Configuration' | translate\"\n [emptyStateText]=\"'No configuration to display' | translate\"\n [emptyStateDetails]=\"'No configuration assigned' | translate\"\n [isProfileSelected]=\"!!selectedProfile\"\n [items]=\"configurationItems\"\n [isEmpty]=\"\n !selectedProfile?.c8y_DeviceProfile?.configuration ||\n selectedProfile?.c8y_DeviceProfile?.configuration?.length === 0\n \"\n ></c8y-device-tab-profile-detail>\n </div>\n <!-- fill in the remanining vertical space when empty -->\n <div class=\"card--grid grid__col--6-6--md flex-grow\">\n <div class=\"bg-level-0\"></div>\n <div class=\"bg-level-1\"></div>\n </div>\n </div>\n</div>\n" }] }], ctorParameters: () => [{ type: i1.ManagedObjectRealtimeService }, { type: i2.DeviceProfileService }, { type: i3.ActivatedRoute }, { type: i1.OperationRealtimeService }, { type: i1.AlertService }] }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGV2aWNlLXRhYi1wcm9maWxlLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL2RldmljZS1wcm9maWxlL2RldmljZS10YWItcHJvZmlsZS9kZXZpY2UtdGFiLXByb2ZpbGUuY29tcG9uZW50LnRzIiwiLi4vLi4vLi4vLi4vZGV2aWNlLXByb2ZpbGUvZGV2aWNlLXRhYi1wcm9maWxlL2RldmljZS10YWItcHJvZmlsZS5jb21wb25lbnQuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFFLFVBQVUsRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFVLE1BQU0sZUFBZSxDQUFDO0FBQ2xGLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBQ2hFLE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUVqRCxPQUFPLEVBQ0wsWUFBWSxFQUVaLE9BQU8sRUFDUCw0QkFBNEIsRUFDNUIsd0JBQXdCLEVBQ3hCLCtCQUErQixFQUdoQyxNQUFNLHFCQUFxQixDQUFDO0FBQzdCLE9BQU8sRUFBRSxHQUFHLEVBQUUsTUFBTSxFQUFFLE1BQU0sV0FBVyxDQUFDO0FBQ3hDLE9BQU8sRUFBRSxlQUFlLEVBQUUsYUFBYSxFQUFjLElBQUksRUFBRSxNQUFNLE1BQU0sQ0FBQztBQUN4RSxPQUFPLEVBQUUsTUFBTSxFQUFFLEdBQUcsRUFBRSxTQUFTLEVBQUUsR0FBRyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDN0QsT0FBTyxFQUdMLGlDQUFpQyxFQUNsQyxNQUFNLHlCQUF5QixDQUFDO0FBQ2pDLE9BQU8sRUFBRSxvQkFBb0IsRUFBRSxNQUFNLDJCQUEyQixDQUFDOzs7Ozs7Ozs7QUFhakUsTUFBTSxPQUFPLHlCQUF5QjtJQXFCcEMsWUFDUyxjQUE0QyxFQUMzQyxvQkFBMEMsRUFDMUMsS0FBcUIsRUFDckIsaUJBQTJDLEVBQzNDLFlBQTBCO1FBSjNCLG1C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cm95UmVmLCBmb3J3YXJkUmVmLCBpbmplY3QsIE9uSW5pdCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgdGFrZVVudGlsRGVzdHJveWVkIH0gZnJvbSAnQGFuZ3VsYXIvY29yZS9yeGpzLWludGVyb3AnO1xuaW1wb3J0IHsgQWN0aXZhdGVkUm91dGUgfSBmcm9tICdAYW5ndWxhci9yb3V0ZXInO1xuaW1wb3J0IHsgSU1hbmFnZWRPYmplY3QsIElPcGVyYXRpb24sIElSZXN1bHRMaXN0IH0gZnJvbSAnQGM4eS9jbGllbnQnO1xuaW1wb3J0IHtcbiAgQWxlcnRTZXJ2aWNlLFxuICBGb3JPZkZpbHRlclBpcGUsXG4gIGdldHRleHQsXG4gIE1hbmFnZWRPYmplY3RSZWFsdGltZVNlcnZpY2UsXG4gIE9wZXJhdGlvblJlYWx0aW1lU2VydmljZSxcbiAgUFJPRFVDVF9FWFBFUklFTkNFX0VWRU5UX1NPVVJDRSxcbiAgUHJvZHVjdEV4cGVyaWVuY2VFdmVudCxcbiAgUHJvZHVjdEV4cGVyaWVuY2VFdmVudFNvdXJjZVxufSBmcm9tICdAYzh5L25neC1jb21wb25lbnRzJztcbmltcG9ydCB7IGhhcywgcGlja0J5IH0gZnJvbSAnbG9kYXNoLWVzJztcbmltcG9ydCB7IEJlaGF2aW9yU3ViamVjdCwgY29tYmluZUxhdGVzdCwgT2JzZXJ2YWJsZSwgcGlwZSB9IGZyb20gJ3J4anMnO1xuaW1wb3J0IHsgZmlsdGVyLCBtYXAsIHN3aXRjaE1hcCwgdGFwIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuaW1wb3J0IHtcbiAgQ29tcGFyaXNvblJlc3VsdCxcbiAgRGV2aWNlUHJvZmlsZSxcbiAgUFJPRFVDVF9FWFBFUklFTkNFX0RFVklDRV9QUk9GSUxFXG59IGZyb20gJy4uL2RldmljZS1wcm9maWxlLm1vZGVsJztcbmltcG9ydCB7IERldmljZVByb2ZpbGVTZXJ2aWNlIH0gZnJvbSAnLi4vZGV2aWNlLXByb2ZpbGUuc2VydmljZSc7XG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ2M4eS1kZXZpY2UtdGFiLXByb2ZpbGUnLFxuICB0ZW1wbGF0ZVVybDogJy4vZGV2aWNlLXRhYi1wcm9maWxlLmNvbXBvbmVudC5odG1sJyxcbiAgcHJvdmlkZXJzOiBbXG4gICAgTWFuYWdlZE9iamVjdFJlYWx0aW1lU2VydmljZSxcbiAgICB7XG4gICAgICBwcm92aWRlOiBQUk9EVUNUX0VYUEVSSUVOQ0VfRVZFTlRfU09VUkNFLFxuICAgICAgdXNlRXhpc3Rpbmc6IGZvcndhcmRSZWYoKCkgPT4gRGV2aWNlVGFiUHJvZmlsZUNvbXBvbmVudClcbiAgICB9XG4gIF1cbn0pXG5leHBvcnQgY2xhc3MgRGV2aWNlVGFiUHJvZmlsZUNvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCwgUHJvZHVjdEV4cGVyaWVuY2VFdmVudFNvdXJjZSB7XG4gIFBST0RVQ1RfRVhQRVJJRU5DRSA9IFBST0RVQ1RfRVhQRVJJRU5DRV9ERVZJQ0VfUFJPRklMRTtcbiAgZGV2aWNlOiBJTWFuYWdlZE9iamVjdDtcbiAgZGV2aWNlUHJvZmlsZXMkOiBPYnNlcnZhYmxlPElSZXN1bHRMaXN0PElNYW5hZ2VkT2JqZWN0Pj47XG4gIHNlbGVjdGVkUHJvZmlsZTogUGFydGlhbDxEZXZpY2VQcm9maWxlPjtcbiAgb3BlcmF0aW9uOiBJT3BlcmF0aW9uO1xuICBmaXJtd2FyZUl0ZW1zOiBDb21wYXJpc29uUmVzdWx0W10gPSBbXTtcbiAgc29mdHdhcmVJdGVtczogQ29tcGFyaXNvblJlc3VsdFtdID0gW107XG4gIGNvbmZpZ3VyYXRpb25JdGVtczogQ29tcGFyaXNvblJlc3VsdFtdID0gW107XG5cbiAgZmlsdGVyUGlwZTogRm9yT2ZGaWx0ZXJQaXBlO1xuICBwYXR0ZXJuJCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8c3RyaW5nPignJyk7XG4gIHJlbG9hZCQgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PGJvb2xlYW4+KHRydWUpO1xuICBwcm9kdWN0RXhwZXJpZW5jZUV2ZW50OiBQcm9kdWN0RXhwZXJpZW5jZUV2ZW50ID0ge1xuICAgIGV2ZW50TmFtZTogUFJPRFVDVF9FWFBFUklFTkNFX0RFVklDRV9QUk9GSUxFLkVWRU5UUy5ERVZJQ0VfVEFCLFxuICAgIGRhdGE6IHtcbiAgICAgIGNvbXBvbmVudDogUFJPRFVDVF9FWFBFUklFTkNFX0RFVklDRV9QUk9GSUxFLkNPTVBPTkVOVFMuREVWSUNFX1RBQl9QUk9GSUxFXG4gICAgfVxuICB9O1xuICBwcml2YXRlIGRlc3Ryb3lSZWYgPSBpbmplY3QoRGVzdHJveVJlZik7XG5cbiAgY29uc3RydWN0b3IoXG4gICAgcHVibGljIGRldmljZVJlYWx0aW1lOiBNYW5hZ2VkT2JqZWN0UmVhbHRpbWVTZXJ2aWNlLFxuICAgIHByaXZhdGUgZGV2aWNlUHJvZmlsZVNlcnZpY2U6IERldmljZVByb2ZpbGVTZXJ2aWNlLFxuICAgIHByaXZhdGUgcm91dGU6IEFjdGl2YXRlZFJvdXRlLFxuICAgIHByaXZhdGUgb3BlcmF0aW9uUmVhbHRpbWU6IE9wZXJhdGlvblJlYWx0aW1lU2VydmljZSxcbiAgICBwcml2YXRlIGFsZXJ0U2VydmljZTogQWxlcnRTZXJ2aWNlXG4gICkge1xuICAgIHRoaXMuZGV2aWNlID0gdGhpcy5yb3V0ZS5zbmFwc2hvdC5wYXJlbnQuZGF0YS5jb250ZXh0RGF0YTtcbiAgfVxuXG4gIGFzeW5jIG5nT25Jbml0KCkge1xuICAgIHRoaXMuZ2V0RGV2aWNlUHJvZmlsZXNBbmRVcGRhdGVQcm9maWxlSXRlbXMoKTtcbiAgICB0aGlzLnN1YnNjcmliZVRvTWFuYWdlZE9iamVjdHMoKTtcbiAgICBjb25zdCBzdXBwb3J0ZWRTb2Z0d2FyZVR5cGVzID0gbmV3IFNldCh0aGlzLmRldmljZS5jOHlfU3VwcG9ydGVkU29mdHdhcmVUeXBlcyk7XG4gICAgY29uc3QgaXNTdWJzZXQgPSAocHJvZmlsZVR5cGVzOiBzdHJpbmdbXSkgPT4ge1xuICAgICAgcmV0dXJuIHByb2ZpbGVUeXBlcy5ldmVyeSh0eXBlID0+IHN1cHBvcnRlZFNvZnR3YXJlVHlwZXMuaGFzKHR5cGUpKTtcbiAgICB9O1xuICAgIHRoaXMuZmlsdGVyUGlwZSA9IHBpcGUoXG4gICAgICBtYXAoZGF0YSA9PiB7XG4gICAgICAgIGlmIChzdXBwb3J0ZWRTb2Z0d2FyZVR5cGVzLnNpemUpIHtcbiAgICAgICAgICByZXR1cm4gZGF0YS5maWx0ZXIobW8gPT5cbiAgICAgICAgICAgIGlzU3Vic2V0KHRoaXMuZGV2aWNlUHJvZmlsZVNlcnZpY2UuZ2V0U29mdHdhcmVUeXBlcyhtbyBhcyB1bmtub3duIGFzIERldmljZVByb2ZpbGUpKVxuICAgICAgICAgICk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgcmV0dXJuIGRhdGE7XG4gICAgICAgIH1cbiAgICAgIH0pXG4gICAgKTtcbiAgfVxuXG4gIGFzeW5jIGdldERldmljZVByb2ZpbGVzQW5kVXBkYXRlUHJvZmlsZUl0ZW1zKCkge1xuICAgIHRoaXMuZGV2aWNlUHJvZmlsZXMkID0gY29tYmluZUxhdGVzdChbdGhpcy5yZWxvYWQkLnBpcGUoZmlsdGVyKEJvb2xlYW4pKSwgdGhpcy5wYXR0ZXJuJF0pLnBpcGUoXG4gICAgICBzd2l0Y2hNYXAoKFtfLCBuYW1lXSkgPT5cbiAgICAgICAgdGhpcy5kZXZpY2VQcm9maWxlU2VydmljZS5nZXREZXZpY2VQcm9maWxlc0J5RGV2aWNlKHRoaXMuZGV2aWNlLCBuYW1lKVxuICAgICAgKSxcbiAgICAgIHRhcChhc3luYyBwcm9maWxlcyA9PiB7XG4gICAgICAgIGlmICh0aGlzLmRldmljZS5jOHlfUHJvZmlsZSkge1xuICAgICAgICAgIGNvbnN0IHByb2ZpbGVJZCA9IHRoaXMuZGV2aWNlLmM4eV9Qcm9maWxlLnByb2ZpbGVJZDtcbiAgICAgICAgICB0aGlzLnNlbGVjdGVkUHJvZmlsZSA9IHByb2ZpbGVzLmRhdGEuZmluZChtbyA9PiBtby5pZCA9PT0gcHJvZmlsZUlkKTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLnVwZGF0ZVByb2ZpbGVJdGVtcyh0aGlzLmRldmljZSwgdGhpcy5zZWxlY3RlZFByb2ZpbGUpO1xuICAgICAgICB0aGlzLm9wZXJhdGlvbiA9IGF3YWl0IHRoaXMuZGV2aWNlUHJvZmlsZVNlcnZpY2UuZ2V0UHJvZmlsZU9wZXJhdGlvbih0aGlzLmRldmljZS5pZCk7XG4gICAgICAgIHRoaXMuc3Vic2NyaWJlVG9PcGVyYXRpb25zKCk7XG4gICAgICB9KSxcbiAgICAgIHRhcCgoKSA9PiB0aGlzLnJlbG9hZCQubmV4dChmYWxzZSkpLFxuICAgICAgdGFrZVVudGlsRGVzdHJveWVkKHRoaXMuZGVzdHJveVJlZilcbiAgICApO1xuICB9XG5cbiAgc2VsZWN0UHJvZmlsZShtbzogRGV2aWNlUHJvZmlsZSkge1xuICAgIHRoaXMuc2VsZWN0ZWRQcm9maWxlID0gdGhpcy50b1Byb2ZpbGVGb3JEZXZpY2UobW8pO1xuICAgIHRoaXMudXBkYXRlUHJvZmlsZUl0ZW1zKHRoaXMuZGV2aWNlLCB0aGlzLnNlbGVjdGVkUHJvZmlsZSk7XG4gIH1cblxuICBhc3luYyBjcmVhdGVPcGVyYXRpb24oKSB7XG4gICAgdGhpcy5vcGVyYXRpb24gPSBhd2FpdCB0aGlzLmRldmljZVByb2ZpbGVTZXJ2aWNlLmNyZWF0ZVByb2ZpbGVPcGVyYXRpb24oXG4gICAgICB0aGlzLmRldmljZSxcbiAgICAgIHRoaXMuc2VsZWN0ZWRQcm9maWxlXG4gICAgKTtcbiAgfVxuXG4gIHVwZGF0ZVByb2ZpbGVJdGVtcyhkZXZpY2UsIHByb2ZpbGUpIHtcbiAgICB0aGlzLmZpcm13YXJlSXRlbXMgPSB0aGlzLmRldmljZVByb2ZpbGVTZXJ2aWNlLmdldEZpcm13YXJlSXRlbXMoZGV2aWNlLCBwcm9maWxlKTtcbiAgICB0aGlzLnNvZnR3YXJlSXRlbXMgPSB0aGlzLmRldmljZVByb2ZpbGVTZXJ2aWNlLmdldFNvZnR3YXJlSXRlbXMoZGV2aWNlLCBwcm9maWxlKTtcbiAgICB0aGlzLmNvbmZpZ3VyYXRpb25JdGVtcyA9IHRoaXMuZGV2aWNlUHJvZmlsZVNlcnZpY2UuZ2V0Q29uZmlndXJhdGlvbkl0ZW1zKGRldmljZSwgcHJvZmlsZSk7XG4gIH1cblxuICBwcml2YXRlIHN1YnNjcmliZVRvTWFuYWdlZE9iamVjdHMoKSB7XG4gICAgdGhpcy5kZXZpY2VSZWFsdGltZVxuICAgICAgLm9uVXBkYXRlJCh0aGlzLmRldmljZS5pZClcbiAgICAgIC5waXBlKHRha2VVbnRpbERlc3Ryb3llZCh0aGlzLmRlc3Ryb3lSZWYpKVxuICAgICAgLnN1YnNjcmliZSgobWFuYWdlZE9iamVjdDogSU1hbmFnZWRPYmplY3QpID0+IHtcbiAgICAgICAgdGhpcy51cGRhdGVQcm9maWxlSXRlbXMobWFuYWdlZE9iamVjdCwgdGhpcy5zZWxlY3RlZFByb2ZpbGUpO1xuICAgICAgfSk7XG4gICAgdGhpcy5kZXZpY2VSZWFsdGltZVxuICAgICAgLm9uRGVsZXRlJCh0aGlzLmRldmljZS5pZClcbiAgICAgIC5waXBlKHRha2VVbnRpbERlc3Ryb3llZCh0aGlzLmRlc3Ryb3lSZWYpKVxuICAgICAgLnN1YnNjcmliZSgoKSA9PiB7XG4gICAgICAgIHRoaXMuYWxlcnRTZXJ2aWNlLmRhbmdlcihcbiAgICAgICAgICBnZXR0ZXh0KFxuICAgICAgICAgICAgJ1RoaXMgZGV2aWNlIGhhcyBqdXN0IGJlZW4gZGVsZXRlZC4gWW91IHdpbGwgYmUgcmVkaXJlY3RlZCB0byBcIkFsbCBkZXZpY2VzXCIgcGFnZSBub3cuJ1xuICAgICAgICAgIClcbiAgICAgICAgKTtcbiAgICAgICAgd2luZG93LmxvY2F0aW9uLmhyZWYgPSAnIy9kZXZpY2UnO1xuICAgICAgfSk7XG4gIH1cblxuICBwcml2YXRlIHN1YnNjcmliZVRvT3BlcmF0aW9ucygpIHtcbiAgICB0aGlzLm9wZXJhdGlvblJlYWx0aW1lXG4gICAgICAub25BbGwkKHRoaXMuZGV2aWNlLmlkKVxuICAgICAgLnBpcGUoXG4gICAgICAgIG1hcCgoeyBkYXRhIH0pID0+IGRhdGEgYXMgSU9wZXJhdGlvbiksXG4gICAgICAgIGZpbHRlcihvcGVyYXRpb24gPT4gb3BlcmF0aW9uLmM4eV9EZXZpY2VQcm9maWxlKSxcbiAgICAgICAgdGFrZVVudGlsRGVzdHJveWVkKHRoaXMuZGVzdHJveVJlZilcbiAgICAgIClcbiAgICAgIC5zdWJzY3JpYmUob3BlcmF0aW9uID0+IHtcbiAgICAgICAgdGhpcy5vcGVyYXRpb24gPSBvcGVyYXRpb247XG4gICAgICB9KTtcbiAgfVxuXG4gIHByaXZhdGUgdG9Qcm9maWxlRm9yRGV2aWNlKHByb2ZpbGU6IERldmljZVByb2ZpbGUpOiBEZXZpY2VQcm9maWxlIHtcbiAgICBpZiAoXG4gICAgICBBcnJheS5mcm9tKHByb2ZpbGU/LmM4eV9EZXZpY2VQcm9maWxlPy5zb2Z0d2FyZSB8fCBbXSkubGVuZ3RoID09PSAwIHx8XG4gICAgICBoYXModGhpcy5kZXZpY2UsICdjOHlfU3VwcG9ydGVkU29mdHdhcmVUeXBlcycpXG4gICAgKSB7XG4gICAgICByZXR1cm4gcHJvZmlsZTtcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgLi4ucHJvZmlsZSxcbiAgICAgICAgYzh5X0RldmljZVByb2ZpbGU6IHtcbiAgICAgICAgICAuLi5wcm9maWxlLmM4eV9EZXZpY2VQcm9maWxlLFxuICAgICAgICAgIHNvZnR3YXJlOiBwcm9maWxlLmM4eV9EZXZpY2VQcm9maWxlLnNvZnR3YXJlLm1hcChzdyA9PlxuICAgICAgICAgICAgcGlja0J5KHN3LCAoXywga2V5KSA9PiBrZXkgIT09ICdzb2Z0d2FyZVR5cGUnKVxuICAgICAgICAgIClcbiAgICAgICAgfVxuICAgICAgfTtcbiAgICB9XG4gIH1cbn1cbiIsIjxjOHktYWN0aW9uLWJhci1pdGVtIFtwbGFjZW1lbnRdPVwiJ3JpZ2h0J1wiPlxuICA8YnV0dG9uXG4gICAgY2xhc3M9XCJidG4gYnRuLWxpbmtcIlxuICAgIHRpdGxlPVwie3sgJ1JlbG9hZCcgfCB0cmFuc2xhdGUgfX1cIlxuICAgIHR5cGU9XCJidXR0b25cIlxuICAgIChjbGljayk9XCJyZWxvYWQkLm5leHQodHJ1ZSlcIlxuICA+XG4gICAgPGlcbiAgICAgIGM4eUljb249XCJyZWZyZXNoXCJcbiAgICAgIFtuZ0NsYXNzXT1cInsgJ2ljb24tc3Bpbic6IHJlbG9hZCQudmFsdWUgfVwiXG4gICAgPjwvaT5cbiAgICB7eyAnUmVsb2FkJyB8IHRyYW5zbGF0ZSB9fVxuICA8L2J1dHRvbj5cbjwvYzh5LWFjdGlvbi1iYXItaXRlbT5cbjxjOHktYWN0aW9uLWJhci1pdGVtIFtwbGFjZW1lbnRdPVwiJ3JpZ2h0J1wiPlxuICA8Yzh5LXJlYWx0aW1lLWJ0biBbc2VydmljZV09XCJkZXZpY2VSZWFsdGltZVwiPjwvYzh5LXJlYWx0aW1lLWJ0bj5cbjwvYzh5LWFjdGlvbi1iYXItaXRlbT5cblxuPGRpdiBjbGFzcz1cImNhcmQgY2FyZC0tZ3JpZC0tZnVsbHBhZ2UgY2FyZC0tZ3JpZC0tZnVsbHBhZ2UgY2FyZC0tZ3JpZCBncmlkX19yb3ctLTItMTAtLW1kXCI+XG4gIDxkaXYgY2xhc3M9XCJjYXJkLS1ncmlkIGdyaWRfX2NvbC0tNi02LS1tZFwiPlxuICAgIDwhLS0gQVZBSUxBQkxFIFBST0ZJTEVTIC0tPlxuICAgIDxkaXYgY2xhc3M9XCJiZy1sZXZlbC0wXCI+XG4gICAgICA8ZGl2IGNsYXNzPVwiY2FyZC1oZWFkZXIgc2VwYXJhdG9yXCI+XG4gICAgICAgIDxkaXZcbiAgICAgICAgICBjbGFzcz1cImNhcmQtdGl0bGVcIlxuICAgICAgICAgIHRyYW5zbGF0ZVxuICAgICAgICA+XG4gICAgICAgICAgRGV2aWNlIHByb2ZpbGVcbiAgICAgICAgPC9kaXY+XG4gICAgICA8L2Rpdj5cbiAgICAgIDxkaXYgY2xhc3M9XCJwLTE2XCI+XG4gICAgICAgIDxmb3JtICNkZXZpY2VQcm9maWxlRm9ybT1cIm5nRm9ybVwiPlxuICAgICAgICAgIDxkaXYgY2xhc3M9XCJpbnB1dC1ncm91cFwiPlxuICAgICAgICAgICAgPGM4eS10eXBlYWhlYWRcbiAgICAgICAgICAgICAgY2xhc3M9XCJmbGV4LWdyb3dcIlxuICAgICAgICAgICAgICBwbGFjZWhvbGRlcj1cInt7ICdTZWxlY3QgZGV2aWNlIHByb2ZpbGUnIHwgdHJhbnNsYXRlIH19XCJcbiAgICAgICAgICAgICAgbmFtZT1cInNlbGVjdFByb2ZpbGVcIlxuICAgICAgICAgICAgICBkYXRhLWN5PVwiZGV2aWNlLXRhYi1wcm9maWxlLS1zZWxlY3QtZGV2aWNlLXByb2ZpbGVcIlxuICAgICAgICAgICAgICBbKG5nTW9kZWwpXT1cInNlbGVjdGVkUHJvZmlsZVwiXG4gICAgICAgICAgICAgIChvblNlYXJjaCk9XCJwYXR0ZXJuJC5uZXh0KCRldmVudClcIlxuICAgICAgICAgICAgICBbYWxsb3dGcmVlRW50cmllc109XCJmYWxzZVwiXG4gICAgICAgICAgICA+XG4gICAgICAgICAgICAgIDxjOHktbGlcbiAgICAgICAgICAgICAgICBjbGFzcz1cInAtbC04IHAtci04IGM4eS1saXN0X19pdGVtLS1saW5rXCJcbiAgICAgICAgICAgICAgICAqYzh5Rm9yPVwibGV0IHByb2ZpbGUgb2YgZGV2aWNlUHJvZmlsZXMkOyBwaXBlOiBmaWx0ZXJQaXBlXCJcbiAgICAgICAgICAgICAgICAoY2xpY2spPVwic2VsZWN0UHJvZmlsZShwcm9maWxlKTsgcGF0dGVybiQubmV4dCgnJylcIlxuICAgICAgICAgICAgICA+XG4gICAgICAgICAgICAgICAgPGM4eS1oaWdobGlnaHRcbiAgICAgICAgICAgICAgICAgIFt0ZXh0XT1cInByb2ZpbGUubmFtZSB8fCAnJiM0NTsmIzQ1OydcIlxuICAgICAgICAgICAgICAgICAgW3BhdHRlcm5dPVwicGF0dGVybiQudmFsdWVcIlxuICAgICAgICAgICAgICAgID48L2M4eS1oaWdobGlnaHQ+XG4gICAgICAgICAgICAgIDwvYzh5LWxpPlxuICAgICAgICAgICAgPC9jOHktdHlwZWFoZWFkPlxuICAgICAgICAgICAgPGRpdiBjbGFzcz1cImlucHV0LWdyb3VwLWJ0blwiPlxuICAgICAgICAgICAgICA8YnV0dG9uXG4gICAgICAgICAgICAgICAgY2xhc3M9XCJidG4gYnRuLXByaW1hcnlcIlxuICAgICAgICAgICAgICAgIHRpdGxlPVwie3sgJ0Fzc2lnbiBkZXZpY2UgcHJvZmlsZScgfCB0cmFuc2xhdGUgfX1cIlxuICAgICAgICAgICAgICAgIHR5cGU9XCJidXR0b25cIlxuICAgICAgICAgICAgICAgIChjbGljayk9XCJjcmVhdGVPcGVyYXRpb24oKVwiXG4gICAgICAgICAgICAgICAgZGF0YS1jeT1cImRldmljZS10YWItcHJvZmlsZS0tQXNzaWduLWRldmljZS1wcm9maWxlLWJ1dHRvblwiXG4gICAgICAgICAgICAgICAgW2Rpc2FibGVkXT1cIiFzZWxlY3RlZFByb2ZpbGU/LmlkXCJcbiAgICAgICAgICAgICAgICBjOHlQcm9kdWN0RXhwZXJpZW5jZVxuICAgICAgICAgICAgICAgIGluaGVyaXRcbiAgICAgICAgICAgICAgICBbYWN0aW9uRGF0YV09XCJ7IGFjdGlvbjogUFJPRFVDVF9FWFBFUklFTkNFLkFDVElPTlMuQVNTSUdOX0RFVklDRV9QUk9GSUxFIH1cIlxuICAgICAgICAgICAgICA+XG4gICAgICAgICAgICAgICAgPHNwYW4+e3sgJ0Fzc2lnbiBkZXZpY2UgcHJvZmlsZScgfCB0cmFuc2xhdGUgfX08L3NwYW4+XG4gICAgICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgIDwvZm9ybT5cbiAgICAgIDwvZGl2PlxuICAgIDwvZGl2PlxuXG4gICAgPCEtLSBJTlNUQUxMIFBST0ZJTEUgT1BFUkFUSU9OIC0tPlxuICAgIDxkaXYgY2xhc3M9XCJiZy1sZXZlbC0xXCI+XG4gICAgICA8ZGl2IGNsYXNzPVwiY2FyZC1oZWFkZXIgc2VwYXJhdG9yXCI+XG4gICAgICAgIDxkaXZcbiAgICAgICAgICBjbGFzcz1cImNhcmQtdGl0bGVcIlxuICAgICAgICAgIHRyYW5zbGF0ZVxuICAgICAgICA+XG4gICAgICAgICAgQ3VycmVudGx5IGluc3RhbGxlZFxuICAgICAgICA8L2Rpdj5cbiAgICAgIDwvZGl2PlxuICAgICAgPGRpdiBjbGFzcz1cImNhcmQtYmxvY2tcIj5cbiAgICAgICAgPGM4eS1vcGVyYXRpb24tZGV0YWlsc1xuICAgICAgICAgIFtvcGVyYXRpb25dPVwib3BlcmF0aW9uXCJcbiAgICAgICAgICBjOHlQcm9kdWN0RXhwZXJpZW5jZVxuICAgICAgICAgIGluaGVyaXRcbiAgICAgICAgICBzdXBwcmVzc0RhdGFPdmVycmlkaW5nXG4gICAgICAgID48L2M4eS1vcGVyYXRpb24tZGV0YWlscz5cbiAgICAgIDwvZGl2PlxuICAgIDwvZGl2PlxuICA8L2Rpdj5cbiAgPGRpdiBjbGFzcz1cImNhcmQtLWdyaWRfX2lubmVyLXNjcm9sbCBkLWNvbCBuby1hbGlnbi1pdGVtc1wiPlxuICAgIDxkaXYgY2xhc3M9XCJkLWNvbnRlbnRzXCI+XG4gICAgICA8IS0tIEZJUk1XQVJFIC0tPlxuICAgICAgPGM4eS1kZXZpY2UtdGFiLXByb2ZpbGUtZGV0YWlsXG4gICAgICAgIGNsYXNzPVwiZC1jb250ZW50c1wiXG4gICAgICAgIFtzZWN0aW9uSWNvbl09XCInYzh5LWZpcm13YXJlJ1wiXG4gICAgICAgIFtzZWN0aW9uVGl0bGVdPVwiJ0Zpcm13YXJlJyB8IHRyYW5zbGF0ZVwiXG4gICAgICAgIFtlbXB0eVN0YXRlVGV4dF09XCInTm8gZmlybXdhcmUgdG8gZGlzcGxheS4nIHwgdHJhbnNsYXRlXCJcbiAgICAgICAgW2VtcHR5U3RhdGVEZXRhaWxzXT1cIidObyBmaXJtd2FyZSBhc3NpZ25lZC4nIHwgdHJhbnNsYXRlXCJcbiAgICAgICAgW2lzUHJvZmlsZVNlbGVjdGVkXT1cIiEhc2VsZWN0ZWRQcm9maWxlXCJcbiAgICAgICAgW2l0ZW1zXT1cImZpcm13YXJlSXRlbXNcIlxuICAgICAgICBbaXNFbXB0eV09XCIhc2VsZWN0ZWRQcm9maWxlPy5jOHlfRGV2aWNlUHJvZmlsZT8uZmlybXdhcmU/Lm5hbWVcIlxuICAgICAgPjwvYzh5LWRldmljZS10YWItcHJvZmlsZS1kZXRhaWw+XG4gICAgPC9kaXY+XG4gICAgPGRpdiBjbGFzcz1cImQtY29udGVudHNcIj5cbiAgICAgIDwhLS0gU09GVFdBUkUgLS0+XG4gICAgICA8Yzh5LWRldmljZS10YWItcHJvZmlsZS1kZXRhaWxcbiAgICAgICAgY2xhc3M9XCJkLWNvbnRlbnRzXCJcbiAgICAgICAgW3NlY3Rpb25JY29uXT1cIidjOHktdG9vbHMnXCJcbiAgICAgICAgW3NlY3Rpb25UaXRsZV09XCInU29mdHdhcmUnIHwgdHJhbnNsYXRlXCJcbiAgICAgICAgW2VtcHR5U3RhdGVUZXh0XT1cIidObyBzb2Z0d2FyZSB0byBkaXNwbGF5LicgfCB0cmFuc2xhdGVcIlxuICAgICAgICBbZW1wdHlTdGF0ZURldGFpbHNdPVwiJ05vIHNvZnR3YXJlIGFzc2lnbmVkLicgfCB0cmFuc2xhdGVcIlxuICAgICAgICBbaXNQcm9maWxlU2VsZWN0ZWRdPVwiISFzZWxlY3RlZFByb2ZpbGVcIlxuICAgICAgICBbaXRlbXNdPVwic29mdHdhcmVJdGVtc1wiXG4gICAgICAgIFtpc0VtcHR5XT1cIlxuICAgICAgICAgICFzZWxlY3RlZFByb2ZpbGU/LmM4eV9EZXZpY2VQcm9maWxlPy5zb2Z0d2FyZSB8fFxuICAgICAgICAgIHNlbGVjdGVkUHJvZmlsZT8uYzh5X0RldmljZVByb2ZpbGU/LnNvZnR3YXJlPy5sZW5ndGggPT09IDBcbiAgICAgICAgXCJcbiAgICAgID48L2M4eS1kZXZpY2UtdGFiLXByb2ZpbGUtZGV0YWlsPlxuICAgIDwvZGl2PlxuICAgIDxkaXYgY2xhc3M9XCJkLWNvbnRlbnRzXCI+XG4gICAgICA8IS0tIENPTkZJR1VSQVRJT04gLS0+XG4gICAgICA8Yzh5LWRldmljZS10YWItcHJvZmlsZS1kZXRhaWxcbiAgICAgICAgY2xhc3M9XCJkLWNvbnRlbnRzXCJcbiAgICAgICAgW3NlY3Rpb25JY29uXT1cIidnZWFycydcIlxuICAgICAgICBbc2VjdGlvblRpdGxlXT1cIidDb25maWd1cmF0aW9uJyB8IHRyYW5zbGF0ZVwiXG4gICAgICAgIFtlbXB0eVN0YXRlVGV4dF09XCInTm8gY29uZmlndXJhdGlvbiB0byBkaXNwbGF5JyB8IHRyYW5zbGF0ZVwiXG4gICAgICAgIFtlbXB0eVN0YXRlRGV0YWlsc109XCInTm8gY29uZmlndXJhdGlvbiBhc3NpZ25lZCcgfCB0cmFuc2xhdGVcIlxuICAgICAgICBbaXNQcm9maWxlU2VsZWN0ZWRdPVwiISFzZWxlY3RlZFByb2ZpbGVcIlxuICAgICAgICBbaXRlbXNdPVwiY29uZmlndXJhdGlvbkl0ZW1zXCJcbiAgICAgICAgW2lzRW1wdHldPVwiXG4gICAgICAgICAgIXNlbGVjdGVkUHJvZmlsZT8uYzh5X0RldmljZVByb2ZpbGU/LmNvbmZpZ3VyYXRpb24gfHxcbiAgICAgICAgICBzZWxlY3RlZFByb2ZpbGU/LmM4eV9EZXZpY2VQcm9maWxlPy5jb25maWd1cmF0aW9uPy5sZW5ndGggPT09IDBcbiAgICAgICAgXCJcbiAgICAgID48L2M4eS1kZXZpY2UtdGFiLXByb2ZpbGUtZGV0YWlsPlxuICAgIDwvZGl2PlxuICAgIDwhLS0gZmlsbCBpbiB0aGUgcmVtYW5pbmluZyB2ZXJ0aWNhbCBzcGFjZSB3aGVuIGVtcHR5IC0tPlxuICAgIDxkaXYgY2xhc3M9XCJjYXJkLS1ncmlkIGdyaWRfX2NvbC0tNi02LS1tZCBmbGV4LWdyb3dcIj5cbiAgICAgIDxkaXYgY2xhc3M9XCJiZy1sZXZlbC0wXCI+PC9kaXY+XG4gICAgICA8ZGl2IGNsYXNzPVwiYmctbGV2ZWwtMVwiPjwvZGl2PlxuICAgIDwvZGl2PlxuICA8L2Rpdj5cbjwvZGl2PlxuIl19