@c8y/ngx-components 1023.28.5 → 1023.37.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (127) hide show
  1. package/alarms/cockpit/index.d.ts.map +1 -1
  2. package/alarms/devicemanagement/index.d.ts.map +1 -1
  3. package/alarms/index.d.ts +25 -2
  4. package/alarms/index.d.ts.map +1 -1
  5. package/asset-properties/index.d.ts +20 -2
  6. package/asset-properties/index.d.ts.map +1 -1
  7. package/bookmarks/index.d.ts +15 -7
  8. package/bookmarks/index.d.ts.map +1 -1
  9. package/cockpit-config/index.d.ts.map +1 -1
  10. package/datapoint-explorer/view/index.d.ts +2 -0
  11. package/datapoint-explorer/view/index.d.ts.map +1 -1
  12. package/datapoint-selector/index.d.ts.map +1 -1
  13. package/device-grid/index.d.ts.map +1 -1
  14. package/echart/index.d.ts +19 -3
  15. package/echart/index.d.ts.map +1 -1
  16. package/feature-toggles/index.d.ts +6 -0
  17. package/feature-toggles/index.d.ts.map +1 -0
  18. package/feature-toggles/list/index.d.ts +63 -0
  19. package/feature-toggles/list/index.d.ts.map +1 -0
  20. package/fesm2022/c8y-ngx-components-alarms-cockpit.mjs +6 -11
  21. package/fesm2022/c8y-ngx-components-alarms-cockpit.mjs.map +1 -1
  22. package/fesm2022/c8y-ngx-components-alarms-devicemanagement.mjs +37 -11
  23. package/fesm2022/c8y-ngx-components-alarms-devicemanagement.mjs.map +1 -1
  24. package/fesm2022/c8y-ngx-components-alarms.mjs +58 -10
  25. package/fesm2022/c8y-ngx-components-alarms.mjs.map +1 -1
  26. package/fesm2022/c8y-ngx-components-asset-properties.mjs +36 -12
  27. package/fesm2022/c8y-ngx-components-asset-properties.mjs.map +1 -1
  28. package/fesm2022/{c8y-ngx-components-asset-property-grid.component-B04ixTyA.mjs → c8y-ngx-components-asset-property-grid.component-BoVrIpap.mjs} +5 -12
  29. package/fesm2022/c8y-ngx-components-asset-property-grid.component-BoVrIpap.mjs.map +1 -0
  30. package/fesm2022/c8y-ngx-components-bookmarks.mjs +86 -39
  31. package/fesm2022/c8y-ngx-components-bookmarks.mjs.map +1 -1
  32. package/fesm2022/c8y-ngx-components-cockpit-config.mjs +9 -9
  33. package/fesm2022/c8y-ngx-components-cockpit-config.mjs.map +1 -1
  34. package/fesm2022/c8y-ngx-components-context-dashboard.mjs +1 -1
  35. package/fesm2022/c8y-ngx-components-context-dashboard.mjs.map +1 -1
  36. package/fesm2022/c8y-ngx-components-datapoint-explorer-view.mjs +21 -36
  37. package/fesm2022/c8y-ngx-components-datapoint-explorer-view.mjs.map +1 -1
  38. package/fesm2022/c8y-ngx-components-datapoint-selector.mjs +3 -11
  39. package/fesm2022/c8y-ngx-components-datapoint-selector.mjs.map +1 -1
  40. package/fesm2022/c8y-ngx-components-device-grid.mjs +5 -2
  41. package/fesm2022/c8y-ngx-components-device-grid.mjs.map +1 -1
  42. package/fesm2022/c8y-ngx-components-echart.mjs +101 -42
  43. package/fesm2022/c8y-ngx-components-echart.mjs.map +1 -1
  44. package/fesm2022/c8y-ngx-components-ecosystem-plugin-setup-stepper.mjs +3 -3
  45. package/fesm2022/c8y-ngx-components-ecosystem-plugin-setup-stepper.mjs.map +1 -1
  46. package/fesm2022/c8y-ngx-components-feature-toggles-list.mjs +242 -0
  47. package/fesm2022/c8y-ngx-components-feature-toggles-list.mjs.map +1 -0
  48. package/fesm2022/c8y-ngx-components-feature-toggles.mjs +36 -0
  49. package/fesm2022/c8y-ngx-components-feature-toggles.mjs.map +1 -0
  50. package/fesm2022/c8y-ngx-components-global-context.mjs +21 -6
  51. package/fesm2022/c8y-ngx-components-global-context.mjs.map +1 -1
  52. package/fesm2022/c8y-ngx-components-map.mjs +127 -33
  53. package/fesm2022/c8y-ngx-components-map.mjs.map +1 -1
  54. package/fesm2022/c8y-ngx-components-tenants.mjs +2 -2
  55. package/fesm2022/c8y-ngx-components-tenants.mjs.map +1 -1
  56. package/fesm2022/c8y-ngx-components-trusted-certificates.mjs +5 -1
  57. package/fesm2022/c8y-ngx-components-trusted-certificates.mjs.map +1 -1
  58. package/fesm2022/c8y-ngx-components-upgrade-not-found.component-CuCuYAkK.mjs +19 -0
  59. package/fesm2022/c8y-ngx-components-upgrade-not-found.component-CuCuYAkK.mjs.map +1 -0
  60. package/fesm2022/c8y-ngx-components-upgrade.mjs +33 -3
  61. package/fesm2022/c8y-ngx-components-upgrade.mjs.map +1 -1
  62. package/fesm2022/c8y-ngx-components-widgets-definitions-html-widget.mjs +3 -3
  63. package/fesm2022/c8y-ngx-components-widgets-definitions-html-widget.mjs.map +1 -1
  64. package/fesm2022/c8y-ngx-components-widgets-definitions-pie-chart.mjs +30 -0
  65. package/fesm2022/c8y-ngx-components-widgets-definitions-pie-chart.mjs.map +1 -0
  66. package/fesm2022/c8y-ngx-components-widgets-definitions.mjs +2 -1
  67. package/fesm2022/c8y-ngx-components-widgets-definitions.mjs.map +1 -1
  68. package/fesm2022/c8y-ngx-components-widgets-exports.mjs +8 -1
  69. package/fesm2022/c8y-ngx-components-widgets-exports.mjs.map +1 -1
  70. package/fesm2022/c8y-ngx-components-widgets-implementations-alarms.mjs +4 -4
  71. package/fesm2022/c8y-ngx-components-widgets-implementations-alarms.mjs.map +1 -1
  72. package/fesm2022/c8y-ngx-components-widgets-implementations-datapoints-graph.mjs +3 -3
  73. package/fesm2022/c8y-ngx-components-widgets-implementations-datapoints-graph.mjs.map +1 -1
  74. package/fesm2022/c8y-ngx-components-widgets-implementations-datapoints-table.mjs +2 -2
  75. package/fesm2022/c8y-ngx-components-widgets-implementations-datapoints-table.mjs.map +1 -1
  76. package/fesm2022/c8y-ngx-components-widgets-implementations-html-widget.mjs +4 -3
  77. package/fesm2022/c8y-ngx-components-widgets-implementations-html-widget.mjs.map +1 -1
  78. package/fesm2022/c8y-ngx-components-widgets-implementations-map.mjs +18 -11
  79. package/fesm2022/c8y-ngx-components-widgets-implementations-map.mjs.map +1 -1
  80. package/fesm2022/c8y-ngx-components-widgets-implementations-pie-chart.mjs +366 -0
  81. package/fesm2022/c8y-ngx-components-widgets-implementations-pie-chart.mjs.map +1 -0
  82. package/fesm2022/c8y-ngx-components-widgets-implementations-three-d-rotation.mjs +4 -0
  83. package/fesm2022/c8y-ngx-components-widgets-implementations-three-d-rotation.mjs.map +1 -1
  84. package/fesm2022/c8y-ngx-components-widgets-widget-providers.mjs +5 -2
  85. package/fesm2022/c8y-ngx-components-widgets-widget-providers.mjs.map +1 -1
  86. package/fesm2022/c8y-ngx-components.mjs +57 -18
  87. package/fesm2022/c8y-ngx-components.mjs.map +1 -1
  88. package/global-context/index.d.ts +12 -2
  89. package/global-context/index.d.ts.map +1 -1
  90. package/index.d.ts +9 -3
  91. package/index.d.ts.map +1 -1
  92. package/locales/de.po +88 -66
  93. package/locales/es.po +26 -20
  94. package/locales/fr.po +25 -20
  95. package/locales/ja_JP.po +18 -20
  96. package/locales/ko.po +24 -20
  97. package/locales/locales.pot +130 -32
  98. package/locales/nl.po +26 -20
  99. package/locales/pl.po +26 -20
  100. package/locales/pt_BR.po +24 -20
  101. package/locales/zh_CN.po +26 -20
  102. package/locales/zh_TW.po +26 -20
  103. package/map/index.d.ts +41 -10
  104. package/map/index.d.ts.map +1 -1
  105. package/package.json +1 -1
  106. package/trusted-certificates/index.d.ts +2 -0
  107. package/trusted-certificates/index.d.ts.map +1 -1
  108. package/upgrade/index.d.ts.map +1 -1
  109. package/widgets/cockpit-exports/index.d.ts +6 -0
  110. package/widgets/cockpit-exports/index.d.ts.map +1 -1
  111. package/widgets/definitions/index.d.ts +1 -0
  112. package/widgets/definitions/index.d.ts.map +1 -1
  113. package/widgets/definitions/pie-chart/index.d.ts +25 -0
  114. package/widgets/definitions/pie-chart/index.d.ts.map +1 -0
  115. package/widgets/device-management-exports/index.d.ts +6 -0
  116. package/widgets/device-management-exports/index.d.ts.map +1 -1
  117. package/widgets/exports/index.d.ts +8 -1
  118. package/widgets/exports/index.d.ts.map +1 -1
  119. package/widgets/implementations/html-widget/index.d.ts +2 -2
  120. package/widgets/implementations/html-widget/index.d.ts.map +1 -1
  121. package/widgets/implementations/map/index.d.ts +1 -0
  122. package/widgets/implementations/map/index.d.ts.map +1 -1
  123. package/widgets/implementations/pie-chart/index.d.ts +129 -0
  124. package/widgets/implementations/pie-chart/index.d.ts.map +1 -0
  125. package/widgets/implementations/three-d-rotation/index.d.ts.map +1 -1
  126. package/widgets/widget-providers/index.d.ts.map +1 -1
  127. package/fesm2022/c8y-ngx-components-asset-property-grid.component-B04ixTyA.mjs.map +0 -1
