stream-chat-react-native-core 9.0.0-beta.4 → 9.0.0-beta.5

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 (46) hide show
  1. package/lib/commonjs/components/Message/Message.js +19 -14
  2. package/lib/commonjs/components/Message/Message.js.map +1 -1
  3. package/lib/commonjs/components/Message/MessageItemView/MessageBubble.js +7 -65
  4. package/lib/commonjs/components/Message/MessageItemView/MessageBubble.js.map +1 -1
  5. package/lib/commonjs/components/Message/MessageItemView/MessageItemView.js +55 -29
  6. package/lib/commonjs/components/Message/MessageItemView/MessageItemView.js.map +1 -1
  7. package/lib/commonjs/components/Message/hooks/useCreateMessageContext.js +2 -0
  8. package/lib/commonjs/components/Message/hooks/useCreateMessageContext.js.map +1 -1
  9. package/lib/commonjs/contexts/messageContext/MessageContext.js.map +1 -1
  10. package/lib/commonjs/contexts/themeContext/utils/theme.js +4 -6
  11. package/lib/commonjs/contexts/themeContext/utils/theme.js.map +1 -1
  12. package/lib/commonjs/version.json +1 -1
  13. package/lib/module/components/Message/Message.js +19 -14
  14. package/lib/module/components/Message/Message.js.map +1 -1
  15. package/lib/module/components/Message/MessageItemView/MessageBubble.js +7 -65
  16. package/lib/module/components/Message/MessageItemView/MessageBubble.js.map +1 -1
  17. package/lib/module/components/Message/MessageItemView/MessageItemView.js +55 -29
  18. package/lib/module/components/Message/MessageItemView/MessageItemView.js.map +1 -1
  19. package/lib/module/components/Message/hooks/useCreateMessageContext.js +2 -0
  20. package/lib/module/components/Message/hooks/useCreateMessageContext.js.map +1 -1
  21. package/lib/module/contexts/messageContext/MessageContext.js.map +1 -1
  22. package/lib/module/contexts/themeContext/utils/theme.js +4 -6
  23. package/lib/module/contexts/themeContext/utils/theme.js.map +1 -1
  24. package/lib/module/version.json +1 -1
  25. package/lib/typescript/components/Message/Message.d.ts.map +1 -1
  26. package/lib/typescript/components/Message/MessageItemView/MessageBubble.d.ts +1 -4
  27. package/lib/typescript/components/Message/MessageItemView/MessageBubble.d.ts.map +1 -1
  28. package/lib/typescript/components/Message/MessageItemView/MessageItemView.d.ts +5 -3
  29. package/lib/typescript/components/Message/MessageItemView/MessageItemView.d.ts.map +1 -1
  30. package/lib/typescript/components/Message/hooks/useCreateMessageContext.d.ts +1 -1
  31. package/lib/typescript/components/Message/hooks/useCreateMessageContext.d.ts.map +1 -1
  32. package/lib/typescript/contexts/messageContext/MessageContext.d.ts +6 -0
  33. package/lib/typescript/contexts/messageContext/MessageContext.d.ts.map +1 -1
  34. package/lib/typescript/contexts/themeContext/ThemeContext.d.ts +4 -6
  35. package/lib/typescript/contexts/themeContext/ThemeContext.d.ts.map +1 -1
  36. package/lib/typescript/contexts/themeContext/utils/theme.d.ts +4 -6
  37. package/lib/typescript/contexts/themeContext/utils/theme.d.ts.map +1 -1
  38. package/package.json +1 -1
  39. package/src/components/Message/Message.tsx +25 -18
  40. package/src/components/Message/MessageItemView/MessageBubble.tsx +5 -98
  41. package/src/components/Message/MessageItemView/MessageItemView.tsx +189 -150
  42. package/src/components/Message/MessageItemView/__tests__/MessageItemView.test.js +18 -0
  43. package/src/components/Message/hooks/useCreateMessageContext.ts +2 -0
  44. package/src/contexts/messageContext/MessageContext.tsx +6 -0
  45. package/src/contexts/themeContext/utils/theme.ts +8 -12
  46. package/src/version.json +1 -1
@@ -1,7 +1,7 @@
1
- import React, { forwardRef, useMemo } from 'react';
1
+ import React, { useMemo } from 'react';
2
2
  import { Dimensions, StyleSheet, View, ViewStyle } from 'react-native';
