@gravity-ui/charts 1.36.0 → 1.37.2
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/dist/cjs/components/ChartInner/index.js +1 -1
- package/dist/cjs/components/ChartInner/useChartInnerProps.d.ts +24 -24
- package/dist/cjs/components/ChartInner/useChartInnerProps.js +57 -17
- package/dist/cjs/components/Legend/index.d.ts +2 -1
- package/dist/cjs/components/Legend/index.js +17 -16
- package/dist/cjs/components/Tooltip/ChartTooltipContent.js +8 -1
- package/dist/cjs/components/Tooltip/styles.css +1 -1
- package/dist/cjs/hooks/useAxis/index.d.ts +2 -1
- package/dist/cjs/hooks/useAxis/index.js +9 -2
- package/dist/cjs/hooks/useChartDimensions/index.d.ts +2 -1
- package/dist/cjs/hooks/useChartDimensions/index.js +27 -13
- package/dist/cjs/hooks/useRangeSlider/index.js +2 -1
- package/dist/cjs/hooks/useRangeSlider/types.d.ts +2 -1
- package/dist/cjs/hooks/useSeries/prepare-legend.d.ts +4 -2
- package/dist/cjs/hooks/useSeries/prepare-legend.js +76 -55
- package/dist/cjs/hooks/useSeries/types.d.ts +1 -13
- package/dist/cjs/types/chart/tooltip.d.ts +2 -0
- package/dist/cjs/types/chart-ui.d.ts +15 -0
- package/dist/cjs/utils/chart/index.js +4 -2
- package/dist/esm/components/ChartInner/index.js +1 -1
- package/dist/esm/components/ChartInner/useChartInnerProps.d.ts +17 -17
- package/dist/esm/components/ChartInner/useChartInnerProps.js +57 -17
- package/dist/esm/components/Legend/index.d.ts +2 -1
- package/dist/esm/components/Legend/index.js +17 -16
- package/dist/esm/components/Tooltip/ChartTooltipContent.js +8 -1
- package/dist/esm/components/Tooltip/styles.css +1 -1
- package/dist/esm/hooks/useAxis/index.d.ts +2 -1
- package/dist/esm/hooks/useAxis/index.js +9 -2
- package/dist/esm/hooks/useChartDimensions/index.d.ts +2 -1
- package/dist/esm/hooks/useChartDimensions/index.js +27 -13
- package/dist/esm/hooks/useRangeSlider/index.js +2 -1
- package/dist/esm/hooks/useRangeSlider/types.d.ts +2 -1
- package/dist/esm/hooks/useSeries/prepare-legend.d.ts +4 -2
- package/dist/esm/hooks/useSeries/prepare-legend.js +76 -55
- package/dist/esm/hooks/useSeries/types.d.ts +1 -13
- package/dist/esm/types/chart/tooltip.d.ts +2 -0
- package/dist/esm/types/chart-ui.d.ts +15 -0
- package/dist/esm/utils/chart/index.js +4 -2
- package/package.json +1 -1
|
@@ -3,10 +3,11 @@ import { isAxisRelatedSeries } from '../../utils';
|
|
|
3
3
|
import { getBoundsWidth } from './utils';
|
|
4
4
|
export { getBoundsWidth } from './utils';
|
|
5
5
|
const getBottomOffset = (args) => {
|
|
6
|
-
|
|
6
|
+
var _a;
|
|
7
|
+
const { hasAxisRelatedSeries, preparedLegend, legendConfig, preparedXAxis } = args;
|
|
7
8
|
let result = 0;
|
|
8
9
|
if ((preparedLegend === null || preparedLegend === void 0 ? void 0 : preparedLegend.enabled) && preparedLegend.position === 'bottom') {
|
|
9
|
-
result +=
|
|
10
|
+
result += ((_a = legendConfig === null || legendConfig === void 0 ? void 0 : legendConfig.height) !== null && _a !== void 0 ? _a : 0) + preparedLegend.margin;
|
|
10
11
|
}
|
|
11
12
|
if (!(preparedXAxis === null || preparedXAxis === void 0 ? void 0 : preparedXAxis.visible)) {
|
|
12
13
|
return result;
|
|
@@ -24,26 +25,29 @@ const getBottomOffset = (args) => {
|
|
|
24
25
|
}
|
|
25
26
|
return result;
|
|
26
27
|
};
|
|
27
|
-
const getTopOffset = ({ preparedLegend }) => {
|
|
28
|
+
const getTopOffset = ({ preparedLegend, legendConfig, }) => {
|
|
29
|
+
var _a;
|
|
28
30
|
if ((preparedLegend === null || preparedLegend === void 0 ? void 0 : preparedLegend.enabled) && preparedLegend.position === 'top') {
|
|
29
|
-
return
|
|
31
|
+
return ((_a = legendConfig === null || legendConfig === void 0 ? void 0 : legendConfig.height) !== null && _a !== void 0 ? _a : 0) + preparedLegend.margin;
|
|
30
32
|
}
|
|
31
33
|
return 0;
|
|
32
34
|
};
|
|
33
|
-
const getRightOffset = ({ preparedLegend }) => {
|
|
35
|
+
const getRightOffset = ({ preparedLegend, legendConfig, }) => {
|
|
36
|
+
var _a;
|
|
34
37
|
if ((preparedLegend === null || preparedLegend === void 0 ? void 0 : preparedLegend.enabled) && preparedLegend.position === 'right') {
|
|
35
|
-
return
|
|
38
|
+
return ((_a = legendConfig === null || legendConfig === void 0 ? void 0 : legendConfig.width) !== null && _a !== void 0 ? _a : 0) + preparedLegend.margin;
|
|
36
39
|
}
|
|
37
40
|
return 0;
|
|
38
41
|
};
|
|
39
|
-
const getLeftOffset = ({ preparedLegend }) => {
|
|
42
|
+
const getLeftOffset = ({ preparedLegend, legendConfig, }) => {
|
|
43
|
+
var _a;
|
|
40
44
|
if ((preparedLegend === null || preparedLegend === void 0 ? void 0 : preparedLegend.enabled) && preparedLegend.position === 'left') {
|
|
41
|
-
return
|
|
45
|
+
return ((_a = legendConfig === null || legendConfig === void 0 ? void 0 : legendConfig.width) !== null && _a !== void 0 ? _a : 0) + preparedLegend.margin;
|
|
42
46
|
}
|
|
43
47
|
return 0;
|
|
44
48
|
};
|
|
45
49
|
export const useChartDimensions = (args) => {
|
|
46
|
-
const { height, margin, preparedLegend, preparedSeries, preparedXAxis, preparedYAxis, width } = args;
|
|
50
|
+
const { height, margin, preparedLegend, preparedSeries, preparedXAxis, preparedYAxis, width, legendConfig, } = args;
|
|
47
51
|
return React.useMemo(() => {
|
|
48
52
|
const hasAxisRelatedSeries = preparedSeries.some(isAxisRelatedSeries);
|
|
49
53
|
const boundsWidth = getBoundsWidth({ chartWidth: width, chartMargin: margin, preparedYAxis });
|
|
@@ -51,12 +55,22 @@ export const useChartDimensions = (args) => {
|
|
|
51
55
|
hasAxisRelatedSeries,
|
|
52
56
|
preparedLegend,
|
|
53
57
|
preparedXAxis,
|
|
58
|
+
legendConfig,
|
|
54
59
|
});
|
|
55
|
-
const topOffset = getTopOffset({ preparedLegend });
|
|
56
|
-
const rightOffset = getRightOffset({ preparedLegend });
|
|
57
|
-
const leftOffset = getLeftOffset({ preparedLegend });
|
|
60
|
+
const topOffset = getTopOffset({ preparedLegend, legendConfig });
|
|
61
|
+
const rightOffset = getRightOffset({ preparedLegend, legendConfig });
|
|
62
|
+
const leftOffset = getLeftOffset({ preparedLegend, legendConfig });
|
|
58
63
|
const boundsHeight = height - margin.top - margin.bottom - bottomOffset - topOffset;
|
|
59
64
|
const adjustedBoundsWidth = boundsWidth - rightOffset - leftOffset;
|
|
60
65
|
return { boundsWidth: adjustedBoundsWidth, boundsHeight };
|
|
61
|
-
}, [
|
|
66
|
+
}, [
|
|
67
|
+
height,
|
|
68
|
+
margin,
|
|
69
|
+
preparedLegend,
|
|
70
|
+
legendConfig,
|
|
71
|
+
preparedSeries,
|
|
72
|
+
preparedXAxis,
|
|
73
|
+
preparedYAxis,
|
|
74
|
+
width,
|
|
75
|
+
]);
|
|
62
76
|
};
|
|
@@ -17,7 +17,7 @@ const CLIP_PATH_BY_SERIES_TYPE = {
|
|
|
17
17
|
[SERIES_TYPE.Scatter]: true,
|
|
18
18
|
};
|
|
19
19
|
export function useRangeSlider(props) {
|
|
20
|
-
const { boundsWidth, boundsOffsetLeft, clipPathId, height, htmlLayout, onUpdate, preparedChart, preparedLegend, preparedSeries, preparedSeriesOptions, preparedRangeSlider, rangeSliderState, width, xAxis, yAxis, } = props;
|
|
20
|
+
const { boundsWidth, boundsOffsetLeft, clipPathId, height, htmlLayout, onUpdate, preparedChart, preparedLegend, legendConfig, preparedSeries, preparedSeriesOptions, preparedRangeSlider, rangeSliderState, width, xAxis, yAxis, } = props;
|
|
21
21
|
const filteredPreparedSeries = React.useMemo(() => {
|
|
22
22
|
return preparedSeries.filter((s) => {
|
|
23
23
|
if ('rangeSlider' in s && !s.rangeSlider.visible) {
|
|
@@ -31,6 +31,7 @@ export function useRangeSlider(props) {
|
|
|
31
31
|
height,
|
|
32
32
|
preparedChart,
|
|
33
33
|
preparedLegend,
|
|
34
|
+
legendConfig,
|
|
34
35
|
preparedSeries,
|
|
35
36
|
preparedSeriesOptions,
|
|
36
37
|
width,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ChartXAxis, ChartYAxis } from '../../types';
|
|
1
|
+
import type { ChartXAxis, ChartYAxis, LegendConfig } from '../../types';
|
|
2
2
|
import type { PreparedRangeSlider, PreparedXAxis, PreparedYAxis } from '../useAxis/types';
|
|
3
3
|
import type { ChartScale } from '../useAxisScales/types';
|
|
4
4
|
import type { BrushSelection, UseBrushProps } from '../useBrush/types';
|
|
@@ -16,6 +16,7 @@ export interface RangeSliderProps {
|
|
|
16
16
|
onUpdate: (nextRangeSliderState?: RangeSliderState) => void;
|
|
17
17
|
preparedChart: PreparedChart;
|
|
18
18
|
preparedLegend: PreparedLegend | null;
|
|
19
|
+
legendConfig: LegendConfig | undefined;
|
|
19
20
|
preparedRangeSlider: PreparedRangeSlider;
|
|
20
21
|
preparedSeries: PreparedSeries[];
|
|
21
22
|
preparedSeriesOptions: PreparedSeriesOptions;
|
|
@@ -11,7 +11,7 @@ export declare function getLegendComponents(args: {
|
|
|
11
11
|
chartMargin: PreparedChart['margin'];
|
|
12
12
|
series: PreparedSeries[];
|
|
13
13
|
preparedLegend: PreparedLegend;
|
|
14
|
-
}): {
|
|
14
|
+
}): Promise<{
|
|
15
15
|
legendConfig: {
|
|
16
16
|
offset: {
|
|
17
17
|
left: number;
|
|
@@ -24,6 +24,8 @@ export declare function getLegendComponents(args: {
|
|
|
24
24
|
}[];
|
|
25
25
|
} | undefined;
|
|
26
26
|
maxWidth: number;
|
|
27
|
+
height: number;
|
|
28
|
+
width: number;
|
|
27
29
|
};
|
|
28
30
|
legendItems: LegendItem[][];
|
|
29
|
-
}
|
|
31
|
+
}>;
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import { select } from 'd3';
|
|
2
1
|
import { groupBy } from 'lodash';
|
|
3
2
|
import clone from 'lodash/clone';
|
|
4
3
|
import get from 'lodash/get';
|
|
5
4
|
import merge from 'lodash/merge';
|
|
6
5
|
import { CONTINUOUS_LEGEND_SIZE, legendDefaults } from '../../constants';
|
|
7
|
-
import { getDefaultColorStops, getDomainForContinuousColorScale, getLabelsSize } from '../../utils';
|
|
6
|
+
import { getDefaultColorStops, getDomainForContinuousColorScale, getLabelsSize, getTextSizeFn, getTextWithElipsis, } from '../../utils';
|
|
8
7
|
export async function getPreparedLegend(args) {
|
|
9
8
|
var _a, _b, _c, _d, _e, _f, _g;
|
|
10
9
|
const { legend, series } = args;
|
|
@@ -87,68 +86,81 @@ function getFlattenLegendItems(series, preparedLegend) {
|
|
|
87
86
|
return Object.values(grouped).reduce((acc, items) => {
|
|
88
87
|
const s = items.find((item) => item.legend.enabled);
|
|
89
88
|
if (s) {
|
|
90
|
-
acc.push(Object.assign(Object.assign({}, s), { id: s.legend.groupId, name: s.legend.itemText, height: preparedLegend.lineHeight, symbol: s.legend.symbol }));
|
|
89
|
+
acc.push(Object.assign(Object.assign({}, s), { id: s.legend.groupId, name: s.legend.itemText, text: s.legend.itemText, height: preparedLegend.lineHeight, symbol: s.legend.symbol }));
|
|
91
90
|
}
|
|
92
91
|
return acc;
|
|
93
92
|
}, []);
|
|
94
93
|
}
|
|
95
|
-
function getGroupedLegendItems(args) {
|
|
94
|
+
async function getGroupedLegendItems(args) {
|
|
96
95
|
const { maxLegendWidth, items, preparedLegend } = args;
|
|
97
96
|
const result = [[]];
|
|
98
|
-
const bodySelection = select(document.body);
|
|
99
97
|
let textWidthsInLine = [0];
|
|
100
98
|
let lineIndex = 0;
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
99
|
+
const getLegendItemTextSize = getTextSizeFn({ style: preparedLegend.itemStyle });
|
|
100
|
+
for (let i = 0; i < items.length; i++) {
|
|
101
|
+
const item = items[i];
|
|
102
|
+
const resultItem = clone(item);
|
|
103
|
+
resultItem.text = item.name;
|
|
104
|
+
const maxTextWidth = maxLegendWidth - resultItem.symbol.width - resultItem.symbol.padding;
|
|
105
|
+
let textHeight = 0;
|
|
106
|
+
let textWidth = 0;
|
|
107
|
+
if (preparedLegend.html) {
|
|
108
|
+
const textSize = await getLabelsSize({
|
|
109
|
+
labels: [resultItem.text],
|
|
110
|
+
html: true,
|
|
111
|
+
style: preparedLegend.itemStyle,
|
|
112
|
+
});
|
|
113
|
+
textHeight = textSize.maxHeight;
|
|
114
|
+
textWidth = textSize.maxWidth;
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
const textSize = await getLegendItemTextSize(resultItem.text);
|
|
118
|
+
textHeight = textSize.height;
|
|
119
|
+
textWidth = textSize.width;
|
|
120
|
+
}
|
|
121
|
+
resultItem.height = textHeight;
|
|
122
|
+
if (textWidth > maxTextWidth) {
|
|
123
|
+
if (preparedLegend.html) {
|
|
118
124
|
resultItem.overflowed = true;
|
|
119
|
-
resultItem.textWidth =
|
|
120
|
-
maxLegendWidth - resultItem.symbol.width - resultItem.symbol.padding;
|
|
125
|
+
resultItem.textWidth = maxTextWidth;
|
|
121
126
|
}
|
|
122
127
|
else {
|
|
123
|
-
resultItem.
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
128
|
+
resultItem.text = await getTextWithElipsis({
|
|
129
|
+
text: resultItem.text,
|
|
130
|
+
getTextWidth: async (s) => (await getLegendItemTextSize(s)).width,
|
|
131
|
+
maxWidth: maxTextWidth,
|
|
132
|
+
});
|
|
133
|
+
resultItem.textWidth = (await getLegendItemTextSize(resultItem.text)).width;
|
|
129
134
|
}
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
resultItem.textWidth = textWidth;
|
|
138
|
+
}
|
|
139
|
+
textWidthsInLine.push(textWidth);
|
|
140
|
+
const textsWidth = textWidthsInLine.reduce((acc, width) => acc + width, 0);
|
|
141
|
+
if (!result[lineIndex]) {
|
|
142
|
+
result[lineIndex] = [];
|
|
143
|
+
}
|
|
144
|
+
result[lineIndex].push(resultItem);
|
|
145
|
+
const symbolsWidth = result[lineIndex].reduce((acc, { symbol }) => {
|
|
146
|
+
return acc + symbol.width + symbol.padding;
|
|
147
|
+
}, 0);
|
|
148
|
+
const distancesWidth = (result[lineIndex].length - 1) * preparedLegend.itemDistance;
|
|
149
|
+
const isOverflowedAsOnlyItemInLine = resultItem.overflowed && result[lineIndex].length === 1;
|
|
150
|
+
const isCurrentLineOverMaxWidth = maxLegendWidth < textsWidth + symbolsWidth + distancesWidth;
|
|
151
|
+
if (isOverflowedAsOnlyItemInLine) {
|
|
152
|
+
lineIndex += 1;
|
|
153
|
+
textWidthsInLine = [];
|
|
154
|
+
}
|
|
155
|
+
else if (isCurrentLineOverMaxWidth) {
|
|
156
|
+
result[lineIndex].pop();
|
|
157
|
+
lineIndex += 1;
|
|
158
|
+
textWidthsInLine = [textWidth];
|
|
159
|
+
const nextLineIndex = lineIndex;
|
|
160
|
+
result[nextLineIndex] = [];
|
|
161
|
+
result[nextLineIndex].push(resultItem);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
152
164
|
return result;
|
|
153
165
|
}
|
|
154
166
|
function getPagination(args) {
|
|
@@ -227,7 +239,7 @@ function getMaxLegendHeight(args) {
|
|
|
227
239
|
}
|
|
228
240
|
return (chartHeight - chartMargin.top - chartMargin.bottom - preparedLegend.margin) / 2;
|
|
229
241
|
}
|
|
230
|
-
export function getLegendComponents(args) {
|
|
242
|
+
export async function getLegendComponents(args) {
|
|
231
243
|
const { chartWidth, chartHeight, chartMargin, series, preparedLegend } = args;
|
|
232
244
|
const isVerticalPosition = preparedLegend.position === 'right' || preparedLegend.position === 'left';
|
|
233
245
|
const maxLegendWidth = getMaxLegendWidth({
|
|
@@ -243,7 +255,7 @@ export function getLegendComponents(args) {
|
|
|
243
255
|
isVerticalPosition,
|
|
244
256
|
});
|
|
245
257
|
const flattenLegendItems = getFlattenLegendItems(series, preparedLegend);
|
|
246
|
-
const items = getGroupedLegendItems({
|
|
258
|
+
const items = await getGroupedLegendItems({
|
|
247
259
|
maxLegendWidth,
|
|
248
260
|
items: flattenLegendItems,
|
|
249
261
|
preparedLegend,
|
|
@@ -278,5 +290,14 @@ export function getLegendComponents(args) {
|
|
|
278
290
|
legendWidth: preparedLegend.width,
|
|
279
291
|
legendHeight: preparedLegend.height,
|
|
280
292
|
});
|
|
281
|
-
return {
|
|
293
|
+
return {
|
|
294
|
+
legendConfig: {
|
|
295
|
+
offset,
|
|
296
|
+
pagination,
|
|
297
|
+
maxWidth: maxLegendWidth,
|
|
298
|
+
height: preparedLegend.height,
|
|
299
|
+
width: preparedLegend.width,
|
|
300
|
+
},
|
|
301
|
+
legendItems: items,
|
|
302
|
+
};
|
|
282
303
|
}
|
|
@@ -44,25 +44,13 @@ export type LegendItem = {
|
|
|
44
44
|
color: string;
|
|
45
45
|
height: number;
|
|
46
46
|
name: string;
|
|
47
|
+
text: string;
|
|
47
48
|
symbol: PreparedLegendSymbol;
|
|
48
49
|
textWidth: number;
|
|
49
50
|
dashStyle?: DashStyle;
|
|
50
51
|
overflowed?: boolean;
|
|
51
52
|
visible?: boolean;
|
|
52
53
|
};
|
|
53
|
-
export type LegendConfig = {
|
|
54
|
-
offset: {
|
|
55
|
-
left: number;
|
|
56
|
-
top: number;
|
|
57
|
-
};
|
|
58
|
-
maxWidth: number;
|
|
59
|
-
pagination?: {
|
|
60
|
-
pages: {
|
|
61
|
-
start: number;
|
|
62
|
-
end: number;
|
|
63
|
-
}[];
|
|
64
|
-
};
|
|
65
|
-
};
|
|
66
54
|
export type PreparedHaloOptions = {
|
|
67
55
|
enabled: boolean;
|
|
68
56
|
opacity: number;
|
|
@@ -97,6 +97,8 @@ export interface ChartTooltipRendererArgs<T = MeaningfulAny> {
|
|
|
97
97
|
hoveredPlotBands?: AxisPlotBand[];
|
|
98
98
|
xAxis?: ChartXAxis | null;
|
|
99
99
|
yAxis?: ChartYAxis;
|
|
100
|
+
/** Formatting settings for tooltip header row (includes computed default). */
|
|
101
|
+
headerFormat?: ValueFormat | CustomFormat;
|
|
100
102
|
}
|
|
101
103
|
export interface ChartTooltipTotalsAggregationArgs<T = MeaningfulAny> extends ChartTooltipRendererArgs<T> {
|
|
102
104
|
}
|
|
@@ -27,3 +27,18 @@ export interface HtmlItem {
|
|
|
27
27
|
export interface ShapeDataWithHtmlItems {
|
|
28
28
|
htmlElements: HtmlItem[];
|
|
29
29
|
}
|
|
30
|
+
export type LegendConfig = {
|
|
31
|
+
offset: {
|
|
32
|
+
left: number;
|
|
33
|
+
top: number;
|
|
34
|
+
};
|
|
35
|
+
pagination?: {
|
|
36
|
+
pages: {
|
|
37
|
+
start: number;
|
|
38
|
+
end: number;
|
|
39
|
+
}[];
|
|
40
|
+
};
|
|
41
|
+
maxWidth: number;
|
|
42
|
+
height: number;
|
|
43
|
+
width: number;
|
|
44
|
+
};
|
|
@@ -107,8 +107,10 @@ export const getDomainDataYBySeries = (series) => {
|
|
|
107
107
|
let yValue = 0;
|
|
108
108
|
const points = seriesList.map((s) => s.data).flat();
|
|
109
109
|
sortBy(points, (p) => p.index).forEach((d) => {
|
|
110
|
-
|
|
111
|
-
|
|
110
|
+
if (!d.total) {
|
|
111
|
+
yValue += Number(d.y) || 0;
|
|
112
|
+
acc.push(yValue);
|
|
113
|
+
}
|
|
112
114
|
});
|
|
113
115
|
break;
|
|
114
116
|
}
|