@@ -0,0 +1,366 @@
1
+ import * as i0 from '@angular/core';
2
+ import { Injectable, inject, ViewChild, Input, ChangeDetectionStrategy, Component } from '@angular/core';
3
+ import { WidgetConfigService } from '@c8y/ngx-components/context-dashboard';
4
+ import { of, BehaviorSubject, switchMap, tap, map as map$1, combineLatest, Subject } from 'rxjs';
5
+ import { map, catchError, takeUntil } from 'rxjs/operators';
6
+ import * as i2 from '@angular/forms';
7
+ import { FormBuilder, Validators, FormsModule, ReactiveFormsModule } from '@angular/forms';
8
+ import * as i3 from '@c8y/ngx-components/datapoint-selector';
9
+ import { DatapointSelectorModule } from '@c8y/ngx-components/datapoint-selector';
10
+ import * as i1 from '@c8y/ngx-components';
11
+ import { DynamicComponentAlertAggregator, DynamicComponentAlert, MeasurementRealtimeService, CommonModule, CoreModule } from '@c8y/ngx-components';
12
+ import * as i1$1 from 'ngx-echarts';
13
+ import { NgxEchartsModule, NGX_ECHARTS_CONFIG } from 'ngx-echarts';
14
+ import { AsyncPipe } from '@angular/common';
15
+ import { ChartAlertsComponent } from '@c8y/ngx-components/echart';
16
+ import { TranslateService } from '@ngx-translate/core';
17
+ import { gettext } from '@c8y/ngx-components/gettext';
18
+ import * as echarts from 'echarts';
19
+
20
+ class CurrentMeasurementService {
21
+ constructor(realtime) {
22
+ this.realtime = realtime;
23
+ }
24
+ /**
25
+ * Fetches the latest measurement value for a given datapoint.
26
+ * Combines initial historical value with realtime updates.
27
+ *
28
+ * @param datapoint - The KPI datapoint configuration
29
+ * @returns Observable emitting measurement value, unit, date, and notFound flag
30
+ */
31
+ getLatest(datapoint) {
32
+ return this.realtime
33
+ .latestValueOfSpecificMeasurement$(datapoint.fragment, datapoint.series, datapoint.__target, 1, true)
34
+ .pipe(map(m => {
35
+ if (!m) {
36
+ return {
37
+ value: Number.NaN,
38
+ unit: datapoint.unit || '',
39
+ date: '',
40
+ notFound: true
41
+ };
42
+ }
43
+ const v = m[datapoint.fragment][datapoint.series];
44
+ return {
45
+ value: v.value,
46
+ unit: v.unit || datapoint.unit,
47
+ date: m.time
48
+ };
49
+ }), catchError(() => of({
50
+ value: Number.NaN,
51
+ unit: datapoint.unit || '',
52
+ date: '',
53
+ notFound: true
54
+ })));
55
+ }
56
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CurrentMeasurementService, deps: [{ token: i1.MeasurementRealtimeService }], target: i0.ɵɵFactoryTarget.Injectable }); }
57
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CurrentMeasurementService, providedIn: 'root' }); }
58
+ }
59
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CurrentMeasurementService, decorators: [{
60
+ type: Injectable,
61
+ args: [{ providedIn: 'root' }]
62
+ }], ctorParameters: () => [{ type: i1.MeasurementRealtimeService }] });
63
+
64
+ /** Chart layout constants */
65
+ const CHART_LAYOUT = {
66
+ LEGEND_TOP: '5%',
67
+ SERIES_TOP: '5%',
68
+ PIE_RADIUS: '80%',
69
+ EMPTY_STATE_FONT_SIZE: 30
70
+ };
71
+ class PieChartWidgetViewComponent {
72
+ constructor() {
73
+ this.activeDatapoints = [];
74
+ this.alerts = new DynamicComponentAlertAggregator();
75
+ this.configChanged$ = new BehaviorSubject(undefined);
76
+ this.measurements = inject(CurrentMeasurementService);
77
+ this.translateService = inject(TranslateService);
78
+ this.chartOptions$ = this.configChanged$.pipe(switchMap(() => this.fetchMeasurements()), tap(entries => this.handleNegativeValues(entries)), map$1(entries => this.buildChartOptions(entries)), tap(options => this.updateChartInstance(options)));
79
+ }
80
+ ngOnChanges(_) {
81
+ if (this.config?.datapoints?.length) {
82
+ this.configChanged$.next();
83
+ }
84
+ }
85
+ onChartInit(ec) {
86
+ this.echartsInstance = ec;
87
+ }
88
+ /**
89
+ * Fetches latest measurements for all configured datapoints.
90
+ */
91
+ fetchMeasurements() {
92
+ this.activeDatapoints = this.config?.datapoints?.filter(dp => dp.__active);
93
+ const streams = this.activeDatapoints.map(dp => this.measurements.getLatest(dp).pipe(map$1(m => this.mapToDatapointValue(dp, m))));
94
+ return combineLatest(streams);
95
+ }
96
+ /**
97
+ * Maps a datapoint and its measurement to a DatapointValue.
98
+ */
99
+ mapToDatapointValue(datapoint, measurement) {
100
+ const rawValue = measurement.value;
101
+ return {
102
+ label: datapoint.label || '',
103
+ value: rawValue < 0 || Number.isNaN(rawValue) ? 0 : rawValue,
104
+ rawValue,
105
+ unit: datapoint.unit || measurement.unit || '',
106
+ color: datapoint.color || ''
107
+ };
108
+ }
109
+ /**
110
+ * Handles negative value alerts - clears existing alerts and adds warning if needed.
111
+ */
112
+ handleNegativeValues(entries) {
113
+ this.alerts.clear();
114
+ const negatives = entries.filter(e => e.rawValue < 0);
115
+ if (negatives.length === 0) {
116
+ return;
117
+ }
118
+ const negativeDpList = negatives
119
+ .map(n => `${this.encodeHtml(n.label)}: ${n.rawValue} ${this.encodeHtml(n.unit)}`)
120
+ .join('; ');
121
+ const errorMessage = this.translateService.instant(gettext('Negative measurements received from data point(s): {{ datapoints }}'), { datapoints: negativeDpList });
122
+ this.alerts.addAlerts(new DynamicComponentAlert({ type: 'warning', text: errorMessage }));
123
+ }
124
+ /**
125
+ * Builds the ECharts options based on datapoint values.
126
+ */
127
+ buildChartOptions(datapoints) {
128
+ if (this.isEmptyState(datapoints)) {
129
+ return this.buildEmptyStateOptions();
130
+ }
131
+ return this.buildPieChartOptions(datapoints);
132
+ }
133
+ /**
134
+ * Checks if chart should display empty state (no positive data).
135
+ */
136
+ isEmptyState(entries) {
137
+ const hasPositiveData = entries.some(e => e.rawValue > 0);
138
+ const hasNegativeData = entries.some(e => e.rawValue < 0);
139
+ return !hasPositiveData && !hasNegativeData;
140
+ }
141
+ /**
142
+ * Builds options for empty state display.
143
+ */
144
+ buildEmptyStateOptions() {
145
+ return {
146
+ title: {
147
+ text: gettext('No data available.'),
148
+ left: 'center',
149
+ top: 'center',
150
+ textStyle: { fontSize: CHART_LAYOUT.EMPTY_STATE_FONT_SIZE }
151
+ },
152
+ series: []
153
+ };
154
+ }
155
+ /**
156
+ * Builds the pie chart options with data.
157
+ */
158
+ buildPieChartOptions(entries) {
159
+ const options = this.config.pieChartOptions;
160
+ const total = this.calculateTotal(entries);
161
+ return {
162
+ tooltip: this.buildTooltipConfig(entries, options),
163
+ legend: this.buildLegendConfig(options),
164
+ series: [this.buildPieSeriesConfig(entries, total, options)]
165
+ };
166
+ }
167
+ /**
168
+ * Calculates total of all entry values.
169
+ */
170
+ calculateTotal(entries) {
171
+ return entries.reduce((sum, e) => sum + e.value, 0);
172
+ }
173
+ /**
174
+ * Builds tooltip configuration.
175
+ */
176
+ buildTooltipConfig(entries, options) {
177
+ return {
178
+ show: options?.showTooltips ?? false,
179
+ formatter: (params) => {
180
+ const entry = entries.find(e => e.label === params.name);
181
+ const unit = entry?.unit || '';
182
+ const value = params.value.toFixed(2);
183
+ return `${this.encodeHtml(params.name)}: ${value} ${this.encodeHtml(unit)}`;
184
+ }
185
+ };
186
+ }
187
+ /**
188
+ * Builds legend configuration.
189
+ */
190
+ buildLegendConfig(options) {
191
+ return {
192
+ top: CHART_LAYOUT.LEGEND_TOP,
193
+ left: 'right',
194
+ show: options?.showLegend ?? false,
195
+ formatter: (name) => {
196
+ const match = name.match(/^(.+)_\d+$/);
197
+ return match ? match[1] : name;
198
+ }
199
+ };
200
+ }
201
+ /**
202
+ * Builds pie series configuration.
203
+ */
204
+ buildPieSeriesConfig(entries, total, options) {
205
+ return {
206
+ top: CHART_LAYOUT.SERIES_TOP,
207
+ type: 'pie',
208
+ radius: CHART_LAYOUT.PIE_RADIUS,
209
+ label: {
210
+ show: options?.showLabels ?? false,
211
+ position: 'inside',
212
+ formatter: (params) => this.formatPercentageLabel(params.value, total)
213
+ },
214
+ data: entries.map((e, index) => ({
215
+ name: `${e.label}_${index}`,
216
+ value: e.value,
217
+ itemStyle: { color: e.color }
218
+ }))
219
+ };
220
+ }
221
+ /**
222
+ * Formats percentage label for pie slice.
223
+ */
224
+ formatPercentageLabel(value, total) {
225
+ const percentage = total > 0 ? Math.round((value / total) * 100) : 0;
226
+ return percentage === 0 ? '' : `${percentage}%`;
227
+ }
228
+ /**
229
+ * Updates the ECharts instance with new options.
230
+ */
231
+ updateChartInstance(options) {
232
+ if (this.echartsInstance) {
233
+ this.echartsInstance.setOption(options, true);
234
+ }
235
+ }
236
+ /**
237
+ * Encodes HTML to prevent XSS attacks.
238
+ */
239
+ encodeHtml(text) {
240
+ return echarts.format.encodeHTML(text);
241
+ }
242
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: PieChartWidgetViewComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
243
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.16", type: PieChartWidgetViewComponent, isStandalone: true, selector: "c8y-pie-chart", inputs: { config: "config" }, providers: [
244
+ MeasurementRealtimeService,
245
+ CurrentMeasurementService,
246
+ { provide: NGX_ECHARTS_CONFIG, useFactory: () => ({ echarts: () => import('echarts') }) }
247
+ ], viewQueries: [{ propertyName: "chart", first: true, predicate: ["chart"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<div class=\"p-relative fit-h\">\n <div\n class=\"p-absolute fit-w fit-h\"\n #chart\n echarts\n [options]=\"chartOptions$ | async\"\n (chartInit)=\"onChartInit($event)\"\n ></div>\n\n <c8y-chart-alerts [alerts]=\"alerts\"></c8y-chart-alerts>\n</div>\n", dependencies: [{ kind: "ngmodule", type: NgxEchartsModule }, { kind: "directive", type: i1$1.NgxEchartsDirective, selector: "echarts, [echarts]", inputs: ["options", "theme", "initOpts", "merge", "autoResize", "loading", "loadingType", "loadingOpts"], outputs: ["chartInit", "optionsError", "chartClick", "chartDblClick", "chartMouseDown", "chartMouseMove", "chartMouseUp", "chartMouseOver", "chartMouseOut", "chartGlobalOut", "chartContextMenu", "chartHighlight", "chartDownplay", "chartSelectChanged", "chartLegendSelectChanged", "chartLegendSelected", "chartLegendUnselected", "chartLegendLegendSelectAll", "chartLegendLegendInverseSelect", "chartLegendScroll", "chartDataZoom", "chartDataRangeSelected", "chartGraphRoam", "chartGeoRoam", "chartTreeRoam", "chartTimelineChanged", "chartTimelinePlayChanged", "chartRestore", "chartDataViewChanged", "chartMagicTypeChanged", "chartGeoSelectChanged", "chartGeoSelected", "chartGeoUnselected", "chartAxisAreaSelected", "chartBrush", "chartBrushEnd", "chartBrushSelected", "chartGlobalCursorTaken", "chartRendered", "chartFinished"], exportAs: ["echarts"] }, { kind: "component", type: ChartAlertsComponent, selector: "c8y-chart-alerts", inputs: ["alerts"] }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
248
+ }
249
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: PieChartWidgetViewComponent, decorators: [{
250
+ type: Component,
251
+ args: [{ selector: 'c8y-pie-chart', providers: [
252
+ MeasurementRealtimeService,
253
+ CurrentMeasurementService,
254
+ { provide: NGX_ECHARTS_CONFIG, useFactory: () => ({ echarts: () => import('echarts') }) }
255
+ ], imports: [NgxEchartsModule, AsyncPipe, ChartAlertsComponent], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"p-relative fit-h\">\n <div\n class=\"p-absolute fit-w fit-h\"\n #chart\n echarts\n [options]=\"chartOptions$ | async\"\n (chartInit)=\"onChartInit($event)\"\n ></div>\n\n <c8y-chart-alerts [alerts]=\"alerts\"></c8y-chart-alerts>\n</div>\n" }]
256
+ }], ctorParameters: () => [], propDecorators: { config: [{
257
+ type: Input
258
+ }], chart: [{
259
+ type: ViewChild,
260
+ args: ['chart', { static: false }]
261
+ }] } });
262
+
263
+ class PieChartWidgetConfigComponent {
264
+ constructor() {
265
+ this.differentUnits = false;
266
+ this.destroy$ = new Subject();
267
+ this.widgetConfigService = inject(WidgetConfigService);
268
+ this.formBuilder = inject(FormBuilder);
269
+ }
270
+ set previewMapSet(template) {
271
+ if (template) {
272
+ this.widgetConfigService.setPreview(template);
273
+ return;
274
+ }
275
+ this.widgetConfigService.setPreview(null);
276
+ }
277
+ ngOnInit() {
278
+ this.formGroup = this.initForm();
279
+ this.subscribeToDatapointsChanges();
280
+ }
281
+ ngOnDestroy() {
282
+ this.destroy$.next();
283
+ this.destroy$.complete();
284
+ }
285
+ onBeforeSave(config) {
286
+ if (!this.formGroup.valid || !config)
287
+ return false;
288
+ const formValue = this.formGroup.value;
289
+ config.datapoints = formValue.datapoints;
290
+ config.pieChartOptions = config.pieChartOptions || {
291
+ showLabels: false,
292
+ showLegend: false,
293
+ showTooltips: false
294
+ };
295
+ config.pieChartOptions.showLabels = formValue.pieChartOptions.showLabels;
296
+ config.pieChartOptions.showLegend = formValue.pieChartOptions.showLegend;
297
+ config.pieChartOptions.showTooltips = formValue.pieChartOptions.showTooltips;
298
+ this.widgetConfigService.updateConfig(config);
299
+ return true;
300
+ }
301
+ initForm() {
302
+ const form = this.formBuilder.group({
303
+ datapoints: [this.config.datapoints, [Validators.required, Validators.minLength(1)]],
304
+ pieChartOptions: this.formBuilder.group({
305
+ showLabels: [this.config.pieChartOptions?.showLabels ?? false],
306
+ showLegend: [this.config.pieChartOptions?.showLegend ?? false],
307
+ showTooltips: [this.config.pieChartOptions?.showTooltips ?? false]
308
+ })
309
+ });
310
+ return form;
311
+ }
312
+ subscribeToDatapointsChanges() {
313
+ this.formGroup
314
+ .get('datapoints')
315
+ ?.valueChanges.pipe(takeUntil(this.destroy$))
316
+ .subscribe(datapoints => {
317
+ this.checkUnitsMatch(datapoints);
318
+ });
319
+ // Initial check
320
+ this.checkUnitsMatch(this.formGroup.get('datapoints')?.value);
321
+ }
322
+ /**
323
+ * Checks if selected datapoints have different units and sets warning flag.
324
+ * Different units in a pie chart can be misleading to users.
325
+ *
326
+ * @param datapoints - Array of selected datapoints to check
327
+ */
328
+ checkUnitsMatch(datapoints) {
329
+ if (!datapoints || datapoints.length <= 1) {
330
+ this.differentUnits = false;
331
+ return;
332
+ }
333
+ const units = datapoints.filter(dp => dp && dp.unit).map(dp => dp.unit);
334
+ if (units.length <= 1) {
335
+ this.differentUnits = false;
336
+ return;
337
+ }
338
+ const firstUnit = units[0];
339
+ this.differentUnits = units.some(unit => unit !== firstUnit);
340
+ }
341
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: PieChartWidgetConfigComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
342
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: PieChartWidgetConfigComponent, isStandalone: true, selector: "app-pie-chart-config", inputs: { config: "config" }, viewQueries: [{ propertyName: "previewMapSet", first: true, predicate: ["pieChartPreview"], descendants: true }], ngImport: i0, template: "@if (formGroup) {\n <form\n class=\"p-4\"\n [formGroup]=\"formGroup\"\n >\n <c8y-datapoint-selection-list\n class=\"bg-component separator-bottom d-block\"\n name=\"datapoints\"\n [minActiveCount]=\"1\"\n formControlName=\"datapoints\"\n >\n @if (differentUnits) {\n <div\n class=\"alert alert-warning m-t-8\"\n role=\"alert\"\n >\n <i class=\"c8y-icon c8y-icon-warning text-warning\"></i>\n {{ 'Selected data points have different units.' | translate }}\n </div>\n }\n </c8y-datapoint-selection-list>\n\n <fieldset class=\"c8y-fieldset m-t-16 p-b-8\">\n <legend>Pie chart options</legend>\n <div\n class=\"d-flex flex-column gap-8 form-group-sm\"\n formGroupName=\"pieChartOptions\"\n >\n <label class=\"c8y-checkbox\">\n <input\n type=\"checkbox\"\n formControlName=\"showLabels\"\n />\n <span></span>\n <span>\n {{ 'Show Labels' | translate }}\n </span>\n </label>\n <label class=\"c8y-checkbox\">\n <input\n type=\"checkbox\"\n formControlName=\"showLegend\"\n />\n <span></span>\n <span>\n {{ 'Show Legend' | translate }}\n </span>\n </label>\n <label class=\"c8y-checkbox\">\n <input\n type=\"checkbox\"\n formControlName=\"showTooltips\"\n />\n <span></span>\n <span>\n {{ 'Show Tooltips' | translate }}\n </span>\n </label>\n </div>\n </fieldset>\n </form>\n\n <ng-template #pieChartPreview>\n @if (formGroup.value.datapoints?.length > 0) {\n <c8y-pie-chart\n class=\"w-100 h-100\"\n [config]=\"{\n datapoints: formGroup.value.datapoints,\n pieChartOptions: {\n showLabels: formGroup.value.pieChartOptions.showLabels,\n showLegend: formGroup.value.pieChartOptions.showLegend,\n showTooltips: formGroup.value.pieChartOptions.showTooltips\n }\n }\"\n ></c8y-pie-chart>\n } @else {\n <div class=\"col-md-6 d-col a-i-start j-c-center\">\n <c8y-ui-empty-state\n [icon]=\"'c8y-data-points'\"\n [title]=\"'No data points selected' | translate\"\n [subtitle]=\"'Select data point to render content' | translate\"\n [horizontal]=\"false\"\n data-cy=\"kpi-widget--empty-state-no-data-point-selected\"\n >\n <p c8y-guide-docs>\n <small\n translate\n ngNonBindable\n >\n Find out more in the\n <a c8y-guide-href=\"/docs/cockpit/widgets-collection/#kpi\">user documentation</a>\n .\n </small>\n </p>\n </c8y-ui-empty-state>\n </div>\n }\n </ng-template>\n}\n", dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "component", type: i1.EmptyStateComponent, selector: "c8y-ui-empty-state", inputs: ["icon", "title", "subtitle", "horizontal"] }, { kind: "directive", type: i1.C8yTranslateDirective, selector: "[translate],[ngx-translate]" }, { kind: "ngmodule", type: CoreModule }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.RequiredInputPlaceholderDirective, selector: "input[required], input[formControlName]" }, { kind: "directive", type: i1.GuideHrefDirective, selector: "[c8y-guide-href]", inputs: ["c8y-guide-href"] }, { kind: "component", type: i1.GuideDocsComponent, selector: "[c8y-guide-docs]" }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i2.FormGroupName, selector: "[formGroupName]", inputs: ["formGroupName"] }, { kind: "ngmodule", type: DatapointSelectorModule }, { kind: "component", type: i3.DatapointSelectionListComponent, selector: "c8y-datapoint-selection-list", inputs: ["actions", "allowDragAndDrop", "config", "defaultFormOptions", "maxActiveCount", "minActiveCount", "resolveContext", "listTitle"], outputs: ["isValid", "change"] }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "component", type: PieChartWidgetViewComponent, selector: "c8y-pie-chart", inputs: ["config"] }, { kind: "pipe", type: i1.C8yTranslatePipe, name: "translate" }] }); }
343
+ }
344
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: PieChartWidgetConfigComponent, decorators: [{
345
+ type: Component,
346
+ args: [{ selector: 'app-pie-chart-config', imports: [
347
+ CommonModule,
348
+ CoreModule,
349
+ DatapointSelectorModule,
350
+ FormsModule,
351
+ ReactiveFormsModule,
352
+ PieChartWidgetViewComponent
353
+ ], template: "@if (formGroup) {\n <form\n class=\"p-4\"\n [formGroup]=\"formGroup\"\n >\n <c8y-datapoint-selection-list\n class=\"bg-component separator-bottom d-block\"\n name=\"datapoints\"\n [minActiveCount]=\"1\"\n formControlName=\"datapoints\"\n >\n @if (differentUnits) {\n <div\n class=\"alert alert-warning m-t-8\"\n role=\"alert\"\n >\n <i class=\"c8y-icon c8y-icon-warning text-warning\"></i>\n {{ 'Selected data points have different units.' | translate }}\n </div>\n }\n </c8y-datapoint-selection-list>\n\n <fieldset class=\"c8y-fieldset m-t-16 p-b-8\">\n <legend>Pie chart options</legend>\n <div\n class=\"d-flex flex-column gap-8 form-group-sm\"\n formGroupName=\"pieChartOptions\"\n >\n <label class=\"c8y-checkbox\">\n <input\n type=\"checkbox\"\n formControlName=\"showLabels\"\n />\n <span></span>\n <span>\n {{ 'Show Labels' | translate }}\n </span>\n </label>\n <label class=\"c8y-checkbox\">\n <input\n type=\"checkbox\"\n formControlName=\"showLegend\"\n />\n <span></span>\n <span>\n {{ 'Show Legend' | translate }}\n </span>\n </label>\n <label class=\"c8y-checkbox\">\n <input\n type=\"checkbox\"\n formControlName=\"showTooltips\"\n />\n <span></span>\n <span>\n {{ 'Show Tooltips' | translate }}\n </span>\n </label>\n </div>\n </fieldset>\n </form>\n\n <ng-template #pieChartPreview>\n @if (formGroup.value.datapoints?.length > 0) {\n <c8y-pie-chart\n class=\"w-100 h-100\"\n [config]=\"{\n datapoints: formGroup.value.datapoints,\n pieChartOptions: {\n showLabels: formGroup.value.pieChartOptions.showLabels,\n showLegend: formGroup.value.pieChartOptions.showLegend,\n showTooltips: formGroup.value.pieChartOptions.showTooltips\n }\n }\"\n ></c8y-pie-chart>\n } @else {\n <div class=\"col-md-6 d-col a-i-start j-c-center\">\n <c8y-ui-empty-state\n [icon]=\"'c8y-data-points'\"\n [title]=\"'No data points selected' | translate\"\n [subtitle]=\"'Select data point to render content' | translate\"\n [horizontal]=\"false\"\n data-cy=\"kpi-widget--empty-state-no-data-point-selected\"\n >\n <p c8y-guide-docs>\n <small\n translate\n ngNonBindable\n >\n Find out more in the\n <a c8y-guide-href=\"/docs/cockpit/widgets-collection/#kpi\">user documentation</a>\n .\n </small>\n </p>\n </c8y-ui-empty-state>\n </div>\n }\n </ng-template>\n}\n" }]
354
+ }], propDecorators: { config: [{
355
+ type: Input
356
+ }], previewMapSet: [{
357
+ type: ViewChild,
358
+ args: ['pieChartPreview']
359
+ }] } });
360
+
361
+ /**
362
+ * Generated bundle index. Do not edit.
363
+ */
364
+
365
+ export { PieChartWidgetConfigComponent, PieChartWidgetViewComponent };
366
+ //# sourceMappingURL=c8y-ngx-components-widgets-implementations-pie-chart.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"c8y-ngx-components-widgets-implementations-pie-chart.mjs","sources":["../../widgets/implementations/pie-chart/current-measurement.service.ts","../../widgets/implementations/pie-chart/pie-chart-widget-view/pie-chart-widget-view.component.ts","../../widgets/implementations/pie-chart/pie-chart-widget-view/pie-chart-widget-view.component.html","../../widgets/implementations/pie-chart/pie-chart-widget-config/pie-chart-widget-config.component.ts","../../widgets/implementations/pie-chart/pie-chart-widget-config/pie-chart-widget-config.component.html","../../widgets/implementations/pie-chart/c8y-ngx-components-widgets-implementations-pie-chart.ts"],"sourcesContent":["import { Injectable } from '@angular/core';\nimport { MeasurementRealtimeService } from '@c8y/ngx-components';\nimport { IMeasurementValue } from '@c8y/client';\nimport { KPIDetails } from '@c8y/ngx-components/datapoint-selector';\nimport { Observable, of } from 'rxjs';\nimport { map, catchError } from 'rxjs/operators';\n\n@Injectable({ providedIn: 'root' })\nexport class CurrentMeasurementService {\n constructor(private realtime: MeasurementRealtimeService) {}\n\n /**\n * Fetches the latest measurement value for a given datapoint.\n * Combines initial historical value with realtime updates.\n *\n * @param datapoint - The KPI datapoint configuration\n * @returns Observable emitting measurement value, unit, date, and notFound flag\n */\n getLatest(datapoint: KPIDetails): Observable<{\n value: number;\n unit: string;\n date: string;\n notFound?: boolean;\n }> {\n return this.realtime\n .latestValueOfSpecificMeasurement$(\n datapoint.fragment,\n datapoint.series,\n datapoint.__target,\n 1,\n true\n )\n .pipe(\n map(m => {\n if (!m) {\n return {\n value: Number.NaN,\n unit: datapoint.unit || '',\n date: '',\n notFound: true\n };\n }\n\n const v: IMeasurementValue = m[datapoint.fragment][datapoint.series];\n return {\n value: v.value,\n unit: v.unit || datapoint.unit,\n date: m.time\n };\n }),\n catchError(() =>\n of({\n value: Number.NaN,\n unit: datapoint.unit || '',\n date: '',\n notFound: true\n })\n )\n );\n }\n}\n","import {\n Component,\n ElementRef,\n inject,\n Input,\n OnChanges,\n SimpleChanges,\n ChangeDetectionStrategy,\n ViewChild\n} from '@angular/core';\nimport {\n DatapointValue,\n MeasurementValue,\n PieChartConfig,\n PieChartOptions\n} from '../pie-chart.model';\nimport { ECharts } from 'echarts/core';\nimport { BehaviorSubject, combineLatest, map, Observable, switchMap, tap } from 'rxjs';\nimport { NGX_ECHARTS_CONFIG, NgxEchartsModule } from 'ngx-echarts';\nimport { AsyncPipe } from '@angular/common';\nimport { CurrentMeasurementService } from '../current-measurement.service';\nimport {\n DynamicComponent,\n DynamicComponentAlert,\n DynamicComponentAlertAggregator,\n MeasurementRealtimeService\n} from '@c8y/ngx-components';\nimport { ChartAlertsComponent } from '@c8y/ngx-components/echart';\nimport { TranslateService } from '@ngx-translate/core';\nimport { gettext } from '@c8y/ngx-components/gettext';\nimport * as echarts from 'echarts';\nimport type { EChartsOption, PieSeriesOption } from 'echarts';\nimport { KPIDetails } from '@c8y/ngx-components/datapoint-selector';\nimport { CallbackDataParams } from 'echarts/types/dist/shared';\n\n/** Chart layout constants */\nconst CHART_LAYOUT = {\n LEGEND_TOP: '5%',\n SERIES_TOP: '5%',\n PIE_RADIUS: '80%',\n EMPTY_STATE_FONT_SIZE: 30\n} as const;\n\n@Component({\n selector: 'c8y-pie-chart',\n templateUrl: './pie-chart-widget-view.component.html',\n providers: [\n MeasurementRealtimeService,\n CurrentMeasurementService,\n { provide: NGX_ECHARTS_CONFIG, useFactory: () => ({ echarts: () => import('echarts') }) }\n ],\n imports: [NgxEchartsModule, AsyncPipe, ChartAlertsComponent],\n changeDetection: ChangeDetectionStrategy.OnPush\n})\nexport class PieChartWidgetViewComponent implements OnChanges, DynamicComponent {\n @Input() config!: PieChartConfig;\n @ViewChild('chart', { static: false }) chart!: ElementRef;\n activeDatapoints: KPIDetails[] = [];\n\n chartOptions$!: Observable<EChartsOption>;\n alerts = new DynamicComponentAlertAggregator();\n echartsInstance!: ECharts;\n\n private readonly configChanged$ = new BehaviorSubject<void>(undefined);\n private readonly measurements = inject(CurrentMeasurementService);\n private readonly translateService = inject(TranslateService);\n\n constructor() {\n this.chartOptions$ = this.configChanged$.pipe(\n switchMap(() => this.fetchMeasurements()),\n tap(entries => this.handleNegativeValues(entries)),\n map(entries => this.buildChartOptions(entries)),\n tap(options => this.updateChartInstance(options))\n );\n }\n\n ngOnChanges(_: SimpleChanges) {\n if (this.config?.datapoints?.length) {\n this.configChanged$.next();\n }\n }\n\n onChartInit(ec: ECharts) {\n this.echartsInstance = ec;\n }\n\n /**\n * Fetches latest measurements for all configured datapoints.\n */\n private fetchMeasurements(): Observable<DatapointValue[]> {\n this.activeDatapoints = this.config?.datapoints?.filter(dp => dp.__active);\n const streams = this.activeDatapoints.map(dp =>\n this.measurements.getLatest(dp).pipe(map(m => this.mapToDatapointValue(dp, m)))\n );\n return combineLatest(streams);\n }\n\n /**\n * Maps a datapoint and its measurement to a DatapointValue.\n */\n private mapToDatapointValue(\n datapoint: KPIDetails,\n measurement: MeasurementValue\n ): DatapointValue {\n const rawValue = measurement.value;\n return {\n label: datapoint.label || '',\n value: rawValue < 0 || Number.isNaN(rawValue) ? 0 : rawValue,\n rawValue,\n unit: datapoint.unit || measurement.unit || '',\n color: datapoint.color || ''\n };\n }\n\n /**\n * Handles negative value alerts - clears existing alerts and adds warning if needed.\n */\n private handleNegativeValues(entries: DatapointValue[]): void {\n this.alerts.clear();\n\n const negatives = entries.filter(e => e.rawValue < 0);\n if (negatives.length === 0) {\n return;\n }\n\n const negativeDpList = negatives\n .map(n => `${this.encodeHtml(n.label)}: ${n.rawValue} ${this.encodeHtml(n.unit)}`)\n .join('; ');\n\n const errorMessage = this.translateService.instant(\n gettext('Negative measurements received from data point(s): {{ datapoints }}'),\n { datapoints: negativeDpList }\n );\n\n this.alerts.addAlerts(new DynamicComponentAlert({ type: 'warning', text: errorMessage }));\n }\n\n /**\n * Builds the ECharts options based on datapoint values.\n */\n private buildChartOptions(datapoints: DatapointValue[]): EChartsOption {\n if (this.isEmptyState(datapoints)) {\n return this.buildEmptyStateOptions();\n }\n return this.buildPieChartOptions(datapoints);\n }\n\n /**\n * Checks if chart should display empty state (no positive data).\n */\n private isEmptyState(entries: DatapointValue[]): boolean {\n const hasPositiveData = entries.some(e => e.rawValue > 0);\n const hasNegativeData = entries.some(e => e.rawValue < 0);\n return !hasPositiveData && !hasNegativeData;\n }\n\n /**\n * Builds options for empty state display.\n */\n private buildEmptyStateOptions(): EChartsOption {\n return {\n title: {\n text: gettext('No data available.'),\n left: 'center',\n top: 'center',\n textStyle: { fontSize: CHART_LAYOUT.EMPTY_STATE_FONT_SIZE }\n },\n series: []\n };\n }\n\n /**\n * Builds the pie chart options with data.\n */\n private buildPieChartOptions(entries: DatapointValue[]): EChartsOption {\n const options = this.config.pieChartOptions;\n const total = this.calculateTotal(entries);\n\n return {\n tooltip: this.buildTooltipConfig(entries, options),\n legend: this.buildLegendConfig(options),\n series: [this.buildPieSeriesConfig(entries, total, options)]\n };\n }\n\n /**\n * Calculates total of all entry values.\n */\n private calculateTotal(entries: DatapointValue[]): number {\n return entries.reduce((sum, e) => sum + e.value, 0);\n }\n\n /**\n * Builds tooltip configuration.\n */\n private buildTooltipConfig(\n entries: DatapointValue[],\n options?: PieChartOptions\n ): EChartsOption['tooltip'] {\n return {\n show: options?.showTooltips ?? false,\n formatter: (params: CallbackDataParams) => {\n const entry = entries.find(e => e.label === params.name);\n const unit = entry?.unit || '';\n const value = (params.value as number).toFixed(2);\n return `${this.encodeHtml(params.name as string)}: ${value} ${this.encodeHtml(unit)}`;\n }\n };\n }\n\n /**\n * Builds legend configuration.\n */\n private buildLegendConfig(options?: PieChartOptions): EChartsOption['legend'] {\n return {\n top: CHART_LAYOUT.LEGEND_TOP,\n left: 'right',\n show: options?.showLegend ?? false,\n formatter: (name: string) => {\n const match = name.match(/^(.+)_\\d+$/);\n return match ? match[1] : name;\n }\n };\n }\n\n /**\n * Builds pie series configuration.\n */\n private buildPieSeriesConfig(\n entries: DatapointValue[],\n total: number,\n options?: PieChartOptions\n ): PieSeriesOption {\n return {\n top: CHART_LAYOUT.SERIES_TOP,\n type: 'pie',\n radius: CHART_LAYOUT.PIE_RADIUS,\n label: {\n show: options?.showLabels ?? false,\n position: 'inside',\n formatter: (params: CallbackDataParams) =>\n this.formatPercentageLabel(params.value as number, total)\n },\n data: entries.map((e, index) => ({\n name: `${e.label}_${index}`,\n value: e.value,\n itemStyle: { color: e.color }\n }))\n };\n }\n\n /**\n * Formats percentage label for pie slice.\n */\n private formatPercentageLabel(value: number, total: number): string {\n const percentage = total > 0 ? Math.round((value / total) * 100) : 0;\n return percentage === 0 ? '' : `${percentage}%`;\n }\n\n /**\n * Updates the ECharts instance with new options.\n */\n private updateChartInstance(options: EChartsOption): void {\n if (this.echartsInstance) {\n this.echartsInstance.setOption(options, true);\n }\n }\n\n /**\n * Encodes HTML to prevent XSS attacks.\n */\n private encodeHtml(text: string): string {\n return echarts.format.encodeHTML(text);\n }\n}\n","<div class=\"p-relative fit-h\">\n <div\n class=\"p-absolute fit-w fit-h\"\n #chart\n echarts\n [options]=\"chartOptions$ | async\"\n (chartInit)=\"onChartInit($event)\"\n ></div>\n\n <c8y-chart-alerts [alerts]=\"alerts\"></c8y-chart-alerts>\n</div>\n","import { Component, inject, Input, OnDestroy, OnInit, TemplateRef, ViewChild } from '@angular/core';\nimport { PieChartConfig } from '../pie-chart.model';\nimport { WidgetConfigService } from '@c8y/ngx-components/context-dashboard';\nimport { Observable, Subject } from 'rxjs';\nimport { takeUntil } from 'rxjs/operators';\nimport { FormBuilder, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms';\nimport { DatapointSelectorModule, KPIDetails } from '@c8y/ngx-components/datapoint-selector';\nimport { CommonModule, CoreModule } from '@c8y/ngx-components';\nimport { PieChartWidgetViewComponent } from '../pie-chart-widget-view/pie-chart-widget-view.component';\n\n@Component({\n selector: 'app-pie-chart-config',\n templateUrl: './pie-chart-widget-config.component.html',\n imports: [\n CommonModule,\n CoreModule,\n DatapointSelectorModule,\n FormsModule,\n ReactiveFormsModule,\n PieChartWidgetViewComponent\n ]\n})\nexport class PieChartWidgetConfigComponent implements OnInit, OnDestroy {\n @Input() config: PieChartConfig;\n formGroup!: ReturnType<PieChartWidgetConfigComponent['initForm']>;\n differentUnits = false;\n private readonly destroy$ = new Subject<void>();\n\n @ViewChild('pieChartPreview')\n set previewMapSet(template: TemplateRef<any>) {\n if (template) {\n this.widgetConfigService.setPreview(template);\n return;\n }\n this.widgetConfigService.setPreview(null);\n }\n\n private readonly widgetConfigService = inject(WidgetConfigService);\n private readonly formBuilder = inject(FormBuilder);\n\n ngOnInit() {\n this.formGroup = this.initForm();\n this.subscribeToDatapointsChanges();\n }\n\n ngOnDestroy() {\n this.destroy$.next();\n this.destroy$.complete();\n }\n\n onBeforeSave(config?: PieChartConfig): boolean | Promise<boolean> | Observable<boolean> {\n if (!this.formGroup.valid || !config) return false;\n\n const formValue = this.formGroup.value;\n config.datapoints = formValue.datapoints;\n config.pieChartOptions = config.pieChartOptions || {\n showLabels: false,\n showLegend: false,\n showTooltips: false\n };\n config.pieChartOptions.showLabels = formValue.pieChartOptions.showLabels;\n config.pieChartOptions.showLegend = formValue.pieChartOptions.showLegend;\n config.pieChartOptions.showTooltips = formValue.pieChartOptions.showTooltips;\n\n this.widgetConfigService.updateConfig(config);\n\n return true;\n }\n\n private initForm() {\n const form = this.formBuilder.group({\n datapoints: [this.config.datapoints, [Validators.required, Validators.minLength(1)]],\n pieChartOptions: this.formBuilder.group({\n showLabels: [this.config.pieChartOptions?.showLabels ?? false],\n showLegend: [this.config.pieChartOptions?.showLegend ?? false],\n showTooltips: [this.config.pieChartOptions?.showTooltips ?? false]\n })\n });\n return form;\n }\n\n private subscribeToDatapointsChanges() {\n this.formGroup\n .get('datapoints')\n ?.valueChanges.pipe(takeUntil(this.destroy$))\n .subscribe(datapoints => {\n this.checkUnitsMatch(datapoints);\n });\n\n // Initial check\n this.checkUnitsMatch(this.formGroup.get('datapoints')?.value);\n }\n\n /**\n * Checks if selected datapoints have different units and sets warning flag.\n * Different units in a pie chart can be misleading to users.\n *\n * @param datapoints - Array of selected datapoints to check\n */\n private checkUnitsMatch(datapoints: KPIDetails[]) {\n if (!datapoints || datapoints.length <= 1) {\n this.differentUnits = false;\n return;\n }\n\n const units = datapoints.filter(dp => dp && dp.unit).map(dp => dp.unit);\n\n if (units.length <= 1) {\n this.differentUnits = false;\n return;\n }\n\n const firstUnit = units[0];\n this.differentUnits = units.some(unit => unit !== firstUnit);\n }\n}\n","@if (formGroup) {\n <form\n class=\"p-4\"\n [formGroup]=\"formGroup\"\n >\n <c8y-datapoint-selection-list\n class=\"bg-component separator-bottom d-block\"\n name=\"datapoints\"\n [minActiveCount]=\"1\"\n formControlName=\"datapoints\"\n >\n @if (differentUnits) {\n <div\n class=\"alert alert-warning m-t-8\"\n role=\"alert\"\n >\n <i class=\"c8y-icon c8y-icon-warning text-warning\"></i>\n {{ 'Selected data points have different units.' | translate }}\n </div>\n }\n </c8y-datapoint-selection-list>\n\n <fieldset class=\"c8y-fieldset m-t-16 p-b-8\">\n <legend>Pie chart options</legend>\n <div\n class=\"d-flex flex-column gap-8 form-group-sm\"\n formGroupName=\"pieChartOptions\"\n >\n <label class=\"c8y-checkbox\">\n <input\n type=\"checkbox\"\n formControlName=\"showLabels\"\n />\n <span></span>\n <span>\n {{ 'Show Labels' | translate }}\n </span>\n </label>\n <label class=\"c8y-checkbox\">\n <input\n type=\"checkbox\"\n formControlName=\"showLegend\"\n />\n <span></span>\n <span>\n {{ 'Show Legend' | translate }}\n </span>\n </label>\n <label class=\"c8y-checkbox\">\n <input\n type=\"checkbox\"\n formControlName=\"showTooltips\"\n />\n <span></span>\n <span>\n {{ 'Show Tooltips' | translate }}\n </span>\n </label>\n </div>\n </fieldset>\n </form>\n\n <ng-template #pieChartPreview>\n @if (formGroup.value.datapoints?.length > 0) {\n <c8y-pie-chart\n class=\"w-100 h-100\"\n [config]=\"{\n datapoints: formGroup.value.datapoints,\n pieChartOptions: {\n showLabels: formGroup.value.pieChartOptions.showLabels,\n showLegend: formGroup.value.pieChartOptions.showLegend,\n showTooltips: formGroup.value.pieChartOptions.showTooltips\n }\n }\"\n ></c8y-pie-chart>\n } @else {\n <div class=\"col-md-6 d-col a-i-start j-c-center\">\n <c8y-ui-empty-state\n [icon]=\"'c8y-data-points'\"\n [title]=\"'No data points selected' | translate\"\n [subtitle]=\"'Select data point to render content' | translate\"\n [horizontal]=\"false\"\n data-cy=\"kpi-widget--empty-state-no-data-point-selected\"\n >\n <p c8y-guide-docs>\n <small\n translate\n ngNonBindable\n >\n Find out more in the\n <a c8y-guide-href=\"/docs/cockpit/widgets-collection/#kpi\">user documentation</a>\n .\n </small>\n </p>\n </c8y-ui-empty-state>\n </div>\n }\n </ng-template>\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":["map","i1"],"mappings":"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"}
@@ -76,6 +76,10 @@ class ThreeDRotationComponent {
76
76
  this.controls.enableDamping = true;
77
77
  this.controls.dampingFactor = 0.25;
78
78
  this.controls.rotateSpeed = 0.35;
79
+ this.controls.minDistance = 20;
80
+ this.controls.maxDistance = 50;
81
+ this.controls.minZoom = 0.5;
82
+ this.controls.maxZoom = 2;
79
83
  this.controls.addEventListener('change', () => this.render());
80
84
  }
