@linagora/twake-mui 9.11.1 → 9.12.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/CHANGELOG.md +17 -0
- package/dist/components/ContactPopover/AttendeeInfo.js +2 -2
- package/dist/components/ContactPopover/ContactPopoverCalendarAction.d.ts +3 -1
- package/dist/components/ContactPopover/ContactPopoverCalendarAction.js +2 -2
- package/dist/components/ContactPopover/ContactPopoverChatAction.d.ts +3 -1
- package/dist/components/ContactPopover/ContactPopoverChatAction.js +2 -2
- package/dist/components/ContactPopover/ContactPopoverEmailAction.d.ts +3 -1
- package/dist/components/ContactPopover/ContactPopoverEmailAction.js +2 -2
- package/dist/components/ContactPopover/ContactPopoverVideoAction.d.ts +3 -1
- package/dist/components/ContactPopover/ContactPopoverVideoAction.js +2 -2
- package/dist/components/ContactPopover/index.js +2 -1
- package/dist/components/ListItemSkeleton/ListItemSkeleton.stories.d.ts +7 -0
- package/dist/components/ListItemSkeleton/ListItemSkeleton.stories.js +43 -0
- package/dist/components/ListItemSkeleton/index.d.ts +9 -0
- package/dist/components/ListItemSkeleton/index.js +12 -0
- package/dist/components/ListSkeleton/ListSkeleton.stories.d.ts +7 -0
- package/dist/components/ListSkeleton/ListSkeleton.stories.js +40 -0
- package/dist/components/ListSkeleton/index.d.ts +9 -0
- package/dist/components/ListSkeleton/index.js +6 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +2 -0
- package/dist/stories/Menu.stories.js +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,20 @@
|
|
|
1
|
+
# @linagora/twake-mui [9.12.0](https://github.com/linagora/twake-ui/compare/@linagora/twake-mui@9.11.2...@linagora/twake-mui@9.12.0) (2026-09-29)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* **twake-mui:** Migrate ListItemSkeleton from cozy-ui ([b1ec8f8](https://github.com/linagora/twake-ui/commit/b1ec8f86a86f5caf1003dc139c57697e5e314bce))
|
|
7
|
+
* **twake-mui:** Migrate ListSkeleton from cozy-ui ([782492a](https://github.com/linagora/twake-ui/commit/782492a0a5b5f30f9454641e645081cb6689d415))
|
|
8
|
+
|
|
9
|
+
## @linagora/twake-mui [9.11.2](https://github.com/linagora/twake-ui/compare/@linagora/twake-mui@9.11.1...@linagora/twake-mui@9.11.2) (2026-09-29)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
### Bug Fixes
|
|
13
|
+
|
|
14
|
+
* Added break-word to long name and email ([fdfcd16](https://github.com/linagora/twake-ui/commit/fdfcd16b7a381eb9272e1e405f60fc65c85fbbdd))
|
|
15
|
+
* Added disable param for contact popover actions ([fe4af23](https://github.com/linagora/twake-ui/commit/fe4af23240350aa9df0b2a9a58a2bb255340efce))
|
|
16
|
+
* Removed fullwidth from email action button ([e7eb7da](https://github.com/linagora/twake-ui/commit/e7eb7dae06b5afc4421b5f77c512e765ee7b7dfb))
|
|
17
|
+
|
|
1
18
|
## @linagora/twake-mui [9.11.1](https://github.com/linagora/twake-ui/compare/@linagora/twake-mui@9.11.0...@linagora/twake-mui@9.11.1) (2026-09-29)
|
|
2
19
|
|
|
3
20
|
|
|
@@ -25,9 +25,9 @@ export const AttendeeInfo = ({ name, email, onEmailCopy }) => {
|
|
|
25
25
|
return (React.createElement(Box, { sx: { display: 'flex', alignItems: 'center', gap: 2 } },
|
|
26
26
|
React.createElement(Avatar, { color: avatarColor, size: 48, sx: { width: 48, height: 48, fontSize: '1.25rem' } }, initials),
|
|
27
27
|
React.createElement(Box, { sx: { minWidth: 0 } },
|
|
28
|
-
name && name !== email ? (React.createElement(Typography, { variant: "body1", sx: { fontWeight: 500
|
|
28
|
+
name && name !== email ? (React.createElement(Typography, { variant: "body1", sx: { fontWeight: 500, wordBreak: 'break-word' } }, name)) : null,
|
|
29
29
|
React.createElement(Box, { sx: { display: 'flex', alignItems: 'center', gap: 1 } },
|
|
30
|
-
React.createElement(Typography, { variant: "body2", color: "text.secondary",
|
|
30
|
+
React.createElement(Typography, { variant: "body2", color: "text.secondary", sx: { wordBreak: 'break-word' } }, email),
|
|
31
31
|
React.createElement(IconButton, { size: "small", onClick: () => void handleCopy(), sx: { p: 0.5, color: alpha(theme.palette.grey[900], 0.9) }, title: showCopied
|
|
32
32
|
? t('ContactPopover.copiedTooltip')
|
|
33
33
|
: t('ContactPopover.copyTooltip') },
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export interface ContactPopoverCalendarActionProps {
|
|
2
2
|
/** URL for calendar action (e.g., view attendee's calendar) */
|
|
3
3
|
url: string;
|
|
4
|
+
/** Disable the action button */
|
|
5
|
+
disabled?: boolean;
|
|
4
6
|
}
|
|
5
|
-
export declare const ContactPopoverCalendarAction: ({ url }: ContactPopoverCalendarActionProps) => JSX.Element;
|
|
7
|
+
export declare const ContactPopoverCalendarAction: ({ url, disabled }: ContactPopoverCalendarActionProps) => JSX.Element;
|
|
@@ -2,8 +2,8 @@ import { Icon } from '@linagora/twake-icons';
|
|
|
2
2
|
import { CalendarToday } from '@linagora/twake-icons';
|
|
3
3
|
import { IconButton, useTheme } from '@mui/material';
|
|
4
4
|
import React from 'react';
|
|
5
|
-
export const ContactPopoverCalendarAction = ({ url }) => {
|
|
5
|
+
export const ContactPopoverCalendarAction = ({ url, disabled = false }) => {
|
|
6
6
|
const theme = useTheme();
|
|
7
|
-
return (React.createElement(IconButton, { href: url, target: "_blank", rel: "noopener noreferrer", size: "small", sx: { border: `1px solid ${theme.palette.divider}` } },
|
|
7
|
+
return (React.createElement(IconButton, { href: url, target: "_blank", rel: "noopener noreferrer", size: "small", disabled: disabled, sx: { border: `1px solid ${theme.palette.divider}` } },
|
|
8
8
|
React.createElement(Icon, { icon: CalendarToday, size: 20, color: theme.palette.text.icon })));
|
|
9
9
|
};
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export interface ContactPopoverChatActionProps {
|
|
2
2
|
/** URL for chat action (e.g., Twake Chat link) */
|
|
3
3
|
url: string;
|
|
4
|
+
/** Disable the action button */
|
|
5
|
+
disabled?: boolean;
|
|
4
6
|
}
|
|
5
|
-
export declare const ContactPopoverChatAction: ({ url }: ContactPopoverChatActionProps) => JSX.Element;
|
|
7
|
+
export declare const ContactPopoverChatAction: ({ url, disabled }: ContactPopoverChatActionProps) => JSX.Element;
|
|
@@ -2,8 +2,8 @@ import { Icon } from '@linagora/twake-icons';
|
|
|
2
2
|
import { Discuss } from '@linagora/twake-icons';
|
|
3
3
|
import { IconButton, useTheme } from '@mui/material';
|
|
4
4
|
import React from 'react';
|
|
5
|
-
export const ContactPopoverChatAction = ({ url }) => {
|
|
5
|
+
export const ContactPopoverChatAction = ({ url, disabled = false }) => {
|
|
6
6
|
const theme = useTheme();
|
|
7
|
-
return (React.createElement(IconButton, { href: url, target: "_blank", rel: "noopener noreferrer", size: "small", sx: { border: `1px solid ${theme.palette.divider}` } },
|
|
7
|
+
return (React.createElement(IconButton, { href: url, target: "_blank", rel: "noopener noreferrer", size: "small", disabled: disabled, sx: { border: `1px solid ${theme.palette.divider}` } },
|
|
8
8
|
React.createElement(Icon, { icon: Discuss, size: 20, color: theme.palette.text.icon })));
|
|
9
9
|
};
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export interface ContactPopoverEmailActionProps {
|
|
2
2
|
/** URL for email action */
|
|
3
3
|
url: string;
|
|
4
|
+
/** Disable the action button */
|
|
5
|
+
disabled?: boolean;
|
|
4
6
|
}
|
|
5
|
-
export declare const ContactPopoverEmailAction: ({ url }: ContactPopoverEmailActionProps) => JSX.Element;
|
|
7
|
+
export declare const ContactPopoverEmailAction: ({ url, disabled }: ContactPopoverEmailActionProps) => JSX.Element;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { Button, useTheme } from '@mui/material';
|
|
2
2
|
import React from 'react';
|
|
3
3
|
import { useI18n } from 'twake-i18n';
|
|
4
|
-
export const ContactPopoverEmailAction = ({ url }) => {
|
|
4
|
+
export const ContactPopoverEmailAction = ({ url, disabled = false }) => {
|
|
5
5
|
const theme = useTheme();
|
|
6
6
|
const { t } = useI18n();
|
|
7
|
-
return (React.createElement(Button, { href: url, target: "_blank", rel: "noopener noreferrer", variant: "outlined", size: "small",
|
|
7
|
+
return (React.createElement(Button, { href: url, target: "_blank", rel: "noopener noreferrer", variant: "outlined", size: "small", disabled: disabled, sx: {
|
|
8
8
|
justifyContent: 'center',
|
|
9
9
|
color: theme.palette.text.primary,
|
|
10
10
|
borderColor: theme.palette.divider
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
export interface ContactPopoverVideoActionProps {
|
|
2
2
|
/** URL for video call action (e.g., Twake Meet link) */
|
|
3
3
|
url: string;
|
|
4
|
+
/** Disable the action button */
|
|
5
|
+
disabled?: boolean;
|
|
4
6
|
}
|
|
5
|
-
export declare const ContactPopoverVideoAction: ({ url }: ContactPopoverVideoActionProps) => JSX.Element;
|
|
7
|
+
export declare const ContactPopoverVideoAction: ({ url, disabled }: ContactPopoverVideoActionProps) => JSX.Element;
|
|
@@ -2,8 +2,8 @@ import { Icon } from '@linagora/twake-icons';
|
|
|
2
2
|
import { Camera } from '@linagora/twake-icons';
|
|
3
3
|
import { IconButton, useTheme } from '@mui/material';
|
|
4
4
|
import React from 'react';
|
|
5
|
-
export const ContactPopoverVideoAction = ({ url }) => {
|
|
5
|
+
export const ContactPopoverVideoAction = ({ url, disabled = false }) => {
|
|
6
6
|
const theme = useTheme();
|
|
7
|
-
return (React.createElement(IconButton, { href: url, target: "_blank", rel: "noopener noreferrer", size: "small", sx: { border: `1px solid ${theme.palette.divider}` } },
|
|
7
|
+
return (React.createElement(IconButton, { href: url, target: "_blank", rel: "noopener noreferrer", size: "small", disabled: disabled, sx: { border: `1px solid ${theme.palette.divider}` } },
|
|
8
8
|
React.createElement(Icon, { icon: Camera, size: 20, color: theme.palette.text.icon })));
|
|
9
9
|
};
|
|
@@ -113,7 +113,8 @@ export const ContactPopover = ({ name, email, children, onEmailCopy, onClose, di
|
|
|
113
113
|
paper: {
|
|
114
114
|
elevation: 4,
|
|
115
115
|
sx: {
|
|
116
|
-
borderRadius: 2
|
|
116
|
+
borderRadius: 2,
|
|
117
|
+
maxWidth: 400
|
|
117
118
|
},
|
|
118
119
|
onMouseEnter: handlePopoverMouseEnter,
|
|
119
120
|
onMouseLeave: handleMouseLeave
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
2
|
+
import ListItemSkeleton from './index';
|
|
3
|
+
declare const meta: Meta<typeof ListItemSkeleton>;
|
|
4
|
+
export default meta;
|
|
5
|
+
type Story = StoryObj<typeof meta>;
|
|
6
|
+
export declare const Default: Story;
|
|
7
|
+
export declare const Screenshot: Story;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { Box, List, Stack } from '@mui/material';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import ListItemSkeleton from './index';
|
|
4
|
+
const meta = {
|
|
5
|
+
title: 'ListItemSkeleton',
|
|
6
|
+
component: ListItemSkeleton,
|
|
7
|
+
tags: ['autodocs'],
|
|
8
|
+
argTypes: {
|
|
9
|
+
hasSecondary: { control: 'boolean' },
|
|
10
|
+
divider: { control: 'boolean' },
|
|
11
|
+
gutters: {
|
|
12
|
+
control: 'select',
|
|
13
|
+
options: ['default', 'double', 'disabled']
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
decorators: [
|
|
17
|
+
(Story) => (React.createElement(Box, { sx: { maxWidth: 480 } },
|
|
18
|
+
React.createElement(List, null,
|
|
19
|
+
React.createElement(Story, null))))
|
|
20
|
+
]
|
|
21
|
+
};
|
|
22
|
+
export default meta;
|
|
23
|
+
export const Default = {
|
|
24
|
+
args: {
|
|
25
|
+
hasSecondary: false,
|
|
26
|
+
divider: false,
|
|
27
|
+
gutters: 'default'
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
const Example = ({ title, ...props }) => (React.createElement("section", null,
|
|
31
|
+
React.createElement("h3", null, title),
|
|
32
|
+
React.createElement(ListItemSkeleton, { ...props })));
|
|
33
|
+
// Visual Regression - Combined view for Argos testing
|
|
34
|
+
export const Screenshot = {
|
|
35
|
+
tags: ['argos'],
|
|
36
|
+
render: () => (React.createElement(Stack, { spacing: 4 },
|
|
37
|
+
React.createElement(Example, { title: "Default" }),
|
|
38
|
+
React.createElement(Example, { title: "With secondary", hasSecondary: true }),
|
|
39
|
+
React.createElement(Example, { title: "With divider", divider: true }),
|
|
40
|
+
React.createElement(Example, { title: "Disabled gutters", gutters: "disabled" }),
|
|
41
|
+
React.createElement(Example, { title: "Double gutters", gutters: "double" }),
|
|
42
|
+
React.createElement(Example, { title: "With secondary, divider and double gutters", hasSecondary: true, divider: true, gutters: "double" })))
|
|
43
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { ListItemGutters } from '../ListItem';
|
|
3
|
+
export interface ListItemSkeletonProps {
|
|
4
|
+
hasSecondary?: boolean;
|
|
5
|
+
divider?: boolean;
|
|
6
|
+
gutters?: ListItemGutters;
|
|
7
|
+
}
|
|
8
|
+
declare const ListItemSkeleton: ({ hasSecondary, divider, gutters }: ListItemSkeletonProps) => React.ReactElement;
|
|
9
|
+
export default ListItemSkeleton;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Divider, ListItemIcon, Skeleton } from '@mui/material';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { radius } from '../../lib/radius';
|
|
4
|
+
import ListItem from '../ListItem';
|
|
5
|
+
import ListItemText from '../ListItemText';
|
|
6
|
+
const ListItemSkeleton = ({ hasSecondary, divider, gutters }) => (React.createElement(React.Fragment, null,
|
|
7
|
+
React.createElement(ListItem, { gutters: gutters },
|
|
8
|
+
React.createElement(ListItemIcon, null,
|
|
9
|
+
React.createElement(Skeleton, { variant: "rectangular", width: 32, height: 32, sx: { borderRadius: radius.md } })),
|
|
10
|
+
React.createElement(ListItemText, { primary: React.createElement(Skeleton, { width: "75%", height: 13 }), secondary: hasSecondary ? React.createElement(Skeleton, { width: "37%", height: 13 }) : undefined })),
|
|
11
|
+
divider && React.createElement(Divider, null)));
|
|
12
|
+
export default ListItemSkeleton;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react-vite';
|
|
2
|
+
import ListSkeleton from './index';
|
|
3
|
+
declare const meta: Meta<typeof ListSkeleton>;
|
|
4
|
+
export default meta;
|
|
5
|
+
type Story = StoryObj<typeof meta>;
|
|
6
|
+
export declare const Default: Story;
|
|
7
|
+
export declare const Screenshot: Story;
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Box, Stack } from '@mui/material';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import ListSkeleton from './index';
|
|
4
|
+
const meta = {
|
|
5
|
+
title: 'ListSkeleton',
|
|
6
|
+
component: ListSkeleton,
|
|
7
|
+
tags: ['autodocs'],
|
|
8
|
+
argTypes: {
|
|
9
|
+
count: { control: { type: 'number', min: 1 } },
|
|
10
|
+
hasSecondary: { control: 'boolean' },
|
|
11
|
+
withSubheader: { control: 'boolean' },
|
|
12
|
+
divider: { control: 'boolean' }
|
|
13
|
+
},
|
|
14
|
+
decorators: [
|
|
15
|
+
(Story) => (React.createElement(Box, { sx: { maxWidth: 480 } },
|
|
16
|
+
React.createElement(Story, null)))
|
|
17
|
+
]
|
|
18
|
+
};
|
|
19
|
+
export default meta;
|
|
20
|
+
export const Default = {
|
|
21
|
+
args: {
|
|
22
|
+
count: 5,
|
|
23
|
+
hasSecondary: false,
|
|
24
|
+
withSubheader: false,
|
|
25
|
+
divider: false
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
const Example = ({ title, ...props }) => (React.createElement("section", null,
|
|
29
|
+
React.createElement("h3", null, title),
|
|
30
|
+
React.createElement(ListSkeleton, { count: 3, ...props })));
|
|
31
|
+
// Visual Regression - Combined view for Argos testing
|
|
32
|
+
export const Screenshot = {
|
|
33
|
+
tags: ['argos'],
|
|
34
|
+
render: () => (React.createElement(Stack, { spacing: 4 },
|
|
35
|
+
React.createElement(Example, { title: "Default" }),
|
|
36
|
+
React.createElement(Example, { title: "With secondary", hasSecondary: true }),
|
|
37
|
+
React.createElement(Example, { title: "With subheader", withSubheader: true }),
|
|
38
|
+
React.createElement(Example, { title: "With divider", divider: true }),
|
|
39
|
+
React.createElement(Example, { title: "With secondary, subheader and divider", hasSecondary: true, withSubheader: true, divider: true })))
|
|
40
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
export interface ListSkeletonProps {
|
|
3
|
+
count?: number;
|
|
4
|
+
hasSecondary?: boolean;
|
|
5
|
+
withSubheader?: boolean;
|
|
6
|
+
divider?: boolean;
|
|
7
|
+
}
|
|
8
|
+
declare const ListSkeleton: ({ count, hasSecondary, withSubheader, divider }: ListSkeletonProps) => React.ReactElement;
|
|
9
|
+
export default ListSkeleton;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { List } from '@mui/material';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import ListItemSkeleton from '../ListItemSkeleton';
|
|
4
|
+
import ListSubheader from '../ListSubheader';
|
|
5
|
+
const ListSkeleton = ({ count = 1, hasSecondary, withSubheader, divider }) => (React.createElement(List, { subheader: withSubheader ? React.createElement(ListSubheader, null, "\u00A0") : undefined }, Array.from({ length: count }, (_, idx) => (React.createElement(ListItemSkeleton, { key: idx, hasSecondary: hasSecondary, divider: divider })))));
|
|
6
|
+
export default ListSkeleton;
|
package/dist/index.d.ts
CHANGED
|
@@ -16,6 +16,8 @@ export { default as DropdownText } from './components/DropdownText';
|
|
|
16
16
|
export { default as ListItem } from './components/ListItem';
|
|
17
17
|
export { default as ListItemButton } from './components/ListItemButton';
|
|
18
18
|
export { default as ListItemText } from './components/ListItemText';
|
|
19
|
+
export { default as ListItemSkeleton } from './components/ListItemSkeleton';
|
|
20
|
+
export { default as ListSkeleton } from './components/ListSkeleton';
|
|
19
21
|
export { default as ListSubheader } from './components/ListSubheader';
|
|
20
22
|
export { Tabs, default as TabsDefault } from './components/Tabs';
|
|
21
23
|
export { Switch, default as SwitchDefault } from './components/Switch';
|
|
@@ -52,6 +54,8 @@ export type { DropdownTextProps, DropdownTextVariant } from './components/Dropdo
|
|
|
52
54
|
export type { ListItemProps, ListItemGutters, ListItemSize } from './components/ListItem';
|
|
53
55
|
export type { ListItemButtonProps } from './components/ListItemButton';
|
|
54
56
|
export type { ListItemTextProps } from './components/ListItemText';
|
|
57
|
+
export type { ListItemSkeletonProps } from './components/ListItemSkeleton';
|
|
58
|
+
export type { ListSkeletonProps } from './components/ListSkeleton';
|
|
55
59
|
export type { ListSubheaderProps } from './components/ListSubheader';
|
|
56
60
|
export type { TabsProps } from './components/Tabs';
|
|
57
61
|
export type { SwitchProps } from './components/Switch';
|
package/dist/index.js
CHANGED
|
@@ -19,6 +19,8 @@ export { default as DropdownText } from './components/DropdownText';
|
|
|
19
19
|
export { default as ListItem } from './components/ListItem';
|
|
20
20
|
export { default as ListItemButton } from './components/ListItemButton';
|
|
21
21
|
export { default as ListItemText } from './components/ListItemText';
|
|
22
|
+
export { default as ListItemSkeleton } from './components/ListItemSkeleton';
|
|
23
|
+
export { default as ListSkeleton } from './components/ListSkeleton';
|
|
22
24
|
export { default as ListSubheader } from './components/ListSubheader';
|
|
23
25
|
export { Tabs, default as TabsDefault } from './components/Tabs';
|
|
24
26
|
export { Switch, default as SwitchDefault } from './components/Switch';
|
|
@@ -68,5 +68,5 @@ export const Screenshot = {
|
|
|
68
68
|
tags: ['argos'],
|
|
69
69
|
parameters: { layout: 'padded' },
|
|
70
70
|
render: () => (React.createElement(Box, { sx: { minHeight: 440 } },
|
|
71
|
-
React.createElement(ExampleMenu, { defaultOpen: true, autoFocus: false, disablePortal: true, disableScrollLock: true
|
|
71
|
+
React.createElement(ExampleMenu, { defaultOpen: true, autoFocus: false, disablePortal: true, disableScrollLock: true })))
|
|
72
72
|
};
|