@droppii-org/chat-sdk 0.1.38 → 0.1.39
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/components/biz-thread-detail/BizMessageList.d.ts.map +1 -1
- package/dist/components/biz-thread-detail/BizMessageList.js +2 -4
- package/dist/context/ChatContext.d.ts.map +1 -1
- package/dist/context/ChatContext.js +24 -20
- package/dist/hooks/global/useGlobalEvent.d.ts.map +1 -1
- package/dist/hooks/global/useGlobalEvent.js +5 -3
- package/dist/hooks/message/useMessage.d.ts.map +1 -1
- package/dist/hooks/message/useMessage.js +67 -35
- package/dist/screens/desk-message/index.d.ts.map +1 -1
- package/dist/screens/desk-message/index.js +3 -3
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"BizMessageList.d.ts","sourceRoot":"","sources":["../../../src/components/biz-thread-detail/BizMessageList.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"BizMessageList.d.ts","sourceRoot":"","sources":["../../../src/components/biz-thread-detail/BizMessageList.tsx"],"names":[],"mappings":"AAgBA,QAAA,MAAM,cAAc,+CAwEnB,CAAC;AAEF,eAAe,cAAc,CAAC"}
|
|
@@ -10,7 +10,6 @@ import { useMessageListScroll } from "../../hooks/message/useMessageListScroll";
|
|
|
10
10
|
import useBizConversationStore from "../../store/bizConversation";
|
|
11
11
|
import useConversationStore from "../../store/conversation";
|
|
12
12
|
import useAuthStore from "../../store/auth";
|
|
13
|
-
import { useIsSdkMessageReady } from "../../hooks/common/useIsSdkMessageReady";
|
|
14
13
|
import { isBizGroupChat } from "../../utils/bizConversation";
|
|
15
14
|
import emitter from "../../utils/events";
|
|
16
15
|
import BizMessageItem from "./item/BizMessageItem";
|
|
@@ -18,15 +17,14 @@ const BizMessageList = () => {
|
|
|
18
17
|
const { t } = useTranslation("biz-inbox");
|
|
19
18
|
const { user } = useChatContext();
|
|
20
19
|
const authUserID = useAuthStore((state) => state.userID);
|
|
21
|
-
const isSdkReady = useIsSdkMessageReady();
|
|
22
20
|
const conversation = useBizConversationStore((state) => state.conversationData);
|
|
23
21
|
const selectedConversationId = useConversationStore((state) => state.selectedConversationId);
|
|
24
22
|
const conversationId = selectedConversationId || (conversation === null || conversation === void 0 ? void 0 : conversation.conversationId) || "";
|
|
25
23
|
const isGroupChat = conversation ? isBizGroupChat(conversation) : false;
|
|
26
|
-
const messageController = useMessage(conversationId
|
|
24
|
+
const messageController = useMessage(conversationId);
|
|
27
25
|
const { scrollRef, loadMoreOldMessage, handleInfiniteScroll, scrollToBottomIfAtBottom, } = useMessageListScroll(Object.assign({ conversationId, userId: (user === null || user === void 0 ? void 0 : user.userID) || authUserID }, messageController));
|
|
28
26
|
const { loadState, moreOldLoading } = messageController;
|
|
29
|
-
const isMessageLoading = !conversationId ||
|
|
27
|
+
const isMessageLoading = !conversationId || loadState.initLoading;
|
|
30
28
|
useEffect(() => {
|
|
31
29
|
emitter.on("BIZ_CHAT_SCROLL_TO_BOTTOM_IF_AT_BOTTOM", scrollToBottomIfAtBottom);
|
|
32
30
|
return () => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ChatContext.d.ts","sourceRoot":"","sources":["../../src/context/ChatContext.tsx"],"names":[],"mappings":"AAEA,OAAO,sBAAsB,CAAC;AAG9B,OAAO,EACL,eAAe,EACf,iBAAiB,EAGlB,MAAM,cAAc,CAAC;AAStB,eAAO,MAAM,WAAW,0CAOtB,CAAC;AAEH,eAAO,MAAM,cAAc,uBAAgC,CAAC;AAE5D,eAAO,MAAM,YAAY,GAAI,sBAAsB,iBAAiB,
|
|
1
|
+
{"version":3,"file":"ChatContext.d.ts","sourceRoot":"","sources":["../../src/context/ChatContext.tsx"],"names":[],"mappings":"AAEA,OAAO,sBAAsB,CAAC;AAG9B,OAAO,EACL,eAAe,EACf,iBAAiB,EAGlB,MAAM,cAAc,CAAC;AAStB,eAAO,MAAM,WAAW,0CAOtB,CAAC;AAEH,eAAO,MAAM,cAAc,uBAAgC,CAAC;AAE5D,eAAO,MAAM,YAAY,GAAI,sBAAsB,iBAAiB,4CAqGnE,CAAC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
3
|
import "../styles/global.css";
|
|
4
|
-
import { createContext, useContext, useEffect, useState } from "react";
|
|
4
|
+
import { createContext, useContext, useEffect, useRef, useState } from "react";
|
|
5
5
|
import { ConnectStatus, SyncStatus, } from "../types/chat";
|
|
6
6
|
import { DChatSDK } from "../constants/sdk";
|
|
7
7
|
import MainLayout from "../layout";
|
|
@@ -12,7 +12,7 @@ const queryClient = new QueryClient();
|
|
|
12
12
|
export const ChatContext = createContext({
|
|
13
13
|
user: null,
|
|
14
14
|
connectStatus: ConnectStatus.Disconnected,
|
|
15
|
-
syncStatus: SyncStatus.
|
|
15
|
+
syncStatus: SyncStatus.Success,
|
|
16
16
|
getSelfUserInfo: () => { },
|
|
17
17
|
updateConnectStatus: () => { },
|
|
18
18
|
updateSyncStatus: () => { },
|
|
@@ -20,9 +20,10 @@ export const ChatContext = createContext({
|
|
|
20
20
|
export const useChatContext = () => useContext(ChatContext);
|
|
21
21
|
export const ChatProvider = ({ children, config }) => {
|
|
22
22
|
const [connectStatus, setConnectStatus] = useState(ConnectStatus.Disconnected);
|
|
23
|
-
const [syncStatus, setSyncStatus] = useState(SyncStatus.
|
|
23
|
+
const [syncStatus, setSyncStatus] = useState(SyncStatus.Success);
|
|
24
24
|
const [user, setUser] = useState(null);
|
|
25
25
|
const initAuthStore = useAuthStore((state) => state.initAuthStore);
|
|
26
|
+
const lastUserIdRef = useRef();
|
|
26
27
|
const setFallbackUserFromAuth = () => {
|
|
27
28
|
const { userID } = useAuthStore.getState();
|
|
28
29
|
if (!userID)
|
|
@@ -62,24 +63,27 @@ export const ChatProvider = ({ children, config }) => {
|
|
|
62
63
|
setSyncStatus(status);
|
|
63
64
|
};
|
|
64
65
|
useEffect(() => {
|
|
65
|
-
if (config)
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
66
|
+
if (!config)
|
|
67
|
+
return;
|
|
68
|
+
initAuthStore({
|
|
69
|
+
accessToken: config.accessToken,
|
|
70
|
+
apiAddress: config.apiAddr,
|
|
71
|
+
platformID: config.platformID,
|
|
72
|
+
userID: config.userID,
|
|
73
|
+
wsAddress: config.wsAddr,
|
|
74
|
+
applicationType: config.applicationType,
|
|
75
|
+
isCrm: config.isCrm,
|
|
76
|
+
});
|
|
77
|
+
setUser({
|
|
78
|
+
userID: config.userID,
|
|
79
|
+
nickname: "",
|
|
80
|
+
faceURL: "",
|
|
81
|
+
});
|
|
82
|
+
if (lastUserIdRef.current !== config.userID) {
|
|
83
|
+
lastUserIdRef.current = config.userID;
|
|
84
|
+
setConnectStatus(ConnectStatus.Disconnected);
|
|
81
85
|
}
|
|
82
|
-
}, [config]);
|
|
86
|
+
}, [config, initAuthStore]);
|
|
83
87
|
return (_jsx(ChatContext.Provider, { value: {
|
|
84
88
|
user,
|
|
85
89
|
connectStatus,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useGlobalEvent.d.ts","sourceRoot":"","sources":["../../../src/hooks/global/useGlobalEvent.ts"],"names":[],"mappings":"AAiCA,eAAO,MAAM,cAAc,
|
|
1
|
+
{"version":3,"file":"useGlobalEvent.d.ts","sourceRoot":"","sources":["../../../src/hooks/global/useGlobalEvent.ts"],"names":[],"mappings":"AAiCA,eAAO,MAAM,cAAc,YAuT1B,CAAC"}
|
|
@@ -25,6 +25,7 @@ export const useGlobalEvent = () => {
|
|
|
25
25
|
const { mutate: refetchChatToken } = useRefetchChatToken();
|
|
26
26
|
const accessToken = useAuthStore((state) => state.accessToken);
|
|
27
27
|
const chatToken = useAuthStore((state) => state.chatToken);
|
|
28
|
+
const userID = useAuthStore((state) => state.userID);
|
|
28
29
|
const apiAddress = useAuthStore((state) => {
|
|
29
30
|
return state.apiAddress;
|
|
30
31
|
});
|
|
@@ -254,8 +255,9 @@ export const useGlobalEvent = () => {
|
|
|
254
255
|
}
|
|
255
256
|
}, [accessToken, apiAddress]);
|
|
256
257
|
useEffect(() => {
|
|
257
|
-
if (
|
|
258
|
-
|
|
258
|
+
if (!chatToken || !apiAddress || !userID) {
|
|
259
|
+
return;
|
|
259
260
|
}
|
|
260
|
-
|
|
261
|
+
loginCheck();
|
|
262
|
+
}, [chatToken, apiAddress, userID]);
|
|
261
263
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useMessage.d.ts","sourceRoot":"","sources":["../../../src/hooks/message/useMessage.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,WAAW,EACX,WAAW,EAEZ,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"useMessage.d.ts","sourceRoot":"","sources":["../../../src/hooks/message/useMessage.ts"],"names":[],"mappings":"AACA,OAAO,EAEL,WAAW,EACX,WAAW,EAEZ,MAAM,yBAAyB,CAAC;AAUjC,eAAO,MAAM,kBAAkB,eAgB9B,CAAC;AAEF,eAAO,MAAM,UAAU,GACrB,iBAAiB,MAAM,EACvB,oBAAoB,MAAM,EAC1B,iBAAc;;;;;qBAcO,WAAW,EAAE;;;;;;qBAAb,WAAW,EAAE;;;;;;CA2QnC,CAAC;AAEF,eAAO,MAAM,cAAc,GAAI,SAAS,WAAW,SACpB,CAAC;AAChC,eAAO,MAAM,gBAAgB,GAAI,SAAS,WAAW,SACpB,CAAC;AAClC,eAAO,MAAM,gBAAgB,GAAI,aAAa,MAAM,SACf,CAAC;AAEtC,eAAO,MAAM,kBAAkB,GAC7B,aAAa,WAAW,EAAE,EAC1B,SAAS,WAAW,EACpB,WAAW,MAAM,GAAG,MAAM,KACzB,WAAW,GAAG,SAkBhB,CAAC"}
|
|
@@ -5,6 +5,9 @@ import { PAGE_SIZE } from "../../constants";
|
|
|
5
5
|
import { useLatest, useRequest } from "ahooks";
|
|
6
6
|
import emitter, { emit } from "../../utils/events";
|
|
7
7
|
import isEmpty from "lodash/isEmpty";
|
|
8
|
+
import { useChatContext } from "../../context/ChatContext";
|
|
9
|
+
import useAuthStore from "../../store/auth";
|
|
10
|
+
import { ConnectStatus } from "../../types/chat";
|
|
8
11
|
export const visibleTypeMessage = [
|
|
9
12
|
MessageType.TextMessage,
|
|
10
13
|
MessageType.PictureMessage,
|
|
@@ -23,6 +26,12 @@ export const visibleTypeMessage = [
|
|
|
23
26
|
MessageType.LogTextMessage,
|
|
24
27
|
];
|
|
25
28
|
export const useMessage = (conversationId, searchClientMsgID, enabled = true) => {
|
|
29
|
+
const { connectStatus } = useChatContext();
|
|
30
|
+
const userID = useAuthStore((state) => state.userID);
|
|
31
|
+
const canLoad = enabled &&
|
|
32
|
+
connectStatus === ConnectStatus.Connected &&
|
|
33
|
+
!!conversationId &&
|
|
34
|
+
!!userID;
|
|
26
35
|
const [loadState, setLoadState] = useState({
|
|
27
36
|
initLoading: true,
|
|
28
37
|
hasMoreOld: true,
|
|
@@ -30,7 +39,8 @@ export const useMessage = (conversationId, searchClientMsgID, enabled = true) =>
|
|
|
30
39
|
messageList: [],
|
|
31
40
|
});
|
|
32
41
|
const latestLoadState = useLatest(loadState);
|
|
33
|
-
const
|
|
42
|
+
const canLoadRef = useLatest(canLoad);
|
|
43
|
+
const conversationIdRef = useLatest(conversationId);
|
|
34
44
|
const { loading: moreOldLoading, runAsync: getMoreOldMessages } = useRequest(async (loadMore = true) => {
|
|
35
45
|
var _a, _b, _c, _d, _e;
|
|
36
46
|
const reqConversationID = conversationId;
|
|
@@ -42,41 +52,63 @@ export const useMessage = (conversationId, searchClientMsgID, enabled = true) =>
|
|
|
42
52
|
conversationID: conversationId !== null && conversationId !== void 0 ? conversationId : "",
|
|
43
53
|
viewType: ViewType.History,
|
|
44
54
|
};
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
55
|
+
try {
|
|
56
|
+
const { data } = await DChatSDK.getAdvancedHistoryMessageList(params);
|
|
57
|
+
if (conversationIdRef.current !== reqConversationID)
|
|
58
|
+
return;
|
|
59
|
+
setTimeout(() => {
|
|
60
|
+
if (conversationIdRef.current !== reqConversationID)
|
|
61
|
+
return;
|
|
62
|
+
setLoadState((preState) => {
|
|
63
|
+
let messageList = [
|
|
64
|
+
...(loadMore ? preState.messageList : []),
|
|
65
|
+
...data.messageList.toReversed(),
|
|
66
|
+
];
|
|
67
|
+
messageList = removeDuplicateMessages(messageList);
|
|
68
|
+
return Object.assign(Object.assign({}, preState), { initLoading: false, hasMoreOld: !data.isEnd, messageList });
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
catch (_f) {
|
|
73
|
+
if (conversationIdRef.current !== reqConversationID)
|
|
74
|
+
return;
|
|
75
|
+
setLoadState((preState) => (Object.assign(Object.assign({}, preState), { initLoading: false })));
|
|
76
|
+
}
|
|
56
77
|
}, {
|
|
57
78
|
manual: true,
|
|
58
79
|
});
|
|
59
80
|
const { loading: moreNewLoading, runAsync: getMoreNewMessages } = useRequest(async (loadMore = true) => {
|
|
60
81
|
var _a, _b;
|
|
61
82
|
const reqConversationID = conversationId;
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
83
|
+
try {
|
|
84
|
+
const { data } = await DChatSDK.getAdvancedHistoryMessageListReverse({
|
|
85
|
+
count: PAGE_SIZE.large,
|
|
86
|
+
startClientMsgID: loadMore
|
|
87
|
+
? ((_b = (_a = latestLoadState.current) === null || _a === void 0 ? void 0 : _a.messageList[0]) === null || _b === void 0 ? void 0 : _b.clientMsgID) || ""
|
|
88
|
+
: "",
|
|
89
|
+
conversationID: conversationId !== null && conversationId !== void 0 ? conversationId : "",
|
|
90
|
+
viewType: ViewType.Search,
|
|
91
|
+
});
|
|
92
|
+
if (conversationIdRef.current !== reqConversationID)
|
|
93
|
+
return;
|
|
94
|
+
setTimeout(() => {
|
|
95
|
+
if (conversationIdRef.current !== reqConversationID)
|
|
96
|
+
return;
|
|
97
|
+
setLoadState((preState) => {
|
|
98
|
+
let messageList = [
|
|
99
|
+
...data.messageList.toReversed(),
|
|
100
|
+
...(loadMore ? preState.messageList : []),
|
|
101
|
+
];
|
|
102
|
+
messageList = removeDuplicateMessages(messageList);
|
|
103
|
+
return Object.assign(Object.assign({}, preState), { initLoading: false, hasMoreNew: !data.isEnd, messageList });
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
catch (_c) {
|
|
108
|
+
if (conversationIdRef.current !== reqConversationID)
|
|
109
|
+
return;
|
|
110
|
+
setLoadState((preState) => (Object.assign(Object.assign({}, preState), { initLoading: false })));
|
|
111
|
+
}
|
|
80
112
|
}, {
|
|
81
113
|
manual: true,
|
|
82
114
|
});
|
|
@@ -127,7 +159,7 @@ export const useMessage = (conversationId, searchClientMsgID, enabled = true) =>
|
|
|
127
159
|
useEffect(() => {
|
|
128
160
|
const pushNewMessage = (message) => {
|
|
129
161
|
var _a, _b;
|
|
130
|
-
if (!
|
|
162
|
+
if (!canLoadRef.current)
|
|
131
163
|
return;
|
|
132
164
|
if ((_b = (_a = latestLoadState.current) === null || _a === void 0 ? void 0 : _a.messageList) === null || _b === void 0 ? void 0 : _b.find((item) => item.clientMsgID === message.clientMsgID)) {
|
|
133
165
|
return;
|
|
@@ -138,7 +170,7 @@ export const useMessage = (conversationId, searchClientMsgID, enabled = true) =>
|
|
|
138
170
|
});
|
|
139
171
|
};
|
|
140
172
|
const updateOneMessage = (message) => {
|
|
141
|
-
if (!
|
|
173
|
+
if (!canLoadRef.current)
|
|
142
174
|
return;
|
|
143
175
|
setLoadState((preState) => {
|
|
144
176
|
var _a, _b, _c, _d;
|
|
@@ -167,7 +199,7 @@ export const useMessage = (conversationId, searchClientMsgID, enabled = true) =>
|
|
|
167
199
|
});
|
|
168
200
|
};
|
|
169
201
|
const removeOneMessage = (clientMsgID) => {
|
|
170
|
-
if (!
|
|
202
|
+
if (!canLoadRef.current)
|
|
171
203
|
return;
|
|
172
204
|
setLoadState((preState) => (Object.assign(Object.assign({}, preState), { messageList: preState.messageList.filter((msg) => msg.clientMsgID !== clientMsgID) })));
|
|
173
205
|
};
|
|
@@ -181,7 +213,7 @@ export const useMessage = (conversationId, searchClientMsgID, enabled = true) =>
|
|
|
181
213
|
};
|
|
182
214
|
}, []);
|
|
183
215
|
useEffect(() => {
|
|
184
|
-
if (!
|
|
216
|
+
if (!canLoad) {
|
|
185
217
|
setLoadState({
|
|
186
218
|
initLoading: true,
|
|
187
219
|
hasMoreOld: true,
|
|
@@ -206,7 +238,7 @@ export const useMessage = (conversationId, searchClientMsgID, enabled = true) =>
|
|
|
206
238
|
messageList: [],
|
|
207
239
|
}));
|
|
208
240
|
};
|
|
209
|
-
}, [conversationId, searchClientMsgID,
|
|
241
|
+
}, [conversationId, searchClientMsgID, canLoad, userID]);
|
|
210
242
|
return {
|
|
211
243
|
loadState,
|
|
212
244
|
latestLoadState,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/screens/desk-message/index.tsx"],"names":[],"mappings":"AAWA,UAAU,qBAAqB;IAC7B,qBAAqB,CAAC,EAAE,MAAM,IAAI,CAAC;CACpC;AAED,QAAA,MAAM,gBAAgB,GAAI,2BAA2B,qBAAqB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/screens/desk-message/index.tsx"],"names":[],"mappings":"AAWA,UAAU,qBAAqB;IAC7B,qBAAqB,CAAC,EAAE,MAAM,IAAI,CAAC;CACpC;AAED,QAAA,MAAM,gBAAgB,GAAI,2BAA2B,qBAAqB,4CA6BzE,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
|
|
@@ -4,14 +4,14 @@ import MessageList from "../../components/message/MessageList";
|
|
|
4
4
|
import DeskConversationList from "../../components/conversation/DeskConversationList";
|
|
5
5
|
import { useChatContext } from "../../context/ChatContext";
|
|
6
6
|
import { Spin } from "antd";
|
|
7
|
-
import { ConnectStatus
|
|
7
|
+
import { ConnectStatus } from "../../types/chat";
|
|
8
8
|
import useConversationStore from "../../store/conversation";
|
|
9
9
|
import DeskAssignedSession from "../../components/session/DeskAssignedSession";
|
|
10
10
|
import ThreadInfo from "../../components/thread/ThreadInfo";
|
|
11
11
|
const DChatDeskMessage = ({ openCreateCannedModal }) => {
|
|
12
12
|
const selectedConversationId = useConversationStore((state) => state.selectedConversationId);
|
|
13
13
|
const searchClientMsgID = useConversationStore((state) => state.searchClientMsgID);
|
|
14
|
-
const { connectStatus
|
|
15
|
-
return (_jsx(_Fragment, { children: connectStatus === ConnectStatus.Connected ? (
|
|
14
|
+
const { connectStatus } = useChatContext();
|
|
15
|
+
return (_jsx(_Fragment, { children: connectStatus === ConnectStatus.Connected ? (_jsxs("div", { className: "flex flex-1 flex-row h-screen bg-gray-50", children: [_jsx(DeskAssignedSession, {}), _jsx(DeskConversationList, {}), _jsx(MessageList, { conversationId: selectedConversationId, searchClientMsgID: searchClientMsgID, openCreateCannedModal: openCreateCannedModal }), _jsx(ThreadInfo, {})] })) : (_jsx("div", { className: "flex flex-1 flex-row h-screen bg-gray-50", children: connectStatus === ConnectStatus.Connecting && _jsx(Spin, { fullscreen: true }) })) }));
|
|
16
16
|
};
|
|
17
17
|
export default DChatDeskMessage;
|