81
85
  setWireframe(parsedModel, isWireframe) {
@@ -1 +1 @@
1
- {"version":3,"file":"c8y-ngx-components-widgets-implementations-three-d-rotation.mjs","sources":["../../widgets/implementations/three-d-rotation/three-d-rotation/three-d-rotation.component.ts","../../widgets/implementations/three-d-rotation/three-d-rotation/three-d-rotation.component.html","../../widgets/implementations/three-d-rotation/three-d-rotation-widget-view/three-d-rotation-widget-view.component.ts","../../widgets/implementations/three-d-rotation/three-d-rotation-widget-view/three-d-rotation-widget-view.component.html","../../widgets/implementations/three-d-rotation/three-d-rotation-widget-config/three-d-rotation-widget-config.component.ts","../../widgets/implementations/three-d-rotation/three-d-rotation-widget-config/three-d-rotation-widget-config.component.html","../../widgets/implementations/three-d-rotation/c8y-ngx-components-widgets-implementations-three-d-rotation.ts"],"sourcesContent":["import {\n AfterViewInit,\n Component,\n ElementRef,\n Input,\n OnDestroy,\n OnInit,\n ViewChild\n} from '@angular/core';\nimport { combineLatest, from, Observable, of, Subject, Subscription } from 'rxjs';\nimport { distinctUntilChanged, filter, map, shareReplay, switchMap } from 'rxjs/operators';\nimport { loadThree } from '@c8y/ngx-components/lazy/three';\nimport { ThreeDRotationWidgetRotate } from '../three-d-rotation.model';\nimport { loadOrbitControls } from '@c8y/ngx-components/lazy/three-orbit-controls';\nimport type * as THREE from 'three';\nimport type { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';\n\n@Component({\n selector: 'c8y-three-d-rotation',\n templateUrl: './three-d-rotation.component.html',\n standalone: true,\n imports: []\n})\nexport class ThreeDRotationComponent implements AfterViewInit, OnInit, OnDestroy {\n @ViewChild('canvas')\n private canvasRef: ElementRef;\n\n @Input() angles$: Observable<ThreeDRotationWidgetRotate> = of({ x: 0, y: 0, z: 0 });\n @Input() modelObj$: Observable<any>;\n @Input() cameraType$: Observable<string> = of('PC');\n @Input() isWireframe$: Observable<boolean> = of(true);\n\n get canvas(): HTMLCanvasElement | null {\n return this.canvasRef?.nativeElement;\n }\n\n scene: THREE.Scene;\n camera: THREE.PerspectiveCamera | THREE.OrthographicCamera;\n model: THREE.Object3D;\n private renderer: THREE.WebGLRenderer;\n\n private afterViewInit$ = new Subject<void>();\n\n private renderSubscription: Subscription;\n private controls: OrbitControls;\n\n ngOnInit() {\n const three$ = from(loadThree()).pipe(shareReplay(1));\n const model$ = combineLatest([three$, this.modelObj$]).pipe(\n filter(([, modelObj]) => !!modelObj),\n switchMap(([three, modelObj]) => this.loadModel(modelObj, three))\n );\n const modelWithWireframe$ = combineLatest([model$, this.isWireframe$]).pipe(\n map(([model, isWireframe]) => this.setWireframe(model, isWireframe))\n );\n\n const rotatedModel$ = combineLatest([modelWithWireframe$, this.angles$]).pipe(\n filter(([, angles]) => !!angles),\n map(([model, angles]) => {\n Object.assign(model.rotation, angles);\n return model;\n })\n );\n\n const cameraType$ = this.cameraType$.pipe(\n filter(type => !!type),\n distinctUntilChanged()\n );\n\n let previousCameraType: string;\n this.renderSubscription = combineLatest([\n three$,\n rotatedModel$,\n cameraType$,\n this.afterViewInit$\n ])\n .pipe(filter(([, model]) => !!model))\n .subscribe(async ([three, model, cameraType]) => {\n if (model !== this.model || previousCameraType !== cameraType) {\n this.model = model;\n previousCameraType = cameraType;\n this.createScene(three, model, cameraType);\n }\n if (!this.renderer) {\n await this.setupRenderer(three);\n }\n this.render();\n });\n }\n\n ngOnDestroy(): void {\n this.renderSubscription?.unsubscribe();\n this.controls?.dispose();\n }\n\n ngAfterViewInit() {\n this.afterViewInit$.next();\n }\n\n async loadModel(\n modelObj: any,\n three: typeof THREE\n ): Promise<THREE.Object3D<THREE.Object3DEventMap>> {\n const loader = new three.ObjectLoader();\n const parsedModel = await loader.parse(modelObj);\n return parsedModel;\n }\n\n async setupRenderer(three: typeof THREE) {\n //* Renderer\n // Use canvas element in template\n this.renderer = new three.WebGLRenderer({ canvas: this.canvas });\n this.renderer.setPixelRatio(devicePixelRatio);\n this.renderer.setSize(this.canvas.clientWidth, this.canvas.clientHeight);\n\n const OrbitControls = await loadOrbitControls();\n this.controls = new OrbitControls(this.camera, this.renderer.domElement);\n this.controls.enableDamping = true;\n this.controls.dampingFactor = 0.25;\n this.controls.rotateSpeed = 0.35;\n this.controls.addEventListener('change', () => this.render());\n }\n\n setWireframe(parsedModel: THREE.Object3D, isWireframe: boolean) {\n parsedModel.children.forEach((child: any) => {\n if (child.material) {\n child.material.wireframe = isWireframe;\n }\n });\n return parsedModel;\n }\n\n private render(): void {\n this.renderer?.render(this.scene, this.camera);\n }\n\n private createScene(three: typeof THREE, model: THREE.Object3D, cameraType: string) {\n //* Scene\n this.scene = new three.Scene();\n this.scene.background = new three.Color(0xffffff);\n this.scene.add(model);\n\n const light = new three.AmbientLight(0xffffff, 0.5);\n const lightDirectional = new three.DirectionalLight(0xffffff);\n const lightDirectional2 = new three.DirectionalLight(0xffffff);\n\n lightDirectional.position.set(20, 25, 30);\n lightDirectional2.position.set(-20, -25, -30);\n this.scene.add(lightDirectional);\n this.scene.add(lightDirectional2);\n this.scene.add(light);\n\n this.camera = this.createCamera(three, cameraType);\n }\n\n private createCamera(three: typeof THREE, cameraType: string) {\n let camera: THREE.OrthographicCamera | THREE.PerspectiveCamera;\n switch (cameraType) {\n case 'OC':\n camera = new three.OrthographicCamera(30 / -2, 30 / 2, 30 / 2, 30 / -2, 1, 1000);\n break;\n case 'PC':\n default:\n camera = new three.PerspectiveCamera(30, this.getAspectRatio(), 0.1, 1000);\n break;\n }\n\n camera.rotateX(Math.PI / 2);\n camera.rotateY(Math.PI / 2);\n\n camera.position.z = 23;\n camera.position.x = 14;\n camera.position.y = 7;\n\n return camera;\n }\n\n private getAspectRatio() {\n return this.canvas.clientWidth / this.canvas.clientHeight;\n }\n}\n","<canvas #canvas class=\"fit-w fit-h\"></canvas>\n","import {\n Component,\n Input,\n OnChanges,\n OnInit,\n Optional,\n signal,\n SimpleChanges\n} from '@angular/core';\nimport {\n DynamicComponent,\n DynamicComponentAlert,\n DynamicComponentAlertAggregator,\n MeasurementRealtimeService\n} from '@c8y/ngx-components';\nimport { gettext } from '@c8y/ngx-components/gettext';\nimport { BehaviorSubject, Observable } from 'rxjs';\nimport {\n distinctUntilChanged,\n filter,\n map,\n shareReplay,\n startWith,\n switchMap\n} from 'rxjs/operators';\nimport { ThreeDRotationWidgetConfig, ThreeDRotationWidgetRotate } from '../three-d-rotation.model';\n// eslint-disable-next-line @typescript-eslint/no-restricted-imports\nimport { loadBoxModel } from '@c8y/ngx-components/widgets/implementations/three-d-rotation/lazy-box-model';\nimport { ContextDashboardComponent } from '@c8y/ngx-components/context-dashboard';\n// eslint-disable-next-line @typescript-eslint/no-restricted-imports\nimport { loadPhoneModel } from '@c8y/ngx-components/widgets/implementations/three-d-rotation/lazy-phone-model';\nimport { ThreeDRotationComponent } from '../three-d-rotation/three-d-rotation.component';\n\n@Component({\n selector: 'c8y-three-d-rotation-widget-view',\n templateUrl: './three-d-rotation-widget-view.component.html',\n providers: [MeasurementRealtimeService],\n standalone: true,\n imports: [ThreeDRotationComponent]\n})\nexport class ThreeDRotationWidgetViewComponent implements OnChanges, OnInit, DynamicComponent {\n @Input() config: ThreeDRotationWidgetConfig;\n alerts = new DynamicComponentAlertAggregator();\n webGLAvailable = signal(true);\n angles$: Observable<ThreeDRotationWidgetRotate>;\n modelObj$: Observable<any>;\n deviceId$ = new BehaviorSubject<string>(null);\n modelName$ = new BehaviorSubject<string>(null);\n cameraType$ = new BehaviorSubject<string>('PC');\n isWireframe$ = new BehaviorSubject<boolean>(true);\n\n private webGLErrorText = gettext(\n 'WebGL is not available. Hardware acceleration may be disabled in your browser. Enable it in browser settings to use this widget.'\n );\n\n constructor(\n private measurementRealtime: MeasurementRealtimeService,\n @Optional() private dashboard: ContextDashboardComponent\n ) {\n this.modelObj$ = this.modelName$.pipe(\n filter(name => !!name),\n distinctUntilChanged(),\n switchMap(name => this.getModelUrl(name)),\n shareReplay(1)\n );\n this.angles$ = this.deviceId$.pipe(\n filter(id => !!id),\n distinctUntilChanged(),\n switchMap(id => this.getAnglesOfDevice$(id)),\n startWith({ x: 0, y: 0, z: 0 })\n );\n }\n\n ngOnInit(): void {\n if (!this.isWebGLAvailable()) {\n this.webGLAvailable.set(false);\n this.alerts.addAlerts(\n new DynamicComponentAlert({\n type: 'warning',\n text: this.webGLErrorText\n })\n );\n }\n }\n\n ngOnChanges(changes: SimpleChanges): void {\n if (changes.config && this.config) {\n this.onConfigChange();\n }\n }\n\n private onConfigChange() {\n if (this.config.device?.id) {\n this.deviceId$.next(`${this.config.device.id}`);\n } else if (this.dashboard?.context?.id) {\n this.deviceId$.next(`${this.dashboard.context?.id}`);\n }\n\n if (this.config.objectModel) {\n this.modelName$.next(this.config.objectModel);\n }\n\n if (this.config.cameraType) {\n this.cameraType$.next(this.config.cameraType);\n }\n\n if (this.config.isWireframe !== undefined) {\n this.isWireframe$.next(this.config.isWireframe);\n }\n }\n\n private async getModelUrl(model: string): Promise<any> {\n // The name *.min.json still exist for backwards compatibility\n // it might be stored in certain widget configs.\n if (model === 'box.min.json') {\n return await loadBoxModel();\n } else {\n return await loadPhoneModel();\n }\n }\n\n private getAnglesOfDevice$(deviceId: string): Observable<ThreeDRotationWidgetRotate> {\n const fragment = 'c8y_Acceleration';\n const series = ['accelerationX', 'accelerationY', 'accelerationZ'];\n return this.measurementRealtime\n .latestValueOfSpecificMeasurement$(fragment, series[0], deviceId, 1)\n .pipe(\n filter(m => !!m && m[fragment] && series.every(axisSeries => m[fragment][axisSeries])),\n map(measurement => {\n const [xAxisValue, yAxisValue, zAxisValue] = series.map(axisSeries =>\n Math.round(measurement[fragment][axisSeries].value)\n );\n return this.convertValues(xAxisValue, yAxisValue, zAxisValue);\n })\n );\n }\n\n private convertValues(x: number, y: number, z: number): ThreeDRotationWidgetRotate {\n let rotateX = Math.atan2(y, z);\n let rotateY = Math.atan2(x, Math.sqrt(y * y + z * z));\n rotateX = rotateX ? rotateX % (Math.PI * 2) : 0;\n rotateY = rotateY ? rotateY % (Math.PI * 2) : 0;\n\n return {\n x: rotateX,\n y: 0,\n z: rotateY\n };\n }\n\n private isWebGLAvailable(): boolean {\n try {\n const canvas = document.createElement('canvas');\n const context = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');\n return !!context;\n } catch {\n return false;\n }\n }\n}\n","@if (webGLAvailable()) {\n <c8y-three-d-rotation\n [modelObj$]=\"modelObj$\"\n [angles$]=\"angles$\"\n [cameraType$]=\"cameraType$\"\n [isWireframe$]=\"isWireframe$\"\n ></c8y-three-d-rotation>\n}\n","import { Component, OnInit, Input } from '@angular/core';\nimport { ControlContainer, FormBuilder, NgForm, Validators } from '@angular/forms';\nimport { CoreModule, OnBeforeSave } from '@c8y/ngx-components';\nimport { Observable } from 'rxjs';\nimport { ThreeDRotationWidgetConfig } from '../three-d-rotation.model';\nimport { ButtonsModule } from 'ngx-bootstrap/buttons';\n\n@Component({\n selector: 'c8y-three-d-rotation-widget-config',\n templateUrl: './three-d-rotation-widget-config.component.html',\n viewProviders: [{ provide: ControlContainer, useExisting: NgForm }],\n standalone: true,\n imports: [CoreModule, ButtonsModule]\n})\nexport class ThreeDRotationWidgetConfigComponent implements OnInit, OnBeforeSave {\n @Input() config: ThreeDRotationWidgetConfig;\n formGroup: ReturnType<ThreeDRotationWidgetConfigComponent['createForm']>;\n\n constructor(\n private formBuilder: FormBuilder,\n private form: NgForm\n ) {}\n\n onBeforeSave(\n config?: ThreeDRotationWidgetConfig\n ): boolean | Promise<boolean> | Observable<boolean> {\n if (this.formGroup.valid) {\n Object.assign(config, this.formGroup.value);\n return true;\n }\n return false;\n }\n\n ngOnInit() {\n this.initForm();\n }\n\n private initForm(): void {\n this.formGroup = this.createForm(this.formBuilder);\n this.form.form.addControl('config', this.formGroup);\n this.formGroup.patchValue(this.config);\n }\n\n private createForm(formBuilder: FormBuilder) {\n return formBuilder.group({\n objectModel: ['box.min.json', [Validators.minLength(1)]],\n isWireframe: [true, []],\n cameraType: ['PC', [Validators.minLength(2), Validators.maxLength(2)]]\n });\n }\n}\n","<fieldset class=\"c8y-fieldset\">\n <legend>{{ 'Rendering' | translate }}</legend>\n<form [formGroup]=\"formGroup\">\n <c8y-form-group class=\"form-group-sm m-b-8\">\n <label translate>Select object model for rendering</label>\n <div class=\"input-group input-group-sm\">\n <div class=\"c8y-select-wrapper\">\n <select class=\"form-control\" formControlName=\"objectModel\">\n <option value=\"box.min.json\" translate>Box model</option>\n <option value=\"phoneModel.min.json\" translate>Phone model</option>\n </select>\n </div>\n <span class=\"input-group-addon bg-level-0\">\n <label class=\"c8y-switch\">\n <input type=\"checkbox\" formControlName=\"isWireframe\" />\n <span></span>\n <span translate>Wireframe</span>\n </label>\n </span>\n </div>\n </c8y-form-group>\n\n <c8y-form-group class=\"form-group-sm\">\n <label translate>Camera type</label>\n <div class=\"c8y-select-wrapper\">\n <select class=\"form-control\" formControlName=\"cameraType\">\n <option value=\"OC\" translate>Orthographic camera</option>\n <option value=\"PC\" translate>Perspective camera</option>\n </select>\n </div>\n </c8y-form-group>\n</form>\n</fieldset>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":["i1","i2"],"mappings":";;;;;;;;;;;;;;;;MAuBa,uBAAuB,CAAA;AANpC,IAAA,WAAA,GAAA;AAUW,QAAA,IAAA,CAAA,OAAO,GAA2C,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;AAE1E,QAAA,IAAA,CAAA,WAAW,GAAuB,EAAE,CAAC,IAAI,CAAC;AAC1C,QAAA,IAAA,CAAA,YAAY,GAAwB,EAAE,CAAC,IAAI,CAAC;AAW7C,QAAA,IAAA,CAAA,cAAc,GAAG,IAAI,OAAO,EAAQ;AA2I7C,IAAA;AApJC,IAAA,IAAI,MAAM,GAAA;AACR,QAAA,OAAO,IAAI,CAAC,SAAS,EAAE,aAAa;IACtC;IAYA,QAAQ,GAAA;AACN,QAAA,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;QACrD,MAAM,MAAM,GAAG,aAAa,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CACzD,MAAM,CAAC,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,EACpC,SAAS,CAAC,CAAC,CAAC,KAAK,EAAE,QAAQ,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC,CAClE;AACD,QAAA,MAAM,mBAAmB,GAAG,aAAa,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CACzE,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,WAAW,CAAC,KAAK,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC,CACrE;AAED,QAAA,MAAM,aAAa,GAAG,aAAa,CAAC,CAAC,mBAAmB,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAC3E,MAAM,CAAC,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,EAChC,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,MAAM,CAAC,KAAI;YACtB,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE,MAAM,CAAC;AACrC,YAAA,OAAO,KAAK;QACd,CAAC,CAAC,CACH;QAED,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CACvC,MAAM,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,CAAC,EACtB,oBAAoB,EAAE,CACvB;AAED,QAAA,IAAI,kBAA0B;AAC9B,QAAA,IAAI,CAAC,kBAAkB,GAAG,aAAa,CAAC;YACtC,MAAM;YACN,aAAa;YACb,WAAW;AACX,YAAA,IAAI,CAAC;SACN;AACE,aAAA,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC;aACnC,SAAS,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,EAAE,UAAU,CAAC,KAAI;YAC9C,IAAI,KAAK,KAAK,IAAI,CAAC,KAAK,IAAI,kBAAkB,KAAK,UAAU,EAAE;AAC7D,gBAAA,IAAI,CAAC,KAAK,GAAG,KAAK;gBAClB,kBAAkB,GAAG,UAAU;gBAC/B,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,KAAK,EAAE,UAAU,CAAC;YAC5C;AACA,YAAA,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE;AAClB,gBAAA,MAAM,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC;YACjC;YACA,IAAI,CAAC,MAAM,EAAE;AACf,QAAA,CAAC,CAAC;IACN;IAEA,WAAW,GAAA;AACT,QAAA,IAAI,CAAC,kBAAkB,EAAE,WAAW,EAAE;AACtC,QAAA,IAAI,CAAC,QAAQ,EAAE,OAAO,EAAE;IAC1B;IAEA,eAAe,GAAA;AACb,QAAA,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE;IAC5B;AAEA,IAAA,MAAM,SAAS,CACb,QAAa,EACb,KAAmB,EAAA;AAEnB,QAAA,MAAM,MAAM,GAAG,IAAI,KAAK,CAAC,YAAY,EAAE;QACvC,MAAM,WAAW,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC;AAChD,QAAA,OAAO,WAAW;IACpB;IAEA,MAAM,aAAa,CAAC,KAAmB,EAAA;;;AAGrC,QAAA,IAAI,CAAC,QAAQ,GAAG,IAAI,KAAK,CAAC,aAAa,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC;AAChE,QAAA,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,gBAAgB,CAAC;AAC7C,QAAA,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC;AAExE,QAAA,MAAM,aAAa,GAAG,MAAM,iBAAiB,EAAE;AAC/C,QAAA,IAAI,CAAC,QAAQ,GAAG,IAAI,aAAa,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC;AACxE,QAAA,IAAI,CAAC,QAAQ,CAAC,aAAa,GAAG,IAAI;AAClC,QAAA,IAAI,CAAC,QAAQ,CAAC,aAAa,GAAG,IAAI;AAClC,QAAA,IAAI,CAAC,QAAQ,CAAC,WAAW,GAAG,IAAI;AAChC,QAAA,IAAI,CAAC,QAAQ,CAAC,gBAAgB,CAAC,QAAQ,EAAE,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC;IAC/D;IAEA,YAAY,CAAC,WAA2B,EAAE,WAAoB,EAAA;QAC5D,WAAW,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,KAAU,KAAI;AAC1C,YAAA,IAAI,KAAK,CAAC,QAAQ,EAAE;AAClB,gBAAA,KAAK,CAAC,QAAQ,CAAC,SAAS,GAAG,WAAW;YACxC;AACF,QAAA,CAAC,CAAC;AACF,QAAA,OAAO,WAAW;IACpB;IAEQ,MAAM,GAAA;AACZ,QAAA,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC;IAChD;AAEQ,IAAA,WAAW,CAAC,KAAmB,EAAE,KAAqB,EAAE,UAAkB,EAAA;;QAEhF,IAAI,CAAC,KAAK,GAAG,IAAI,KAAK,CAAC,KAAK,EAAE;AAC9B,QAAA,IAAI,CAAC,KAAK,CAAC,UAAU,GAAG,IAAI,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC;AACjD,QAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC;QAErB,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,YAAY,CAAC,QAAQ,EAAE,GAAG,CAAC;QACnD,MAAM,gBAAgB,GAAG,IAAI,KAAK,CAAC,gBAAgB,CAAC,QAAQ,CAAC;QAC7D,MAAM,iBAAiB,GAAG,IAAI,KAAK,CAAC,gBAAgB,CAAC,QAAQ,CAAC;QAE9D,gBAAgB,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC;AACzC,QAAA,iBAAiB,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;AAC7C,QAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,gBAAgB,CAAC;AAChC,QAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,iBAAiB,CAAC;AACjC,QAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC;QAErB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,UAAU,CAAC;IACpD;IAEQ,YAAY,CAAC,KAAmB,EAAE,UAAkB,EAAA;AAC1D,QAAA,IAAI,MAA0D;QAC9D,QAAQ,UAAU;AAChB,YAAA,KAAK,IAAI;AACP,gBAAA,MAAM,GAAG,IAAI,KAAK,CAAC,kBAAkB,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC;gBAChF;AACF,YAAA,KAAK,IAAI;AACT,YAAA;AACE,gBAAA,MAAM,GAAG,IAAI,KAAK,CAAC,iBAAiB,CAAC,EAAE,EAAE,IAAI,CAAC,cAAc,EAAE,EAAE,GAAG,EAAE,IAAI,CAAC;gBAC1E;;QAGJ,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC;QAC3B,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC;AAE3B,QAAA,MAAM,CAAC,QAAQ,CAAC,CAAC,GAAG,EAAE;AACtB,QAAA,MAAM,CAAC,QAAQ,CAAC,CAAC,GAAG,EAAE;AACtB,QAAA,MAAM,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC;AAErB,QAAA,OAAO,MAAM;IACf;IAEQ,cAAc,GAAA;QACpB,OAAO,IAAI,CAAC,MAAM,CAAC,WAAW,GAAG,IAAI,CAAC,MAAM,CAAC,YAAY;IAC3D;+GA5JW,uBAAuB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA;AAAvB,IAAA,SAAA,IAAA,CAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,IAAA,EAAA,uBAAuB,uSCvBpC,mDACA,EAAA,CAAA,CAAA;;4FDsBa,uBAAuB,EAAA,UAAA,EAAA,CAAA;kBANnC,SAAS;+BACE,sBAAsB,EAAA,UAAA,EAEpB,IAAI,EAAA,OAAA,EACP,EAAE,EAAA,QAAA,EAAA,mDAAA,EAAA;;sBAGV,SAAS;uBAAC,QAAQ;;sBAGlB;;sBACA;;sBACA;;sBACA;;;MEUU,iCAAiC,CAAA;IAe5C,WAAA,CACU,mBAA+C,EACnC,SAAoC,EAAA;QADhD,IAAA,CAAA,mBAAmB,GAAnB,mBAAmB;QACP,IAAA,CAAA,SAAS,GAAT,SAAS;AAf/B,QAAA,IAAA,CAAA,MAAM,GAAG,IAAI,+BAA+B,EAAE;AAC9C,QAAA,IAAA,CAAA,cAAc,GAAG,MAAM,CAAC,IAAI,0DAAC;AAG7B,QAAA,IAAA,CAAA,SAAS,GAAG,IAAI,eAAe,CAAS,IAAI,CAAC;AAC7C,QAAA,IAAA,CAAA,UAAU,GAAG,IAAI,eAAe,CAAS,IAAI,CAAC;AAC9C,QAAA,IAAA,CAAA,WAAW,GAAG,IAAI,eAAe,CAAS,IAAI,CAAC;AAC/C,QAAA,IAAA,CAAA,YAAY,GAAG,IAAI,eAAe,CAAU,IAAI,CAAC;AAEzC,QAAA,IAAA,CAAA,cAAc,GAAG,OAAO,CAC9B,kIAAkI,CACnI;AAMC,QAAA,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CACnC,MAAM,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,CAAC,EACtB,oBAAoB,EAAE,EACtB,SAAS,CAAC,IAAI,IAAI,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,EACzC,WAAW,CAAC,CAAC,CAAC,CACf;QACD,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAChC,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,CAAC,EAClB,oBAAoB,EAAE,EACtB,SAAS,CAAC,EAAE,IAAI,IAAI,CAAC,kBAAkB,CAAC,EAAE,CAAC,CAAC,EAC5C,SAAS,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAChC;IACH;IAEA,QAAQ,GAAA;AACN,QAAA,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,EAAE;AAC5B,YAAA,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC;AAC9B,YAAA,IAAI,CAAC,MAAM,CAAC,SAAS,CACnB,IAAI,qBAAqB,CAAC;AACxB,gBAAA,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE,IAAI,CAAC;AACZ,aAAA,CAAC,CACH;QACH;IACF;AAEA,IAAA,WAAW,CAAC,OAAsB,EAAA;QAChC,IAAI,OAAO,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,EAAE;YACjC,IAAI,CAAC,cAAc,EAAE;QACvB;IACF;IAEQ,cAAc,GAAA;QACpB,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,EAAE;AAC1B,YAAA,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA,EAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAA,CAAE,CAAC;QACjD;aAAO,IAAI,IAAI,CAAC,SAAS,EAAE,OAAO,EAAE,EAAE,EAAE;AACtC,YAAA,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA,EAAG,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,EAAE,CAAA,CAAE,CAAC;QACtD;AAEA,QAAA,IAAI,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE;YAC3B,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC;QAC/C;AAEA,QAAA,IAAI,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE;YAC1B,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC;QAC/C;QAEA,IAAI,IAAI,CAAC,MAAM,CAAC,WAAW,KAAK,SAAS,EAAE;YACzC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC;QACjD;IACF;IAEQ,MAAM,WAAW,CAAC,KAAa,EAAA;;;AAGrC,QAAA,IAAI,KAAK,KAAK,cAAc,EAAE;YAC5B,OAAO,MAAM,YAAY,EAAE;QAC7B;aAAO;YACL,OAAO,MAAM,cAAc,EAAE;QAC/B;IACF;AAEQ,IAAA,kBAAkB,CAAC,QAAgB,EAAA;QACzC,MAAM,QAAQ,GAAG,kBAAkB;QACnC,MAAM,MAAM,GAAG,CAAC,eAAe,EAAE,eAAe,EAAE,eAAe,CAAC;QAClE,OAAO,IAAI,CAAC;aACT,iCAAiC,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC;AAClE,aAAA,IAAI,CACH,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,UAAU,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EACtF,GAAG,CAAC,WAAW,IAAG;AAChB,YAAA,MAAM,CAAC,UAAU,EAAE,UAAU,EAAE,UAAU,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,UAAU,IAChE,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,CACpD;YACD,OAAO,IAAI,CAAC,aAAa,CAAC,UAAU,EAAE,UAAU,EAAE,UAAU,CAAC;QAC/D,CAAC,CAAC,CACH;IACL;AAEQ,IAAA,aAAa,CAAC,CAAS,EAAE,CAAS,EAAE,CAAS,EAAA;QACnD,IAAI,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;QAC9B,IAAI,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;AACrD,QAAA,OAAO,GAAG,OAAO,GAAG,OAAO,IAAI,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC;AAC/C,QAAA,OAAO,GAAG,OAAO,GAAG,OAAO,IAAI,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC;QAE/C,OAAO;AACL,YAAA,CAAC,EAAE,OAAO;AACV,YAAA,CAAC,EAAE,CAAC;AACJ,YAAA,CAAC,EAAE;SACJ;IACH;IAEQ,gBAAgB,GAAA;AACtB,QAAA,IAAI;YACF,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC;AAC/C,YAAA,MAAM,OAAO,GAAG,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,UAAU,CAAC,oBAAoB,CAAC;YACrF,OAAO,CAAC,CAAC,OAAO;QAClB;AAAE,QAAA,MAAM;AACN,YAAA,OAAO,KAAK;QACd;IACF;+GAtHW,iCAAiC,EAAA,IAAA,EAAA,CAAA,EAAA,KAAA,EAAAA,EAAA,CAAA,0BAAA,EAAA,EAAA,EAAA,KAAA,EAAAC,IAAA,CAAA,yBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA;AAAjC,IAAA,SAAA,IAAA,CAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,IAAA,EAAA,iCAAiC,6GAJjC,CAAC,0BAA0B,CAAC,EAAA,aAAA,EAAA,IAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,ECpCzC,sNAQA,4CD8BY,uBAAuB,EAAA,QAAA,EAAA,sBAAA,EAAA,MAAA,EAAA,CAAA,SAAA,EAAA,WAAA,EAAA,aAAA,EAAA,cAAA,CAAA,EAAA,CAAA,EAAA,CAAA,CAAA;;4FAEtB,iCAAiC,EAAA,UAAA,EAAA,CAAA;kBAP7C,SAAS;+BACE,kCAAkC,EAAA,SAAA,EAEjC,CAAC,0BAA0B,CAAC,cAC3B,IAAI,EAAA,OAAA,EACP,CAAC,uBAAuB,CAAC,EAAA,QAAA,EAAA,sNAAA,EAAA;;0BAmB/B;;sBAhBF;;;ME3BU,mCAAmC,CAAA;IAI9C,WAAA,CACU,WAAwB,EACxB,IAAY,EAAA;QADZ,IAAA,CAAA,WAAW,GAAX,WAAW;QACX,IAAA,CAAA,IAAI,GAAJ,IAAI;IACX;AAEH,IAAA,YAAY,CACV,MAAmC,EAAA;AAEnC,QAAA,IAAI,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE;YACxB,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;AAC3C,YAAA,OAAO,IAAI;QACb;AACA,QAAA,OAAO,KAAK;IACd;IAEA,QAAQ,GAAA;QACN,IAAI,CAAC,QAAQ,EAAE;IACjB;IAEQ,QAAQ,GAAA;QACd,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,WAAW,CAAC;AAClD,QAAA,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC;QACnD,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC;IACxC;AAEQ,IAAA,UAAU,CAAC,WAAwB,EAAA;QACzC,OAAO,WAAW,CAAC,KAAK,CAAC;AACvB,YAAA,WAAW,EAAE,CAAC,cAAc,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;AACxD,YAAA,WAAW,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC;AACvB,YAAA,UAAU,EAAE,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AACtE,SAAA,CAAC;IACJ;+GAnCW,mCAAmC,EAAA,IAAA,EAAA,CAAA,EAAA,KAAA,EAAA,EAAA,CAAA,WAAA,EAAA,EAAA,EAAA,KAAA,EAAA,EAAA,CAAA,MAAA,EAAA,CAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA;AAAnC,IAAA,SAAA,IAAA,CAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,IAAA,EAAA,mCAAmC,4HCdhD,swCAiCA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EDrBY,UAAU,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,qBAAA,EAAA,QAAA,EAAA,6BAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,aAAA,EAAA,QAAA,EAAA,8CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,cAAA,EAAA,QAAA,EAAA,QAAA,EAAA,MAAA,EAAA,CAAA,SAAA,EAAA,OAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,uBAAA,EAAA,QAAA,EAAA,QAAA,EAAA,MAAA,EAAA,CAAA,SAAA,EAAA,OAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,4BAAA,EAAA,QAAA,EAAA,uGAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,0BAAA,EAAA,QAAA,EAAA,6GAAA,EAAA,MAAA,EAAA,CAAA,aAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,eAAA,EAAA,QAAA,EAAA,2CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,oBAAA,EAAA,QAAA,EAAA,0FAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,kBAAA,EAAA,QAAA,EAAA,gBAAA,EAAA,MAAA,EAAA,CAAA,UAAA,EAAA,YAAA,EAAA,YAAA,EAAA,cAAA,EAAA,QAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,iCAAA,EAAA,QAAA,EAAA,yCAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,kBAAA,EAAA,QAAA,EAAA,aAAA,EAAA,MAAA,EAAA,CAAA,WAAA,CAAA,EAAA,OAAA,EAAA,CAAA,UAAA,CAAA,EAAA,QAAA,EAAA,CAAA,QAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,eAAA,EAAA,QAAA,EAAA,mBAAA,EAAA,MAAA,EAAA,CAAA,iBAAA,EAAA,UAAA,EAAA,SAAA,CAAA,EAAA,OAAA,EAAA,CAAA,eAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAE,aAAa,EAAA,EAAA,EAAA,IAAA,EAAA,MAAA,EAAA,IAAA,EAAA,EAAA,CAAA,gBAAA,EAAA,IAAA,EAAA,WAAA,EAAA,CAAA,EAAA,aAAA,EAFpB,CAAC,EAAE,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC,EAAA,CAAA,CAAA;;4FAIxD,mCAAmC,EAAA,UAAA,EAAA,CAAA;kBAP/C,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,oCAAoC,iBAE/B,CAAC,EAAE,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC,cACvD,IAAI,EAAA,OAAA,EACP,CAAC,UAAU,EAAE,aAAa,CAAC,EAAA,QAAA,EAAA,swCAAA,EAAA;;sBAGnC;;;AEfH;;AAEG;;;;"}
1
+ {"version":3,"file":"c8y-ngx-components-widgets-implementations-three-d-rotation.mjs","sources":["../../widgets/implementations/three-d-rotation/three-d-rotation/three-d-rotation.component.ts","../../widgets/implementations/three-d-rotation/three-d-rotation/three-d-rotation.component.html","../../widgets/implementations/three-d-rotation/three-d-rotation-widget-view/three-d-rotation-widget-view.component.ts","../../widgets/implementations/three-d-rotation/three-d-rotation-widget-view/three-d-rotation-widget-view.component.html","../../widgets/implementations/three-d-rotation/three-d-rotation-widget-config/three-d-rotation-widget-config.component.ts","../../widgets/implementations/three-d-rotation/three-d-rotation-widget-config/three-d-rotation-widget-config.component.html","../../widgets/implementations/three-d-rotation/c8y-ngx-components-widgets-implementations-three-d-rotation.ts"],"sourcesContent":["import {\n AfterViewInit,\n Component,\n ElementRef,\n Input,\n OnDestroy,\n OnInit,\n ViewChild\n} from '@angular/core';\nimport { combineLatest, from, Observable, of, Subject, Subscription } from 'rxjs';\nimport { distinctUntilChanged, filter, map, shareReplay, switchMap } from 'rxjs/operators';\nimport { loadThree } from '@c8y/ngx-components/lazy/three';\nimport { ThreeDRotationWidgetRotate } from '../three-d-rotation.model';\nimport { loadOrbitControls } from '@c8y/ngx-components/lazy/three-orbit-controls';\nimport type * as THREE from 'three';\nimport type { OrbitControls } from 'three/examples/jsm/controls/OrbitControls';\n\n@Component({\n selector: 'c8y-three-d-rotation',\n templateUrl: './three-d-rotation.component.html',\n standalone: true,\n imports: []\n})\nexport class ThreeDRotationComponent implements AfterViewInit, OnInit, OnDestroy {\n @ViewChild('canvas')\n private canvasRef: ElementRef;\n\n @Input() angles$: Observable<ThreeDRotationWidgetRotate> = of({ x: 0, y: 0, z: 0 });\n @Input() modelObj$: Observable<any>;\n @Input() cameraType$: Observable<string> = of('PC');\n @Input() isWireframe$: Observable<boolean> = of(true);\n\n get canvas(): HTMLCanvasElement | null {\n return this.canvasRef?.nativeElement;\n }\n\n scene: THREE.Scene;\n camera: THREE.PerspectiveCamera | THREE.OrthographicCamera;\n model: THREE.Object3D;\n private renderer: THREE.WebGLRenderer;\n\n private afterViewInit$ = new Subject<void>();\n\n private renderSubscription: Subscription;\n private controls: OrbitControls;\n\n ngOnInit() {\n const three$ = from(loadThree()).pipe(shareReplay(1));\n const model$ = combineLatest([three$, this.modelObj$]).pipe(\n filter(([, modelObj]) => !!modelObj),\n switchMap(([three, modelObj]) => this.loadModel(modelObj, three))\n );\n const modelWithWireframe$ = combineLatest([model$, this.isWireframe$]).pipe(\n map(([model, isWireframe]) => this.setWireframe(model, isWireframe))\n );\n\n const rotatedModel$ = combineLatest([modelWithWireframe$, this.angles$]).pipe(\n filter(([, angles]) => !!angles),\n map(([model, angles]) => {\n Object.assign(model.rotation, angles);\n return model;\n })\n );\n\n const cameraType$ = this.cameraType$.pipe(\n filter(type => !!type),\n distinctUntilChanged()\n );\n\n let previousCameraType: string;\n this.renderSubscription = combineLatest([\n three$,\n rotatedModel$,\n cameraType$,\n this.afterViewInit$\n ])\n .pipe(filter(([, model]) => !!model))\n .subscribe(async ([three, model, cameraType]) => {\n if (model !== this.model || previousCameraType !== cameraType) {\n this.model = model;\n previousCameraType = cameraType;\n this.createScene(three, model, cameraType);\n }\n if (!this.renderer) {\n await this.setupRenderer(three);\n }\n this.render();\n });\n }\n\n ngOnDestroy(): void {\n this.renderSubscription?.unsubscribe();\n this.controls?.dispose();\n }\n\n ngAfterViewInit() {\n this.afterViewInit$.next();\n }\n\n async loadModel(\n modelObj: any,\n three: typeof THREE\n ): Promise<THREE.Object3D<THREE.Object3DEventMap>> {\n const loader = new three.ObjectLoader();\n const parsedModel = await loader.parse(modelObj);\n return parsedModel;\n }\n\n async setupRenderer(three: typeof THREE) {\n //* Renderer\n // Use canvas element in template\n this.renderer = new three.WebGLRenderer({ canvas: this.canvas });\n this.renderer.setPixelRatio(devicePixelRatio);\n this.renderer.setSize(this.canvas.clientWidth, this.canvas.clientHeight);\n\n const OrbitControls = await loadOrbitControls();\n this.controls = new OrbitControls(this.camera, this.renderer.domElement);\n this.controls.enableDamping = true;\n this.controls.dampingFactor = 0.25;\n this.controls.rotateSpeed = 0.35;\n this.controls.minDistance = 20;\n this.controls.maxDistance = 50;\n this.controls.minZoom = 0.5;\n this.controls.maxZoom = 2;\n this.controls.addEventListener('change', () => this.render());\n }\n\n setWireframe(parsedModel: THREE.Object3D, isWireframe: boolean) {\n parsedModel.children.forEach((child: any) => {\n if (child.material) {\n child.material.wireframe = isWireframe;\n }\n });\n return parsedModel;\n }\n\n private render(): void {\n this.renderer?.render(this.scene, this.camera);\n }\n\n private createScene(three: typeof THREE, model: THREE.Object3D, cameraType: string) {\n //* Scene\n this.scene = new three.Scene();\n this.scene.background = new three.Color(0xffffff);\n this.scene.add(model);\n\n const light = new three.AmbientLight(0xffffff, 0.5);\n const lightDirectional = new three.DirectionalLight(0xffffff);\n const lightDirectional2 = new three.DirectionalLight(0xffffff);\n\n lightDirectional.position.set(20, 25, 30);\n lightDirectional2.position.set(-20, -25, -30);\n this.scene.add(lightDirectional);\n this.scene.add(lightDirectional2);\n this.scene.add(light);\n\n this.camera = this.createCamera(three, cameraType);\n }\n\n private createCamera(three: typeof THREE, cameraType: string) {\n let camera: THREE.OrthographicCamera | THREE.PerspectiveCamera;\n switch (cameraType) {\n case 'OC':\n camera = new three.OrthographicCamera(30 / -2, 30 / 2, 30 / 2, 30 / -2, 1, 1000);\n break;\n case 'PC':\n default:\n camera = new three.PerspectiveCamera(30, this.getAspectRatio(), 0.1, 1000);\n break;\n }\n\n camera.rotateX(Math.PI / 2);\n camera.rotateY(Math.PI / 2);\n\n camera.position.z = 23;\n camera.position.x = 14;\n camera.position.y = 7;\n\n return camera;\n }\n\n private getAspectRatio() {\n return this.canvas.clientWidth / this.canvas.clientHeight;\n }\n}\n","<canvas #canvas class=\"fit-w fit-h\"></canvas>\n","import {\n Component,\n Input,\n OnChanges,\n OnInit,\n Optional,\n signal,\n SimpleChanges\n} from '@angular/core';\nimport {\n DynamicComponent,\n DynamicComponentAlert,\n DynamicComponentAlertAggregator,\n MeasurementRealtimeService\n} from '@c8y/ngx-components';\nimport { gettext } from '@c8y/ngx-components/gettext';\nimport { BehaviorSubject, Observable } from 'rxjs';\nimport {\n distinctUntilChanged,\n filter,\n map,\n shareReplay,\n startWith,\n switchMap\n} from 'rxjs/operators';\nimport { ThreeDRotationWidgetConfig, ThreeDRotationWidgetRotate } from '../three-d-rotation.model';\n// eslint-disable-next-line @typescript-eslint/no-restricted-imports\nimport { loadBoxModel } from '@c8y/ngx-components/widgets/implementations/three-d-rotation/lazy-box-model';\nimport { ContextDashboardComponent } from '@c8y/ngx-components/context-dashboard';\n// eslint-disable-next-line @typescript-eslint/no-restricted-imports\nimport { loadPhoneModel } from '@c8y/ngx-components/widgets/implementations/three-d-rotation/lazy-phone-model';\nimport { ThreeDRotationComponent } from '../three-d-rotation/three-d-rotation.component';\n\n@Component({\n selector: 'c8y-three-d-rotation-widget-view',\n templateUrl: './three-d-rotation-widget-view.component.html',\n providers: [MeasurementRealtimeService],\n standalone: true,\n imports: [ThreeDRotationComponent]\n})\nexport class ThreeDRotationWidgetViewComponent implements OnChanges, OnInit, DynamicComponent {\n @Input() config: ThreeDRotationWidgetConfig;\n alerts = new DynamicComponentAlertAggregator();\n webGLAvailable = signal(true);\n angles$: Observable<ThreeDRotationWidgetRotate>;\n modelObj$: Observable<any>;\n deviceId$ = new BehaviorSubject<string>(null);\n modelName$ = new BehaviorSubject<string>(null);\n cameraType$ = new BehaviorSubject<string>('PC');\n isWireframe$ = new BehaviorSubject<boolean>(true);\n\n private webGLErrorText = gettext(\n 'WebGL is not available. Hardware acceleration may be disabled in your browser. Enable it in browser settings to use this widget.'\n );\n\n constructor(\n private measurementRealtime: MeasurementRealtimeService,\n @Optional() private dashboard: ContextDashboardComponent\n ) {\n this.modelObj$ = this.modelName$.pipe(\n filter(name => !!name),\n distinctUntilChanged(),\n switchMap(name => this.getModelUrl(name)),\n shareReplay(1)\n );\n this.angles$ = this.deviceId$.pipe(\n filter(id => !!id),\n distinctUntilChanged(),\n switchMap(id => this.getAnglesOfDevice$(id)),\n startWith({ x: 0, y: 0, z: 0 })\n );\n }\n\n ngOnInit(): void {\n if (!this.isWebGLAvailable()) {\n this.webGLAvailable.set(false);\n this.alerts.addAlerts(\n new DynamicComponentAlert({\n type: 'warning',\n text: this.webGLErrorText\n })\n );\n }\n }\n\n ngOnChanges(changes: SimpleChanges): void {\n if (changes.config && this.config) {\n this.onConfigChange();\n }\n }\n\n private onConfigChange() {\n if (this.config.device?.id) {\n this.deviceId$.next(`${this.config.device.id}`);\n } else if (this.dashboard?.context?.id) {\n this.deviceId$.next(`${this.dashboard.context?.id}`);\n }\n\n if (this.config.objectModel) {\n this.modelName$.next(this.config.objectModel);\n }\n\n if (this.config.cameraType) {\n this.cameraType$.next(this.config.cameraType);\n }\n\n if (this.config.isWireframe !== undefined) {\n this.isWireframe$.next(this.config.isWireframe);\n }\n }\n\n private async getModelUrl(model: string): Promise<any> {\n // The name *.min.json still exist for backwards compatibility\n // it might be stored in certain widget configs.\n if (model === 'box.min.json') {\n return await loadBoxModel();\n } else {\n return await loadPhoneModel();\n }\n }\n\n private getAnglesOfDevice$(deviceId: string): Observable<ThreeDRotationWidgetRotate> {\n const fragment = 'c8y_Acceleration';\n const series = ['accelerationX', 'accelerationY', 'accelerationZ'];\n return this.measurementRealtime\n .latestValueOfSpecificMeasurement$(fragment, series[0], deviceId, 1)\n .pipe(\n filter(m => !!m && m[fragment] && series.every(axisSeries => m[fragment][axisSeries])),\n map(measurement => {\n const [xAxisValue, yAxisValue, zAxisValue] = series.map(axisSeries =>\n Math.round(measurement[fragment][axisSeries].value)\n );\n return this.convertValues(xAxisValue, yAxisValue, zAxisValue);\n })\n );\n }\n\n private convertValues(x: number, y: number, z: number): ThreeDRotationWidgetRotate {\n let rotateX = Math.atan2(y, z);\n let rotateY = Math.atan2(x, Math.sqrt(y * y + z * z));\n rotateX = rotateX ? rotateX % (Math.PI * 2) : 0;\n rotateY = rotateY ? rotateY % (Math.PI * 2) : 0;\n\n return {\n x: rotateX,\n y: 0,\n z: rotateY\n };\n }\n\n private isWebGLAvailable(): boolean {\n try {\n const canvas = document.createElement('canvas');\n const context = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');\n return !!context;\n } catch {\n return false;\n }\n }\n}\n","@if (webGLAvailable()) {\n <c8y-three-d-rotation\n [modelObj$]=\"modelObj$\"\n [angles$]=\"angles$\"\n [cameraType$]=\"cameraType$\"\n [isWireframe$]=\"isWireframe$\"\n ></c8y-three-d-rotation>\n}\n","import { Component, OnInit, Input } from '@angular/core';\nimport { ControlContainer, FormBuilder, NgForm, Validators } from '@angular/forms';\nimport { CoreModule, OnBeforeSave } from '@c8y/ngx-components';\nimport { Observable } from 'rxjs';\nimport { ThreeDRotationWidgetConfig } from '../three-d-rotation.model';\nimport { ButtonsModule } from 'ngx-bootstrap/buttons';\n\n@Component({\n selector: 'c8y-three-d-rotation-widget-config',\n templateUrl: './three-d-rotation-widget-config.component.html',\n viewProviders: [{ provide: ControlContainer, useExisting: NgForm }],\n standalone: true,\n imports: [CoreModule, ButtonsModule]\n})\nexport class ThreeDRotationWidgetConfigComponent implements OnInit, OnBeforeSave {\n @Input() config: ThreeDRotationWidgetConfig;\n formGroup: ReturnType<ThreeDRotationWidgetConfigComponent['createForm']>;\n\n constructor(\n private formBuilder: FormBuilder,\n private form: NgForm\n ) {}\n\n onBeforeSave(\n config?: ThreeDRotationWidgetConfig\n ): boolean | Promise<boolean> | Observable<boolean> {\n if (this.formGroup.valid) {\n Object.assign(config, this.formGroup.value);\n return true;\n }\n return false;\n }\n\n ngOnInit() {\n this.initForm();\n }\n\n private initForm(): void {\n this.formGroup = this.createForm(this.formBuilder);\n this.form.form.addControl('config', this.formGroup);\n this.formGroup.patchValue(this.config);\n }\n\n private createForm(formBuilder: FormBuilder) {\n return formBuilder.group({\n objectModel: ['box.min.json', [Validators.minLength(1)]],\n isWireframe: [true, []],\n cameraType: ['PC', [Validators.minLength(2), Validators.maxLength(2)]]\n });\n }\n}\n","<fieldset class=\"c8y-fieldset\">\n <legend>{{ 'Rendering' | translate }}</legend>\n<form [formGroup]=\"formGroup\">\n <c8y-form-group class=\"form-group-sm m-b-8\">\n <label translate>Select object model for rendering</label>\n <div class=\"input-group input-group-sm\">\n <div class=\"c8y-select-wrapper\">\n <select class=\"form-control\" formControlName=\"objectModel\">\n <option value=\"box.min.json\" translate>Box model</option>\n <option value=\"phoneModel.min.json\" translate>Phone model</option>\n </select>\n </div>\n <span class=\"input-group-addon bg-level-0\">\n <label class=\"c8y-switch\">\n <input type=\"checkbox\" formControlName=\"isWireframe\" />\n <span></span>\n <span translate>Wireframe</span>\n </label>\n </span>\n </div>\n </c8y-form-group>\n\n <c8y-form-group class=\"form-group-sm\">\n <label translate>Camera type</label>\n <div class=\"c8y-select-wrapper\">\n <select class=\"form-control\" formControlName=\"cameraType\">\n <option value=\"OC\" translate>Orthographic camera</option>\n <option value=\"PC\" translate>Perspective camera</option>\n </select>\n </div>\n </c8y-form-group>\n</form>\n</fieldset>\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":["i1","i2"],"mappings":";;;;;;;;;;;;;;;;MAuBa,uBAAuB,CAAA;AANpC,IAAA,WAAA,GAAA;AAUW,QAAA,IAAA,CAAA,OAAO,GAA2C,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;AAE1E,QAAA,IAAA,CAAA,WAAW,GAAuB,EAAE,CAAC,IAAI,CAAC;AAC1C,QAAA,IAAA,CAAA,YAAY,GAAwB,EAAE,CAAC,IAAI,CAAC;AAW7C,QAAA,IAAA,CAAA,cAAc,GAAG,IAAI,OAAO,EAAQ;AA+I7C,IAAA;AAxJC,IAAA,IAAI,MAAM,GAAA;AACR,QAAA,OAAO,IAAI,CAAC,SAAS,EAAE,aAAa;IACtC;IAYA,QAAQ,GAAA;AACN,QAAA,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;QACrD,MAAM,MAAM,GAAG,aAAa,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CACzD,MAAM,CAAC,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,EACpC,SAAS,CAAC,CAAC,CAAC,KAAK,EAAE,QAAQ,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC,CAClE;AACD,QAAA,MAAM,mBAAmB,GAAG,aAAa,CAAC,CAAC,MAAM,EAAE,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CACzE,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,WAAW,CAAC,KAAK,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC,CACrE;AAED,QAAA,MAAM,aAAa,GAAG,aAAa,CAAC,CAAC,mBAAmB,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAC3E,MAAM,CAAC,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,EAChC,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,MAAM,CAAC,KAAI;YACtB,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,EAAE,MAAM,CAAC;AACrC,YAAA,OAAO,KAAK;QACd,CAAC,CAAC,CACH;QAED,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CACvC,MAAM,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,CAAC,EACtB,oBAAoB,EAAE,CACvB;AAED,QAAA,IAAI,kBAA0B;AAC9B,QAAA,IAAI,CAAC,kBAAkB,GAAG,aAAa,CAAC;YACtC,MAAM;YACN,aAAa;YACb,WAAW;AACX,YAAA,IAAI,CAAC;SACN;AACE,aAAA,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC;aACnC,SAAS,CAAC,OAAO,CAAC,KAAK,EAAE,KAAK,EAAE,UAAU,CAAC,KAAI;YAC9C,IAAI,KAAK,KAAK,IAAI,CAAC,KAAK,IAAI,kBAAkB,KAAK,UAAU,EAAE;AAC7D,gBAAA,IAAI,CAAC,KAAK,GAAG,KAAK;gBAClB,kBAAkB,GAAG,UAAU;gBAC/B,IAAI,CAAC,WAAW,CAAC,KAAK,EAAE,KAAK,EAAE,UAAU,CAAC;YAC5C;AACA,YAAA,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE;AAClB,gBAAA,MAAM,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC;YACjC;YACA,IAAI,CAAC,MAAM,EAAE;AACf,QAAA,CAAC,CAAC;IACN;IAEA,WAAW,GAAA;AACT,QAAA,IAAI,CAAC,kBAAkB,EAAE,WAAW,EAAE;AACtC,QAAA,IAAI,CAAC,QAAQ,EAAE,OAAO,EAAE;IAC1B;IAEA,eAAe,GAAA;AACb,QAAA,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE;IAC5B;AAEA,IAAA,MAAM,SAAS,CACb,QAAa,EACb,KAAmB,EAAA;AAEnB,QAAA,MAAM,MAAM,GAAG,IAAI,KAAK,CAAC,YAAY,EAAE;QACvC,MAAM,WAAW,GAAG,MAAM,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC;AAChD,QAAA,OAAO,WAAW;IACpB;IAEA,MAAM,aAAa,CAAC,KAAmB,EAAA;;;AAGrC,QAAA,IAAI,CAAC,QAAQ,GAAG,IAAI,KAAK,CAAC,aAAa,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC;AAChE,QAAA,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,gBAAgB,CAAC;AAC7C,QAAA,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,IAAI,CAAC,MAAM,CAAC,YAAY,CAAC;AAExE,QAAA,MAAM,aAAa,GAAG,MAAM,iBAAiB,EAAE;AAC/C,QAAA,IAAI,CAAC,QAAQ,GAAG,IAAI,aAAa,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC;AACxE,QAAA,IAAI,CAAC,QAAQ,CAAC,aAAa,GAAG,IAAI;AAClC,QAAA,IAAI,CAAC,QAAQ,CAAC,aAAa,GAAG,IAAI;AAClC,QAAA,IAAI,CAAC,QAAQ,CAAC,WAAW,GAAG,IAAI;AAChC,QAAA,IAAI,CAAC,QAAQ,CAAC,WAAW,GAAG,EAAE;AAC9B,QAAA,IAAI,CAAC,QAAQ,CAAC,WAAW,GAAG,EAAE;AAC9B,QAAA,IAAI,CAAC,QAAQ,CAAC,OAAO,GAAG,GAAG;AAC3B,QAAA,IAAI,CAAC,QAAQ,CAAC,OAAO,GAAG,CAAC;AACzB,QAAA,IAAI,CAAC,QAAQ,CAAC,gBAAgB,CAAC,QAAQ,EAAE,MAAM,IAAI,CAAC,MAAM,EAAE,CAAC;IAC/D;IAEA,YAAY,CAAC,WAA2B,EAAE,WAAoB,EAAA;QAC5D,WAAW,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,KAAU,KAAI;AAC1C,YAAA,IAAI,KAAK,CAAC,QAAQ,EAAE;AAClB,gBAAA,KAAK,CAAC,QAAQ,CAAC,SAAS,GAAG,WAAW;YACxC;AACF,QAAA,CAAC,CAAC;AACF,QAAA,OAAO,WAAW;IACpB;IAEQ,MAAM,GAAA;AACZ,QAAA,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC;IAChD;AAEQ,IAAA,WAAW,CAAC,KAAmB,EAAE,KAAqB,EAAE,UAAkB,EAAA;;QAEhF,IAAI,CAAC,KAAK,GAAG,IAAI,KAAK,CAAC,KAAK,EAAE;AAC9B,QAAA,IAAI,CAAC,KAAK,CAAC,UAAU,GAAG,IAAI,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC;AACjD,QAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC;QAErB,MAAM,KAAK,GAAG,IAAI,KAAK,CAAC,YAAY,CAAC,QAAQ,EAAE,GAAG,CAAC;QACnD,MAAM,gBAAgB,GAAG,IAAI,KAAK,CAAC,gBAAgB,CAAC,QAAQ,CAAC;QAC7D,MAAM,iBAAiB,GAAG,IAAI,KAAK,CAAC,gBAAgB,CAAC,QAAQ,CAAC;QAE9D,gBAAgB,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC;AACzC,QAAA,iBAAiB,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,CAAC;AAC7C,QAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,gBAAgB,CAAC;AAChC,QAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,iBAAiB,CAAC;AACjC,QAAA,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC;QAErB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,KAAK,EAAE,UAAU,CAAC;IACpD;IAEQ,YAAY,CAAC,KAAmB,EAAE,UAAkB,EAAA;AAC1D,QAAA,IAAI,MAA0D;QAC9D,QAAQ,UAAU;AAChB,YAAA,KAAK,IAAI;AACP,gBAAA,MAAM,GAAG,IAAI,KAAK,CAAC,kBAAkB,CAAC,EAAE,GAAG,CAAC,CAAC,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC;gBAChF;AACF,YAAA,KAAK,IAAI;AACT,YAAA;AACE,gBAAA,MAAM,GAAG,IAAI,KAAK,CAAC,iBAAiB,CAAC,EAAE,EAAE,IAAI,CAAC,cAAc,EAAE,EAAE,GAAG,EAAE,IAAI,CAAC;gBAC1E;;QAGJ,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC;QAC3B,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC;AAE3B,QAAA,MAAM,CAAC,QAAQ,CAAC,CAAC,GAAG,EAAE;AACtB,QAAA,MAAM,CAAC,QAAQ,CAAC,CAAC,GAAG,EAAE;AACtB,QAAA,MAAM,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC;AAErB,QAAA,OAAO,MAAM;IACf;IAEQ,cAAc,GAAA;QACpB,OAAO,IAAI,CAAC,MAAM,CAAC,WAAW,GAAG,IAAI,CAAC,MAAM,CAAC,YAAY;IAC3D;+GAhKW,uBAAuB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA;AAAvB,IAAA,SAAA,IAAA,CAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,IAAA,EAAA,uBAAuB,uSCvBpC,mDACA,EAAA,CAAA,CAAA;;4FDsBa,uBAAuB,EAAA,UAAA,EAAA,CAAA;kBANnC,SAAS;+BACE,sBAAsB,EAAA,UAAA,EAEpB,IAAI,EAAA,OAAA,EACP,EAAE,EAAA,QAAA,EAAA,mDAAA,EAAA;;sBAGV,SAAS;uBAAC,QAAQ;;sBAGlB;;sBACA;;sBACA;;sBACA;;;MEUU,iCAAiC,CAAA;IAe5C,WAAA,CACU,mBAA+C,EACnC,SAAoC,EAAA;QADhD,IAAA,CAAA,mBAAmB,GAAnB,mBAAmB;QACP,IAAA,CAAA,SAAS,GAAT,SAAS;AAf/B,QAAA,IAAA,CAAA,MAAM,GAAG,IAAI,+BAA+B,EAAE;AAC9C,QAAA,IAAA,CAAA,cAAc,GAAG,MAAM,CAAC,IAAI,0DAAC;AAG7B,QAAA,IAAA,CAAA,SAAS,GAAG,IAAI,eAAe,CAAS,IAAI,CAAC;AAC7C,QAAA,IAAA,CAAA,UAAU,GAAG,IAAI,eAAe,CAAS,IAAI,CAAC;AAC9C,QAAA,IAAA,CAAA,WAAW,GAAG,IAAI,eAAe,CAAS,IAAI,CAAC;AAC/C,QAAA,IAAA,CAAA,YAAY,GAAG,IAAI,eAAe,CAAU,IAAI,CAAC;AAEzC,QAAA,IAAA,CAAA,cAAc,GAAG,OAAO,CAC9B,kIAAkI,CACnI;AAMC,QAAA,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CACnC,MAAM,CAAC,IAAI,IAAI,CAAC,CAAC,IAAI,CAAC,EACtB,oBAAoB,EAAE,EACtB,SAAS,CAAC,IAAI,IAAI,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,CAAC,EACzC,WAAW,CAAC,CAAC,CAAC,CACf;QACD,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAChC,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,CAAC,EAClB,oBAAoB,EAAE,EACtB,SAAS,CAAC,EAAE,IAAI,IAAI,CAAC,kBAAkB,CAAC,EAAE,CAAC,CAAC,EAC5C,SAAS,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAChC;IACH;IAEA,QAAQ,GAAA;AACN,QAAA,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,EAAE;AAC5B,YAAA,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC;AAC9B,YAAA,IAAI,CAAC,MAAM,CAAC,SAAS,CACnB,IAAI,qBAAqB,CAAC;AACxB,gBAAA,IAAI,EAAE,SAAS;gBACf,IAAI,EAAE,IAAI,CAAC;AACZ,aAAA,CAAC,CACH;QACH;IACF;AAEA,IAAA,WAAW,CAAC,OAAsB,EAAA;QAChC,IAAI,OAAO,CAAC,MAAM,IAAI,IAAI,CAAC,MAAM,EAAE;YACjC,IAAI,CAAC,cAAc,EAAE;QACvB;IACF;IAEQ,cAAc,GAAA;QACpB,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,EAAE;AAC1B,YAAA,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA,EAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAA,CAAE,CAAC;QACjD;aAAO,IAAI,IAAI,CAAC,SAAS,EAAE,OAAO,EAAE,EAAE,EAAE;AACtC,YAAA,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA,EAAG,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,EAAE,CAAA,CAAE,CAAC;QACtD;AAEA,QAAA,IAAI,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE;YAC3B,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC;QAC/C;AAEA,QAAA,IAAI,IAAI,CAAC,MAAM,CAAC,UAAU,EAAE;YAC1B,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC;QAC/C;QAEA,IAAI,IAAI,CAAC,MAAM,CAAC,WAAW,KAAK,SAAS,EAAE;YACzC,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC;QACjD;IACF;IAEQ,MAAM,WAAW,CAAC,KAAa,EAAA;;;AAGrC,QAAA,IAAI,KAAK,KAAK,cAAc,EAAE;YAC5B,OAAO,MAAM,YAAY,EAAE;QAC7B;aAAO;YACL,OAAO,MAAM,cAAc,EAAE;QAC/B;IACF;AAEQ,IAAA,kBAAkB,CAAC,QAAgB,EAAA;QACzC,MAAM,QAAQ,GAAG,kBAAkB;QACnC,MAAM,MAAM,GAAG,CAAC,eAAe,EAAE,eAAe,EAAE,eAAe,CAAC;QAClE,OAAO,IAAI,CAAC;aACT,iCAAiC,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC;AAClE,aAAA,IAAI,CACH,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,UAAU,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EACtF,GAAG,CAAC,WAAW,IAAG;AAChB,YAAA,MAAM,CAAC,UAAU,EAAE,UAAU,EAAE,UAAU,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,UAAU,IAChE,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,CACpD;YACD,OAAO,IAAI,CAAC,aAAa,CAAC,UAAU,EAAE,UAAU,EAAE,UAAU,CAAC;QAC/D,CAAC,CAAC,CACH;IACL;AAEQ,IAAA,aAAa,CAAC,CAAS,EAAE,CAAS,EAAE,CAAS,EAAA;QACnD,IAAI,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC;QAC9B,IAAI,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;AACrD,QAAA,OAAO,GAAG,OAAO,GAAG,OAAO,IAAI,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC;AAC/C,QAAA,OAAO,GAAG,OAAO,GAAG,OAAO,IAAI,IAAI,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC;QAE/C,OAAO;AACL,YAAA,CAAC,EAAE,OAAO;AACV,YAAA,CAAC,EAAE,CAAC;AACJ,YAAA,CAAC,EAAE;SACJ;IACH;IAEQ,gBAAgB,GAAA;AACtB,QAAA,IAAI;YACF,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,CAAC,QAAQ,CAAC;AAC/C,YAAA,MAAM,OAAO,GAAG,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,UAAU,CAAC,oBAAoB,CAAC;YACrF,OAAO,CAAC,CAAC,OAAO;QAClB;AAAE,QAAA,MAAM;AACN,YAAA,OAAO,KAAK;QACd;IACF;+GAtHW,iCAAiC,EAAA,IAAA,EAAA,CAAA,EAAA,KAAA,EAAAA,EAAA,CAAA,0BAAA,EAAA,EAAA,EAAA,KAAA,EAAAC,IAAA,CAAA,yBAAA,EAAA,QAAA,EAAA,IAAA,EAAA,CAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA;AAAjC,IAAA,SAAA,IAAA,CAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,IAAA,EAAA,iCAAiC,6GAJjC,CAAC,0BAA0B,CAAC,EAAA,aAAA,EAAA,IAAA,EAAA,QAAA,EAAA,EAAA,EAAA,QAAA,ECpCzC,sNAQA,4CD8BY,uBAAuB,EAAA,QAAA,EAAA,sBAAA,EAAA,MAAA,EAAA,CAAA,SAAA,EAAA,WAAA,EAAA,aAAA,EAAA,cAAA,CAAA,EAAA,CAAA,EAAA,CAAA,CAAA;;4FAEtB,iCAAiC,EAAA,UAAA,EAAA,CAAA;kBAP7C,SAAS;+BACE,kCAAkC,EAAA,SAAA,EAEjC,CAAC,0BAA0B,CAAC,cAC3B,IAAI,EAAA,OAAA,EACP,CAAC,uBAAuB,CAAC,EAAA,QAAA,EAAA,sNAAA,EAAA;;0BAmB/B;;sBAhBF;;;ME3BU,mCAAmC,CAAA;IAI9C,WAAA,CACU,WAAwB,EACxB,IAAY,EAAA;QADZ,IAAA,CAAA,WAAW,GAAX,WAAW;QACX,IAAA,CAAA,IAAI,GAAJ,IAAI;IACX;AAEH,IAAA,YAAY,CACV,MAAmC,EAAA;AAEnC,QAAA,IAAI,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE;YACxB,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;AAC3C,YAAA,OAAO,IAAI;QACb;AACA,QAAA,OAAO,KAAK;IACd;IAEA,QAAQ,GAAA;QACN,IAAI,CAAC,QAAQ,EAAE;IACjB;IAEQ,QAAQ,GAAA;QACd,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,WAAW,CAAC;AAClD,QAAA,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC;QACnD,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC;IACxC;AAEQ,IAAA,UAAU,CAAC,WAAwB,EAAA;QACzC,OAAO,WAAW,CAAC,KAAK,CAAC;AACvB,YAAA,WAAW,EAAE,CAAC,cAAc,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC;AACxD,YAAA,WAAW,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC;AACvB,YAAA,UAAU,EAAE,CAAC,IAAI,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;AACtE,SAAA,CAAC;IACJ;+GAnCW,mCAAmC,EAAA,IAAA,EAAA,CAAA,EAAA,KAAA,EAAA,EAAA,CAAA,WAAA,EAAA,EAAA,EAAA,KAAA,EAAA,EAAA,CAAA,MAAA,EAAA,CAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,SAAA,EAAA,CAAA,CAAA;AAAnC,IAAA,SAAA,IAAA,CAAA,IAAA,GAAA,EAAA,CAAA,oBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,IAAA,EAAA,mCAAmC,4HCdhD,swCAiCA,EAAA,YAAA,EAAA,CAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EDrBY,UAAU,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,qBAAA,EAAA,QAAA,EAAA,6BAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,aAAA,EAAA,QAAA,EAAA,8CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,cAAA,EAAA,QAAA,EAAA,QAAA,EAAA,MAAA,EAAA,CAAA,SAAA,EAAA,OAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,uBAAA,EAAA,QAAA,EAAA,QAAA,EAAA,MAAA,EAAA,CAAA,SAAA,EAAA,OAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,4BAAA,EAAA,QAAA,EAAA,uGAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,0BAAA,EAAA,QAAA,EAAA,6GAAA,EAAA,MAAA,EAAA,CAAA,aAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,eAAA,EAAA,QAAA,EAAA,2CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,oBAAA,EAAA,QAAA,EAAA,0FAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,kBAAA,EAAA,QAAA,EAAA,gBAAA,EAAA,MAAA,EAAA,CAAA,UAAA,EAAA,YAAA,EAAA,YAAA,EAAA,cAAA,EAAA,QAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,iCAAA,EAAA,QAAA,EAAA,yCAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,kBAAA,EAAA,QAAA,EAAA,aAAA,EAAA,MAAA,EAAA,CAAA,WAAA,CAAA,EAAA,OAAA,EAAA,CAAA,UAAA,CAAA,EAAA,QAAA,EAAA,CAAA,QAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,WAAA,EAAA,IAAA,EAAA,EAAA,CAAA,eAAA,EAAA,QAAA,EAAA,mBAAA,EAAA,MAAA,EAAA,CAAA,iBAAA,EAAA,UAAA,EAAA,SAAA,CAAA,EAAA,OAAA,EAAA,CAAA,eAAA,CAAA,EAAA,EAAA,EAAA,IAAA,EAAA,UAAA,EAAA,IAAA,EAAE,aAAa,EAAA,EAAA,EAAA,IAAA,EAAA,MAAA,EAAA,IAAA,EAAA,EAAA,CAAA,gBAAA,EAAA,IAAA,EAAA,WAAA,EAAA,CAAA,EAAA,aAAA,EAFpB,CAAC,EAAE,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC,EAAA,CAAA,CAAA;;4FAIxD,mCAAmC,EAAA,UAAA,EAAA,CAAA;kBAP/C,SAAS;AACE,YAAA,IAAA,EAAA,CAAA,EAAA,QAAA,EAAA,oCAAoC,iBAE/B,CAAC,EAAE,OAAO,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC,cACvD,IAAI,EAAA,OAAA,EACP,CAAC,UAAU,EAAE,aAAa,CAAC,EAAA,QAAA,EAAA,swCAAA,EAAA;;sBAGnC;;;AEfH;;AAEG;;;;"}