@flozy/editor 3.8.0 → 3.8.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/Editor/ChatEditor.js +55 -45
- package/dist/Editor/Editor.css +1 -12
- package/dist/Editor/Elements/Accordion/AccordionSummary.js +4 -15
- package/dist/Editor/Elements/Emoji/EmojiPicker.js +4 -2
- package/dist/Editor/common/MentionsPopup/MentionsListCard.js +6 -1
- package/dist/Editor/common/StyleBuilder/fieldTypes/bannerSpacing.js +20 -26
- package/dist/Editor/common/StyleBuilder/fieldTypes/borderRadius.js +16 -18
- package/dist/Editor/helper/theme.js +1 -2
- package/dist/Editor/utils/draftToSlate.js +1 -1
- package/dist/Editor/utils/helper.js +22 -12
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React, { useCallback, useMemo, useRef, useState, useEffect, useImperativeHandle, forwardRef } from "react";
|
|
2
2
|
import { Editable, Slate, ReactEditor } from 'slate-react';
|
|
3
|
-
import { createEditor, Transforms } from 'slate';
|
|
3
|
+
import { createEditor, Transforms, Editor } from 'slate';
|
|
4
4
|
import { useDebounce } from "use-debounce";
|
|
5
5
|
import withCommon from "./hooks/withCommon";
|
|
6
6
|
import { getBlock, getMarked } from "./utils/chatEditor/SlateUtilityFunctions";
|
|
@@ -31,7 +31,12 @@ const ChatEditor = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
31
31
|
} = props;
|
|
32
32
|
const classes = usePopupStyle(theme);
|
|
33
33
|
const convertedContent = draftToSlate({
|
|
34
|
-
data: content
|
|
34
|
+
data: content && content?.length > 0 ? content : [{
|
|
35
|
+
type: 'paragraph',
|
|
36
|
+
children: [{
|
|
37
|
+
text: ''
|
|
38
|
+
}]
|
|
39
|
+
}]
|
|
35
40
|
});
|
|
36
41
|
const [isInteracted, setIsInteracted] = useState(false);
|
|
37
42
|
const [value, setValue] = useState(convertedContent);
|
|
@@ -47,57 +52,62 @@ const ChatEditor = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
47
52
|
useImperativeHandle(ref, () => ({
|
|
48
53
|
emojiClick: emoji => {
|
|
49
54
|
if (editor) {
|
|
55
|
+
ReactEditor.focus(editor);
|
|
50
56
|
insertEmoji(editor, emoji?.native, editor.selection);
|
|
51
|
-
if (editor.selection) {
|
|
52
|
-
// const path = editor.selection.anchor.path;
|
|
53
|
-
// const offset = editor.selection.anchor.offset + emoji?.native.length;
|
|
54
|
-
const position = {
|
|
55
|
-
anchor: {
|
|
56
|
-
path: [0],
|
|
57
|
-
offset: 0
|
|
58
|
-
},
|
|
59
|
-
focus: {
|
|
60
|
-
path: [0],
|
|
61
|
-
offset: 0
|
|
62
|
-
}
|
|
63
|
-
};
|
|
64
|
-
// Create a new selection
|
|
65
|
-
Transforms.select(editor, position);
|
|
66
|
-
}
|
|
67
57
|
ReactEditor.focus(editor);
|
|
68
58
|
}
|
|
69
59
|
},
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
60
|
+
submitChat: () => {
|
|
61
|
+
const {
|
|
62
|
+
value: strVal,
|
|
63
|
+
...restVal
|
|
64
|
+
} = getOnSaveData(value);
|
|
65
|
+
onsubmit(false, {
|
|
66
|
+
strVal,
|
|
67
|
+
restVal
|
|
68
|
+
});
|
|
74
69
|
},
|
|
75
70
|
// Focus enable
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
71
|
+
enableFocus: () => {
|
|
72
|
+
if (editor) {
|
|
73
|
+
const position = {
|
|
74
|
+
anchor: {
|
|
75
|
+
path: [0],
|
|
76
|
+
offset: 0
|
|
77
|
+
},
|
|
78
|
+
focus: {
|
|
79
|
+
path: [0],
|
|
80
|
+
offset: 0
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
Transforms.select(editor, position);
|
|
84
|
+
ReactEditor.focus(editor);
|
|
85
|
+
}
|
|
86
|
+
},
|
|
87
|
+
clearAll: (content = null, clear = true) => {
|
|
88
88
|
if (!editor) return;
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
89
|
+
try {
|
|
90
|
+
if (clear) {
|
|
91
|
+
while (editor.children.length > 0) {
|
|
92
|
+
Transforms.removeNodes(editor, {
|
|
93
|
+
at: [0]
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
const newValue = draftToSlate({
|
|
98
|
+
data: content
|
|
92
99
|
});
|
|
100
|
+
setValue(newValue);
|
|
101
|
+
setTimeout(() => {
|
|
102
|
+
if (editor.children.length === 0) {
|
|
103
|
+
Transforms.insertNodes(editor, newValue);
|
|
104
|
+
}
|
|
105
|
+
Transforms.select(editor, Editor.end(editor, []));
|
|
106
|
+
ReactEditor.focus(editor);
|
|
107
|
+
}, 300);
|
|
108
|
+
} catch {
|
|
109
|
+
console.log("error:");
|
|
93
110
|
}
|
|
94
|
-
Transforms.insertNodes(editor, {
|
|
95
|
-
type: 'paragraph',
|
|
96
|
-
children: [{
|
|
97
|
-
text: ''
|
|
98
|
-
}]
|
|
99
|
-
});
|
|
100
|
-
ReactEditor.focus(editor);
|
|
101
111
|
}
|
|
102
112
|
}));
|
|
103
113
|
useEffect(() => {
|
|
@@ -105,7 +115,7 @@ const ChatEditor = /*#__PURE__*/forwardRef((props, ref) => {
|
|
|
105
115
|
setValue(draftToSlate({
|
|
106
116
|
data: content
|
|
107
117
|
}));
|
|
108
|
-
}, [
|
|
118
|
+
}, [content]);
|
|
109
119
|
useEffect(() => {
|
|
110
120
|
if (JSON.stringify(loadedValue) !== JSON.stringify(deboundedValue) && isInteracted && onSave) {
|
|
111
121
|
const {
|
package/dist/Editor/Editor.css
CHANGED
|
@@ -830,17 +830,6 @@ blockquote {
|
|
|
830
830
|
text-align: center;
|
|
831
831
|
}
|
|
832
832
|
|
|
833
|
-
.removeScroll::-webkit-outer-spin-button,
|
|
834
|
-
.removeScroll::-webkit-inner-spin-button {
|
|
835
|
-
-webkit-appearance: none;
|
|
836
|
-
margin: 0;
|
|
837
|
-
}
|
|
838
|
-
|
|
839
|
-
/* For Firefox */
|
|
840
|
-
.removeScroll {
|
|
841
|
-
-moz-appearance: textfield;
|
|
842
|
-
}
|
|
843
|
-
|
|
844
833
|
.borderInput:focus-visible {
|
|
845
834
|
outline: none !important;
|
|
846
835
|
}
|
|
@@ -890,7 +879,7 @@ blockquote {
|
|
|
890
879
|
}
|
|
891
880
|
|
|
892
881
|
.sliderInput {
|
|
893
|
-
width:
|
|
882
|
+
width: 66px;
|
|
894
883
|
padding: 2px 10px;
|
|
895
884
|
margin-left: 18px;
|
|
896
885
|
box-shadow: 0px 4px 16px 0px #0000000d;
|
|
@@ -5,8 +5,6 @@ import AccordionTitlePopup from "./AccordionTitlePopup";
|
|
|
5
5
|
import { IconButton, Tooltip } from "@mui/material";
|
|
6
6
|
import { GridSettingsIcon } from "../../common/iconslist";
|
|
7
7
|
import { useEditorSelection } from "../../hooks/useMouseMove";
|
|
8
|
-
import { getTRBLBreakPoints, getBreakPointsValue } from "../../helper/theme";
|
|
9
|
-
import { Box } from "@mui/material";
|
|
10
8
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
11
9
|
import { jsxs as _jsxs } from "react/jsx-runtime";
|
|
12
10
|
const AccordionSummary = props => {
|
|
@@ -27,9 +25,7 @@ const AccordionSummary = props => {
|
|
|
27
25
|
const {
|
|
28
26
|
textColor,
|
|
29
27
|
bgColor,
|
|
30
|
-
borderColor
|
|
31
|
-
borderRadius,
|
|
32
|
-
bannerSpacing
|
|
28
|
+
borderColor
|
|
33
29
|
} = element;
|
|
34
30
|
const ToolBar = () => {
|
|
35
31
|
return selected && !showTool ? /*#__PURE__*/_jsx("div", {
|
|
@@ -66,23 +62,16 @@ const AccordionSummary = props => {
|
|
|
66
62
|
const onClose = () => {
|
|
67
63
|
setOpenSettings(false);
|
|
68
64
|
};
|
|
69
|
-
return /*#__PURE__*/_jsxs(
|
|
65
|
+
return /*#__PURE__*/_jsxs("div", {
|
|
70
66
|
className: `accordion-summary-container`,
|
|
71
67
|
...attributes,
|
|
72
|
-
|
|
68
|
+
style: {
|
|
73
69
|
width: "100%",
|
|
74
70
|
position: "relative",
|
|
75
71
|
backgroundColor: bgColor,
|
|
76
72
|
border: `1px solid ${borderColor}`,
|
|
77
|
-
color: textColor
|
|
78
|
-
borderRadius: {
|
|
79
|
-
...getBreakPointsValue(borderRadius || {}, null, "overrideBorderRadius", true)
|
|
80
|
-
},
|
|
81
|
-
padding: {
|
|
82
|
-
...getTRBLBreakPoints(bannerSpacing)
|
|
83
|
-
}
|
|
73
|
+
color: textColor
|
|
84
74
|
},
|
|
85
|
-
component: "div",
|
|
86
75
|
children: [children, !readOnly && /*#__PURE__*/_jsx(ToolBar, {}), openSetttings ? /*#__PURE__*/_jsx(AccordionTitlePopup, {
|
|
87
76
|
element: element,
|
|
88
77
|
onSave: onSave,
|
|
@@ -4,12 +4,14 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
4
4
|
import { Fragment as _Fragment } from "react/jsx-runtime";
|
|
5
5
|
const EmojiPicker = props => {
|
|
6
6
|
const {
|
|
7
|
-
onEmojiSelect
|
|
7
|
+
onEmojiSelect,
|
|
8
|
+
onClose
|
|
8
9
|
} = props;
|
|
9
10
|
return /*#__PURE__*/_jsx(_Fragment, {
|
|
10
11
|
children: /*#__PURE__*/_jsx(Picker, {
|
|
11
12
|
data: data,
|
|
12
|
-
onEmojiSelect: onEmojiSelect
|
|
13
|
+
onEmojiSelect: onEmojiSelect,
|
|
14
|
+
onClickOutside: onClose
|
|
13
15
|
})
|
|
14
16
|
});
|
|
15
17
|
};
|
|
@@ -39,7 +39,12 @@ const MentionsListCard = props => {
|
|
|
39
39
|
},
|
|
40
40
|
alt: name,
|
|
41
41
|
children: /*#__PURE__*/_jsx(Avatar, {
|
|
42
|
-
|
|
42
|
+
sx: {
|
|
43
|
+
background: 'linear-gradient(90deg, #5351FC 0%, #19A9FC 100%)'
|
|
44
|
+
},
|
|
45
|
+
alt: name,
|
|
46
|
+
src: avatar_filename,
|
|
47
|
+
children: !avatar_filename && name && name.charAt(0).toUpperCase()
|
|
43
48
|
})
|
|
44
49
|
}), /*#__PURE__*/_jsx(Box, {
|
|
45
50
|
sx: {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import React from "react";
|
|
2
2
|
import { Checkbox, FormControlLabel, Grid, Slider, Typography, Box } from "@mui/material";
|
|
3
3
|
import { squreStyle } from "./radiusStyle";
|
|
4
|
-
import { getBreakPointsValue
|
|
4
|
+
import { getBreakPointsValue } from "../../../helper/theme";
|
|
5
5
|
import useWindowResize from "../../../hooks/useWindowResize";
|
|
6
6
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
7
7
|
import { jsxs as _jsxs } from "react/jsx-runtime";
|
|
@@ -78,12 +78,10 @@ const BannerSpacing = props => {
|
|
|
78
78
|
component: "input",
|
|
79
79
|
sx: classes.sapcingInput,
|
|
80
80
|
name: "top",
|
|
81
|
-
value: !lockSpacing ? "" :
|
|
82
|
-
className: "sliderInput
|
|
81
|
+
value: !lockSpacing ? "" : value?.top || 0,
|
|
82
|
+
className: "sliderInput",
|
|
83
83
|
disabled: !lockSpacing,
|
|
84
|
-
onChange: handleChange
|
|
85
|
-
type: "number",
|
|
86
|
-
placeholder: "0"
|
|
84
|
+
onChange: handleChange
|
|
87
85
|
})]
|
|
88
86
|
}), /*#__PURE__*/_jsx(FormControlLabel, {
|
|
89
87
|
className: "ccheckbox-primary",
|
|
@@ -125,54 +123,50 @@ const BannerSpacing = props => {
|
|
|
125
123
|
children: [/*#__PURE__*/_jsx("div", {
|
|
126
124
|
className: "bannerSpaceBoxTop",
|
|
127
125
|
children: /*#__PURE__*/_jsx("input", {
|
|
128
|
-
type: "
|
|
126
|
+
type: "text",
|
|
129
127
|
name: "top",
|
|
130
|
-
value:
|
|
131
|
-
className: "borderInput
|
|
128
|
+
value: value?.top,
|
|
129
|
+
className: "borderInput",
|
|
132
130
|
style: {
|
|
133
131
|
...squreStyle.topRight
|
|
134
132
|
},
|
|
135
|
-
onChange: handleChange
|
|
136
|
-
placeholder: "0"
|
|
133
|
+
onChange: handleChange
|
|
137
134
|
})
|
|
138
135
|
}), /*#__PURE__*/_jsx("div", {
|
|
139
136
|
className: "bannerSpaceBoxRight",
|
|
140
137
|
children: /*#__PURE__*/_jsx("input", {
|
|
141
|
-
type: "
|
|
138
|
+
type: "text",
|
|
142
139
|
name: "right",
|
|
143
|
-
value:
|
|
144
|
-
className: "borderInput
|
|
140
|
+
value: value?.right,
|
|
141
|
+
className: "borderInput",
|
|
145
142
|
style: {
|
|
146
143
|
...squreStyle.bottomLeft
|
|
147
144
|
},
|
|
148
|
-
onChange: handleChange
|
|
149
|
-
placeholder: "0"
|
|
145
|
+
onChange: handleChange
|
|
150
146
|
})
|
|
151
147
|
}), /*#__PURE__*/_jsx("div", {
|
|
152
148
|
className: "bannerSpaceBoxBottom",
|
|
153
149
|
children: /*#__PURE__*/_jsx("input", {
|
|
154
|
-
type: "
|
|
150
|
+
type: "text",
|
|
155
151
|
name: "bottom",
|
|
156
|
-
value:
|
|
157
|
-
className: "borderInput
|
|
152
|
+
value: value?.bottom,
|
|
153
|
+
className: "borderInput",
|
|
158
154
|
style: {
|
|
159
155
|
...squreStyle.bottomRight
|
|
160
156
|
},
|
|
161
|
-
onChange: handleChange
|
|
162
|
-
placeholder: "0"
|
|
157
|
+
onChange: handleChange
|
|
163
158
|
})
|
|
164
159
|
}), /*#__PURE__*/_jsx("div", {
|
|
165
160
|
className: "bannerSpaceBoxLeft",
|
|
166
161
|
children: /*#__PURE__*/_jsx("input", {
|
|
167
|
-
type: "
|
|
162
|
+
type: "text",
|
|
168
163
|
name: "left",
|
|
169
|
-
className: "borderInput
|
|
170
|
-
value:
|
|
164
|
+
className: "borderInput",
|
|
165
|
+
value: value?.left,
|
|
171
166
|
style: {
|
|
172
167
|
...squreStyle.topLeft
|
|
173
168
|
},
|
|
174
|
-
onChange: handleChange
|
|
175
|
-
placeholder: "0"
|
|
169
|
+
onChange: handleChange
|
|
176
170
|
})
|
|
177
171
|
})]
|
|
178
172
|
})
|
|
@@ -2,7 +2,7 @@ import React from "react";
|
|
|
2
2
|
import { Grid, Typography, Slider, FormControlLabel, Checkbox, Box } from "@mui/material";
|
|
3
3
|
import { radiusStyle } from "./radiusStyle";
|
|
4
4
|
import useWindowResize from "../../../hooks/useWindowResize";
|
|
5
|
-
import { getBreakPointsValue
|
|
5
|
+
import { getBreakPointsValue } from "../../../helper/theme";
|
|
6
6
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
7
7
|
import { jsxs as _jsxs } from "react/jsx-runtime";
|
|
8
8
|
const BORDER_RADIUS_KEYS = ["topLeft", "topRight", "bottomLeft", "bottomRight"];
|
|
@@ -80,13 +80,11 @@ const BorderRadius = props => {
|
|
|
80
80
|
}), /*#__PURE__*/_jsx(Box, {
|
|
81
81
|
sx: classes.sapcingInput,
|
|
82
82
|
component: "input",
|
|
83
|
-
value: !lockRadius ? "" :
|
|
84
|
-
className: "sliderInput
|
|
83
|
+
value: !lockRadius ? "" : value?.topLeft || 0,
|
|
84
|
+
className: "sliderInput",
|
|
85
85
|
name: "topLeft",
|
|
86
86
|
disabled: !lockRadius,
|
|
87
|
-
onChange: handleChange
|
|
88
|
-
type: "number",
|
|
89
|
-
placeholder: "0"
|
|
87
|
+
onChange: handleChange
|
|
90
88
|
})]
|
|
91
89
|
}), /*#__PURE__*/_jsx(FormControlLabel, {
|
|
92
90
|
className: "ccheckbox-primary",
|
|
@@ -127,10 +125,10 @@ const BorderRadius = props => {
|
|
|
127
125
|
borderRadius: `${value?.topLeft}px ${value?.topRight}px ${value?.bottomLeft}px ${value?.bottomRight}px`
|
|
128
126
|
},
|
|
129
127
|
children: [/*#__PURE__*/_jsx("input", {
|
|
130
|
-
type: "
|
|
128
|
+
type: "text",
|
|
131
129
|
name: "topLeft",
|
|
132
|
-
value:
|
|
133
|
-
className: "borderInput
|
|
130
|
+
value: value?.topLeft,
|
|
131
|
+
className: "borderInput",
|
|
134
132
|
placeholder: "0",
|
|
135
133
|
style: {
|
|
136
134
|
...radiusStyle.topLeft,
|
|
@@ -138,10 +136,10 @@ const BorderRadius = props => {
|
|
|
138
136
|
},
|
|
139
137
|
onChange: handleChange
|
|
140
138
|
}), /*#__PURE__*/_jsx("input", {
|
|
141
|
-
type: "
|
|
139
|
+
type: "text",
|
|
142
140
|
name: "topRight",
|
|
143
|
-
value:
|
|
144
|
-
className: "borderInput
|
|
141
|
+
value: value?.topRight,
|
|
142
|
+
className: "borderInput",
|
|
145
143
|
placeholder: "0",
|
|
146
144
|
style: {
|
|
147
145
|
...radiusStyle.topRight,
|
|
@@ -150,10 +148,10 @@ const BorderRadius = props => {
|
|
|
150
148
|
},
|
|
151
149
|
onChange: handleChange
|
|
152
150
|
}), /*#__PURE__*/_jsx("input", {
|
|
153
|
-
type: "
|
|
151
|
+
type: "text",
|
|
154
152
|
name: "bottomLeft",
|
|
155
|
-
value:
|
|
156
|
-
className: "borderInput
|
|
153
|
+
value: value?.bottomLeft,
|
|
154
|
+
className: "borderInput",
|
|
157
155
|
placeholder: "0",
|
|
158
156
|
style: {
|
|
159
157
|
...radiusStyle.bottomLeft,
|
|
@@ -162,10 +160,10 @@ const BorderRadius = props => {
|
|
|
162
160
|
},
|
|
163
161
|
onChange: handleChange
|
|
164
162
|
}), /*#__PURE__*/_jsx("input", {
|
|
165
|
-
type: "
|
|
163
|
+
type: "text",
|
|
166
164
|
name: "bottomRight",
|
|
167
|
-
value:
|
|
168
|
-
className: "borderInput
|
|
165
|
+
value: value?.bottomRight,
|
|
166
|
+
className: "borderInput",
|
|
169
167
|
placeholder: "0",
|
|
170
168
|
style: {
|
|
171
169
|
...radiusStyle.bottomRight,
|
|
@@ -216,6 +216,17 @@ const getScrollElement = () => {
|
|
|
216
216
|
const scrollFrom = isSlateWrapperScroll ? slateWrapper : window;
|
|
217
217
|
return scrollFrom;
|
|
218
218
|
};
|
|
219
|
+
const handleLinkBtnClick = (e, props) => {
|
|
220
|
+
if (e) {
|
|
221
|
+
e.preventDefault();
|
|
222
|
+
e.stopPropagation();
|
|
223
|
+
}
|
|
224
|
+
if (props.target) {
|
|
225
|
+
window.open(props.href);
|
|
226
|
+
} else {
|
|
227
|
+
window.location.href = props.href;
|
|
228
|
+
}
|
|
229
|
+
};
|
|
219
230
|
export const handleLinkType = (url, linkType, readOnly, openInNewTab, onClick = () => {}) => {
|
|
220
231
|
const props = {};
|
|
221
232
|
if (!readOnly) {
|
|
@@ -306,23 +317,22 @@ export const handleLinkType = (url, linkType, readOnly, openInNewTab, onClick =
|
|
|
306
317
|
|
|
307
318
|
// for iphone fix
|
|
308
319
|
if (props.component === "a" && props.href) {
|
|
309
|
-
|
|
320
|
+
const isMobile = getDevice(window.innerWidth) === "xs";
|
|
321
|
+
if (isMobile) {
|
|
310
322
|
props.component = "button"; // iphone is opening two tabs, on open in new tab because of a tag.
|
|
311
323
|
}
|
|
312
324
|
|
|
325
|
+
let touchEndClicked = false;
|
|
313
326
|
props.onTouchEnd = e => {
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
e.preventDefault();
|
|
317
|
-
e.stopPropagation();
|
|
318
|
-
}
|
|
319
|
-
if (props.target) {
|
|
320
|
-
window.open(props.href);
|
|
321
|
-
} else {
|
|
322
|
-
window.location.href = props.href;
|
|
323
|
-
}
|
|
327
|
+
touchEndClicked = true;
|
|
328
|
+
handleLinkBtnClick(e, props);
|
|
324
329
|
};
|
|
325
|
-
props.onClick =
|
|
330
|
+
props.onClick = e => {
|
|
331
|
+
// This condition is used for mobile preview in the page editor.
|
|
332
|
+
// 'touchEnd' will not work in the mobile page preview.
|
|
333
|
+
if (!touchEndClicked && isMobile) {
|
|
334
|
+
handleLinkBtnClick(e, props);
|
|
335
|
+
}
|
|
326
336
|
return false;
|
|
327
337
|
};
|
|
328
338
|
}
|