@dexteel/mesf-core 7.20.1 → 7.21.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.
- package/.release-please-manifest.json +1 -1
- package/CHANGELOG.md +7 -0
- package/dist/index.esm.js +147 -11
- package/dist/index.esm.js.map +1 -1
- package/dist/pages/trendings-v2/TrendingsPageV2.d.ts +2 -1
- package/dist/pages/trendings-v2/components/chart/models/TrendingModelsV2.d.ts +1 -0
- package/dist/pages/trendings-v2/components/chart/sections/HeaderSectionV2.d.ts +3 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [7.21.0](https://github.com/dexteel/mesf-core-frontend/compare/@dexteel/mesf-core-v7.20.1...@dexteel/mesf-core-v7.21.0) (2026-04-24)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### Features
|
|
7
|
+
|
|
8
|
+
* **trendings-v2:** add stepped mode and URL state sync ([d87f8b6](https://github.com/dexteel/mesf-core-frontend/commit/d87f8b6f1e22b46d2a32b7e59017a4f62a9b0323))
|
|
9
|
+
|
|
3
10
|
## [7.20.1](https://github.com/dexteel/mesf-core-frontend/compare/@dexteel/mesf-core-v7.20.0...@dexteel/mesf-core-v7.20.1) (2026-04-20)
|
|
4
11
|
|
|
5
12
|
|
package/dist/index.esm.js
CHANGED
|
@@ -11851,19 +11851,21 @@ const dateNavigator = (startDate, endDate, scope, operator, current = false) =>
|
|
|
11851
11851
|
return { newStartDate, newEndDate };
|
|
11852
11852
|
};
|
|
11853
11853
|
|
|
11854
|
-
const HeaderSectionV2 = React__default.memo(({ autoRefresh, setAutoRefresh, setChartOptions, chartInstance }) => {
|
|
11854
|
+
const HeaderSectionV2 = React__default.memo(({ autoRefresh, setAutoRefresh, setChartOptions, setAggregationMode, chartInstance, }) => {
|
|
11855
11855
|
const queryClient = useQueryClient();
|
|
11856
11856
|
const { state: { timeScopeStart, timeScopeEnd, scope, viewSelected, views }, actions: { setTotalScope, setViewSelected }, } = useTrendingContextV2();
|
|
11857
11857
|
const [customOptions, setCustomOptions] = useState({
|
|
11858
11858
|
showGridLines: true,
|
|
11859
11859
|
showSymbols: false,
|
|
11860
|
-
smoothLines:
|
|
11860
|
+
smoothLines: false,
|
|
11861
|
+
steppedLines: true,
|
|
11861
11862
|
showLegend: false,
|
|
11862
11863
|
showTooltip: true,
|
|
11863
11864
|
combinedView: false,
|
|
11864
11865
|
showToolbox: true,
|
|
11865
11866
|
showYAxisNames: true,
|
|
11866
11867
|
});
|
|
11868
|
+
const [aggregationMode, setAggregationModeState] = useState("avg");
|
|
11867
11869
|
// View management state
|
|
11868
11870
|
const [viewModalMode, setViewModalMode] = useState(null);
|
|
11869
11871
|
const [viewForModal, setViewForModal] = useState(null);
|
|
@@ -11980,6 +11982,11 @@ const HeaderSectionV2 = React__default.memo(({ autoRefresh, setAutoRefresh, setC
|
|
|
11980
11982
|
setChartOptions(customOptions);
|
|
11981
11983
|
}
|
|
11982
11984
|
}, [customOptions, setChartOptions]);
|
|
11985
|
+
useEffect(() => {
|
|
11986
|
+
if (setAggregationMode) {
|
|
11987
|
+
setAggregationMode(aggregationMode);
|
|
11988
|
+
}
|
|
11989
|
+
}, [aggregationMode, setAggregationMode]);
|
|
11983
11990
|
return (React__default.createElement(React__default.Fragment, null,
|
|
11984
11991
|
React__default.createElement(Grid2, { size: 12, container: true, spacing: 1, justifyContent: "space-between", alignItems: "center", style: { height: "auto" } },
|
|
11985
11992
|
React__default.createElement(Grid2, { size: { md: 5, sm: 12, xs: 12 }, container: true, justifyContent: "flex-start", alignItems: "center", wrap: "wrap" },
|
|
@@ -12061,17 +12068,20 @@ const HeaderSectionV2 = React__default.memo(({ autoRefresh, setAutoRefresh, setC
|
|
|
12061
12068
|
...(customOptions.showGridLines ? ["grid"] : []),
|
|
12062
12069
|
...(customOptions.showSymbols ? ["symbols"] : []),
|
|
12063
12070
|
...(customOptions.smoothLines ? ["smooth"] : []),
|
|
12071
|
+
...(customOptions.steppedLines ? ["stepped"] : []),
|
|
12064
12072
|
...(customOptions.showTooltip ? ["tooltip"] : []),
|
|
12065
12073
|
...(customOptions.showToolbox ? ["toolbox"] : []),
|
|
12066
12074
|
...(customOptions.showYAxisNames ? ["yAxisNames"] : []),
|
|
12067
12075
|
], onChange: (e) => {
|
|
12068
12076
|
const selected = e.target.value;
|
|
12069
|
-
setCustomOptions((prevOptions) => (Object.assign(Object.assign({}, prevOptions), { showGridLines: selected.includes("grid"), showSymbols: selected.includes("symbols"), smoothLines: selected.includes("smooth")
|
|
12077
|
+
setCustomOptions((prevOptions) => (Object.assign(Object.assign({}, prevOptions), { showGridLines: selected.includes("grid"), showSymbols: selected.includes("symbols"), smoothLines: selected.includes("smooth") &&
|
|
12078
|
+
!selected.includes("stepped"), steppedLines: selected.includes("stepped"), showTooltip: selected.includes("tooltip"), showToolbox: selected.includes("toolbox"), showYAxisNames: selected.includes("yAxisNames") })));
|
|
12070
12079
|
}, renderValue: (selected) => {
|
|
12071
12080
|
const labels = {
|
|
12072
12081
|
grid: "Grid",
|
|
12073
12082
|
symbols: "Symbols",
|
|
12074
12083
|
smooth: "Smooth",
|
|
12084
|
+
stepped: "Stepped",
|
|
12075
12085
|
tooltip: "Tooltip",
|
|
12076
12086
|
toolbox: "Toolbox",
|
|
12077
12087
|
yAxisNames: "Y-Axis Names",
|
|
@@ -12089,6 +12099,9 @@ const HeaderSectionV2 = React__default.memo(({ autoRefresh, setAutoRefresh, setC
|
|
|
12089
12099
|
React__default.createElement(MenuItem, { value: "smooth", style: { padding: 0 } },
|
|
12090
12100
|
React__default.createElement(Checkbox, { checked: customOptions.smoothLines, size: "small" }),
|
|
12091
12101
|
React__default.createElement(ListItemText, null, "Smooth")),
|
|
12102
|
+
React__default.createElement(MenuItem, { value: "stepped", style: { padding: 0 } },
|
|
12103
|
+
React__default.createElement(Checkbox, { checked: customOptions.steppedLines, size: "small" }),
|
|
12104
|
+
React__default.createElement(ListItemText, null, "Stepped")),
|
|
12092
12105
|
React__default.createElement(MenuItem, { value: "tooltip", style: { padding: 0 } },
|
|
12093
12106
|
React__default.createElement(Checkbox, { checked: customOptions.showTooltip, size: "small" }),
|
|
12094
12107
|
React__default.createElement(ListItemText, null, "Tooltip")),
|
|
@@ -12098,6 +12111,15 @@ const HeaderSectionV2 = React__default.memo(({ autoRefresh, setAutoRefresh, setC
|
|
|
12098
12111
|
React__default.createElement(MenuItem, { value: "yAxisNames", style: { padding: 0 } },
|
|
12099
12112
|
React__default.createElement(Checkbox, { checked: customOptions.showYAxisNames, size: "small" }),
|
|
12100
12113
|
React__default.createElement(ListItemText, null, "Y-Axis Names"))))),
|
|
12114
|
+
React__default.createElement(Box, { sx: { minWidth: 150 } },
|
|
12115
|
+
React__default.createElement(FormControl, { fullWidth: true, size: "small" },
|
|
12116
|
+
React__default.createElement(Select, { value: aggregationMode, onChange: (e) => {
|
|
12117
|
+
setAggregationModeState(e.target.value);
|
|
12118
|
+
}, renderValue: (selected) => selected === "last"
|
|
12119
|
+
? "Aggregation: Last value"
|
|
12120
|
+
: "Aggregation: Average" },
|
|
12121
|
+
React__default.createElement(MenuItem, { value: "avg" }, "Average"),
|
|
12122
|
+
React__default.createElement(MenuItem, { value: "last" }, "Last value")))),
|
|
12101
12123
|
React__default.createElement(Divider, { orientation: "vertical", flexItem: true }),
|
|
12102
12124
|
React__default.createElement(FormControlLabel, { checked: customOptions.combinedView, control: React__default.createElement(Switch, { color: "primary", size: "small" }), label: React__default.createElement("span", { style: { fontSize: "0.75rem", fontWeight: 600 } }, "Combined"), style: { margin: "0" }, onChange: (e, checked) => {
|
|
12103
12125
|
setCustomOptions((prevOptions) => (Object.assign(Object.assign({}, prevOptions), { combinedView: checked })));
|
|
@@ -14513,7 +14535,8 @@ const TrendingChartV2 = ({ series = [], customOptions, isLoading = false, onChar
|
|
|
14513
14535
|
const opts = customOptions || {
|
|
14514
14536
|
showGridLines: true,
|
|
14515
14537
|
showSymbols: false,
|
|
14516
|
-
smoothLines:
|
|
14538
|
+
smoothLines: false,
|
|
14539
|
+
steppedLines: true,
|
|
14517
14540
|
showLegend: true,
|
|
14518
14541
|
showTooltip: true,
|
|
14519
14542
|
combinedView: false,
|
|
@@ -15057,7 +15080,8 @@ const TrendingChartV2 = ({ series = [], customOptions, isLoading = false, onChar
|
|
|
15057
15080
|
xAxisIndex: 0,
|
|
15058
15081
|
yAxisIndex: idx, // Map to corresponding analog yAxis
|
|
15059
15082
|
data: s.data,
|
|
15060
|
-
smooth: opts.smoothLines,
|
|
15083
|
+
smooth: opts.steppedLines ? false : opts.smoothLines,
|
|
15084
|
+
step: opts.steppedLines ? "end" : undefined,
|
|
15061
15085
|
symbol: opts.showSymbols ? "circle" : "none",
|
|
15062
15086
|
sampling: "lttb",
|
|
15063
15087
|
show: s.visible,
|
|
@@ -15126,10 +15150,25 @@ const TrendingChartV2 = ({ series = [], customOptions, isLoading = false, onChar
|
|
|
15126
15150
|
if (!params || params.length === 0)
|
|
15127
15151
|
return "";
|
|
15128
15152
|
const date = new Date(params[0].value[0]);
|
|
15153
|
+
const formatTooltipValue = (value) => {
|
|
15154
|
+
if (value === null || value === undefined || value === "") {
|
|
15155
|
+
return "-";
|
|
15156
|
+
}
|
|
15157
|
+
const numericValue = Number(value);
|
|
15158
|
+
if (!Number.isFinite(numericValue)) {
|
|
15159
|
+
return String(value);
|
|
15160
|
+
}
|
|
15161
|
+
if (Number.isInteger(numericValue)) {
|
|
15162
|
+
return numericValue.toString();
|
|
15163
|
+
}
|
|
15164
|
+
return numericValue.toLocaleString(undefined, {
|
|
15165
|
+
maximumFractionDigits: 5,
|
|
15166
|
+
});
|
|
15167
|
+
};
|
|
15129
15168
|
let content = `<div style="font-weight: bold; margin-bottom: 5px;">${date.toLocaleString()}</div>`;
|
|
15130
15169
|
params.forEach((param) => {
|
|
15131
15170
|
const marker = `<span style="display:inline-block;width:10px;height:10px;border-radius:50%;background-color:${param.color};margin-right:5px;"></span>`;
|
|
15132
|
-
content += `<div>${marker}${param.seriesName}: ${param.value[1]}</div>`;
|
|
15171
|
+
content += `<div>${marker}${param.seriesName}: ${formatTooltipValue(param.value[1])}</div>`;
|
|
15133
15172
|
});
|
|
15134
15173
|
return content;
|
|
15135
15174
|
},
|
|
@@ -15499,9 +15538,9 @@ const useSearchViewTags = ({ viewId }) => {
|
|
|
15499
15538
|
enabled: viewId !== null,
|
|
15500
15539
|
});
|
|
15501
15540
|
};
|
|
15502
|
-
const useSearchSeries = ({ start, end, tagIds, autoRefresh = false, }) => {
|
|
15541
|
+
const useSearchSeries = ({ start, end, tagIds, aggregationMode, autoRefresh = false, }) => {
|
|
15503
15542
|
return useQuery({
|
|
15504
|
-
queryKey: ["series-v2", start, end, tagIds],
|
|
15543
|
+
queryKey: ["series-v2", start, end, tagIds, aggregationMode],
|
|
15505
15544
|
queryFn: (_a) => __awaiter(void 0, [_a], void 0, function* ({ signal }) {
|
|
15506
15545
|
try {
|
|
15507
15546
|
if (!tagIds || tagIds.length === 0) {
|
|
@@ -15512,6 +15551,7 @@ const useSearchSeries = ({ start, end, tagIds, autoRefresh = false, }) => {
|
|
|
15512
15551
|
end: end || new Date().getTime(),
|
|
15513
15552
|
tagIds,
|
|
15514
15553
|
sampleCount: 1000,
|
|
15554
|
+
aggregationMode,
|
|
15515
15555
|
}, {
|
|
15516
15556
|
signal,
|
|
15517
15557
|
});
|
|
@@ -15528,14 +15568,60 @@ const useSearchSeries = ({ start, end, tagIds, autoRefresh = false, }) => {
|
|
|
15528
15568
|
enabled: tagIds.length > 0,
|
|
15529
15569
|
});
|
|
15530
15570
|
};
|
|
15571
|
+
const VALID_SCOPE_VALUES = [
|
|
15572
|
+
"10 min",
|
|
15573
|
+
"1 hour",
|
|
15574
|
+
"4 hours",
|
|
15575
|
+
"12 hours",
|
|
15576
|
+
"1 day",
|
|
15577
|
+
"10 days",
|
|
15578
|
+
"custom",
|
|
15579
|
+
];
|
|
15580
|
+
const getInitialUrlParams = () => {
|
|
15581
|
+
if (typeof window === "undefined") {
|
|
15582
|
+
return {
|
|
15583
|
+
viewId: null,
|
|
15584
|
+
start: null,
|
|
15585
|
+
end: null,
|
|
15586
|
+
period: null,
|
|
15587
|
+
};
|
|
15588
|
+
}
|
|
15589
|
+
const searchParams = new URLSearchParams(window.location.search);
|
|
15590
|
+
const viewParam = Number(searchParams.get("view"));
|
|
15591
|
+
const startParam = Number(searchParams.get("start"));
|
|
15592
|
+
const endParam = Number(searchParams.get("end"));
|
|
15593
|
+
const periodParam = searchParams.get("period");
|
|
15594
|
+
return {
|
|
15595
|
+
viewId: Number.isInteger(viewParam) ? viewParam : null,
|
|
15596
|
+
start: Number.isFinite(startParam) ? startParam : null,
|
|
15597
|
+
end: Number.isFinite(endParam) ? endParam : null,
|
|
15598
|
+
period: VALID_SCOPE_VALUES.includes(periodParam)
|
|
15599
|
+
? periodParam
|
|
15600
|
+
: null,
|
|
15601
|
+
};
|
|
15602
|
+
};
|
|
15531
15603
|
const TrendingsPageV2 = () => {
|
|
15532
15604
|
const [autoRefresh, setAutoRefresh] = useState(false);
|
|
15533
|
-
const [chartOptions, setChartOptions] = useState(
|
|
15605
|
+
const [chartOptions, setChartOptions] = useState({
|
|
15606
|
+
showGridLines: true,
|
|
15607
|
+
showSymbols: false,
|
|
15608
|
+
smoothLines: false,
|
|
15609
|
+
steppedLines: true,
|
|
15610
|
+
showLegend: false,
|
|
15611
|
+
showTooltip: true,
|
|
15612
|
+
combinedView: false,
|
|
15613
|
+
showToolbox: true,
|
|
15614
|
+
showYAxisNames: true,
|
|
15615
|
+
});
|
|
15616
|
+
const [aggregationMode, setAggregationMode] = useState("avg");
|
|
15534
15617
|
const [error, setError] = useState("");
|
|
15535
15618
|
const [viewId, setViewId] = useState(null);
|
|
15536
15619
|
const [chartInstance, setChartInstance] = useState(null);
|
|
15537
15620
|
const [dataLoadedTrigger, setDataLoadedTrigger] = useState(0);
|
|
15538
|
-
const { state: { viewSelected, viewTags, timeScopeStart, timeScopeEnd }, actions: { setViews, setViewTagsAndRefetch, setViewSelected, setSeriesMinMax, resetCursors, }, } = useTrendingContextV2();
|
|
15621
|
+
const { state: { viewSelected, viewTags, timeScopeStart, timeScopeEnd, scope }, actions: { setViews, setViewTagsAndRefetch, setViewSelected, setTotalScope, setSeriesMinMax, resetCursors, }, } = useTrendingContextV2();
|
|
15622
|
+
const initialUrlParamsRef = useRef(getInitialUrlParams());
|
|
15623
|
+
const initialTimeScopeAppliedRef = useRef(false);
|
|
15624
|
+
const initialViewSelectionResolvedRef = useRef(false);
|
|
15539
15625
|
// Fetch views
|
|
15540
15626
|
const { data: views, isLoading: viewsLoading, isError: viewsIsError, error: viewsError, isSuccess: viewSuccess, } = useSearchViews({ autoRefresh });
|
|
15541
15627
|
// Fetch view tags
|
|
@@ -15580,6 +15666,7 @@ const TrendingsPageV2 = () => {
|
|
|
15580
15666
|
start: timeScopeStart.getTime(),
|
|
15581
15667
|
end: timeScopeEnd.getTime(),
|
|
15582
15668
|
tagIds: queryTagIds,
|
|
15669
|
+
aggregationMode,
|
|
15583
15670
|
autoRefresh,
|
|
15584
15671
|
});
|
|
15585
15672
|
// Filter and reorder series to match current viewTags order
|
|
@@ -15634,6 +15721,21 @@ const TrendingsPageV2 = () => {
|
|
|
15634
15721
|
}, [series, tagIds, queryTagIds, viewTags]);
|
|
15635
15722
|
// Calculate overall min/max values from filtered series data
|
|
15636
15723
|
const seriesMinMaxData = useSeriesMinMax(filteredSeries, tagIds);
|
|
15724
|
+
// Apply explicit time range from URL once on initial load
|
|
15725
|
+
useEffect(() => {
|
|
15726
|
+
if (initialTimeScopeAppliedRef.current)
|
|
15727
|
+
return;
|
|
15728
|
+
const { start, end, period } = initialUrlParamsRef.current;
|
|
15729
|
+
initialTimeScopeAppliedRef.current = true;
|
|
15730
|
+
if (start === null || end === null || period === null || start >= end) {
|
|
15731
|
+
return;
|
|
15732
|
+
}
|
|
15733
|
+
setTotalScope({
|
|
15734
|
+
start: new Date(start),
|
|
15735
|
+
end: new Date(end),
|
|
15736
|
+
scope: period,
|
|
15737
|
+
});
|
|
15738
|
+
}, [setTotalScope]);
|
|
15637
15739
|
// Load initial view when views are fetched
|
|
15638
15740
|
useEffect(() => {
|
|
15639
15741
|
if (!viewSuccess || !views || !Array.isArray(views))
|
|
@@ -15642,12 +15744,26 @@ const TrendingsPageV2 = () => {
|
|
|
15642
15744
|
setViews(views);
|
|
15643
15745
|
// Only set initial view if none is selected
|
|
15644
15746
|
if (!viewSelected) {
|
|
15747
|
+
const initialViewId = initialUrlParamsRef.current.viewId;
|
|
15748
|
+
if (!initialViewSelectionResolvedRef.current && initialViewId !== null) {
|
|
15749
|
+
initialViewSelectionResolvedRef.current = true;
|
|
15750
|
+
const urlView = views.find((view) => view.ViewId === initialViewId);
|
|
15751
|
+
if (urlView) {
|
|
15752
|
+
setViewId(urlView.ViewId);
|
|
15753
|
+
setViewSelected(urlView);
|
|
15754
|
+
return;
|
|
15755
|
+
}
|
|
15756
|
+
}
|
|
15645
15757
|
const lastCreated = views.reduce((prev, current) => prev && prev.ViewId > current.ViewId ? prev : current, null);
|
|
15646
15758
|
if (lastCreated) {
|
|
15759
|
+
initialViewSelectionResolvedRef.current = true;
|
|
15647
15760
|
setViewId(lastCreated.ViewId);
|
|
15648
15761
|
setViewSelected(lastCreated);
|
|
15649
15762
|
}
|
|
15650
15763
|
}
|
|
15764
|
+
else {
|
|
15765
|
+
initialViewSelectionResolvedRef.current = true;
|
|
15766
|
+
}
|
|
15651
15767
|
}, [viewSuccess, views, viewSelected, setViews, setViewSelected]);
|
|
15652
15768
|
// Update viewId when viewSelected changes (e.g., from LoadViewModal)
|
|
15653
15769
|
useEffect(() => {
|
|
@@ -15655,6 +15771,26 @@ const TrendingsPageV2 = () => {
|
|
|
15655
15771
|
setViewId(viewSelected.ViewId);
|
|
15656
15772
|
}
|
|
15657
15773
|
}, [viewSelected]);
|
|
15774
|
+
useEffect(() => {
|
|
15775
|
+
if (typeof window === "undefined" ||
|
|
15776
|
+
!initialTimeScopeAppliedRef.current ||
|
|
15777
|
+
!initialViewSelectionResolvedRef.current) {
|
|
15778
|
+
return;
|
|
15779
|
+
}
|
|
15780
|
+
const searchParams = new URLSearchParams(window.location.search);
|
|
15781
|
+
if (viewSelected) {
|
|
15782
|
+
searchParams.set("view", String(viewSelected.ViewId));
|
|
15783
|
+
}
|
|
15784
|
+
else {
|
|
15785
|
+
searchParams.delete("view");
|
|
15786
|
+
}
|
|
15787
|
+
searchParams.set("start", String(timeScopeStart.getTime()));
|
|
15788
|
+
searchParams.set("end", String(timeScopeEnd.getTime()));
|
|
15789
|
+
searchParams.set("period", scope);
|
|
15790
|
+
const newSearch = searchParams.toString();
|
|
15791
|
+
const newUrl = `${window.location.pathname}${newSearch ? `?${newSearch}` : ""}${window.location.hash}`;
|
|
15792
|
+
window.history.replaceState(null, "", newUrl);
|
|
15793
|
+
}, [viewSelected, timeScopeStart, timeScopeEnd, scope]);
|
|
15658
15794
|
// Load view tags when fetched - ONLY when viewId changes, not on every data refetch
|
|
15659
15795
|
// This preserves local order changes (from drag-and-drop) until a new view is loaded
|
|
15660
15796
|
const loadedViewIdRef = useRef(null);
|
|
@@ -15806,7 +15942,7 @@ const TrendingsPageV2 = () => {
|
|
|
15806
15942
|
} },
|
|
15807
15943
|
React__default.createElement(CircularProgress, { size: "3rem" }))),
|
|
15808
15944
|
React__default.createElement("div", { style: { flexShrink: 0 } },
|
|
15809
|
-
React__default.createElement(HeaderSectionV2, { autoRefresh: autoRefresh, setAutoRefresh: setAutoRefresh, setChartOptions: setChartOptions, chartInstance: chartInstance })),
|
|
15945
|
+
React__default.createElement(HeaderSectionV2, { autoRefresh: autoRefresh, setAutoRefresh: setAutoRefresh, setChartOptions: setChartOptions, setAggregationMode: setAggregationMode, chartInstance: chartInstance })),
|
|
15810
15946
|
React__default.createElement(Divider, { sx: { my: 2 } }),
|
|
15811
15947
|
React__default.createElement("div", { style: {
|
|
15812
15948
|
flexGrow: 1,
|