UNPKG

@c8y/ngx-components

Version:

Angular modules for Cumulocity IoT applications

241 lines 70.6 kB
import { Component, Input, Optional, ViewChild } from '@angular/core'; import { AGGREGATION_ICONS, AGGREGATION_TEXTS, CoreModule, gettext, WidgetTimeContextDateRangeService } from '@c8y/ngx-components'; import { cloneDeep } from 'lodash-es'; import { FormBuilder, Validators } from '@angular/forms'; import { takeUntil } from 'rxjs/operators'; import { ALARM_STATUS_LABELS } from '@c8y/client'; import { TranslateService } from '@ngx-translate/core'; import { ContextDashboardComponent } from '@c8y/ngx-components/context-dashboard'; import { A11yModule } from '@angular/cdk/a11y'; import { CommonModule } from '@angular/common'; import { ChartsComponent, ChartEventsService, ChartAlarmsService } from '@c8y/ngx-components/echart'; import { TooltipModule } from 'ngx-bootstrap/tooltip'; import { BsDropdownModule } from 'ngx-bootstrap/dropdown'; import { PopoverModule } from 'ngx-bootstrap/popover'; import { AlarmsModule } from '@c8y/ngx-components/alarms'; import { Subject } from 'rxjs'; import { TimeContextComponent } from '@c8y/ngx-components/time-context'; import * as i0 from "@angular/core"; import * as i1 from "@angular/forms"; import * as i2 from "@ngx-translate/core"; import * as i3 from "@c8y/ngx-components"; import * as i4 from "@c8y/ngx-components/context-dashboard"; import * as i5 from "@angular/common"; import * as i6 from "ngx-bootstrap/tooltip"; import * as i7 from "ngx-bootstrap/popover"; import * as i8 from "@c8y/ngx-components/alarms"; export class DatapointsGraphWidgetViewComponent { set config(value) { this.displayConfig = cloneDeep(value); } get config() { throw Error('"config" property should not be referenced in view component to avoid mutating data.'); } constructor(formBuilder, translate, widgetTimeContextDateRangeService, dashboardContextComponent) { this.formBuilder = formBuilder; this.translate = translate; this.widgetTimeContextDateRangeService = widgetTimeContextDateRangeService; this.dashboardContextComponent = dashboardContextComponent; this.events = []; this.alarms = []; this.AGGREGATION_ICONS = AGGREGATION_ICONS; this.AGGREGATION_TEXTS = AGGREGATION_TEXTS; this.datapointsOutOfSync = new Map(); this.hasAtLeastOneDatapointActive = true; this.hasAtLeastOneAlarmActive = true; this.isMarkedAreaEnabled = false; this.legendHelp = this.translate.instant(gettext(`<ul class="m-l-0 p-l-8 m-t-8 m-b-0"> <li> <b>Visibility:</b> use visibility icon to toggle datapoint, alarm or event visibility on chart. At least one datapoint is required to display chart. </li> <li> <b>Alarm details</b> Click alarm legend item to highlight area between alarm raised timestamp and alarm cleared timestamp. You can also click alarm markline on chart to highlight alarm and to pause tooltip. Click on highlighted area or legend item to cancel highlighting. </li> </ul>`)); this.disableZoomInLabel = gettext('Disable zoom in'); this.enableZoomInLabel = gettext('Click to enable zoom, then click and drag on the desired area in the chart.'); this.hideDatapointLabel = gettext('Hide data point'); this.showDatapointLabel = gettext('Show data point'); this.destroy$ = new Subject(); this.timeControlsFormGroup = this.initForm(); this.timeControlsFormGroup.valueChanges.pipe(takeUntil(this.destroy$)).subscribe(value => { this.displayConfig = { ...this.displayConfig, ...value }; }); } ngOnInit() { this.displayConfig?.datapoints?.forEach(dp => this.assignContextFromContextDashboard(dp)); if (this.displayConfig.dateFrom && this.displayConfig.dateTo) { this.timeProps = { dateFrom: new Date(this.displayConfig?.dateFrom), dateTo: new Date(this.displayConfig?.dateTo), interval: this.displayConfig?.interval, realtime: this.displayConfig?.realtime, aggregation: this.displayConfig?.realtime ? null : this.displayConfig?.aggregation }; } } ngOnDestroy() { this.destroy$.next(); this.destroy$.complete(); } ngOnChanges(changes) { this.timeControlsFormGroup.patchValue(this.displayConfig || {}); const config = changes['config']?.currentValue; if (config?.date && config?.widgetInstanceGlobalTimeContext && this.displayConfig?.date) { if (!this.displayConfig.sliderChange) { this.widgetTimeContextDateRangeService.updateInitialTimeRange(null); } this.timePropsChanged({ currentDateContextFromDate: this.displayConfig?.date[0].toISOString(), currentDateContextToDate: this.displayConfig?.date[1].toISOString(), currentDateContextInterval: this.displayConfig?.interval, realtime: this.displayConfig?.realtime, aggregation: this.displayConfig?.aggregation }); } } timePropsChanged(timeProps) { const patchValues = { dateFrom: new Date(timeProps.currentDateContextFromDate), dateTo: new Date(timeProps.currentDateContextToDate), interval: timeProps.currentDateContextInterval, ...(timeProps.aggregation && { aggregation: timeProps.aggregation }), ...(timeProps.realtime && { realtime: timeProps.realtime }) }; this.timeControlsFormGroup.patchValue(patchValues); } updateDashboardTimeContext(timeProps) { if (this.displayConfig?.widgetInstanceGlobalTimeContext) { this.widgetTimeContextDateRangeService.emitPropertyUpdate(timeProps); } this.timeControlsFormGroup.patchValue(timeProps); this.timeProps = { ...timeProps, realtime: false }; } updateTimeRangeOnRealtime(timeRange) { this.timeControlsFormGroup.patchValue(timeRange, { emitEvent: false }); } toggleChart(datapoint) { if (this.displayConfig?.datapoints?.filter(dp => dp.__active).length === 1 && datapoint.__active) { // at least 1 datapoint should be active this.hasAtLeastOneDatapointActive = false; return; } datapoint.__active = !datapoint.__active; this.hasAtLeastOneDatapointActive = true; this.displayConfig = { ...this.displayConfig }; } handleDatapointOutOfSync(dpOutOfSync) { const key = (dp) => dp.__target?.id + dp.fragment + dp.series; const dpMatch = this.displayConfig?.datapoints?.find(dp => key(dp) === key(dpOutOfSync)); if (!dpMatch) { return; } this.datapointsOutOfSync.set(dpMatch, true); } toggleMarkedArea(alarm) { this.enabledMarkedAreaAlarmType = alarm.filters.type; const params = { data: { itemType: alarm.filters.type } }; this.chartComponent.onChartClick(params); } toggleAlarmEventType(alarmOrEvent) { if (alarmOrEvent.timelineType === 'ALARM') { this.alarms = this.alarms.map(alarm => { if (alarm.filters.type === alarmOrEvent.filters.type) { alarm.__hidden = !alarm.__hidden; } return alarm; }); } else { this.events = this.events.map(event => { if (event.filters.type === alarmOrEvent.filters.type) { event.__hidden = !event.__hidden; } return event; }); } this.displayConfig = { ...this.displayConfig }; } updateAlarmsAndEvents(alarmsEventsConfigs) { this.alarms = alarmsEventsConfigs.filter(alarm => alarm.timelineType === 'ALARM'); this.events = alarmsEventsConfigs.filter(event => event.timelineType === 'EVENT'); if (this.alarms.length === 0 || !this.alarms.find(alarm => alarm.__active)) { this.hasAtLeastOneAlarmActive = false; } } filterSeverity(eventTarget) { this.alarms = this.alarms.map(alarm => { if (!alarm.__severity) { alarm.__severity = []; } alarm.__severity = Object.keys(eventTarget.severityOptions).filter((severity) => eventTarget.severityOptions[severity]); if (!alarm.__status) { alarm.__status = []; } const statuses = Object.keys(ALARM_STATUS_LABELS); const filteredStatuses = eventTarget.showCleared ? statuses : statuses.filter(status => status !== 'CLEARED'); alarm.__status = filteredStatuses; return alarm; }); this.displayConfig = { ...this.displayConfig }; } assignContextFromContextDashboard(datapoint) { if (!this.dashboardContextComponent?.isDeviceTypeDashboard) { return; } const context = this.dashboardContextComponent?.context; if (context?.id) { const { name, id } = context; datapoint.__target = { name, id }; } } initForm() { const form = this.formBuilder.group({ dateFrom: [undefined, [Validators.required]], dateTo: [undefined, [Validators.required]], interval: [ this.displayConfig?.interval || 'hours', [Validators.required] ], aggregation: [null, []], realtime: [false, [Validators.required]], widgetInstanceGlobalTimeContext: [false, []] }); form.patchValue(this.displayConfig || {}); return form; } static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DatapointsGraphWidgetViewComponent, deps: [{ token: i1.FormBuilder }, { token: i2.TranslateService }, { token: i3.WidgetTimeContextDateRangeService }, { token: i4.ContextDashboardComponent, optional: true }], target: i0.ɵɵFactoryTarget.Component }); } static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.13", type: DatapointsGraphWidgetViewComponent, isStandalone: true, selector: "c8y-datapoints-graph-widget-view", inputs: { config: "config" }, providers: [ChartEventsService, ChartAlarmsService], viewQueries: [{ propertyName: "chartComponent", first: true, predicate: ChartsComponent, descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"p-l-16 p-r-16\">\n <div class=\"d-flex gap-16 a-i-start\">\n <div\n class=\"btn-group btn-group-sm flex-no-shrink\"\n *ngIf=\"!displayConfig?.widgetInstanceGlobalTimeContext\"\n >\n <button\n class=\"btn btn-default\"\n [attr.aria-label]=\"'Aggregation' | translate\"\n tooltip=\"{{\n (displayConfig?.aggregation\n ? AGGREGATION_TEXTS[displayConfig.aggregation]\n : AGGREGATION_TEXTS.undefined\n ) | translate\n }}\"\n placement=\"top\"\n container=\"body\"\n type=\"button\"\n [adaptivePosition]=\"false\"\n [delay]=\"500\"\n >\n <i\n class=\"icon-14\"\n [c8yIcon]=\"\n displayConfig?.aggregation\n ? AGGREGATION_ICONS[displayConfig.aggregation]\n : AGGREGATION_ICONS.undefined\n \"\n ></i>\n </button>\n\n <c8y-time-context\n class=\"d-contents\"\n (contextChange)=\"timePropsChanged($event)\"\n [changedDateContext]=\"timeProps\"\n [controlsAvailable]=\"{\n realtime: true,\n timeRange: displayConfig?.displayDateSelection,\n interval: displayConfig?.displayDateSelection,\n aggregation: displayConfig?.displayAggregationSelection\n }\"\n ></c8y-time-context>\n </div>\n <c8y-alarms-filter\n class=\"d-contents form-group-sm\"\n *ngIf=\"hasAtLeastOneAlarmActive\"\n (filterApplied)=\"filterSeverity($event)\"\n ></c8y-alarms-filter>\n\n <div class=\"m-l-auto btn-group btn-group-sm flex-no-shrink\">\n <button\n class=\"btn btn-default\"\n [attr.aria-label]=\"'Save as image' | translate\"\n tooltip=\"{{ 'Save as image' | translate }}\"\n container=\"body\"\n type=\"button\"\n (click)=\"chart.saveAsImage()\"\n [adaptivePosition]=\"false\"\n >\n <i\n class=\"icon-14\"\n c8yIcon=\"image-file-checked\"\n ></i>\n </button>\n </div>\n </div>\n <div\n class=\"d-flex\"\n style=\"align-items: center\"\n >\n <button\n class=\"btn-help btn-help--sm m-r-8\"\n [attr.aria-label]=\"'Help' | translate\"\n [popover]=\"legendHelpTemplate\"\n placement=\"bottom\"\n triggers=\"focus\"\n container=\"body\"\n [adaptivePosition]=\"false\"\n ></button>\n <div class=\"inner-scroll\">\n <div class=\"flex-grow p-t-8 d-flex a-i-start gap-8 p-b-4\">\n <div\n class=\"c8y-datapoint-pill flex-no-shrink\"\n title=\"{{ datapoint.label }} - {{ datapoint.__target.name }}\"\n *ngFor=\"let datapoint of displayConfig.datapoints\"\n [ngClass]=\"{ active: datapoint.__active }\"\n >\n <i\n class=\"text-warning m-l-4\"\n c8yIcon=\"exclamation-triangle\"\n [tooltip]=\"'At least 1 active data points must be active.' | translate\"\n container=\"body\"\n *ngIf=\"!hasAtLeastOneDatapointActive && datapoint.__active\"\n [adaptivePosition]=\"false\"\n ></i>\n <button\n class=\"c8y-datapoint-pill__btn\"\n title=\"{{\n (datapoint.__active ? hideDatapointLabel : showDatapointLabel) | translate\n }} \"\n type=\"button\"\n (click)=\"toggleChart(datapoint)\"\n >\n <i\n class=\"icon-14\"\n [c8yIcon]=\"datapoint.__active ? 'eye text-primary' : 'eye-slash text-muted'\"\n ></i>\n </button>\n <div class=\"c8y-datapoint-pill__label c8y-datapoint-pill__btn\">\n <i\n class=\"m-r-4 icon-14\"\n c8yIcon=\"circle\"\n [ngStyle]=\"{\n color: datapoint.color\n }\"\n ></i>\n <span\n class=\"text-truncate\"\n [ngClass]=\"{ 'text-muted': !datapoint.__active }\"\n >\n <span class=\"text-truncate\">\n {{ datapoint.label }}\n </span>\n <small class=\"text-muted text-10\">\n {{ datapoint.__target.name }}\n </small>\n </span>\n <i\n class=\"text-warning m-l-4\"\n c8yIcon=\"exclamation-triangle\"\n [tooltip]=\"\n 'Measurements received for this data point may be out of sync.' | translate\n \"\n container=\"body\"\n *ngIf=\"datapointsOutOfSync.get(datapoint)\"\n [adaptivePosition]=\"false\"\n ></i>\n </div>\n </div>\n <!-- Alarms -->\n\n <ng-container *ngFor=\"let alarm of alarms\">\n <div\n class=\"c8y-alarm-pill flex-no-shrink\"\n title=\"{{ alarm.filters.type }} \"\n *ngIf=\"alarm.__active\"\n >\n <i\n class=\"text-warning m-l-4\"\n c8yIcon=\"exclamation-triangle\"\n [tooltip]=\"\n 'Alarm of this type is currently active and outside of the selected time range'\n | translate\n \"\n container=\"body\"\n *ngIf=\"displayConfig?.activeAlarmTypesOutOfRange?.includes(alarm.filters.type)\"\n [adaptivePosition]=\"false\"\n ></i>\n <button\n class=\"c8y-alarm-pill__btn\"\n title=\"{{ alarm.filters.type }} \"\n type=\"button\"\n (click)=\"toggleAlarmEventType(alarm)\"\n >\n <i\n class=\"icon-14\"\n [c8yIcon]=\"alarm.__hidden ? 'eye-slash text-muted' : 'eye text-primary'\"\n ></i>\n </button>\n <button\n class=\"c8y-alarm-pill__label c8y-alarm-pill__btn\"\n (click)=\"toggleMarkedArea(alarm)\"\n [ngClass]=\"{\n active: !isMarkedAreaEnabled && alarm.filters.type === enabledMarkedAreaAlarmType\n }\"\n >\n <span\n class=\"circle-icon-wrapper circle-icon-wrapper--small m-r-4\"\n [style.background-color]=\"alarm.color\"\n >\n <i\n class=\"stroked-icon\"\n c8yIcon=\"bell\"\n ></i>\n </span>\n <span\n class=\"text-truncate\"\n [ngClass]=\"{ 'text-muted': alarm.__hidden }\"\n >\n <span class=\"text-truncate\">\n {{ alarm.filters.type }}\n </span>\n <small class=\"text-muted text-10\">\n {{ alarm.__target.name }}\n </small>\n </span>\n </button>\n </div>\n </ng-container>\n\n <!-- Events -->\n <ng-container *ngFor=\"let event of events\">\n <div\n class=\"c8y-event-pill flex-no-shrink\"\n title=\"{{ event.filters.type }}\"\n *ngIf=\"event.__active\"\n >\n <button\n class=\"c8y-event-pill__btn\"\n title=\"{{ event.filters.type }} \"\n type=\"button\"\n (click)=\"toggleAlarmEventType(event)\"\n >\n <i\n class=\"icon-14\"\n [c8yIcon]=\"event.__hidden ? 'eye-slash text-muted' : 'eye text-primary'\"\n ></i>\n </button>\n <div class=\"c8y-event-pill__label c8y-event-pill__btn\">\n <span\n class=\"circle-icon-wrapper circle-icon-wrapper--small m-r-4\"\n [ngStyle]=\"{ 'background-color': event.color }\"\n >\n <i\n class=\"stroked-icon\"\n c8yIcon=\"c8y-events\"\n ></i>\n </span>\n <span\n class=\"text-truncate\"\n [ngClass]=\"{ 'text-muted': event.__hidden }\"\n >\n <span class=\"text-truncate\">\n {{ event.filters.type }}\n </span>\n <small class=\"text-muted text-10\">\n {{ event.__target.name }}\n </small>\n </span>\n </div>\n </div>\n </ng-container>\n </div>\n </div>\n </div>\n</div>\n\n<c8y-charts\n #chart\n [config]=\"displayConfig\"\n [alerts]=\"alerts\"\n (updateAlarmsAndEvents)=\"updateAlarmsAndEvents($event)\"\n (configChangeOnZoomOut)=\"updateDashboardTimeContext($event)\"\n (datapointOutOfSync)=\"handleDatapointOutOfSync($event)\"\n (timeRangeChangeOnRealtime)=\"updateTimeRangeOnRealtime($event)\"\n (isMarkedAreaEnabled)=\"isMarkedAreaEnabled = $event\"\n></c8y-charts>\n\n<ng-template #legendHelpTemplate>\n <div [innerHTML]=\"legendHelp\"></div>\n</ng-template>\n", dependencies: [{ kind: "ngmodule", type: A11yModule }, { kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i5.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i5.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i5.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i5.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: ChartsComponent, selector: "c8y-charts", inputs: ["config", "alerts"], outputs: ["configChangeOnZoomOut", "timeRangeChangeOnRealtime", "datapointOutOfSync", "updateAlarmsAndEvents", "isMarkedAreaEnabled"] }, { kind: "ngmodule", type: CoreModule }, { kind: "directive", type: i3.IconDirective, selector: "[c8yIcon]", inputs: ["c8yIcon"] }, { kind: "pipe", type: i3.C8yTranslatePipe, name: "translate" }, { kind: "ngmodule", type: TooltipModule }, { kind: "directive", type: i6.TooltipDirective, selector: "[tooltip], [tooltipHtml]", inputs: ["adaptivePosition", "tooltip", "placement", "triggers", "container", "containerClass", "boundariesElement", "isOpen", "isDisabled", "delay", "tooltipHtml", "tooltipPlacement", "tooltipIsOpen", "tooltipEnable", "tooltipAppendToBody", "tooltipAnimation", "tooltipClass", "tooltipContext", "tooltipPopupDelay", "tooltipFadeDuration", "tooltipTrigger"], outputs: ["tooltipChange", "onShown", "onHidden", "tooltipStateChanged"], exportAs: ["bs-tooltip"] }, { kind: "ngmodule", type: BsDropdownModule }, { kind: "ngmodule", type: PopoverModule }, { kind: "directive", type: i7.PopoverDirective, selector: "[popover]", inputs: ["adaptivePosition", "boundariesElement", "popover", "popoverContext", "popoverTitle", "placement", "outsideClick", "triggers", "container", "containerClass", "isOpen", "delay"], outputs: ["onShown", "onHidden"], exportAs: ["bs-popover"] }, { kind: "ngmodule", type: AlarmsModule }, { kind: "component", type: i8.AlarmsFilterComponent, selector: "c8y-alarms-filter", inputs: ["contextSourceId"], outputs: ["onFilterApplied"] }, { kind: "component", type: TimeContextComponent, selector: "c8y-time-context", inputs: ["changedDateContext", "controlsAvailable", "context"], outputs: ["contextChange"] }] }); } } i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.13", ngImport: i0, type: DatapointsGraphWidgetViewComponent, decorators: [{ type: Component, args: [{ selector: 'c8y-datapoints-graph-widget-view', standalone: true, imports: [ A11yModule, CommonModule, ChartsComponent, CoreModule, TooltipModule, BsDropdownModule, PopoverModule, AlarmsModule, TimeContextComponent ], providers: [ChartEventsService, ChartAlarmsService], template: "<div class=\"p-l-16 p-r-16\">\n <div class=\"d-flex gap-16 a-i-start\">\n <div\n class=\"btn-group btn-group-sm flex-no-shrink\"\n *ngIf=\"!displayConfig?.widgetInstanceGlobalTimeContext\"\n >\n <button\n class=\"btn btn-default\"\n [attr.aria-label]=\"'Aggregation' | translate\"\n tooltip=\"{{\n (displayConfig?.aggregation\n ? AGGREGATION_TEXTS[displayConfig.aggregation]\n : AGGREGATION_TEXTS.undefined\n ) | translate\n }}\"\n placement=\"top\"\n container=\"body\"\n type=\"button\"\n [adaptivePosition]=\"false\"\n [delay]=\"500\"\n >\n <i\n class=\"icon-14\"\n [c8yIcon]=\"\n displayConfig?.aggregation\n ? AGGREGATION_ICONS[displayConfig.aggregation]\n : AGGREGATION_ICONS.undefined\n \"\n ></i>\n </button>\n\n <c8y-time-context\n class=\"d-contents\"\n (contextChange)=\"timePropsChanged($event)\"\n [changedDateContext]=\"timeProps\"\n [controlsAvailable]=\"{\n realtime: true,\n timeRange: displayConfig?.displayDateSelection,\n interval: displayConfig?.displayDateSelection,\n aggregation: displayConfig?.displayAggregationSelection\n }\"\n ></c8y-time-context>\n </div>\n <c8y-alarms-filter\n class=\"d-contents form-group-sm\"\n *ngIf=\"hasAtLeastOneAlarmActive\"\n (filterApplied)=\"filterSeverity($event)\"\n ></c8y-alarms-filter>\n\n <div class=\"m-l-auto btn-group btn-group-sm flex-no-shrink\">\n <button\n class=\"btn btn-default\"\n [attr.aria-label]=\"'Save as image' | translate\"\n tooltip=\"{{ 'Save as image' | translate }}\"\n container=\"body\"\n type=\"button\"\n (click)=\"chart.saveAsImage()\"\n [adaptivePosition]=\"false\"\n >\n <i\n class=\"icon-14\"\n c8yIcon=\"image-file-checked\"\n ></i>\n </button>\n </div>\n </div>\n <div\n class=\"d-flex\"\n style=\"align-items: center\"\n >\n <button\n class=\"btn-help btn-help--sm m-r-8\"\n [attr.aria-label]=\"'Help' | translate\"\n [popover]=\"legendHelpTemplate\"\n placement=\"bottom\"\n triggers=\"focus\"\n container=\"body\"\n [adaptivePosition]=\"false\"\n ></button>\n <div class=\"inner-scroll\">\n <div class=\"flex-grow p-t-8 d-flex a-i-start gap-8 p-b-4\">\n <div\n class=\"c8y-datapoint-pill flex-no-shrink\"\n title=\"{{ datapoint.label }} - {{ datapoint.__target.name }}\"\n *ngFor=\"let datapoint of displayConfig.datapoints\"\n [ngClass]=\"{ active: datapoint.__active }\"\n >\n <i\n class=\"text-warning m-l-4\"\n c8yIcon=\"exclamation-triangle\"\n [tooltip]=\"'At least 1 active data points must be active.' | translate\"\n container=\"body\"\n *ngIf=\"!hasAtLeastOneDatapointActive && datapoint.__active\"\n [adaptivePosition]=\"false\"\n ></i>\n <button\n class=\"c8y-datapoint-pill__btn\"\n title=\"{{\n (datapoint.__active ? hideDatapointLabel : showDatapointLabel) | translate\n }} \"\n type=\"button\"\n (click)=\"toggleChart(datapoint)\"\n >\n <i\n class=\"icon-14\"\n [c8yIcon]=\"datapoint.__active ? 'eye text-primary' : 'eye-slash text-muted'\"\n ></i>\n </button>\n <div class=\"c8y-datapoint-pill__label c8y-datapoint-pill__btn\">\n <i\n class=\"m-r-4 icon-14\"\n c8yIcon=\"circle\"\n [ngStyle]=\"{\n color: datapoint.color\n }\"\n ></i>\n <span\n class=\"text-truncate\"\n [ngClass]=\"{ 'text-muted': !datapoint.__active }\"\n >\n <span class=\"text-truncate\">\n {{ datapoint.label }}\n </span>\n <small class=\"text-muted text-10\">\n {{ datapoint.__target.name }}\n </small>\n </span>\n <i\n class=\"text-warning m-l-4\"\n c8yIcon=\"exclamation-triangle\"\n [tooltip]=\"\n 'Measurements received for this data point may be out of sync.' | translate\n \"\n container=\"body\"\n *ngIf=\"datapointsOutOfSync.get(datapoint)\"\n [adaptivePosition]=\"false\"\n ></i>\n </div>\n </div>\n <!-- Alarms -->\n\n <ng-container *ngFor=\"let alarm of alarms\">\n <div\n class=\"c8y-alarm-pill flex-no-shrink\"\n title=\"{{ alarm.filters.type }} \"\n *ngIf=\"alarm.__active\"\n >\n <i\n class=\"text-warning m-l-4\"\n c8yIcon=\"exclamation-triangle\"\n [tooltip]=\"\n 'Alarm of this type is currently active and outside of the selected time range'\n | translate\n \"\n container=\"body\"\n *ngIf=\"displayConfig?.activeAlarmTypesOutOfRange?.includes(alarm.filters.type)\"\n [adaptivePosition]=\"false\"\n ></i>\n <button\n class=\"c8y-alarm-pill__btn\"\n title=\"{{ alarm.filters.type }} \"\n type=\"button\"\n (click)=\"toggleAlarmEventType(alarm)\"\n >\n <i\n class=\"icon-14\"\n [c8yIcon]=\"alarm.__hidden ? 'eye-slash text-muted' : 'eye text-primary'\"\n ></i>\n </button>\n <button\n class=\"c8y-alarm-pill__label c8y-alarm-pill__btn\"\n (click)=\"toggleMarkedArea(alarm)\"\n [ngClass]=\"{\n active: !isMarkedAreaEnabled && alarm.filters.type === enabledMarkedAreaAlarmType\n }\"\n >\n <span\n class=\"circle-icon-wrapper circle-icon-wrapper--small m-r-4\"\n [style.background-color]=\"alarm.color\"\n >\n <i\n class=\"stroked-icon\"\n c8yIcon=\"bell\"\n ></i>\n </span>\n <span\n class=\"text-truncate\"\n [ngClass]=\"{ 'text-muted': alarm.__hidden }\"\n >\n <span class=\"text-truncate\">\n {{ alarm.filters.type }}\n </span>\n <small class=\"text-muted text-10\">\n {{ alarm.__target.name }}\n </small>\n </span>\n </button>\n </div>\n </ng-container>\n\n <!-- Events -->\n <ng-container *ngFor=\"let event of events\">\n <div\n class=\"c8y-event-pill flex-no-shrink\"\n title=\"{{ event.filters.type }}\"\n *ngIf=\"event.__active\"\n >\n <button\n class=\"c8y-event-pill__btn\"\n title=\"{{ event.filters.type }} \"\n type=\"button\"\n (click)=\"toggleAlarmEventType(event)\"\n >\n <i\n class=\"icon-14\"\n [c8yIcon]=\"event.__hidden ? 'eye-slash text-muted' : 'eye text-primary'\"\n ></i>\n </button>\n <div class=\"c8y-event-pill__label c8y-event-pill__btn\">\n <span\n class=\"circle-icon-wrapper circle-icon-wrapper--small m-r-4\"\n [ngStyle]=\"{ 'background-color': event.color }\"\n >\n <i\n class=\"stroked-icon\"\n c8yIcon=\"c8y-events\"\n ></i>\n </span>\n <span\n class=\"text-truncate\"\n [ngClass]=\"{ 'text-muted': event.__hidden }\"\n >\n <span class=\"text-truncate\">\n {{ event.filters.type }}\n </span>\n <small class=\"text-muted text-10\">\n {{ event.__target.name }}\n </small>\n </span>\n </div>\n </div>\n </ng-container>\n </div>\n </div>\n </div>\n</div>\n\n<c8y-charts\n #chart\n [config]=\"displayConfig\"\n [alerts]=\"alerts\"\n (updateAlarmsAndEvents)=\"updateAlarmsAndEvents($event)\"\n (configChangeOnZoomOut)=\"updateDashboardTimeContext($event)\"\n (datapointOutOfSync)=\"handleDatapointOutOfSync($event)\"\n (timeRangeChangeOnRealtime)=\"updateTimeRangeOnRealtime($event)\"\n (isMarkedAreaEnabled)=\"isMarkedAreaEnabled = $event\"\n></c8y-charts>\n\n<ng-template #legendHelpTemplate>\n <div [innerHTML]=\"legendHelp\"></div>\n</ng-template>\n" }] }], ctorParameters: () => [{ type: i1.FormBuilder }, { type: i2.TranslateService }, { type: i3.WidgetTimeContextDateRangeService }, { type: i4.ContextDashboardComponent, decorators: [{ type: Optional }] }], propDecorators: { config: [{ type: Input }], chartComponent: [{ type: ViewChild, args: [ChartsComponent] }] } }); //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGF0YXBvaW50cy1ncmFwaC13aWRnZXQtdmlldy5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi93aWRnZXRzL2ltcGxlbWVudGF0aW9ucy9kYXRhcG9pbnRzLWdyYXBoL2RhdGFwb2ludHMtZ3JhcGgtdmlldy9kYXRhcG9pbnRzLWdyYXBoLXdpZGdldC12aWV3LmNvbXBvbmVudC50cyIsIi4uLy4uLy4uLy4uLy4uLy4uL3dpZGdldHMvaW1wbGVtZW50YXRpb25zL2RhdGFwb2ludHMtZ3JhcGgvZGF0YXBvaW50cy1ncmFwaC12aWV3L2RhdGFwb2ludHMtZ3JhcGgtd2lkZ2V0LXZpZXcuY29tcG9uZW50Lmh0bWwiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUNMLFNBQVMsRUFDVCxLQUFLLEVBR0wsUUFBUSxFQUVSLFNBQVMsRUFDVixNQUFNLGVBQWUsQ0FBQztBQUN2QixPQUFPLEVBQ0wsaUJBQWlCLEVBQ2pCLGlCQUFpQixFQUNqQixVQUFVLEVBRVYsT0FBTyxFQUNQLGlDQUFpQyxFQUNsQyxNQUFNLHFCQUFxQixDQUFDO0FBQzdCLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFDdEMsT0FBTyxFQUFFLFdBQVcsRUFBRSxVQUFVLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUN6RCxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDM0MsT0FBTyxFQUNMLG1CQUFtQixFQUlwQixNQUFNLGFBQWEsQ0FBQztBQUVyQixPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQztBQUN2RCxPQUFPLEVBQUUseUJBQXlCLEVBQUUsTUFBTSx1Q0FBdUMsQ0FBQztBQUNsRixPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFDL0MsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBQy9DLE9BQU8sRUFD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S0FBSyxFQUFFLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1lBQ3hDLCtCQUErQixFQUFFLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQztTQUM3QyxDQUFDLENBQUM7UUFDSCxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxhQUFhLElBQUksRUFBRSxDQUFDLENBQUM7UUFDMUMsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDOytHQXhPVSxrQ0FBa0M7bUdBQWxDLGtDQUFrQyw2R0FGbEMsQ0FBQyxrQkFBa0IsRUFBRSxrQkFBa0IsQ0FBQywwRUEyQnhDLGVBQWUscUVDOUY1Qix5MVJBcVFBLDJDRDVNSSxVQUFVLDhCQUNWLFlBQVksbWJBQ1osZUFBZSwyTkFDZixVQUFVLHlMQUNWLGFBQWEsaWtCQUNiLGdCQUFnQiw4QkFDaEIsYUFBYSw4VkFDYixZQUFZLGdMQUNaLG9CQUFvQjs7NEZBSVgsa0NBQWtDO2tCQWpCOUMsU0FBUzsrQkFDRSxrQ0FBa0MsY0FFaEMsSUFBSSxXQUNQO3dCQUNQLFVBQVU7d0JBQ1YsWUFBWTt3QkFDWixlQUFlO3dCQUNmLFVBQVU7d0JBQ1YsYUFBYTt3QkFDYixnQkFBZ0I7d0JBQ2hCLGFBQWE7d0JBQ2IsWUFBWTt3QkFDWixvQkFBb0I7cUJBQ3JCLGFBQ1UsQ0FBQyxrQkFBa0IsRUFBRSxrQkFBa0IsQ0FBQzs7MEJBc0RoRCxRQUFRO3lDQW5DRSxNQUFNO3NCQUFsQixLQUFLO2dCQVFzQixjQUFjO3NCQUF6QyxTQUFTO3VCQUFDLGVBQWUiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBDb21wb25lbnQsXG4gIElucHV0LFxuICBPbkNoYW5nZXMsXG4gIE9uRGVzdHJveSxcbiAgT3B0aW9uYWwsXG4gIFNpbXBsZUNoYW5nZXMsXG4gIFZpZXdDaGlsZFxufSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7XG4gIEFHR1JFR0FUSU9OX0lDT05TLFxuICBBR0dSRUdBVElPTl9URVhUUyxcbiAgQ29yZU1vZHVsZSxcbiAgRHluYW1pY0NvbXBvbmVudEFsZXJ0QWdncmVnYXRvcixcbiAgZ2V0dGV4dCxcbiAgV2lkZ2V0VGltZUNvbnRleHREYXRlUmFuZ2VTZXJ2aWNlXG59IGZyb20gJ0BjOHkvbmd4LWNvbXBvbmVudHMnO1xuaW1wb3J0IHsgY2xvbmVEZWVwIH0gZnJvbSAnbG9kYXNoLWVzJztcbmltcG9ydCB7IEZvcm1CdWlsZGVyLCBWYWxpZGF0b3JzIH0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xuaW1wb3J0IHsgdGFrZVVudGlsIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnO1xuaW1wb3J0IHtcbiAgQUxBUk1fU1RBVFVTX0xBQkVMUyxcbiAgQWxhcm1TdGF0dXNUeXBlLFxuICBTZXZlcml0eVNldHRpbmdzLFxuICBhZ2dyZWdhdGlvblR5cGVcbn0gZnJvbSAnQGM4eS9jbGllbnQnO1xuaW1wb3J0IHR5cGUgeyBLUElEZXRhaWxzIH0gZnJvbSAnQGM4eS9uZ3gtY29tcG9uZW50cy9kYXRhcG9pbnQtc2VsZWN0b3InO1xuaW1wb3J0IHsgVHJhbnNsYXRlU2VydmljZSB9IGZyb20gJ0BuZ3gtdHJhbnNsYXRlL2NvcmUnO1xuaW1wb3J0IHsgQ29udGV4dERhc2hib2FyZENvbXBvbmVudCB9IGZyb20gJ0BjOHkvbmd4LWNvbXBvbmVudHMvY29udGV4dC1kYXNoYm9hcmQnO1xuaW1wb3J0IHsgQTExeU1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2Nkay9hMTF5JztcbmltcG9ydCB7IENvbW1vbk1vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XG5pbXBvcnQge1xuICBDaGFydHNDb21wb25lbnQsXG4gIERhdGFwb2ludHNHcmFwaEtQSURldGFpbHMsXG4gIERhdGFwb2ludHNHcmFwaFdpZGdldENvbmZpZyxcbiAgRGF0YXBvaW50c0dyYXBoV2lkZ2V0VGltZVByb3BzLFxuICBTZXZlcml0eVR5cGUsXG4gIEFsYXJtRGV0YWlsc0V4dGVuZGVkLFxuICBBbGFybU9yRXZlbnRFeHRlbmRlZCxcbiAgRXZlbnREZXRhaWxzRXh0ZW5kZWQsXG4gIENoYXJ0RXZlbnRzU2VydmljZSxcbiAgQ2hhcnRBbGFybXNTZXJ2aWNlLFxuICBUaW1lQ29udGV4dFByb3BzXG59IGZyb20gJ0BjOHkvbmd4LWNvbXBvbmVudHMvZWNoYXJ0JztcbmltcG9ydCB7IFRvb2x0aXBNb2R1bGUgfSBmcm9tICduZ3gtYm9vdHN0cmFwL3Rvb2x0aXAnO1xuaW1wb3J0IHsgQnNEcm9wZG93bk1vZHVsZSB9IGZyb20gJ25neC1ib290c3RyYXAvZHJvcGRvd24nO1xuaW1wb3J0IHsgUG9wb3Zlck1vZHVsZSB9IGZyb20gJ25neC1ib290c3RyYXAvcG9wb3Zlcic7XG5pbXBvcnQgeyBBbGFybXNNb2R1bGUgfSBmcm9tICdAYzh5L25neC1jb21wb25lbnRzL2FsYXJtcyc7XG5pbXBvcnQgeyBTdWJqZWN0IH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyBUaW1lQ29udGV4dENvbXBvbmVudCB9IGZyb20gJ0BjOHkvbmd4LWNvbXBvbmVudHMvdGltZS1jb250ZXh0JztcbmltcG9ydCB7IEludGVydmFsIH0gZnJvbSAnQGM4eS9uZ3gtY29tcG9uZW50cy9pbnRlcnZhbC1waWNrZXInO1xuXG5AQ29tcG9uZW50KHtcbiAgc2VsZWN0b3I6ICdjOHktZGF0YXBvaW50cy1ncmFwaC13aWRnZXQtdmlldycsXG4gIHRlbXBsYXRlVXJsOiAnLi9kYXRhcG9pbnRzLWdyYXBoLXdpZGdldC12aWV3LmNvbXBvbmVudC5odG1sJyxcbiAgc3RhbmRhbG9uZTogdHJ1ZSxcbiAgaW1wb3J0czogW1xuICAgIEExMXlNb2R1bGUsXG4gICAgQ29tbW9uTW9kdWxlLFxuICAgIENoYXJ0c0NvbXBvbmVudCxcbiAgICBDb3JlTW9kdWxlLFxuICAgIFRvb2x0aXBNb2R1bGUsXG4gICAgQnNEcm9wZG93bk1vZHVsZSxcbiAgICBQb3BvdmVyTW9kdWxlLFxuICAgIEFsYXJtc01vZHVsZSxcbiAgICBUaW1lQ29udGV4dENvbXBvbmVudFxuICBdLFxuICBwcm92aWRlcnM6IFtDaGFydEV2ZW50c1NlcnZpY2UsIENoYXJ0QWxhcm1zU2VydmljZV1cbn0pXG5leHBvcnQgY2xhc3MgRGF0YXBvaW50c0dyYXBoV2lkZ2V0Vmlld0NvbXBvbmVudCBpbXBsZW1lbnRzIE9uQ2hhbmdlcywgT25EZXN0cm95IHtcbiAgZXZlbnRzOiBFdmVudERldGFpbHNFeHRlbmRlZFtdID0gW107XG4gIGFsYXJtczogQWxhcm1EZXRhaWxzRXh0ZW5kZWRbXSA9IFtdO1xuICBBR0dSRUdBVElPTl9JQ09OUyA9IEFHR1JFR0FUSU9OX0lDT05TO1xuICBBR0dSRUdBVElPTl9URVhUUyA9IEFHR1JFR0FUSU9OX1RFWFRTO1xuICBhbGVydHM6IER5bmFtaWNDb21wb25lbnRBbGVydEFnZ3JlZ2F0b3IgfCB1bmRlZmluZWQ7XG4gIGRhdGFwb2ludHNPdXRPZlN5bmMgPSBuZXcgTWFwPERhdGFwb2ludHNHcmFwaEtQSURldGFpbHMsIGJvb2xlYW4+KCk7XG4gIHRpbWVQcm9wczogRGF0YXBvaW50c0dyYXBoV2lkZ2V0VGltZVByb3BzIHwgdW5kZWZpbmVkO1xuICBoYXNBdExlYXN0T25lRGF0YXBvaW50QWN0aXZlID0gdHJ1ZTtcbiAgaGFzQXRMZWFzdE9uZUFsYXJtQWN0aXZlID0gdHJ1ZTtcbiAgdGltZUNvbnRyb2xzRm9ybUdyb3VwOiBSZXR1cm5UeXBlPERhdGFwb2ludHNHcmFwaFdpZGdldFZpZXdDb21wb25lbnRbJ2luaXRGb3JtJ10+O1xuICBpc01hcmtlZEFyZWFFbmFibGVkID0gZmFsc2U7XG4gIC8qXG4gICAqIEBkZXNjcmlwdGlvbjogVGhlIHR5cGUgb2YgYWxhcm0gdGhhdCBoYXMgbWFya2VkIGFyZWEgZW5hYmxlZC5cbiAgICovXG4gIGVuYWJsZWRNYXJrZWRBcmVhQWxhcm1UeXBlOiBzdHJpbmcgfCB1bmRlZmluZWQ7XG5cbiAgQElucHV0KCkgc2V0IGNvbmZpZyh2YWx1ZTogRGF0YXBvaW50c0dyYXBoV2lkZ2V0Q29uZmlnKSB7XG4gICAgdGhpcy5kaXNwbGF5Q29uZmlnID0gY2xvbmVEZWVwKHZhbHVlKTtcbiAgfVxuICBnZXQgY29uZmlnKCk6IG5ldmVyIHtcbiAgICB0aHJvdyBFcnJvcihcbiAgICAgICdcImNvbmZpZ1wiIHByb3BlcnR5IHNob3VsZCBub3QgYmUgcmVmZXJlbmNlZCBpbiB2aWV3IGNvbXBvbmVudCB0byBhdm9pZCBtdXRhdGluZyBkYXRhLidcbiAgICApO1xuICB9XG4gIEBWaWV3Q2hpbGQoQ2hhcnRzQ29tcG9uZW50KSBjaGFydENvbXBvbmVudCE6IENoYXJ0c0NvbXBvbmVudDtcbiAgZGlzcGxheUNvbmZpZzogRGF0YXBvaW50c0dyYXBoV2lkZ2V0Q29uZmlnIHwgdW5kZWZpbmVkO1xuICBsZWdlbmRIZWxwID0gdGhpcy50cmFuc2xhdGUuaW5zdGFudChcbiAgICBnZXR0ZXh0KGA8dWwgY2xhc3M9XCJtLWwtMCBwLWwtOCBtLXQtOCBtLWItMFwiPlxuICAgIDxsaT5cbiAgICAgIDxiPlZpc2liaWxpdHk6PC9iPlxuICAgICAgdXNlIHZpc2liaWxpdHkgaWNvbiB0byB0b2dnbGUgZGF0YXBvaW50LCBhbGFybSBvciBldmVudCB2aXNpYmlsaXR5IG9uIGNoYXJ0LiBBdCBsZWFzdCBvbmUgZGF0YXBvaW50IGlzIHJlcXVpcmVkIHRvIGRpc3BsYXkgY2hhcnQuXG4gICAgPC9saT5cbiAgICA8bGk+XG4gICAgICA8Yj5BbGFybSBkZXRhaWxzPC9iPlxuICAgICAgQ2xpY2sgYWxhcm0gbGVnZW5kIGl0ZW0gdG8gaGlnaGxpZ2h0IGFyZWEgYmV0d2VlbiBhbGFybSByYWlzZWQgdGltZXN0YW1wIGFuZCBhbGFybSBjbGVhcmVkIHRpbWVzdGFtcC5cbiAgICAgIFlvdSBjYW4gYWxzbyBjbGljayBhbGFybSBtYXJrbGluZSBvbiBjaGFydCB0byBoaWdobGlnaHQgYWxhcm0gYW5kIHRvIHBhdXNlIHRvb2x0aXAuIENsaWNrIG9uIGhpZ2hsaWdodGVkIGFyZWEgb3IgbGVnZW5kIGl0ZW0gdG8gY2FuY2VsIGhpZ2hsaWdodGluZy5cbiAgICA8L2xpPlxuICA8L3VsPmApXG4gICk7XG4gIHJlYWRvbmx5IGRpc2FibGVab29tSW5MYWJlbCA9IGdldHRleHQoJ0Rpc2FibGUgem9vbSBpbicpO1xuICByZWFkb25seSBlbmFibGVab29tSW5MYWJlbCA9IGdldHRleHQoXG4gICAgJ0NsaWNrIHRvIGVuYWJsZSB6b29tLCB0aGVuIGNsaWNrIGFuZCBkcmFnIG9uIHRoZSBkZXNpcmVkIGFyZWEgaW4gdGhlIGNoYXJ0LidcbiAgKTtcbiAgcmVhZG9ubHkgaGlkZURhdGFwb2ludExhYmVsID0gZ2V0dGV4dCgnSGlkZSBkYXRhIHBvaW50Jyk7XG4gIHJlYWRvbmx5IHNob3dEYXRhcG9pbnRMYWJlbCA9IGdldHRleHQoJ1Nob3cgZGF0YSBwb2ludCcpO1xuICBwcml2YXRlIGRlc3Ryb3kkID0gbmV3IFN1YmplY3Q8dm9pZD4oKTtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIGZvcm1CdWlsZGVyOiBGb3JtQnVpbGRlcixcbiAgICBwcml2YXRlIHRyYW5zbGF0ZTogVHJhbnNsYXRlU2VydmljZSxcbiAgICBwcml2YXRlIHdpZGdldFRpbWVDb250ZXh0RGF0ZVJhbmdlU2VydmljZTogV2lkZ2V0VGltZUNvbnRleHREYXRlUmFuZ2VTZXJ2aWNlLFxuICAgIEBPcHRpb25hbCgpIHByaXZhdGUgZGFzaGJvYXJkQ29udGV4dENvbXBvbmVudDogQ29udGV4dERhc2hib2FyZENvbXBvbmVudFxuICApIHtcbiAgICB0aGlzLnRpbWVDb250cm9sc0Zvcm1Hcm91cCA9IHRoaXMuaW5pdEZvcm0oKTtcbiAgICB0aGlzLnRpbWVDb250cm9sc0Zvcm1Hcm91cC52YWx1ZUNoYW5nZXMucGlwZSh0YWtlVW50aWwodGhpcy5kZXN0cm95JCkpLnN1YnNjcmliZSh2YWx1ZSA9PiB7XG4gICAgICB0aGlzL