3
3
 
4
- import { MessageBubble, SwipableMessageWrapper } from './MessageBubble';
4
+ import { SwipableMessageWrapper } from './MessageBubble';
5
5
 
6
6
  import {
7
7
  Alignment,
@@ -43,6 +43,10 @@ const useStyles = ({
43
43
  theme: {
44
44
  messageItemView: {
45
45
  container,
46
+ bubbleContentContainer,
47
+ bubbleErrorContainer,
48
+ bubbleReactionListTopContainer,
49
+ bubbleWrapper,
46
50
  contentContainer,
47
51
  repliesContainer,
48
52
  leftAlignItems,
@@ -78,6 +82,23 @@ const useStyles = ({
78
82
  gap: primitives.spacingXxs,
79
83
  ...contentContainer,
80
84
  },
85
+ bubbleContentContainer: {
86
+ alignSelf: alignment === 'left' ? 'flex-start' : 'flex-end',
87
+ ...bubbleContentContainer,
88
+ },
89
+ bubbleErrorContainer: {
90
+ position: 'absolute',
91
+ top: 8,
92
+ right: -12,
93
+ ...bubbleErrorContainer,
94
+ },
95
+ bubbleReactionListTopContainer: {
96
+ alignSelf: alignment === 'left' ? 'flex-end' : 'flex-start',
97
+ ...bubbleReactionListTopContainer,
98
+ },
99
+ bubbleWrapper: {
100
+ ...bubbleWrapper,
101
+ },
81
102
  repliesContainer: {
82
103
  marginTop: -primitives.spacingXxs, // Reducing the margin to account the gap added in the content container
83
104
  ...repliesContainer,
@@ -91,7 +112,18 @@ const useStyles = ({
91
112
  ...rightAlignItems,
92
113
  },
93
114
  }),
94
- [alignment, container, contentContainer, leftAlignItems, repliesContainer, rightAlignItems],
115
+ [
116
+ alignment,
117
+ bubbleContentContainer,
118
+ bubbleErrorContainer,
119
+ bubbleReactionListTopContainer,
120
+ bubbleWrapper,
121
+ container,
122
+ contentContainer,
123
+ leftAlignItems,
124
+ repliesContainer,
125
+ rightAlignItems,
126
+ ],
95
127
  );
96
128
 
97
129
  const groupStylesMap = useMemo(() => {
@@ -151,6 +183,10 @@ const useStyles = ({
151
183
 
152
184
  return {
153
185
  container: containerStyle,
186
+ bubbleContentContainer: styles.bubbleContentContainer,
187
+ bubbleErrorContainer: styles.bubbleErrorContainer,
188
+ bubbleReactionListTopContainer: styles.bubbleReactionListTopContainer,
189
+ bubbleWrapper: styles.bubbleWrapper,
154
190
  contentContainer: styles.contentContainer,
155
191
  repliesContainer: styles.repliesContainer,
156
192
  leftAlignItems: styles.leftAlignItems,
@@ -169,6 +205,7 @@ export type MessageItemViewPropsWithContext = Pick<
169
205
  | 'otherAttachments'
170
206
  | 'setQuotedMessage'
171
207
  | 'lastGroupMessage'
208
+ | 'contextMenuAnchorRef'
172
209
  | 'members'
173
210
  > &
174
211
  Pick<
@@ -193,159 +230,160 @@ export type MessageItemViewPropsWithContext = Pick<
193
230
  | 'ReactionListTop'
194
231
  >;
195
232
 
196
- const MessageItemViewWithContext = forwardRef<View, MessageItemViewPropsWithContext>(
197
- (props, ref) => {
198
- const { width } = Dimensions.get('screen');
199
- const {
200
- alignment,
201
- channel,
202
- customMessageSwipeAction,
203
- enableMessageGroupingByUser,
204
- enableSwipeToReply,
205
- groupStyles,
206
- isMyMessage,
207
- message,
208
- MessageAuthor,
209
- MessageContent,
210
- MessageDeleted,
211
- MessageError,
212
- MessageFooter,
213
- MessageHeader,
214
- MessageReplies,
215
- MessageSpacer,
216
- MessageSwipeContent,
217
- messageSwipeToReplyHitSlop = { left: width, right: width },
218
- onlyEmojis,
219
- otherAttachments,
220
- ReactionListBottom,
221
- reactionListPosition,
222
- reactionListType,
223
- ReactionListTop,
224
- setQuotedMessage,
225
- } = props;
226
-
227
- const {
228
- theme: {
229
- semantics,
230
- messageItemView: {
231
- content: { errorContainer },
232
- },
233
+ const MessageItemViewWithContext = (props: MessageItemViewPropsWithContext) => {
234
+ const { width } = Dimensions.get('screen');
235
+ const {
236
+ alignment,
237
+ channel,
238
+ contextMenuAnchorRef,
239
+ customMessageSwipeAction,
240
+ enableMessageGroupingByUser,
241
+ enableSwipeToReply,
242
+ groupStyles,
243
+ isMyMessage,
244
+ message,
245
+ MessageAuthor,
246
+ MessageContent,
247
+ MessageDeleted,
248
+ MessageError,
249
+ MessageFooter,
250
+ MessageHeader,
251
+ MessageReplies,
252
+ MessageSpacer,
253
+ MessageSwipeContent,
254
+ messageSwipeToReplyHitSlop = { left: width, right: width },
255
+ onlyEmojis,
256
+ otherAttachments,
257
+ ReactionListBottom,
258
+ reactionListPosition,
259
+ reactionListType,
260
+ ReactionListTop,
261
+ setQuotedMessage,
262
+ } = props;
263
+
264
+ const {
265
+ theme: {
266
+ semantics,
267
+ messageItemView: {
268
+ content: { errorContainer },
233
269
  },
234
- } = useTheme();
235
-
236
- const {
237
- isMessageErrorType,
238
- isMessageReceivedOrErrorType,
239
- isMessageTypeDeleted,
240
- isVeryLastMessage,
241
- messageGroupedSingle,
242
- messageGroupedBottom,
243
- messageGroupedTop,
244
- messageGroupedSingleOrBottom,
245
- messageGroupedMiddle,
246
- } = useMessageData({});
247
-
248
- const styles = useStyles({
249
- alignment,
250
- isVeryLastMessage,
251
- messageGroupedSingle,
252
- messageGroupedBottom,
253
- messageGroupedTop,
254
- messageGroupedMiddle,
255
- enableMessageGroupingByUser,
256
- });
257
-
258
- const groupStyle = `${alignment}_${groupStyles?.[0]?.toLowerCase?.()}`;
259
-
260
- let noBorder = onlyEmojis && !message.quoted_message;
261
- if (otherAttachments.length) {
262
- if (otherAttachments[0].type === 'giphy' && !isMyMessage) {
263
- noBorder = false;
264
- } else {
265
- noBorder = true;
266
- }
270
+ },
271
+ } = useTheme();
272
+
273
+ const {
274
+ isMessageErrorType,
275
+ isMessageReceivedOrErrorType,
276
+ isMessageTypeDeleted,
277
+ isVeryLastMessage,
278
+ messageGroupedSingle,
279
+ messageGroupedBottom,
280
+ messageGroupedTop,
281
+ messageGroupedSingleOrBottom,
282
+ messageGroupedMiddle,
283
+ } = useMessageData({});
284
+
285
+ const styles = useStyles({
286
+ alignment,
287
+ isVeryLastMessage,
288
+ messageGroupedSingle,
289
+ messageGroupedBottom,
290
+ messageGroupedTop,
291
+ messageGroupedMiddle,
292
+ enableMessageGroupingByUser,
293
+ });
294
+
295
+ const groupStyle = `${alignment}_${groupStyles?.[0]?.toLowerCase?.()}`;
296
+
297
+ let noBorder = onlyEmojis && !message.quoted_message;
298
+ if (otherAttachments.length) {
299
+ if (otherAttachments[0].type === 'giphy' && !isMyMessage) {
300
+ noBorder = false;
301
+ } else {
302
+ noBorder = true;
267
303
  }
304
+ }
268
305
 
269
- let backgroundColor = semantics.chatBgOutgoing;
270
- if (onlyEmojis && !message.quoted_message) {
306
+ let backgroundColor = semantics.chatBgOutgoing;
307
+ if (onlyEmojis && !message.quoted_message) {
308
+ backgroundColor = 'transparent';
309
+ } else if (otherAttachments.length) {
310
+ if (otherAttachments[0].type === 'giphy') {
271
311
  backgroundColor = 'transparent';
272
- } else if (otherAttachments.length) {
273
- if (otherAttachments[0].type === 'giphy') {
274
- backgroundColor = 'transparent';
275
- }
276
- } else if (isMessageReceivedOrErrorType) {
277
- backgroundColor = semantics.chatBgIncoming;
278
312
  }
313
+ } else if (isMessageReceivedOrErrorType) {
314
+ backgroundColor = semantics.chatBgIncoming;
315
+ }
279
316
 
280
- const onSwipeActionHandler = useStableCallback(() => {
281
- if (customMessageSwipeAction) {
282
- customMessageSwipeAction({ channel, message });
283
- return;
284
- }
285
- setQuotedMessage(message);
286
- });
287
-
288
- const itemViewContent = (
289
- <View pointerEvents='box-none' style={styles.container} testID='message-item-view-wrapper'>
290
- {alignment === 'left' ? <MessageAuthor /> : null}
291
- {isMessageTypeDeleted ? (
292
- <MessageDeleted date={message.created_at} groupStyle={groupStyle} />
293
- ) : (
294
- <View
295
- style={[
296
- styles.contentContainer,
297
- isMyMessage ? styles.rightAlignItems : styles.leftAlignItems,
298
- isMessageErrorType ? errorContainer : {},
299
- ]}
300
- testID='message-components'
301
- >
302
- <MessageHeader />
303
- <MessageBubble
304
- alignment={alignment}
305
- backgroundColor={backgroundColor}
306
- isVeryLastMessage={isVeryLastMessage}
307
- MessageContent={MessageContent}
308
- MessageError={MessageError}
309
- messageGroupedSingleOrBottom={messageGroupedSingleOrBottom}
310
- noBorder={noBorder}
311
- reactionListPosition={reactionListPosition}
312
- ReactionListTop={ReactionListTop}
313
- reactionListType={reactionListType}
314
- message={message}
315
- />
316
-
317
- <View style={styles.repliesContainer}>
318
- <MessageReplies />
317
+ const onSwipeActionHandler = useStableCallback(() => {
318
+ if (customMessageSwipeAction) {
319
+ customMessageSwipeAction({ channel, message });
320
+ return;
321
+ }
322
+ setQuotedMessage(message);
323
+ });
324
+
325
+ const itemViewContent = (
326
+ <View pointerEvents='box-none' style={styles.container} testID='message-item-view-wrapper'>
327
+ {alignment === 'left' ? <MessageAuthor /> : null}
328
+ {isMessageTypeDeleted ? (
329
+ <MessageDeleted date={message.created_at} groupStyle={groupStyle} />
330
+ ) : (
331
+ <View
332
+ style={[
333
+ styles.contentContainer,
334
+ isMyMessage ? styles.rightAlignItems : styles.leftAlignItems,
335
+ isMessageErrorType ? errorContainer : {},
336
+ ]}
337
+ testID='message-components'
338
+ >
339
+ <MessageHeader />
340
+ <View style={styles.bubbleWrapper}>
341
+ {reactionListPosition === 'top' && ReactionListTop ? (
342
+ <View style={styles.bubbleReactionListTopContainer}>
343
+ <ReactionListTop type={reactionListType} />
344
+ </View>
345
+ ) : null}
346
+ <View ref={contextMenuAnchorRef} style={styles.bubbleContentContainer}>
347
+ <MessageContent
348
+ backgroundColor={backgroundColor}
349
+ isVeryLastMessage={isVeryLastMessage}
350
+ messageGroupedSingleOrBottom={messageGroupedSingleOrBottom}
351
+ noBorder={noBorder}
352
+ />
353
+ {isMessageErrorType ? (
354
+ <View style={styles.bubbleErrorContainer}>
355
+ <MessageError />
356
+ </View>
357
+ ) : null}
319
358
  </View>
359
+ </View>
320
360
 
321
- {reactionListPosition === 'bottom' && ReactionListBottom ? (
322
- <ReactionListBottom type={reactionListType} />
323
- ) : null}
324
- <MessageFooter date={message.created_at} />
361
+ <View style={styles.repliesContainer}>
362
+ <MessageReplies />
325
363
  </View>
326
- )}
327
- {MessageSpacer ? <MessageSpacer /> : null}
328
- </View>
329
- );
330
-
331
- return (
332
- <View ref={ref}>
333
- {enableSwipeToReply && !isMessageTypeDeleted ? (
334
- <SwipableMessageWrapper
335
- alignment={alignment}
336
- MessageSwipeContent={MessageSwipeContent}
337
- messageSwipeToReplyHitSlop={messageSwipeToReplyHitSlop}
338
- onSwipe={onSwipeActionHandler}
339
- >
340
- {itemViewContent}
341
- </SwipableMessageWrapper>
342
- ) : (
343
- itemViewContent
344
- )}
345
- </View>
346
- );
347
- },
348
- );
364
+
365
+ {reactionListPosition === 'bottom' && ReactionListBottom ? (
366
+ <ReactionListBottom type={reactionListType} />
367
+ ) : null}
368
+ <MessageFooter date={message.created_at} />
369
+ </View>
370
+ )}
371
+ {MessageSpacer ? <MessageSpacer /> : null}
372
+ </View>
373
+ );
374
+
375
+ return enableSwipeToReply && !isMessageTypeDeleted ? (
376
+ <SwipableMessageWrapper
377
+ MessageSwipeContent={MessageSwipeContent}
378
+ messageSwipeToReplyHitSlop={messageSwipeToReplyHitSlop}
379
+ onSwipe={onSwipeActionHandler}
380
+ >
381
+ {itemViewContent}
382
+ </SwipableMessageWrapper>
383
+ ) : (
384
+ itemViewContent
385
+ );
386
+ };
349
387
 
350
388
  const areEqual = (
351
389
  prevProps: MessageItemViewPropsWithContext,
@@ -476,13 +514,14 @@ export type MessageItemViewProps = Partial<MessageItemViewPropsWithContext>;
476
514
  *
477
515
  * Message UI component
478
516
  */
479
- export const MessageItemView = forwardRef<View, MessageItemViewProps>((props, ref) => {
517
+ export const MessageItemView = (props: MessageItemViewProps) => {
480
518
  const {
481
519
  alignment,
482
520
  channel,
483
521
  groupStyles,
484
522
  isMyMessage,
485
523
  message,
524
+ contextMenuAnchorRef,
486
525
  onlyEmojis,
487
526
  otherAttachments,
488
527
  setQuotedMessage,
@@ -516,6 +555,7 @@ export const MessageItemView = forwardRef<View, MessageItemViewProps>((props, re
516
555
  {...{
517
556
  alignment,
518
557
  channel,
558
+ contextMenuAnchorRef,
519
559
  customMessageSwipeAction,
520
560
  enableMessageGroupingByUser,
521
561
  enableSwipeToReply,
@@ -543,10 +583,9 @@ export const MessageItemView = forwardRef<View, MessageItemViewProps>((props, re
543
583
  lastGroupMessage,
544
584
  members,
545
585
  }}
546
- ref={ref}
547
586
  {...props}
548
587
  />
549
588
  );
550
- });
589
+ };
551
590
 
552
591
  MessageItemView.displayName = 'MessageItemView{messageItemView{container}}';
@@ -6,6 +6,7 @@ import { GestureDetector } from 'react-native-gesture-handler';
6
6
  import { cleanup, render, screen, waitFor } from '@testing-library/react-native';
7
7
 
8
8
  import { ChannelsStateProvider } from '../../../../contexts/channelsStateContext/ChannelsStateContext';
9
+ import { useMessageContext } from '../../../../contexts/messageContext/MessageContext';
9
10
 
10
11
  import { getOrCreateChannelApi } from '../../../../mock-builders/api/getOrCreateChannel';
11
12
  import { useMockedApis } from '../../../../mock-builders/api/useMockedApis';
@@ -121,6 +122,23 @@ describe('MessageItemView', () => {
121
122
  });
122
123
  });
123
124
 
125
+ it('exposes contextMenuAnchorRef through MessageContext for custom renderers', async () => {
126
+ const user = generateUser();
127
+ const message = generateMessage({ user });
128
+
129
+ const CustomMessageItemView = () => {
130
+ const { contextMenuAnchorRef } = useMessageContext();
131
+
132
+ return <Text ref={contextMenuAnchorRef}>Custom Message Item</Text>;
133
+ };
134
+
135
+ renderMessage({ message }, { MessageItemView: CustomMessageItemView });
136
+
137
+ await waitFor(() => {
138
+ expect(screen.queryByText('Custom Message Item')).not.toBeNull();
139
+ });
140
+ });
141
+
124
142
  it('renders MessageSpacer component if defined', async () => {
125
143
  const user = generateUser();
126
144
  const message = generateMessage({ user });
@@ -18,6 +18,7 @@ export const useCreateMessageContext = ({
18
18
  actionsEnabled,
19
19
  alignment,
20
20
  channel,
21
+ contextMenuAnchorRef,
21
22
  deliveredToCount,
22
23
  dismissOverlay,
23
24
  files,
@@ -71,6 +72,7 @@ export const useCreateMessageContext = ({
71
72
  actionsEnabled,
72
73
  alignment,
73
74
  channel,
75
+ contextMenuAnchorRef,
74
76
  deliveredToCount,
75
77
  dismissOverlay,
76
78
  files,
@@ -1,4 +1,5 @@
1
1
  import React, { PropsWithChildren, useContext } from 'react';
2
+ import type { View } from 'react-native';
2
3
 
3
4
  import type { Attachment, LocalMessage } from 'stream-chat';
4
5
 
@@ -56,6 +57,11 @@ export type MessageContextValue = {
56
57
  lastGroupMessage: boolean;
57
58
  /** Current [message object](https://getstream.io/chat/docs/#message_format) */
58
59
  message: LocalMessage;
60
+ /**
61
+ * Ref to the view that the message context menu should align with.
62
+ * Custom message renderers can attach this to a different subview if needed.
63
+ */
64
+ contextMenuAnchorRef: React.RefObject<View | null>;
59
65
  /**
60
66
  * Stable UI-instance identifier for the rendered message.
61
67
  * Used for overlay state so two rendered instances of the same message do not collide.
@@ -583,6 +583,10 @@ export type Theme = {
583
583
  };
584
584
  messageItemView: {
585
585
  blockedMessageContainer: ViewStyle;
586
+ bubbleContentContainer: ViewStyle;
587
+ bubbleErrorContainer: ViewStyle;
588
+ bubbleReactionListTopContainer: ViewStyle;
589
+ bubbleWrapper: ViewStyle;
586
590
  actions: {
587
591
  button: ViewStyle & {
588
592
  defaultBackgroundColor?: ViewStyle['backgroundColor'];
@@ -728,12 +732,6 @@ export type Theme = {
728
732
  container: ViewStyle;
729
733
  text: TextStyle;
730
734
  };
731
- bubble: {
732
- reactionListTopContainer: ViewStyle;
733
- contentContainer: ViewStyle;
734
- wrapper: ViewStyle;
735
- errorContainer: ViewStyle;
736
- };
737
735
  pinnedHeader: {
738
736
  container: ViewStyle;
739
737
  label: TextStyle;
@@ -1491,6 +1489,10 @@ export const defaultTheme: Theme = {
1491
1489
  },
1492
1490
  messageItemView: {
1493
1491
  blockedMessageContainer: {},
1492
+ bubbleContentContainer: {},
1493
+ bubbleErrorContainer: {},
1494
+ bubbleReactionListTopContainer: {},
1495
+ bubbleWrapper: {},
1494
1496
  actions: {
1495
1497
  button: {},
1496
1498
  buttonText: {},
@@ -1635,12 +1637,6 @@ export const defaultTheme: Theme = {
1635
1637
  container: {},
1636
1638
  text: {},
1637
1639
  },
1638
- bubble: {
1639
- reactionListTopContainer: {},
1640
- contentContainer: {},
1641
- wrapper: {},
1642
- errorContainer: {},
1643
- },
1644
1640
  messageGroupedSingleOrBottomContainer: {},
1645
1641
  messageGroupedTopContainer: {},
1646
1642
  pinnedHeader: {
package/src/version.json CHANGED
@@ -1,3 +1,3 @@
1
1
  {
2
- "version": "9.0.0-beta.4"
2
+ "version": "9.0.0-beta.5"
3
3
  }