@c8y/ngx-components
Version:
Angular modules for Cumulocity IoT applications
203 lines • 41.4 kB
JavaScript
import { Component, ViewChildren, QueryList, ChangeDetectorRef } from '@angular/core';
import { Router } from '@angular/router';
import { OpcuaService } from './opcuaService';
import { AlertService, gettext } from '@c8y/ngx-components';
import { find, assign, omit, findIndex, pick, get, isNil } from 'lodash-es';
import { OpcuaDeviceProtocolMapping } from './opcua-device-protocol-mapping.component';
import * as i0 from "@angular/core";
import * as i1 from "./opcuaService";
import * as i2 from "@c8y/ngx-components";
import * as i3 from "@angular/router";
import * as i4 from "@angular/common";
import * as i5 from "@angular/forms";
import * as i6 from "./opcua-device-protocol-description.component";
import * as i7 from "./opcua-device-protocol-data-reporting.component";
import * as i8 from "./opcua-device-protocol-mapping.component";
import * as i9 from "./opcua-auto-apply-settings.component";
export class OpcuaDeviceProtocolDetailComponent {
constructor(changeDetectorRef, opcuaService, alertService, router) {
this.changeDetectorRef = changeDetectorRef;
this.opcuaService = opcuaService;
this.alertService = alertService;
this.router = router;
this.initialModel = {
id: '',
fieldbusType: 'opcuaV2',
description: '',
unit: '',
fieldbusVersion: 4,
name: '',
referencedServerId: '',
referencedRootNodeId: '',
subscriptionType: {
type: 'None'
},
mappings: [],
overriddenSubscriptions: [],
applyConstraints: {
browsePathMatchesRegex: '',
matchesNodeIds: [],
serverObjectHasFragment: '',
matchesServerIds: []
},
enabled: ''
};
this.isLoaded = true;
this.getParentAttr = key => get(this.model, key);
}
ngAfterContentChecked() {
this.changeDetectorRef.detectChanges();
}
getMapping() {
return this.model.mappings;
}
getEmptyMappingObject() {
const { mappings } = this.model;
return {
id: mappings.length > 0 ? Math.max(...mappings.map(m => m.id)) + 1 : 0,
browsePath: []
};
}
getOverriddenSubscriptionsByPath(browsePath) {
if (isNil(browsePath) || browsePath.length === 0) {
return undefined;
}
return find(this.model.overriddenSubscriptions, { browsePath });
}
getStructuredResource(resource) {
const overriddenSubscriptions = this.getOverriddenSubscriptionsByPath(resource.browsePath);
let result = assign({}, resource);
if (overriddenSubscriptions) {
result = assign({}, resource, { subscriptionType: overriddenSubscriptions.subscriptionType });
}
return result;
}
async ngOnInit() {
const id = this.opcuaService.getId();
if (id) {
const res = await this.opcuaService.getDeviceProtocol(id);
if (res && res.status !== 200) {
const data = res.json ? await res.json() : undefined;
this.alertService.addServerFailure({ data, res });
this.isLoaded = false;
}
else {
const data = await res.json();
if (data && data.applyConstraints === null) {
delete data.applyConstraints;
}
if (data && data.subscriptionType === null) {
delete data.subscriptionType;
}
this.model = assign(this.initialModel, data);
if (!this.model.mappings) {
this.model.mappings = [];
}
this.model = assign(this.initialModel, this.updateViableMapping(data));
this.isLoaded = false;
}
}
}
updateViableMapping(model) {
const { mappings } = model;
let result = [];
if (mappings) {
result = mappings.map((item, i) => {
return assign(this.getStructuredResource(item), { id: i });
});
}
return assign(model, { mappings: result });
}
trackById(_index, el) {
return get(el, 'id');
}
addVariable() {
this.model.mappings.push(this.getEmptyMappingObject());
}
updateVariable(mappingObject) {
const { mappings } = this.model;
const { id } = mappingObject;
const index = findIndex(mappings, { id });
mappings[index > -1 ? index : 0] = mappingObject;
}
removeVariable(mappingObject) {
const { mappings } = this.model;
const { id } = mappingObject;
let index = -1;
// id typeof string || number
if (!isNil(id) && (id.length > 0 || id > -1)) {
index = findIndex(mappings, { id });
}
if (index > -1) {
mappings.splice(index, 1);
}
}
actionHandler(actionObject) {
switch (actionObject.action) {
case 'save':
this.updateVariable(actionObject.data);
break;
case 'delete':
this.removeVariable(actionObject.data);
break;
}
}
extractOverridSubscriptionType(_mapping) {
const overriddenSubscriptions = [];
const variableMapping = [];
_mapping.forEach(element => {
if (element.id !== 'new') {
if (element.subscriptionType) {
overriddenSubscriptions.push(assign({ browsePath: element.browsePath }, { subscriptionType: element.subscriptionType }));
}
variableMapping.push(omit(element, ['subscriptionType']));
}
});
return [variableMapping, overriddenSubscriptions];
}
prepareRequestJson(_model) {
let requestJson = {};
const [mappings, overriddenSubscriptions] = this.extractOverridSubscriptionType(_model.mappings);
requestJson = assign(requestJson, pick(_model, Object.keys(this.initialModel)), {
mappings,
overriddenSubscriptions
});
return requestJson;
}
async save() {
try {
const res = await this.opcuaService.updateDeviceProtocol(this.prepareRequestJson(this.model));
const data = await res.json();
if (res && res.status === 200) {
this.router.navigate(['deviceprotocols']);
this.alertService.success(gettext('Device protocol saved.'));
}
else {
const { details } = data;
this.alertService.addServerFailure({ res, data: details });
}
}
catch (ex) {
this.alertService.danger(gettext('Failed to save. Try again.'));
}
}
canSave(deviceTypeForm) {
if (this.instanceList) {
const activeInstances = this.instanceList.filter(item => item.isActive());
if (activeInstances.length > 0) {
return true;
}
}
return !deviceTypeForm.form.valid;
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: OpcuaDeviceProtocolDetailComponent, deps: [{ token: i0.ChangeDetectorRef }, { token: i1.OpcuaService }, { token: i2.AlertService }, { token: i3.Router }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: OpcuaDeviceProtocolDetailComponent, selector: "opcua-device-protocol-detail", viewQueries: [{ propertyName: "instanceList", predicate: OpcuaDeviceProtocolMapping, descendants: true }], ngImport: i0, template: "<c8y-title *ngIf=\"!isLoaded\">{{ model.name }}</c8y-title>\n<c8y-breadcrumb>\n <c8y-breadcrumb-item\n [icon]=\"'c8y-device-protocols'\"\n [label]=\"'Device types' | translate\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item\n [icon]=\"'c8y-device-protocols'\"\n [label]=\"'Device protocols' | translate\"\n [path]=\"'deviceprotocols'\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [icon]=\"'c8y-device-protocols'\" [label]=\"model?.name\"></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n<div class=\"row\">\n <div class=\"col-lg-12 col-lg-max\">\n <form #deviceTypeForm=\"ngForm\" name=\"detailForm\" *ngIf=\"!isLoaded\" class=\"card card--fullpage\">\n <opcua-device-protocol-description [model]=\"model\"></opcua-device-protocol-description>\n <div class=\"inner-scroll\">\n <div class=\"d-contents\">\n <div class=\"card-header separator-top-bottom bg-component sticky-top\">\n <div class=\"h4\" translate>Variables</div>\n </div>\n <div class=\"p-l-16 p-r-16\">\n <div class=\"c8y-list__group\" *ngIf=\"model.mappings.length > 0\" ngModelGroup=\"variable\">\n <opcua-device-protocol-mapping\n *ngFor=\"let resource of getMapping(); index as i; trackBy: trackById\"\n [index]=\"i\"\n [referencedServerId]=\"model.referencedServerId\"\n [referencedRootNodeId]=\"model.referencedRootNodeId\"\n [resource]=\"getStructuredResource(resource)\"\n [getParentAttr]=\"getParentAttr\"\n (onAction)=\"actionHandler($event)\"\n ></opcua-device-protocol-mapping>\n </div>\n </div>\n <div class=\"p-l-16 p-r-16 p-t-16\">\n <c8y-ui-empty-state\n *ngIf=\"model.mappings.length === 0\"\n [icon]=\"'sliders'\"\n [title]=\"'No variables to display.' | translate\"\n [subtitle]=\"'Click below to add your first variable.' | translate\"\n ></c8y-ui-empty-state>\n\n <div class=\"card-footer\">\n <button\n type=\"button\"\n title=\"{{ 'Add variable' | translate }}\"\n class=\"btn btn-default addVariableBtn\"\n (click)=\"addVariable()\"\n >\n <i c8yIcon=\"plus-circle\"></i>\n {{ 'Add variable' | translate }}\n </button>\n </div>\n </div>\n </div>\n <div class=\"d-contents\">\n <div class=\"card-header separator-top-bottom bg-component sticky-top\">\n <div class=\"h4\" translate>Data reporting</div>\n </div>\n <div class=\"p-l-16 p-r-16 p-t-16\" ngModelGroup=\"subscription\">\n <opcua-device-protocol-data-reporting\n [groupName]=\"'subscription'\"\n [model]=\"model\"\n ></opcua-device-protocol-data-reporting>\n </div>\n </div>\n <div class=\"d-contents\">\n <div class=\"card-header separator-top-bottom sticky-top\">\n <div class=\"h4\" translate>Auto apply constraints</div>\n </div>\n <div class=\"p-l-16 p-r-16 p-t-16 overflow-visible\" ngModelGroup=\"autoApply\">\n <opcua-auto-apply [model]=\"model\"></opcua-auto-apply>\n </div>\n </div>\n\n <div class=\"card-footer sticky-bottom separator\" style=\"z-index: 101\">\n <button\n title=\"{{ 'Save' | translate }}\"\n id=\"deviceTypeSave\"\n class=\"btn btn-primary\"\n (click)=\"save()\"\n [disabled]=\"canSave(deviceTypeForm)\"\n type=\"button\"\n >\n {{ 'Save' | translate }}\n </button>\n </div>\n </div>\n </form>\n </div>\n</div>\n", dependencies: [{ kind: "component", type: i2.BreadcrumbComponent, selector: "c8y-breadcrumb" }, { kind: "component", type: i2.BreadcrumbItemComponent, selector: "c8y-breadcrumb-item", inputs: ["icon", "translate", "label", "path", "injector"] }, { kind: "component", type: i2.EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "directive", type: i2.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "directive", type: i2.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "directive", type: i4.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i4.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i2.TitleComponent, selector: "c8y-title", inputs: ["pageTitleUpdate"] }, { kind: "directive", type: i5.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i5.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i5.NgModelGroup, selector: "[ngModelGroup]", inputs: ["ngModelGroup"], exportAs: ["ngModelGroup"] }, { kind: "directive", type: i5.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: i6.OpcuaDeviceProtocolDescription, selector: "opcua-device-protocol-description", inputs: ["model"] }, { kind: "component", type: i7.OpcuaDeviceProtocolDataReportingComponent, selector: "opcua-device-protocol-data-reporting", inputs: ["model", "groupName"], outputs: ["onSubscriptionChange"] }, { kind: "component", type: i8.OpcuaDeviceProtocolMapping, selector: "opcua-device-protocol-mapping", inputs: ["resource", "index", "getParentAttr", "referencedServerId", "referencedRootNodeId"], outputs: ["onAction"] }, { kind: "component", type: i9.OpcuaAutoApplySettingsComponent, selector: "opcua-auto-apply", inputs: ["model"] }, { kind: "pipe", type: i2.C8yTranslatePipe, name: "translate" }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: OpcuaDeviceProtocolDetailComponent, decorators: [{
type: Component,
args: [{ selector: 'opcua-device-protocol-detail', template: "<c8y-title *ngIf=\"!isLoaded\">{{ model.name }}</c8y-title>\n<c8y-breadcrumb>\n <c8y-breadcrumb-item\n [icon]=\"'c8y-device-protocols'\"\n [label]=\"'Device types' | translate\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item\n [icon]=\"'c8y-device-protocols'\"\n [label]=\"'Device protocols' | translate\"\n [path]=\"'deviceprotocols'\"\n ></c8y-breadcrumb-item>\n <c8y-breadcrumb-item [icon]=\"'c8y-device-protocols'\" [label]=\"model?.name\"></c8y-breadcrumb-item>\n</c8y-breadcrumb>\n<div class=\"row\">\n <div class=\"col-lg-12 col-lg-max\">\n <form #deviceTypeForm=\"ngForm\" name=\"detailForm\" *ngIf=\"!isLoaded\" class=\"card card--fullpage\">\n <opcua-device-protocol-description [model]=\"model\"></opcua-device-protocol-description>\n <div class=\"inner-scroll\">\n <div class=\"d-contents\">\n <div class=\"card-header separator-top-bottom bg-component sticky-top\">\n <div class=\"h4\" translate>Variables</div>\n </div>\n <div class=\"p-l-16 p-r-16\">\n <div class=\"c8y-list__group\" *ngIf=\"model.mappings.length > 0\" ngModelGroup=\"variable\">\n <opcua-device-protocol-mapping\n *ngFor=\"let resource of getMapping(); index as i; trackBy: trackById\"\n [index]=\"i\"\n [referencedServerId]=\"model.referencedServerId\"\n [referencedRootNodeId]=\"model.referencedRootNodeId\"\n [resource]=\"getStructuredResource(resource)\"\n [getParentAttr]=\"getParentAttr\"\n (onAction)=\"actionHandler($event)\"\n ></opcua-device-protocol-mapping>\n </div>\n </div>\n <div class=\"p-l-16 p-r-16 p-t-16\">\n <c8y-ui-empty-state\n *ngIf=\"model.mappings.length === 0\"\n [icon]=\"'sliders'\"\n [title]=\"'No variables to display.' | translate\"\n [subtitle]=\"'Click below to add your first variable.' | translate\"\n ></c8y-ui-empty-state>\n\n <div class=\"card-footer\">\n <button\n type=\"button\"\n title=\"{{ 'Add variable' | translate }}\"\n class=\"btn btn-default addVariableBtn\"\n (click)=\"addVariable()\"\n >\n <i c8yIcon=\"plus-circle\"></i>\n {{ 'Add variable' | translate }}\n </button>\n </div>\n </div>\n </div>\n <div class=\"d-contents\">\n <div class=\"card-header separator-top-bottom bg-component sticky-top\">\n <div class=\"h4\" translate>Data reporting</div>\n </div>\n <div class=\"p-l-16 p-r-16 p-t-16\" ngModelGroup=\"subscription\">\n <opcua-device-protocol-data-reporting\n [groupName]=\"'subscription'\"\n [model]=\"model\"\n ></opcua-device-protocol-data-reporting>\n </div>\n </div>\n <div class=\"d-contents\">\n <div class=\"card-header separator-top-bottom sticky-top\">\n <div class=\"h4\" translate>Auto apply constraints</div>\n </div>\n <div class=\"p-l-16 p-r-16 p-t-16 overflow-visible\" ngModelGroup=\"autoApply\">\n <opcua-auto-apply [model]=\"model\"></opcua-auto-apply>\n </div>\n </div>\n\n <div class=\"card-footer sticky-bottom separator\" style=\"z-index: 101\">\n <button\n title=\"{{ 'Save' | translate }}\"\n id=\"deviceTypeSave\"\n class=\"btn btn-primary\"\n (click)=\"save()\"\n [disabled]=\"canSave(deviceTypeForm)\"\n type=\"button\"\n >\n {{ 'Save' | translate }}\n </button>\n </div>\n </div>\n </form>\n </div>\n</div>\n" }]
}], ctorParameters: () => [{ type: i0.ChangeDetectorRef }, { type: i1.OpcuaService }, { type: i2.AlertService }, { type: i3.Router }], propDecorators: { instanceList: [{
type: ViewChildren,
args: [OpcuaDeviceProtocolMapping]
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3BjdWEtZGV2aWNlLXByb3RvY29sLWRldGFpbC5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9wcm90b2NvbC1vcGN1YS9vcGN1YS1kZXZpY2UtcHJvdG9jb2wtZGV0YWlsLmNvbXBvbmVudC50cyIsIi4uLy4uLy4uL3Byb3RvY29sLW9wY3VhL29wY3VhLWRldmljZS1wcm90b2NvbC1kZXRhaWwuaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsU0FBUyxFQUFVLFlBQVksRUFBRSxTQUFTLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDOUYsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQ3pDLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUM5QyxPQUFPLEVBQUUsWUFBWSxFQUFFLE9BQU8sRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBRTVELE9BQU8sRUFBRSxJQUFJLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSxTQUFTLEVBQUUsSUFBSSxFQUFFLEdBQUcsRUFBRSxLQUFLLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFDNUUsT0FBTyxFQUFFLDBCQUEwQixFQUFFLE1BQU0sMkNBQTJDLENBQUM7Ozs7Ozs7Ozs7O0FBTXZGLE1BQU0sT0FBTyxrQ0FBa0M7SUErQjdDLFlBQ1UsaUJBQW9DLEVBQ3BDLFlBQTBCLEVBQzFCLFlBQTBCLEVBQzFCLE1BQWM7UUFIZCxzQkFBaUIsR0FBakIsaUJBQWlCLENBQW1CO1FBQ3BDLGlCQUFZLEdBQVosWUFBWSxDQUFjO1FBQzFCLGlCQUFZLEdBQVosWUFBWSxDQUFjO1FBQzFCLFdBQU0sR0FBTixNQUFNLENBQVE7UUFoQ3hCLGlCQUFZLEdBQW9CO1lBQzlCLEVBQUUsRUFBRSxFQUFFO1lBQ04sWUFBWSxFQUFFLFNBQVM7WUFDdkIsV0FBVyxFQUFFLEVBQUU7WUFDZixJQUFJLEVBQUUsRUFBRTtZ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TyxFQUFFLEVBQUUsQ0FBQztZQUNaLElBQUksQ0FBQyxZQUFZLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyw0QkFBNEIsQ0FBQyxDQUFDLENBQUM7UUFDbEUsQ0FBQztJQUNILENBQUM7SUFFRCxPQUFPLENBQUMsY0FBYztRQUNwQixJQUFJLElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQztZQUN0QixNQUFNLGVBQWUsR0FBRyxJQUFJLENBQUMsWUFBWSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQyxDQUFDO1lBRTFFLElBQUksZUFBZSxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQztnQkFDL0IsT0FBTyxJQUFJLENBQUM7WUFDZCxDQUFDO1FBQ0gsQ0FBQztRQUNELE9BQU8sQ0FBQyxjQUFjLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQztJQUNwQyxDQUFDOytHQWpOVSxrQ0FBa0M7bUdBQWxDLGtDQUFrQyxxR0FDL0IsMEJBQTBCLGdEQ2IxQywreUhBNEZBOzs0RkRoRmEsa0NBQWtDO2tCQUo5QyxTQUFTOytCQUNFLDhCQUE4QjtpS0FJRSxZQUFZO3NCQUFyRCxZQUFZO3VCQUFDLDBCQUEwQiIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCwgT25Jbml0LCBWaWV3Q2hpbGRyZW4sIFF1ZXJ5TGlzdCwgQ2hhbmdlRGV0ZWN0b3JSZWYgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IFJvdXRlciB9IGZyb20gJ0Bhbmd1bGFyL3JvdXRlcic7XG5pbXBvcnQgeyBPcGN1YVNlcnZpY2UgfSBmcm9tICcuL29wY3VhU2VydmljZSc7XG5pbXBvcnQgeyBBbGVydFNlcnZpY2UsIGdldHRleHQgfSBmcm9tICdAYzh5L25neC1jb21wb25lbnRzJztcbmltcG9ydCB7IE9wY3VhRGV2aWNlVHlwZSB9IGZyb20gJy4vb3BjdWEtcHJvdG9jb2wtZGV2aWNlLXR5cGUuaW50ZXJmYWNlJztcbmltcG9ydCB7IGZpbmQsIGFzc2lnbiwgb21pdCwgZmluZEluZGV4LCBwaWNrLCBnZXQsIGlzTmlsIH0gZnJvbSAnbG9kYXNoLWVzJztcbmltcG9ydCB7IE9wY3VhRGV2aWNlUHJvdG9jb2xNYXBwaW5nIH0gZnJvbSAnLi9vcGN1YS1kZXZpY2UtcHJvdG9jb2wtbWFwcGluZy5jb21wb25lbnQnO1xuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICdvcGN1YS1kZXZpY2UtcHJvdG9jb2wtZGV0YWlsJyxcbiAgdGVtcGxhdGVVcmw6ICcuL29wY3VhLWRldmljZS1wcm90b2NvbC1kZXRhaWwuaHRtbCdcbn0pXG5leHBvcnQgY2xhc3MgT3BjdWFEZXZpY2VQcm90b2NvbERldGFpbENvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCB7XG4gIEBWaWV3Q2hpbGRyZW4oT3BjdWFEZXZpY2VQcm90b2NvbE1hcHBpbmcpIGluc3RhbmNlTGlzdDogUXVlcnlMaXN0PE9wY3VhRGV2aWNlUHJvdG9jb2xNYXBwaW5nPjtcblxuICBpbml0aWFsTW9kZWw6IE9wY3VhRGV2aWNlVHlwZSA9IHtcbiAgICBpZDogJycsXG4gICAgZmllbGRidXNUeXBlOiAnb3BjdWFWMicsXG4gICAgZGVzY3JpcHRpb246ICcnLFxuICAgIHVuaXQ6ICcnLFxuICAgIGZpZWxkYnVzVmVyc2lvbjogNCxcbiAgICBuYW1lOiAnJyxcbiAgICByZWZlcmVuY2VkU2VydmVySWQ6ICcnLFxuICAgIHJlZmVyZW5jZWRSb290Tm9kZUlkOiAnJyxcbiAgICBzdWJzY3JpcHRpb25UeXBlOiB7XG4gICAgICB0eXBlOiAnTm9uZSdcbiAgICB9LFxuICAgIG1hcHBpbmdzOiBbXSxcbiAgICBvdmVycmlkZGVuU3Vic2NyaXB0aW9uczogW10sXG4gICAgYXBwbHlDb25zdHJhaW50czoge1xuICAgICAgYnJvd3NlUGF0aE1hdGNoZXNSZWdleDogJycsXG4gICAgICBtYXRjaGVzTm9kZUlkczogW10sXG4gICAgICBzZXJ2ZXJPYmplY3RIYXNGcmFnbWVudDogJycsXG4gICAgICBtYXRjaGVzU2VydmVySWRzOiBbXVxuICAgIH0sXG4gICAgZW5hYmxlZDogJydcbiAgfTtcblxuICBtb2RlbDogYW55O1xuICBzZXJ2ZXI6IGFueTtcbiAgc2VsZWN0ZWROb2RlOiBhbnk7XG4gIGlzTG9hZGVkID0gdHJ1ZTtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIGNoYW5nZURldGVjdG9yUmVmOiBDaGFuZ2VEZXRlY3RvclJlZixcbiAgICBwcml2YXRlIG9wY3VhU2VydmljZTogT3BjdWFTZXJ2aWNlLFxuICAgIHByaXZhdGUgYWxlcnRTZXJ2aWNlOiBBbGVydFNlcnZpY2UsXG4gICAgcHJpdmF0ZSByb3V0ZXI6IFJvdXRlclxuICApIHt9XG5cbiAgbmdBZnRlckNvbnRlbnRDaGVja2VkKCkge1xuICAgIHRoaXMuY2hhbmdlRGV0ZWN0b3JSZWYuZGV0ZWN0Q2hhbmdlcygpO1xuICB9XG5cbiAgZ2V0UGFyZW50QXR0ciA9IGtleSA9PiBnZXQodGhpcy5tb2RlbCwga2V5KTtcblxuICBnZXRNYXBwaW5nKCkge1xuICAgIHJldHVybiB0aGlzLm1vZGVsLm1hcHBpbmdzO1xuICB9XG5cbiAgZ2V0RW1wdHlNYXBwaW5nT2JqZWN0KCkge1xuICAgIGNvbnN0IHsgbWFwcGluZ3MgfSA9IHRoaXMubW9kZWw7XG4gICAgcmV0dXJuIHtcbiAgICAgIGlkOiBtYXBwaW5ncy5sZW5ndGggPiAwID8gTWF0aC5tYXgoLi4ubWFwcGluZ3MubWFwKG0gPT4gbS5pZCkpICsgMSA6IDAsXG4gICAgICBicm93c2VQYXRoOiBbXVxuICAgIH07XG4gIH1cblxuICBnZXRPdmVycmlkZGVuU3Vic2NyaXB0aW9uc0J5UGF0aChicm93c2VQYXRoOiBzdHJpbmdbXSk6IGFueSB7XG4gICAgaWYgKGlzTmlsKGJyb3dzZVBhdGgpIHx8IGJyb3dzZVBhdGgubGVuZ3RoID09PSAwKSB7XG4gICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgIH1cbiAgICByZXR1cm4gZmluZCh0aGlzLm1vZGVsLm92ZXJyaWRkZW5TdWJzY3JpcHRpb25zLCB7IGJyb3dzZVBhdGggfSk7XG4gIH1cblxuICBnZXRTdHJ1Y3R1cmVkUmVzb3VyY2UocmVzb3VyY2UpIHtcbiAgICBjb25zdCBvdmVycmlkZGVuU3Vic2NyaXB0aW9uczogYW55ID0gdGhpcy5nZXRPdmVycmlkZGVuU3Vic2NyaXB0aW9uc0J5UGF0aChyZXNvdXJjZS5icm93c2VQYXRoKTtcbiAgICBsZXQgcmVzdWx0ID0gYXNzaWduKHt9LCByZXNvdXJjZSk7XG4gICAgaWYgKG92ZXJyaWRkZW5TdWJzY3JpcHRpb25zKSB7XG4gICAgICByZXN1bHQgPSBhc3NpZ24oe30sIHJlc291cmNlLCB7IHN1YnNjcmlwdGlvblR5cGU6IG92ZXJyaWRkZW5TdWJzY3JpcHRpb25zLnN1YnNjcmlwdGlvblR5cGUgfSk7XG4gICAgfVxuICAgIHJldHVybiByZXN1bHQ7XG4gIH1cblxuICBhc3luYyBuZ09uSW5pdCgpIHtcbiAgICBjb25zdCBpZCA9IHRoaXMub3BjdWFTZXJ2aWNlLmdldElkKCk7XG5cbiAgICBpZiAoaWQpIHtcbiAgICAgIGNvbnN0IHJlcyA9IGF3YWl0IHRoaXMub3BjdWFTZXJ2aWNlLmdldERldmljZVByb3RvY29sKGlkKTtcbiAgICAgIGlmIChyZXMgJiYgcmVzLnN0YXR1cyAhPT0gMjAwKSB7XG4gICAgICAgIGNvbnN0IGRhdGEgPSByZXMuanNvbiA/IGF3YWl0IHJlcy5qc29uKCkgOiB1bmRlZmluZWQ7XG4gICAgICAgIHRoaXMuYWxlcnRTZXJ2aWNlLmFkZFNlcnZlckZhaWx1cmUoeyBkYXRhLCByZXMgfSk7XG4gICAgICAgIHRoaXMuaXNMb2FkZWQgPSBmYWxzZTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnN0IGRhdGEgPSBhd2FpdCByZXMuanNvbigpO1xuICAgICAgICBpZiAoZGF0YSAmJiBkYXRhLmFwcGx5Q29uc3RyYWludHMgPT09IG51bGwpIHtcbiAgICAgICAgICBkZWxldGUgZGF0YS5hcHBseUNvbnN0cmFpbnRzO1xuICAgICAgICB9XG4gICAgICAgIGlmIChkYXRhICYmIGRhdGEuc3Vic2NyaXB0aW9uVHlwZSA9PT0gbnVsbCkge1xuICAgICAgICAgIGRlbGV0ZSBkYXRhLnN1YnNjcmlwdGlvblR5cGU7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5tb2RlbCA9IGFzc2lnbih0aGlzLmluaXRpYWxNb2RlbCwgZGF0YSk7XG4gICAgICAgIGlmICghdGhpcy5tb2RlbC5tYXBwaW5ncykge1xuICAgICAgICAgIHRoaXMubW9kZWwubWFwcGluZ3MgPSBbXTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLm1vZGVsID0gYXNzaWduKHRoaXMuaW5pdGlhbE1vZGVsLCB0aGlzLnVwZGF0ZVZpYWJsZU1hcHBpbmcoZGF0YSkpO1xuICAgICAgICB0aGlzLmlzTG9hZGVkID0gZmFsc2U7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgdXBkYXRlVmlhYmxlTWFwcGluZyhtb2RlbCkge1xuICAgIGNvbnN0IHsgbWFwcGluZ3MgfSA9IG1vZGVsO1xuICAgIGxldCByZXN1bHQgPSBbXTtcbiAgICBpZiAobWFwcGluZ3MpIHtcbiAgICAgIHJlc3VsdCA9IG1hcHBpbmdzLm1hcCgoaXRlbSwgaSkgPT4ge1xuICAgICAgICByZXR1cm4gYXNzaWduKHRoaXMuZ2V0U3RydWN0dXJlZFJlc291cmNlKGl0ZW0pLCB7IGlkOiBpIH0pO1xuICAgICAgfSk7XG4gICAgfVxuICAgIHJldHVybiBhc3NpZ24obW9kZWwsIHsgbWFwcGluZ3M6IHJlc3VsdCB9KTtcbiAgfVxuXG4gIHRyYWNrQnlJZChfaW5kZXg6IG51bWJlciwgZWw6IGFueSk6IG51bWJlciB7XG4gICAgcmV0dXJuIGdldChlbCwgJ2lkJyk7XG4gIH1cblxuICBhZGRWYXJpYWJsZSgpIHtcbiAgICB0aGlzLm1vZGVsLm1hcHBpbmdzLnB1c2godGhpcy5nZXRFbXB0eU1hcHBpbmdPYmplY3QoKSk7XG4gIH1cblxuICB1cGRhdGVWYXJpYWJsZShtYXBwaW5nT2JqZWN0KSB7XG4gICAgY29uc3QgeyBtYXBwaW5ncyB9ID0gdGhpcy5tb2RlbDtcbiAgICBjb25zdCB7IGlkIH0gPSBtYXBwaW5nT2JqZWN0O1xuICAgIGNvbnN0IGluZGV4ID0gZmluZEluZGV4KG1hcHBpbmdzLCB7IGlkIH0pO1xuICAgIG1hcHBpbmdzW2luZGV4ID4gLTEgPyBpbmRleCA6IDBdID0gbWFwcGluZ09iamVjdDtcbiAgfVxuXG4gIHJlbW92ZVZhcmlhYmxlKG1hcHBpbmdPYmplY3QpIHtcbiAgICBjb25zdCB7IG1hcHBpbmdzIH0gPSB0aGlzLm1vZGVsO1xuICAgIGNvbnN0IHsgaWQgfSA9IG1hcHBpbmdPYmplY3Q7XG4gICAgbGV0IGluZGV4ID0gLTE7XG5cbiAgICAvLyBpZCB0eXBlb2Ygc3RyaW5nIHx8IG51bWJlclxuICAgIGlmICghaXNOaWwoaWQpICYmIChpZC5sZW5ndGggPiAwIHx8IGlkID4gLTEpKSB7XG4gICAgICBpbmRleCA9IGZpbmRJbmRleChtYXBwaW5ncywgeyBpZCB9KTtcbiAgICB9XG5cbiAgICBpZiAoaW5kZXggPiAtMSkge1xuICAgICAgbWFwcGluZ3Muc3BsaWNlKGluZGV4LCAxKTtcbiAgICB9XG4gIH1cblxuICBhY3Rpb25IYW5kbGVyKGFjdGlvbk9iamVjdCkge1xuICAgIHN3aXRjaCAoYWN0aW9uT2JqZWN0LmFjdGlvbikge1xuICAgICAgY2FzZSAnc2F2ZSc6XG4gICAgICAgIHRoaXMudXBkYXRlVmFyaWFibGUoYWN0aW9uT2JqZWN0LmRhdGEpO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgJ2RlbGV0ZSc6XG4gICAgICAgIHRoaXMucmVtb3ZlVmFyaWFibGUoYWN0aW9uT2JqZWN0LmRhdGEpO1xuICAgICAgICBicmVhaztcbiAgICB9XG4gIH1cblxuICBleHRyYWN0T3ZlcnJpZFN1YnNjcmlwdGlvblR5cGUoX21hcHBpbmcpIHtcbiAgICBjb25zdCBvdmVycmlkZGVuU3Vic2NyaXB0aW9ucyA9IFtdO1xuXG4gICAgY29uc3QgdmFyaWFibGVNYXBwaW5nID0gW107XG4gICAgX21hcHBpbmcuZm9yRWFjaChlbGVtZW50ID0+IHtcbiAgICAgIGlmIChlbGVtZW50LmlkICE9PSAnbmV3Jykge1xuICAgICAgICBpZiAoZWxlbWVudC5zdWJzY3JpcHRpb25UeXBlKSB7XG4gICAgICAgICAgb3ZlcnJpZGRlblN1YnNjcmlwdGlvbnMucHVzaChcbiAgICAgICAgICAgIGFzc2lnbihcbiAgICAgICAgICAgICAgeyBicm93c2VQYXRoOiBlbGVtZW50LmJyb3dzZVBhdGggfSxcbiAgICAgICAgICAgICAgeyBzdWJzY3JpcHRpb25UeXBlOiBlbGVtZW50LnN1YnNjcmlwdGlvblR5cGUgfVxuICAgICAgICAgICAgKVxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgICAgdmFyaWFibGVNYXBwaW5nLnB1c2gob21pdChlbGVtZW50LCBbJ3N1YnNjcmlwdGlvblR5cGUnXSkpO1xuICAgICAgfVxuICAgIH0pO1xuICAgIHJldHVybiBbdmFyaWFibGVNYXBwaW5nLCBvdmVycmlkZGVuU3Vic2NyaXB0aW9uc107XG4gIH1cblxuICBwcmVwYXJlUmVxdWVzdEpzb24oX21vZGVsKSB7XG4gICAgbGV0IHJlcXVlc3RKc29uID0ge307XG4gICAgY29uc3QgW21hcHBpbmdzLCBvdmVycmlkZGVuU3Vic2NyaXB0aW9uc10gPSB0aGlzLmV4dHJhY3RPdmVycmlkU3Vic2NyaXB0aW9uVHlwZShcbiAgICAgIF9tb2RlbC5tYXBwaW5nc1xuICAgICk7XG4gICAgcmVxdWVzdEpzb24gPSBhc3NpZ24ocmVxdWVzdEpzb24sIHBpY2soX21vZGVsLCBPYmplY3Qua2V5cyh0aGlzLmluaXRpYWxNb2RlbCkpLCB7XG4gICAgICBtYXBwaW5ncyxcbiAgICAgIG92ZXJyaWRkZW5TdWJzY3JpcHRpb25zXG4gICAgfSk7XG4gICAgcmV0dXJuIHJlcXVlc3RKc29uO1xuICB9XG5cbiAgYXN5bmMgc2F2ZSgpIHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgcmVzID0gYXdhaXQgdGhpcy5vcGN1YVNlcnZpY2UudXBkYXRlRGV2aWNlUHJvdG9jb2wodGhpcy5wcmVwYXJlUmVxdWVzdEpzb24odGhpcy5tb2RlbCkpO1xuICAgICAgY29uc3QgZGF0YSA9IGF3YWl0IHJlcy5qc29uKCk7XG5cbiAgICAgIGlmIChyZXMgJiYgcmVzLnN0YXR1cyA9PT0gMjAwKSB7XG4gICAgICAgIHRoaXMucm91dGVyLm5hdmlnYXRlKFsnZGV2aWNlcHJvdG9jb2xzJ10pO1xuICAgICAgICB0aGlzLmFsZXJ0U2VydmljZS5zdWNjZXNzKGdldHRleHQoJ0RldmljZSBwcm90b2NvbCBzYXZlZC4nKSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb25zdCB7IGRldGFpbHMgfSA9IGRhdGE7XG4gICAgICAgIHRoaXMuYWxlcnRTZXJ2aWNlLmFkZFNlcnZlckZhaWx1cmUoeyByZXMsIGRhdGE6IGRldGFpbHMgfSk7XG4gICAgICB9XG4gICAgfSBjYXRjaCAoZXgpIHtcbiAgICAgIHRoaXMuYWxlcnRTZXJ2aWNlLmRhbmdlcihnZXR0ZXh0KCdGYWlsZWQgdG8gc2F2ZS4gVHJ5IGFnYWluLicpKTtcbiAgICB9XG4gIH1cblxuICBjYW5TYXZlKGRldmljZVR5cGVGb3JtKSB7XG4gICAgaWYgKHRoaXMuaW5zdGFuY2VMaXN0KSB7XG4gICAgICBjb25zdCBhY3RpdmVJbnN0YW5jZXMgPSB0aGlzLmluc3RhbmNlTGlzdC5maWx0ZXIoaXRlbSA9PiBpdGVtLmlzQWN0aXZlKCkpO1xuXG4gICAgICBpZiAoYWN0aXZlSW5zdGFuY2VzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiAhZGV2aWNlVHlwZUZvcm0uZm9ybS52YWxpZDtcbiAgfVxufVxuIiwiPGM4eS10aXRsZSAqbmdJZj1cIiFpc0xvYWRlZFwiPnt7IG1vZGVsLm5hbWUgfX08L2M4eS10aXRsZT5cbjxjOHktYnJlYWRjcnVtYj5cbiAgPGM4eS1icmVhZGNydW1iLWl0ZW1cbiAgICBbaWNvbl09XCInYzh5LWRldmljZS1wcm90b2NvbHMnXCJcbiAgICBbbGFiZWxdPVwiJ0RldmljZSB0eXBlcycgfCB0cmFuc2xhdGVcIlxuICA+PC9jOHktYnJlYWRjcnVtYi1pdGVtPlxuICA8Yzh5LWJyZWFkY3J1bWItaXRlbVxuICAgIFtpY29uXT1cIidjOHktZGV2aWNlLXByb3RvY29scydcIlxuICAgIFtsYWJlbF09XCInRGV2aWNlIHByb3RvY29scycgfCB0cmFuc2xhdGVcIlxuICAgIFtwYXRoXT1cIidkZXZpY2Vwcm90b2NvbHMnXCJcbiAgPjwvYzh5LWJyZWFkY3J1bWItaXRlbT5cbiAgPGM4eS1icmVhZGNydW1iLWl0ZW0gW2ljb25dPVwiJ2M4eS1kZXZpY2UtcHJvdG9jb2xzJ1wiIFtsYWJlbF09XCJtb2RlbD8ubmFtZVwiPjwvYzh5LWJyZWFkY3J1bWItaXRlbT5cbjwvYzh5LWJyZWFkY3J1bWI+XG48ZGl2IGNsYXNzPVwicm93XCI+XG4gIDxkaXYgY2xhc3M9XCJjb2wtbGctMTIgY29sLWxnLW1heFwiPlxuICAgIDxmb3JtICNkZXZpY2VUeXBlRm9ybT1cIm5nRm9ybVwiIG5hbWU9XCJkZXRhaWxGb3JtXCIgKm5nSWY9XCIhaXNMb2FkZWRcIiBjbGFzcz1cImNhcmQgY2FyZC0tZnVsbHBhZ2VcIj5cbiAgICAgIDxvcGN1YS1kZXZpY2UtcHJvdG9jb2wtZGVzY3JpcHRpb24gW21vZGVsXT1cIm1vZGVsXCI+PC9vcGN1YS1kZXZpY2UtcHJvdG9jb2wtZGVzY3JpcHRpb24+XG4gICAgICA8ZGl2IGNsYXNzPVwiaW5uZXItc2Nyb2xsXCI+XG4gICAgICAgIDxkaXYgY2xhc3M9XCJkLWNvbnRlbnRzXCI+XG4gICAgICAgICAgPGRpdiBjbGFzcz1cImNhcmQtaGVhZGVyIHNlcGFyYXRvci10b3AtYm90dG9tIGJnLWNvbXBvbmVudCBzdGlja3ktdG9wXCI+XG4gICAgICAgICAgICA8ZGl2IGNsYXNzPVwiaDRcIiB0cmFuc2xhdGU+VmFyaWFibGVzPC9kaXY+XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgPGRpdiBjbGFzcz1cInAtbC0xNiBwLXItMTZcIj5cbiAgICAgICAgICAgIDxkaXYgY2xhc3M9XCJjOHktbGlzdF9fZ3JvdXBcIiAqbmdJZj1cIm1vZGVsLm1hcHBpbmdzLmxlbmd0aCA+IDBcIiBuZ01vZGVsR3JvdXA9XCJ2YXJpYWJsZVwiPlxuICAgICAgICAgICAgICA8b3BjdWEtZGV2aWNlLXByb3RvY29sLW1hcHBpbmdcbiAgICAgICAgICAgICAgICAqbmdGb3I9XCJsZXQgcmVzb3VyY2Ugb2YgZ2V0TWFwcGluZygpOyBpbmRleCBhcyBpOyB0cmFja0J5OiB0cmFja0J5SWRcIlxuICAgICAgICAgICAgICAgIFtpbmRleF09XCJpXCJcbiAgICAgICAgICAgICAgICBbcmVmZXJlbmNlZFNlcnZlcklkXT1cIm1vZGVsLnJlZmVyZW5jZWRTZXJ2ZXJJZFwiXG4gICAgICAgICAgICAgICAgW3JlZmVyZW5jZWRSb290Tm9kZUlkXT1cIm1vZGVsLnJlZmVyZW5jZWRSb290Tm9kZUlkXCJcbiAgICAgICAgICAgICAgICBbcmVzb3VyY2VdPVwiZ2V0U3RydWN0dXJlZFJlc291cmNlKHJlc291cmNlKVwiXG4gICAgICAgICAgICAgICAgW2dldFBhcmVudEF0dHJdPVwiZ2V0UGFyZW50QXR0clwiXG4gICAgICAgICAgICAgICAgKG9uQWN0aW9uKT1cImFjdGlvbkhhbmRsZXIoJGV2ZW50KVwiXG4gICAgICAgICAgICAgID48L29wY3VhLWRldmljZS1wcm90b2NvbC1tYXBwaW5nPlxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgPGRpdiBjbGFzcz1cInAtbC0xNiBwLXItMTYgcC10LTE2XCI+XG4gICAgICAgICAgICA8Yzh5LXVpLWVtcHR5LXN0YXRlXG4gICAgICAgICAgICAgICpuZ0lmPVwibW9kZWwubWFwcGluZ3MubGVuZ3RoID09PSAwXCJcbiAgICAgICAgICAgICAgW2ljb25dPVwiJ3NsaWRlcnMnXCJcbiAgICAgICAgICAgICAgW3RpdGxlXT1cIidObyB2YXJpYWJsZXMgdG8gZGlzcGxheS4nIHwgdHJhbnNsYXRlXCJcbiAgICAgICAgICAgICAgW3N1YnRpdGxlXT1cIidDbGljayBiZWxvdyB0byBhZGQgeW91ciBmaXJzdCB2YXJpYWJsZS4nIHwgdHJhbnNsYXRlXCJcbiAgICAgICAgICAgID48L2M4eS11aS1lbXB0eS1zdGF0ZT5cblxuICAgICAgICAgICAgPGRpdiBjbGFzcz1cImNhcmQtZm9vdGVyXCI+XG4gICAgICAgICAgICAgIDxidXR0b25cbiAgICAgICAgICAgICAgICB0eXBlPVwiYnV0dG9uXCJcbiAgICAgICAgICAgICAgICB0aXRsZT1cInt7ICdBZGQgdmFyaWFibGUnIHwgdHJhbnNsYXRlIH19XCJcbiAgICAgICAgICAgICAgICBjbGFzcz1cImJ0biBidG4tZGVmYXVsdCBhZGRWYXJpYWJsZUJ0blwiXG4gICAgICAgICAgICAgICAgKGNsaWNrKT1cImFkZFZhcmlhYmxlKClcIlxuICAgICAgICAgICAgICA+XG4gICAgICAgICAgICAgICAgPGkgYzh5SWNvbj1cInBsdXMtY2lyY2xlXCI+PC9pPlxuICAgICAgICAgICAgICAgIHt7ICdBZGQgdmFyaWFibGUnIHwgdHJhbnNsYXRlIH19XG4gICAgICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgIDwvZGl2PlxuICAgICAgICA8ZGl2IGNsYXNzPVwiZC1jb250ZW50c1wiPlxuICAgICAgICAgIDxkaXYgY2xhc3M9XCJjYXJkLWhlYWRlciBzZXBhcmF0b3ItdG9wLWJvdHRvbSBiZy1jb21wb25lbnQgc3RpY2t5LXRvcFwiPlxuICAgICAgICAgICAgPGRpdiBjbGFzcz1cImg0XCIgdHJhbnNsYXRlPkRhdGEgcmVwb3J0aW5nPC9kaXY+XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgPGRpdiBjbGFzcz1cInAtbC0xNiBwLXItMTYgcC10LTE2XCIgbmdNb2RlbEdyb3VwPVwic3Vic2NyaXB0aW9uXCI+XG4gICAgICAgICAgICA8b3BjdWEtZGV2aWNlLXByb3RvY29sLWRhdGEtcmVwb3J0aW5nXG4gICAgICAgICAgICAgIFtncm91cE5hbWVdPVwiJ3N1YnNjcmlwdGlvbidcIlxuICAgICAgICAgICAgICBbbW9kZWxdPVwibW9kZWxcIlxuICAgICAgICAgICAgPjwvb3BjdWEtZGV2aWNlLXByb3RvY29sLWRhdGEtcmVwb3J0aW5nPlxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICA8L2Rpdj5cbiAgICAgICAgPGRpdiBjbGFzcz1cImQtY29udGVudHNcIj5cbiAgICAgICAgICA8ZGl2IGNsYXNzPVwiY2FyZC1oZWFkZXIgc2VwYXJhdG9yLXRvcC1ib3R0b20gc3RpY2t5LXRvcFwiPlxuICAgICAgICAgICAgPGRpdiBjbGFzcz1cImg0XCIgdHJhbnNsYXRlPkF1dG8gYXBwbHkgY29uc3RyYWludHM8L2Rpdj5cbiAgICAgICAgICA8L2Rpdj5cbiAgICAgICAgICA8ZGl2IGNsYXNzPVwicC1sLTE2IHAtci0xNiBwLXQtMTYgb3ZlcmZsb3ctdmlzaWJsZVwiIG5nTW9kZWxHcm91cD1cImF1dG9BcHBseVwiPlxuICAgICAgICAgICAgPG9wY3VhLWF1dG8tYXBwbHkgW21vZGVsXT1cIm1vZGVsXCI+PC9vcGN1YS1hdXRvLWFwcGx5PlxuICAgICAgICAgIDwvZGl2PlxuICAgICAgICA8L2Rpdj5cblxuICAgICAgICA8ZGl2IGNsYXNzPVwiY2FyZC1mb290ZXIgc3RpY2t5LWJvdHRvbSBzZXBhcmF0b3JcIiBzdHlsZT1cInotaW5kZXg6IDEwMVwiPlxuICAgICAgICAgIDxidXR0b25cbiAgICAgICAgICAgIHRpdGxlPVwie3sgJ1NhdmUnIHwgdHJhbnNsYXRlIH19XCJcbiAgICAgICAgICAgIGlkPVwiZGV2aWNlVHlwZVNhdmVcIlxuICAgICAgICAgICAgY2xhc3M9XCJidG4gYnRuLXByaW1hcnlcIlxuICAgICAgICAgICAgKGNsaWNrKT1cInNhdmUoKVwiXG4gICAgICAgICAgICBbZGlzYWJsZWRdPVwiY2FuU2F2ZShkZXZpY2VUeXBlRm9ybSlcIlxuICAgICAgICAgICAgdHlwZT1cImJ1dHRvblwiXG4gICAgICAgICAgPlxuICAgICAgICAgICAge3sgJ1NhdmUnIHwgdHJhbnNsYXRlIH19XG4gICAgICAgICAgPC9idXR0b24+XG4gICAgICAgIDwvZGl2PlxuICAgICAgPC9kaXY+XG4gICAgPC9mb3JtPlxuICA8L2Rpdj5cbjwvZGl2PlxuIl19