@c8y/ngx-components
Version:
Angular modules for Cumulocity IoT applications
134 lines • 32 kB
JavaScript
import { Component, Input, Optional } from '@angular/core';
import { CoreModule, MeasurementRealtimeService } from '@c8y/ngx-components';
import { combineLatest, NEVER } from 'rxjs';
import { distinctUntilChanged, filter, map, pairwise, startWith, tap } from 'rxjs/operators';
import { ContextDashboardComponent } from '@c8y/ngx-components/context-dashboard';
import * as i0 from "@angular/core";
import * as i1 from "@c8y/ngx-components";
import * as i2 from "@c8y/ngx-components/context-dashboard";
import * as i3 from "@angular/common";
var ColorClass;
(function (ColorClass) {
ColorClass["danger"] = "text-danger";
ColorClass["warning"] = "text-warning";
ColorClass["unknown"] = "";
})(ColorClass || (ColorClass = {}));
export class KpiWidgetViewComponent {
constructor(measurementRealtime, dashboard) {
this.measurementRealtime = measurementRealtime;
this.dashboard = dashboard;
this.config = { datapoints: [] };
this.state$ = NEVER;
// used to differentiate between loading state and empty state
this.noDataInitiallyInDB = false;
}
async ngOnInit() {
const datapoints = this.config.datapoints || [];
const datapoint = datapoints.find(tmp => tmp.__active);
if (!datapoint) {
return;
}
this.state$ = this.setupObservable(datapoint);
}
setupObservable(datapoint) {
this.assignContextFromContextDashboard(datapoint);
const latestMeasurement$ = this.getLatestMeasurement$(datapoint);
const lastTwoValues$ = this.getLastTwoValuesOfObservable$(latestMeasurement$);
const previousValue$ = lastTwoValues$.pipe(map(([previousVal]) => previousVal), startWith(undefined));
const unit$ = latestMeasurement$.pipe(map(latestMeasurementValue => datapoint.unit || latestMeasurementValue.unit || ''), startWith(''), distinctUntilChanged());
return combineLatest([
latestMeasurement$,
previousValue$,
this.getTrendOfLatestMeasurements$(lastTwoValues$),
unit$,
this.getColorClass$(latestMeasurement$, datapoint)
]).pipe(map(([latestMeasurement, previousValue, trend, unit, colorClass]) => {
return {
latestMeasurement,
previousValue,
trend,
unit,
colorClass
};
}));
}
getLatestMeasurement$(datapoint) {
return this.measurementRealtime
.latestValueOfSpecificMeasurement$(datapoint.fragment, datapoint.series, datapoint.__target,
// we only need the last two values in case we want to show a trend
this.config.showTrend ? 2 : 1,
// null will be emitted in case no measurement was found initially
true)
.pipe(tap(measurement => {
if (!measurement) {
this.noDataInitiallyInDB = true;
}
}), filter(measurement => !!measurement), map(measurement => {
return {
unit: measurement[datapoint.fragment][datapoint.series].unit,
value: measurement[datapoint.fragment][datapoint.series].value,
date: measurement.time
};
}));
}
getColorClass$(measurementAndDatapointCombination$, datapoint) {
return measurementAndDatapointCombination$.pipe(map(latestMeasurementValue => {
if (this.inRangeOf(datapoint, latestMeasurementValue.value, 'redRangeMin', 'redRangeMax')) {
return ColorClass.danger;
}
if (this.inRangeOf(datapoint, latestMeasurementValue.value, 'yellowRangeMin', 'yellowRangeMax')) {
return ColorClass.warning;
}
return ColorClass.unknown;
}), startWith(ColorClass.unknown), distinctUntilChanged());
}
getLastTwoValuesOfObservable$(input$) {
return input$.pipe(pairwise());
}
getTrendOfLatestMeasurements$(latestMeasurement$) {
return latestMeasurement$.pipe(map(res => {
if (res.length === 2) {
const oldValue = res[0].value;
const newValue = res[1].value;
if (oldValue < newValue) {
return '45deg';
}
if (oldValue > newValue) {
return '135deg';
}
}
return '90deg';
}), startWith('90deg'), distinctUntilChanged());
}
inRangeOf(datapoint, measurementValue, minAttribute, maxAttribute) {
if (typeof datapoint[minAttribute] === 'number' &&
typeof datapoint[maxAttribute] === 'number') {
if (measurementValue >= datapoint[minAttribute] &&
measurementValue < datapoint[maxAttribute]) {
return true;
}
}
return false;
}
assignContextFromContextDashboard(datapoint) {
if (!this.dashboard?.isDeviceTypeDashboard) {
return;
}
const context = this.dashboard?.context;
if (context?.id) {
const { name, id } = context;
datapoint.__target = { name, id };
}
}
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: KpiWidgetViewComponent, deps: [{ token: i1.MeasurementRealtimeService }, { token: i2.ContextDashboardComponent, optional: true }], target: i0.ɵɵFactoryTarget.Component }); }
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: KpiWidgetViewComponent, isStandalone: true, selector: "c8y-kpi-widget-view", inputs: { config: "config" }, providers: [MeasurementRealtimeService], ngImport: i0, template: "<div\n class=\"kpi-widget__container d-flex d-col fit-h fit-w a-i-center j-c-center\"\n *ngIf=\"state$ | async as lastState; else noMeasurementFound\"\n>\n <div class=\"d-flex a-i-center j-c-center fit-w\">\n <div\n class=\"m-r-16 flex-no-shrink text-muted\"\n [ngClass]=\"lastState.colorClass\"\n *ngIf=\"config.icon && config.showIcon\"\n >\n <i class=\"icon-32\" [c8yIcon]=\"config.icon\"></i>\n </div>\n <div class=\"text-truncate\">\n <span\n class=\"text-truncate text-medium\"\n [ngClass]=\"lastState.colorClass\"\n [ngStyle]=\"{ 'font-size': (config.fontSize || '36') + 'px' }\"\n title=\"{{\n lastState.colorClass === 'text-danger'\n ? ('Within red range:' | translate)\n : lastState.colorClass === 'text-warning'\n ? ('Within yellow range:' | translate)\n : ''\n }} {{\n lastState.latestMeasurement.value\n | number\n : '1.' +\n (config.numberOfDecimalPlaces || '0') +\n '-' +\n (config.numberOfDecimalPlaces || '0')\n }} {{ lastState.unit || '' }}\"\n >\n {{\n lastState.latestMeasurement.value\n | number\n : '1.' +\n (config.numberOfDecimalPlaces || '0') +\n '-' +\n (config.numberOfDecimalPlaces || '0')\n }}\n <small class=\"text-regular\">{{ lastState.unit || '' }}</small>\n </span>\n </div>\n <div\n class=\"dot dot-info dot-30 m-l-16 flex-no-shrink\"\n *ngIf=\"config?.showTrend && lastState.previousValue as previousValue\"\n >\n <i\n class=\"icon-20\"\n [title]=\"\n ('Previous value' | translate) +\n ': ' +\n (previousValue.value\n | number\n : '1.' +\n (config.numberOfDecimalPlaces || '0') +\n '-' +\n (config.numberOfDecimalPlaces || '0')) +\n ' (' +\n (previousValue.date | date: 'medium') +\n ')'\n \"\n c8yIcon=\"arrow-dotted-up\"\n [ngStyle]=\"{ transform: 'rotate(' + lastState.trend + ')' }\"\n ></i>\n </div>\n </div>\n <div class=\"d-flex j-c-center\">\n <p *ngIf=\"config?.showTimestamp\" class=\"icon-flex text-center text-muted small\">\n <i c8yIcon=\"calendar\"></i>\n {{ lastState.latestMeasurement.date | date: 'medium' }}\n </p>\n </div>\n</div>\n\n<ng-template #noMeasurementFound>\n <div class=\"d-flex fit-h fit-w j-c-center a-i-center\">\n <c8y-ui-empty-state\n *ngIf=\"noDataInitiallyInDB\"\n class=\"fit-w\"\n [icon]=\"'line-chart'\"\n [title]=\"'No measurement to display.' | translate\"\n [subtitle]=\"'Waiting for measurements to be created.' | translate\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n <c8y-loading *ngIf=\"!noDataInitiallyInDB\"></c8y-loading>\n </div>\n</ng-template>\n", dependencies: [{ kind: "ngmodule", type: CoreModule }, { kind: "component", type: i1.EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "directive", type: i1.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "pipe", type: i1.C8yTranslatePipe, name: "translate" }, { kind: "directive", type: i3.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i3.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i3.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "pipe", type: i3.AsyncPipe, name: "async" }, { kind: "pipe", type: i3.DecimalPipe, name: "number" }, { kind: "pipe", type: i3.DatePipe, name: "date" }, { kind: "component", type: i1.LoadingComponent, selector: "c8y-loading", inputs: ["layout", "progress", "message"] }] }); }
}
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: KpiWidgetViewComponent, decorators: [{
type: Component,
args: [{ selector: 'c8y-kpi-widget-view', standalone: true, imports: [CoreModule], providers: [MeasurementRealtimeService], template: "<div\n class=\"kpi-widget__container d-flex d-col fit-h fit-w a-i-center j-c-center\"\n *ngIf=\"state$ | async as lastState; else noMeasurementFound\"\n>\n <div class=\"d-flex a-i-center j-c-center fit-w\">\n <div\n class=\"m-r-16 flex-no-shrink text-muted\"\n [ngClass]=\"lastState.colorClass\"\n *ngIf=\"config.icon && config.showIcon\"\n >\n <i class=\"icon-32\" [c8yIcon]=\"config.icon\"></i>\n </div>\n <div class=\"text-truncate\">\n <span\n class=\"text-truncate text-medium\"\n [ngClass]=\"lastState.colorClass\"\n [ngStyle]=\"{ 'font-size': (config.fontSize || '36') + 'px' }\"\n title=\"{{\n lastState.colorClass === 'text-danger'\n ? ('Within red range:' | translate)\n : lastState.colorClass === 'text-warning'\n ? ('Within yellow range:' | translate)\n : ''\n }} {{\n lastState.latestMeasurement.value\n | number\n : '1.' +\n (config.numberOfDecimalPlaces || '0') +\n '-' +\n (config.numberOfDecimalPlaces || '0')\n }} {{ lastState.unit || '' }}\"\n >\n {{\n lastState.latestMeasurement.value\n | number\n : '1.' +\n (config.numberOfDecimalPlaces || '0') +\n '-' +\n (config.numberOfDecimalPlaces || '0')\n }}\n <small class=\"text-regular\">{{ lastState.unit || '' }}</small>\n </span>\n </div>\n <div\n class=\"dot dot-info dot-30 m-l-16 flex-no-shrink\"\n *ngIf=\"config?.showTrend && lastState.previousValue as previousValue\"\n >\n <i\n class=\"icon-20\"\n [title]=\"\n ('Previous value' | translate) +\n ': ' +\n (previousValue.value\n | number\n : '1.' +\n (config.numberOfDecimalPlaces || '0') +\n '-' +\n (config.numberOfDecimalPlaces || '0')) +\n ' (' +\n (previousValue.date | date: 'medium') +\n ')'\n \"\n c8yIcon=\"arrow-dotted-up\"\n [ngStyle]=\"{ transform: 'rotate(' + lastState.trend + ')' }\"\n ></i>\n </div>\n </div>\n <div class=\"d-flex j-c-center\">\n <p *ngIf=\"config?.showTimestamp\" class=\"icon-flex text-center text-muted small\">\n <i c8yIcon=\"calendar\"></i>\n {{ lastState.latestMeasurement.date | date: 'medium' }}\n </p>\n </div>\n</div>\n\n<ng-template #noMeasurementFound>\n <div class=\"d-flex fit-h fit-w j-c-center a-i-center\">\n <c8y-ui-empty-state\n *ngIf=\"noDataInitiallyInDB\"\n class=\"fit-w\"\n [icon]=\"'line-chart'\"\n [title]=\"'No measurement to display.' | translate\"\n [subtitle]=\"'Waiting for measurements to be created.' | translate\"\n [horizontal]=\"true\"\n ></c8y-ui-empty-state>\n <c8y-loading *ngIf=\"!noDataInitiallyInDB\"></c8y-loading>\n </div>\n</ng-template>\n" }]
}], ctorParameters: () => [{ type: i1.MeasurementRealtimeService }, { type: i2.ContextDashboardComponent, decorators: [{
type: Optional
}] }], propDecorators: { config: [{
type: Input
}] } });
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoia3BpLXdpZGdldC12aWV3LmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uLy4uL3dpZGdldHMvaW1wbGVtZW50YXRpb25zL2twaS9rcGktd2lkZ2V0LXZpZXcva3BpLXdpZGdldC12aWV3LmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uLy4uL3dpZGdldHMvaW1wbGVtZW50YXRpb25zL2twaS9rcGktd2lkZ2V0LXZpZXcva3BpLXdpZGdldC12aWV3LmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQUUsS0FBSyxFQUFVLFFBQVEsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUNuRSxPQUFPLEVBQUUsVUFBVSxFQUFFLDBCQUEwQixFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFFN0UsT0FBTyxFQUFFLGFBQWEsRUFBRSxLQUFLLEVBQWMsTUFBTSxNQUFNLENBQUM7QUFDeEQsT0FBTyxFQUFFLG9CQUFvQixFQUFFLE1BQU0sRUFBRSxHQUFHLEVBQUUsUUFBUSxFQUFFLFNBQVMsRUFBRSxHQUFHLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUM3RixPQUFPLEVBQUUseUJBQXlCLEVBQUUsTUFBTSx1Q0FBdUMsQ0FBQzs7Ozs7QUFTbEYsSUFBSyxVQUlKO0FBSkQsV0FBSyxVQUFVO0lBQ2Isb0NBQXNCLENBQUE7SUFDdEIsc0NBQXdCLENBQUE7SUFDeEIsMEJBQVksQ0FBQTtBQUNkLENBQUMsRUFKSSxVQUFVLEtBQVYsVUFBVSxRQUlkO0FBU0QsTUFBTSxPQUFPLHNCQUFzQjtJQWFqQyxZQUNVLG1CQUErQyxFQUNuQyxTQUFvQztRQURoRCx3QkFBbUIsR0FBbkIsbUJBQW1CLENBQTRCO1FBQ25DLGNBQVMsR0FBVCxTQUFTLENBQTJCO1FBZGpELFdBQU0sR0FBb0IsRUFBRSxVQUFVLEVBQUUsRUFBRSxFQUFFLENBQUM7UUFDdEQsV0FBTSxHQU1ELEtBQUssQ0FB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QyxDQUFDO0lBQ0gsQ0FBQzsrR0FsTFUsc0JBQXNCO21HQUF0QixzQkFBc0IsZ0dBRnRCLENBQUMsMEJBQTBCLENBQUMsMEJDekJ6QywyOUZBd0ZBLDJDRGhFWSxVQUFVOzs0RkFHVCxzQkFBc0I7a0JBUGxDLFNBQVM7K0JBQ0UscUJBQXFCLGNBRW5CLElBQUksV0FDUCxDQUFDLFVBQVUsQ0FBQyxhQUNWLENBQUMsMEJBQTBCLENBQUM7OzBCQWlCcEMsUUFBUTt5Q0FkRixNQUFNO3NCQUFkLEtBQUsiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBDb21wb25lbnQsIElucHV0LCBPbkluaXQsIE9wdGlvbmFsIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBDb3JlTW9kdWxlLCBNZWFzdXJlbWVudFJlYWx0aW1lU2VydmljZSB9IGZyb20gJ0BjOHkvbmd4LWNvbXBvbmVudHMnO1xuaW1wb3J0IHsgS1BJRGV0YWlscyB9IGZyb20gJ0BjOHkvbmd4LWNvbXBvbmVudHMvZGF0YXBvaW50LXNlbGVjdG9yJztcbmltcG9ydCB7IGNvbWJpbmVMYXRlc3QsIE5FVkVSLCBPYnNlcnZhYmxlIH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyBkaXN0aW5jdFVudGlsQ2hhbmdlZCwgZmlsdGVyLCBtYXAsIHBhaXJ3aXNlLCBzdGFydFdpdGgsIHRhcCB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcbmltcG9ydCB7IENvbnRleHREYXNoYm9hcmRDb21wb25lbnQgfSBmcm9tICdAYzh5L25neC1jb21wb25lbnRzL2NvbnRleHQtZGFzaGJvYXJkJztcbmltcG9ydCB7IEtwaVdpZGdldENvbmZpZyB9IGZyb20gJy4uL2twaS13aWRnZXQubW9kZWwnO1xuXG5pbnRlcmZhY2UgTWVhc3VyZW1lbnRWYWx1ZSB7XG4gIHVuaXQ/OiBzdHJpbmc7XG4gIHZhbHVlOiBudW1iZXI7XG4gIGRhdGU6IHN0cmluZztcbn1cblxuZW51bSBDb2xvckNsYXNzIHtcbiAgZGFuZ2VyID0gJ3RleHQtZGFuZ2VyJyxcbiAgd2FybmluZyA9ICd0ZXh0LXdhcm5pbmcnLFxuICB1bmtub3duID0gJydcbn1cblxuQENvbXBvbmVudCh7XG4gIHNlbGVjdG9yOiAnYzh5LWtwaS13aWRnZXQtdmlldycsXG4gIHRlbXBsYXRlVXJsOiAnLi9rcGktd2lkZ2V0LXZpZXcuY29tcG9uZW50Lmh0bWwnLFxuICBzdGFuZGFsb25lOiB0cnVlLFxuICBpbXBvcnRzOiBbQ29yZU1vZHVsZV0sXG4gIHByb3ZpZGVyczogW01lYXN1cmVtZW50UmVhbHRpbWVTZXJ2aWNlXVxufSlcbmV4cG9ydCBjbGFzcyBLcGlXaWRnZXRWaWV3Q29tcG9uZW50IGltcGxlbWVudHMgT25Jbml0IHtcbiAgQElucHV0KCkgY29uZmlnOiBLcGlXaWRnZXRDb25maWcgPSB7IGRhdGFwb2ludHM6IFtdIH07XG4gIHN0YXRlJDogT2JzZXJ2YWJsZTx7XG4gICAgbGF0ZXN0TWVhc3VyZW1lbnQ6IE1lYXN1cmVtZW50VmFsdWU7XG4gICAgcHJldmlvdXNWYWx1ZTogTWVhc3VyZW1lbnRWYWx1ZSB8IHVuZGVmaW5lZDtcbiAgICB0cmVuZDogc3RyaW5nO1xuICAgIHVuaXQ6IHN0cmluZztcbiAgICBjb2xvckNsYXNzOiBDb2xvckNsYXNzO1xuICB9PiA9IE5FVkVSO1xuXG4gIC8vIHVzZWQgdG8gZGlmZmVyZW50aWF0ZSBiZXR3ZWVuIGxvYWRpbmcgc3RhdGUgYW5kIGVtcHR5IHN0YXRlXG4gIG5vRGF0YUluaXRpYWxseUluREIgPSBmYWxzZTtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIG1lYXN1cmVtZW50UmVhbHRpbWU6IE1lYXN1cmVtZW50UmVhbHRpbWVTZXJ2aWNlLFxuICAgIEBPcHRpb25hbCgpIHByaXZhdGUgZGFzaGJvYXJkOiBDb250ZXh0RGFzaGJvYXJkQ29tcG9uZW50XG4gICkge31cblxuICBhc3luYyBuZ09uSW5pdCgpIHtcbiAgICBjb25zdCBkYXRhcG9pbnRzID0gdGhpcy5jb25maWcuZGF0YXBvaW50cyB8fCBbXTtcbiAgICBjb25zdCBkYXRhcG9pbnQ6IEtQSURldGFpbHMgPSBkYXRhcG9pbnRzLmZpbmQodG1wID0+IHRtcC5fX2FjdGl2ZSk7XG4gICAgaWYgKCFkYXRhcG9pbnQpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB0aGlzLnN0YXRlJCA9IHRoaXMuc2V0dXBPYnNlcnZhYmxlKGRhdGFwb2ludCk7XG4gIH1cblxuICBzZXR1cE9ic2VydmFibGUoZGF0YXBvaW50OiBLUElEZXRhaWxzKTogT2JzZXJ2YWJsZTx7XG4gICAgbGF0ZXN0TWVhc3VyZW1lbnQ6IE1lYXN1cmVtZW50VmFsdWU7XG4gICAgcHJldmlvdXNWYWx1ZTogTWVhc3VyZW1lbnRWYWx1ZSB8IHVuZGVmaW5lZDtcbiAgICB0cmVuZDogc3RyaW5nO1xuICAgIHVuaXQ6IHN0cmluZztcbiAgICBjb2xvckNsYXNzOiBDb2xvckNsYXNzO1xuICB9PiB7XG4gICAgdGhpcy5hc3NpZ25Db250ZXh0RnJvbUNvbnRleHREYXNoYm9hcmQoZGF0YXBvaW50KTtcbiAgICBjb25zdCBsYXRlc3RNZWFzdXJlbWVudCQgPSB0aGlzLmdldExhdGVzdE1lYXN1cmVtZW50JChkYXRhcG9pbnQpO1xuICAgIGNvbnN0IGxhc3RUd29WYWx1ZXMkID0gdGhpcy5nZXRMYXN0VHdvVmFsdWVzT2ZPYnNlcnZhYmxlJChsYXRlc3RNZWFzdXJlbWVudCQpO1xuXG4gICAgY29uc3QgcHJldmlvdXNWYWx1ZSQgPSBsYXN0VHdvVmFsdWVzJC5waXBlKFxuICAgICAgbWFwKChbcHJldmlvdXNWYWxdKSA9PiBwcmV2aW91c1ZhbCksXG4gICAgICBzdGFydFdpdGgodW5kZWZpbmVkIGFzIE1lYXN1cmVtZW50VmFsdWUgfCB1bmRlZmluZWQpXG4gICAgKTtcblxuICAgIGNvbnN0IHVuaXQkID0gbGF0ZXN0TWVhc3VyZW1lbnQkLnBpcGUoXG4gICAgICBtYXAobGF0ZXN0TWVhc3VyZW1lbnRWYWx1ZSA9PiBkYXRhcG9pbnQudW5pdCB8fCBsYXRlc3RNZWFzdXJlbWVudFZhbHVlLnVuaXQgfHwgJycpLFxuICAgICAgc3RhcnRXaXRoKCcnKSxcbiAgICAgIGRpc3RpbmN0VW50aWxDaGFuZ2VkKClcbiAgICApO1xuXG4gICAgcmV0dXJuIGNvbWJpbmVMYXRlc3QoW1xuICAgICAgbGF0ZXN0TWVhc3VyZW1lbnQkLFxuICAgICAgcHJldmlvdXNWYWx1ZSQsXG4gICAgICB0aGlzLmdldFRyZW5kT2ZMYXRlc3RNZWFzdXJlbWVudHMkKGxhc3RUd29WYWx1ZXMkKSxcbiAgICAgIHVuaXQkLFxuICAgICAgdGhpcy5nZXRDb2xvckNsYXNzJChsYXRlc3RNZWFzdXJlbWVudCQsIGRhdGFwb2ludClcbiAgICBdKS5waXBlKFxuICAgICAgbWFwKChbbGF0ZXN0TWVhc3VyZW1lbnQsIHByZXZpb3VzVmFsdWUsIHRyZW5kLCB1bml0LCBjb2xvckNsYXNzXSkgPT4ge1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIGxhdGVzdE1lYXN1cmVtZW50LFxuICAgICAgICAgIHByZXZpb3VzVmFsdWUsXG4gICAgICAgICAgdHJlbmQsXG4gICAgICAgICAgdW5pdCxcbiAgICAgICAgICBjb2xvckNsYXNzXG4gICAgICAgIH07XG4gICAgICB9KVxuICAgICk7XG4gIH1cblxuICBwcml2YXRlIGdldExhdGVzdE1lYXN1cmVtZW50JChkYXRhcG9pbnQ6IEtQSURldGFpbHMpOiBPYnNlcnZhYmxlPE1lYXN1cmVtZW50VmFsdWU+IHtcbiAgICByZXR1cm4gdGhpcy5tZWFzdXJlbWVudFJlYWx0aW1lXG4gICAgICAubGF0ZXN0VmFsdWVPZlNwZWNpZmljTWVhc3VyZW1lbnQkKFxuICAgICAgICBkYXRhcG9pbnQuZnJhZ21lbnQsXG4gICAgICAgIGRhdGFwb2ludC5zZXJpZXMsXG4gICAgICAgIGRhdGFwb2ludC5fX3RhcmdldCxcbiAgICAgICAgLy8gd2Ugb25seSBuZWVkIHRoZSBsYXN0IHR3byB2YWx1ZXMgaW4gY2FzZSB3ZSB3YW50IHRvIHNob3cgYSB0cmVuZFxuICAgICAgICB0aGlzLmNvbmZpZy5zaG93VHJlbmQgPyAyIDogMSxcbiAgICAgICAgLy8gbnVsbCB3aWxsIGJlIGVtaXR0ZWQgaW4gY2FzZSBubyBtZWFzdXJlbWVudCB3YXMgZm91bmQgaW5pdGlhbGx5XG4gICAgICAgIHRydWVcbiAgICAgIClcbiAgICAgIC5waXBlKFxuICAgICAgICB0YXAobWVhc3VyZW1lbnQgPT4ge1xuICAgICAgICAgIGlmICghbWVhc3VyZW1lbnQpIHtcbiAgICAgICAgICAgIHRoaXMubm9EYXRhSW5pdGlhbGx5SW5EQiA9IHRydWU7XG4gICAgICAgICAgfVxuICAgICAgICB9KSxcbiAgICAgICAgZmlsdGVyKG1lYXN1cmVtZW50ID0+ICEhbWVhc3VyZW1lbnQpLFxuICAgICAgICBtYXAobWVhc3VyZW1lbnQgPT4ge1xuICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICB1bml0OiBtZWFzdXJlbWVudFtkYXRhcG9pbnQuZnJhZ21lbnRdW2RhdGFwb2ludC5zZXJpZXNdLnVuaXQsXG4gICAgICAgICAgICB2YWx1ZTogbWVhc3VyZW1lbnRbZGF0YXBvaW50LmZyYWdtZW50XVtkYXRhcG9pbnQuc2VyaWVzXS52YWx1ZSxcbiAgICAgICAgICAgIGRhdGU6IG1lYXN1cmVtZW50LnRpbWUgYXMgc3RyaW5nXG4gICAgICAgICAgfTtcbiAgICAgICAgfSlcbiAgICAgICk7XG4gIH1cblxuICBwcml2YXRlIGdldENvbG9yQ2xhc3MkKFxuICAgIG1lYXN1cmVtZW50QW5kRGF0YXBvaW50Q29tYmluYXRpb24kOiBPYnNlcnZhYmxlPE1lYXN1cmVtZW50VmFsdWU+LFxuICAgIGRhdGFwb2ludDogS1BJRGV0YWlsc1xuICApOiBPYnNlcnZhYmxlPENvbG9yQ2xhc3M+IHtcbiAgICByZXR1cm4gbWVhc3VyZW1lbnRBbmREYXRhcG9pbnRDb21iaW5hdGlvbiQucGlwZShcbiAgICAgIG1hcChsYXRlc3RNZWFzdXJlbWVudFZhbHVlID0+IHtcbiAgICAgICAgaWYgKHRoaXMuaW5SYW5nZU9mKGRhdGFwb2ludCwgbGF0ZXN0TWVhc3VyZW1lbnRWYWx1ZS52YWx1ZSwgJ3JlZFJhbmdlTWluJywgJ3JlZFJhbmdlTWF4JykpIHtcbiAgICAgICAgICByZXR1cm4gQ29sb3JDbGFzcy5kYW5nZXI7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoXG4gICAgICAgICAgdGhpcy5pblJhbmdlT2YoXG4gICAgICAgICAgICBkYXRhcG9pbnQsXG4gICAgICAgICAgICBsYXRlc3RNZWFzdXJlbWVudFZhbHVlLnZhbHVlLFxuICAgICAgICAgICAgJ3llbGxvd1JhbmdlTWluJyxcbiAgICAgICAgICAgICd5ZWxsb3dSYW5nZU1heCdcbiAgICAgICAgICApXG4gICAgICAgICkge1xuICAgICAgICAgIHJldHVybiBDb2xvckNsYXNzLndhcm5pbmc7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gQ29sb3JDbGFzcy51bmtub3duO1xuICAgICAgfSksXG4gICAgICBzdGFydFdpdGgoQ29sb3JDbGFzcy51bmtub3duKSxcbiAgICAgIGRpc3RpbmN0VW50aWxDaGFuZ2VkKClcbiAgICApO1xuICB9XG5cbiAgcHJpdmF0ZSBnZXRMYXN0VHdvVmFsdWVzT2ZPYnNlcnZhYmxlJDxUPihpbnB1dCQ6IE9ic2VydmFibGU8VD4pOiBPYnNlcnZhYmxlPFRbXT4ge1xuICAgIHJldHVybiBpbnB1dCQucGlwZShwYWlyd2lzZSgpKTtcbiAgfVxuXG4gIHByaXZhdGUgZ2V0VHJlbmRPZkxhdGVzdE1lYXN1cmVtZW50cyQobGF0ZXN0TWVhc3VyZW1lbnQkOiBPYnNlcnZhYmxlPE1lYXN1cmVtZW50VmFsdWVbXT4pIHtcbiAgICByZXR1cm4gbGF0ZXN0TWVhc3VyZW1lbnQkLnBpcGUoXG4gICAgICBtYXAocmVzID0+IHtcbiAgICAgICAgaWYgKHJlcy5sZW5ndGggPT09IDIpIHtcbiAgICAgICAgICBjb25zdCBvbGRWYWx1ZSA9IHJlc1swXS52YWx1ZTtcbiAgICAgICAgICBjb25zdCBuZXdWYWx1ZSA9IHJlc1sxXS52YWx1ZTtcbiAgICAgICAgICBpZiAob2xkVmFsdWUgPCBuZXdWYWx1ZSkge1xuICAgICAgICAgICAgcmV0dXJuICc0NWRlZyc7XG4gICAgICAgICAgfVxuICAgICAgICAgIGlmIChvbGRWYWx1ZSA+IG5ld1ZhbHVlKSB7XG4gICAgICAgICAgICByZXR1cm4gJzEzNWRlZyc7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiAnOTBkZWcnO1xuICAgICAgfSksXG4gICAgICBzdGFydFdpdGgoJzkwZGVnJyksXG4gICAgICBkaXN0aW5jdFVudGlsQ2hhbmdlZCgpXG4gICAgKTtcbiAgfVxuXG4gIHByaXZhdGUgaW5SYW5nZU9mKFxuICAgIGRhdGFwb2ludDogS1BJRGV0YWlscyxcbiAgICBtZWFzdXJlbWVudFZhbHVlOiBudW1iZXIsXG4gICAgbWluQXR0cmlidXRlOiBzdHJpbmcsXG4gICAgbWF4QXR0cmlidXRlOiBzdHJpbmdcbiAgKTogYm9vbGVhbiB7XG4gICAgaWYgKFxuICAgICAgdHlwZW9mIGRhdGFwb2ludFttaW5BdHRyaWJ1dGVdID09PSAnbnVtYmVyJyAmJlxuICAgICAgdHlwZW9mIGRhdGFwb2ludFttYXhBdHRyaWJ1dGVdID09PSAnbnVtYmVyJ1xuICAgICkge1xuICAgICAgaWYgKFxuICAgICAgICBtZWFzdXJlbWVudFZhbHVlID49IGRhdGFwb2ludFttaW5BdHRyaWJ1dGVdICYmXG4gICAgICAgIG1lYXN1cmVtZW50VmFsdWUgPCBkYXRhcG9pbnRbbWF4QXR0cmlidXRlXVxuICAgICAgKSB7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICBwcml2YXRlIGFzc2lnbkNvbnRleHRGcm9tQ29udGV4dERhc2hib2FyZChkYXRhcG9pbnQ6IEtQSURldGFpbHMpIHtcbiAgICBpZiAoIXRoaXMuZGFzaGJvYXJkPy5pc0RldmljZVR5cGVEYXNoYm9hcmQpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgY29uc3QgY29udGV4dCA9IHRoaXMuZGFzaGJvYXJkPy5jb250ZXh0O1xuICAgIGlmIChjb250ZXh0Py5pZCkge1xuICAgICAgY29uc3QgeyBuYW1lLCBpZCB9ID0gY29udGV4dDtcbiAgICAgIGRhdGFwb2ludC5fX3RhcmdldCA9IHsgbmFtZSwgaWQgfTtcbiAgICB9XG4gIH1cbn1cbiIsIjxkaXZcbiAgY2xhc3M9XCJrcGktd2lkZ2V0X19jb250YWluZXIgZC1mbGV4IGQtY29sIGZpdC1oIGZpdC13IGEtaS1jZW50ZXIgai1jLWNlbnRlclwiXG4gICpuZ0lmPVwic3RhdGUkIHwgYXN5bmMgYXMgbGFzdFN0YXRlOyBlbHNlIG5vTWVhc3VyZW1lbnRGb3VuZFwiXG4+XG4gIDxkaXYgY2xhc3M9XCJkLWZsZXggYS1pLWNlbnRlciBqLWMtY2VudGVyIGZpdC13XCI+XG4gICAgPGRpdlxuICAgICAgY2xhc3M9XCJtLXItMTYgZmxleC1uby1zaHJpbmsgdGV4dC1tdXRlZFwiXG4gICAgICBbbmdDbGFzc109XCJsYXN0U3RhdGUuY29sb3JDbGFzc1wiXG4gICAgICAqbmdJZj1cImNvbmZpZy5pY29uICYmIGNvbmZpZy5zaG93SWNvblwiXG4gICAgPlxuICAgICAgPGkgY2xhc3M9XCJpY29uLTMyXCIgW2M4eUljb25dPVwiY29uZmlnLmljb25cIj48L2k+XG4gICAgPC9kaXY+XG4gICAgPGRpdiBjbGFzcz1cInRleHQtdHJ1bmNhdGVcIj5cbiAgICAgIDxzcGFuXG4gICAgICAgIGNsYXNzPVwidGV4dC10cnVuY2F0ZSB0ZXh0LW1lZGl1bVwiXG4gICAgICAgIFtuZ0NsYXNzXT1cImxhc3RTdGF0ZS5jb2xvckNsYXNzXCJcbiAgICAgICAgW25nU3R5bGVdPVwieyAnZm9udC1zaXplJzogKGNvbmZpZy5mb250U2l6ZSB8fCAnMzYnKSArICdweCcgfVwiXG4gICAgICAgIHRpdGxlPVwie3tcbiAgICAgICAgICBsYXN0U3RhdGUuY29sb3JDbGFzcyA9PT0gJ3RleHQtZGFuZ2VyJ1xuICAgICAgICAgICAgPyAoJ1dpdGhpbiByZWQgcmFuZ2U6JyB8IHRyYW5zbGF0ZSlcbiAgICAgICAgICAgIDogbGFzdFN0YXRlLmNvbG9yQ2xhc3MgPT09ICd0ZXh0LXdhcm5pbmcnXG4gICAgICAgICAgICA/ICgnV2l0aGluIHllbGxvdyByYW5nZTonIHwgdHJhbnNsYXRlKVxuICAgICAgICAgICAgOiAnJ1xuICAgICAgICB9fSB7e1xuICAgICAgICAgIGxhc3RTdGF0ZS5sYXRlc3RNZWFzdXJlbWVudC52YWx1ZVxuICAgICAgICAgICAgfCBudW1iZXJcbiAgICAgICAgICAgICAgOiAnMS4nICtcbiAgICAgICAgICAgICAgICAgIChjb25maWcubnVtYmVyT2ZEZWNpbWFsUGxhY2VzIHx8ICcwJykgK1xuICAgICAgICAgICAgICAgICAgJy0nICtcbiAgICAgICAgICAgICAgICAgIChjb25maWcubnVtYmVyT2ZEZWNpbWFsUGxhY2VzIHx8ICcwJylcbiAgICAgICAgfX0ge3sgbGFzdFN0YXRlLnVuaXQgfHwgJycgfX1cIlxuICAgICAgPlxuICAgICAgICB7e1xuICAgICAgICAgIGxhc3RTdGF0ZS5sYXRlc3RNZWFzdXJlbWVudC52YWx1ZVxuICAgICAgICAgICAgfCBudW1iZXJcbiAgICAgICAgICAgICAgOiAnMS4nICtcbiAgICAgICAgICAgICAgICAgIChjb25maWcubnVtYmVyT2ZEZWNpbWFsUGxhY2VzIHx8ICcwJykgK1xuICAgICAgICAgICAgICAgICAgJy0nICtcbiAgICAgICAgICAgICAgICAgIChjb25maWcubnVtYmVyT2ZEZWNpbWFsUGxhY2VzIHx8ICcwJylcbiAgICAgICAgfX1cbiAgICAgICAgPHNtYWxsIGNsYXNzPVwidGV4dC1yZWd1bGFyXCI+e3sgbGFzdFN0YXRlLnVuaXQgfHwgJycgfX08L3NtYWxsPlxuICAgICAgPC9zcGFuPlxuICAgIDwvZGl2PlxuICAgIDxkaXZcbiAgICAgIGNsYXNzPVwiZG90IGRvdC1pbmZvIGRvdC0zMCBtLWwtMTYgZmxleC1uby1zaHJpbmtcIlxuICAgICAgKm5nSWY9XCJjb25maWc/LnNob3dUcmVuZCAmJiBsYXN0U3RhdGUucHJldmlvdXNWYWx1ZSBhcyBwcmV2aW91c1ZhbHVlXCJcbiAgICA+XG4gICAgICA8aVxuICAgICAgICBjbGFzcz1cImljb24tMjBcIlxuICAgICAgICBbdGl0bGVdPVwiXG4gICAgICAgICAgKCdQcmV2aW91cyB2YWx1ZScgfCB0cmFuc2xhdGUpICtcbiAgICAgICAgICAnOiAnICtcbiAgICAgICAgICAocHJldmlvdXNWYWx1ZS52YWx1ZVxuICAgICAgICAgICAgfCBudW1iZXJcbiAgICAgICAgICAgICAgOiAnMS4nICtcbiAgICAgICAgICAgICAgICAgIChjb25maWcubnVtYmVyT2ZEZWNpbWFsUGxhY2VzIHx8ICcwJykgK1xuICAgICAgICAgICAgICAgICAgJy0nICtcbiAgICAgICAgICAgICAgICAgIChjb25maWcubnVtYmVyT2ZEZWNpbWFsUGxhY2VzIHx8ICcwJykpICtcbiAgICAgICAgICAnICgnICtcbiAgICAgICAgICAocHJldmlvdXNWYWx1ZS5kYXRlIHwgZGF0ZTogJ21lZGl1bScpICtcbiAgICAgICAgICAnKSdcbiAgICAgICAgXCJcbiAgICAgICAgYzh5SWNvbj1cImFycm93LWRvdHRlZC11cFwiXG4gICAgICAgIFtuZ1N0eWxlXT1cInsgdHJhbnNmb3JtOiAncm90YXRlKCcgKyBsYXN0U3RhdGUudHJlbmQgKyAnKScgfVwiXG4gICAgICA+PC9pPlxuICAgIDwvZGl2PlxuICA8L2Rpdj5cbiAgPGRpdiBjbGFzcz1cImQtZmxleCBqLWMtY2VudGVyXCI+XG4gICAgPHAgKm5nSWY9XCJjb25maWc/LnNob3dUaW1lc3RhbXBcIiBjbGFzcz1cImljb24tZmxleCB0ZXh0LWNlbnRlciB0ZXh0LW11dGVkIHNtYWxsXCI+XG4gICAgICA8aSBjOHlJY29uPVwiY2FsZW5kYXJcIj48L2k+XG4gICAgICB7eyBsYXN0U3RhdGUubGF0ZXN0TWVhc3VyZW1lbnQuZGF0ZSB8IGRhdGU6ICdtZWRpdW0nIH19XG4gICAgPC9wPlxuICA8L2Rpdj5cbjwvZGl2PlxuXG48bmctdGVtcGxhdGUgI25vTWVhc3VyZW1lbnRGb3VuZD5cbiAgPGRpdiBjbGFzcz1cImQtZmxleCBmaXQtaCBmaXQtdyBqLWMtY2VudGVyIGEtaS1jZW50ZXJcIj5cbiAgICA8Yzh5LXVpLWVtcHR5LXN0YXRlXG4gICAgICAqbmdJZj1cIm5vRGF0YUluaXRpYWxseUluREJcIlxuICAgICAgY2xhc3M9XCJmaXQtd1wiXG4gICAgICBbaWNvbl09XCInbGluZS1jaGFydCdcIlxuICAgICAgW3RpdGxlXT1cIidObyBtZWFzdXJlbWVudCB0byBkaXNwbGF5LicgfCB0cmFuc2xhdGVcIlxuICAgICAgW3N1YnRpdGxlXT1cIidXYWl0aW5nIGZvciBtZWFzdXJlbWVudHMgdG8gYmUgY3JlYXRlZC4nIHwgdHJhbnNsYXRlXCJcbiAgICAgIFtob3Jpem9udGFsXT1cInRydWVcIlxuICAgID48L2M4eS11aS1lbXB0eS1zdGF0ZT5cbiAgICA8Yzh5LWxvYWRpbmcgKm5nSWY9XCIhbm9EYXRhSW5pdGlhbGx5SW5EQlwiPjwvYzh5LWxvYWRpbmc+XG4gIDwvZGl2PlxuPC9uZy10ZW1wbGF0ZT5cbiJdfQ==