2020-12-21 21:47:15 +01:00
|
|
|
import React, { createRef, Dispatch, useEffect, useMemo, useState } from 'react'
|
2020-12-14 23:44:57 +01:00
|
|
|
import { Animated, Image, StyleSheet, Text, View } from 'react-native'
|
2020-12-17 09:44:03 +01:00
|
|
|
import { createShimmerPlaceholder } from 'react-native-shimmer-placeholder'
|
2020-11-22 00:46:23 +01:00
|
|
|
import { Feather } from '@expo/vector-icons'
|
|
|
|
|
2020-12-13 14:04:25 +01:00
|
|
|
import ParseContent from '@components/ParseContent'
|
|
|
|
import { useTheme } from '@utils/styles/ThemeManager'
|
|
|
|
import { StyleConstants } from '@utils/styles/constants'
|
2020-11-30 00:24:53 +01:00
|
|
|
import { useTranslation } from 'react-i18next'
|
2020-12-13 14:04:25 +01:00
|
|
|
import Emojis from '@components/Timelines/Timeline/Shared/Emojis'
|
2020-12-17 09:44:03 +01:00
|
|
|
import { LinearGradient } from 'expo-linear-gradient'
|
2020-12-18 00:00:45 +01:00
|
|
|
import { AccountAction } from '../Account'
|
2020-12-21 21:47:15 +01:00
|
|
|
import { ButtonRow } from '@root/components/Button'
|
|
|
|
import { useMutation, useQuery, useQueryClient } from 'react-query'
|
|
|
|
import { relationshipFetch } from '@root/utils/fetches/relationshipFetch'
|
|
|
|
import client from '@root/api/client'
|
|
|
|
import { useNavigation } from '@react-navigation/native'
|
|
|
|
import getCurrentTab from '@root/utils/getCurrentTab'
|
|
|
|
|
|
|
|
const fireMutation = async ({
|
|
|
|
type,
|
|
|
|
id,
|
|
|
|
stateKey,
|
|
|
|
prevState
|
|
|
|
}: {
|
|
|
|
type: 'follow'
|
|
|
|
id: string
|
|
|
|
stateKey: 'following'
|
|
|
|
prevState: boolean
|
|
|
|
}) => {
|
|
|
|
let res
|
|
|
|
switch (type) {
|
|
|
|
case 'follow':
|
|
|
|
res = await client({
|
|
|
|
method: 'post',
|
|
|
|
instance: 'local',
|
|
|
|
url: `accounts/${id}/${prevState ? 'un' : ''}${type}`
|
|
|
|
})
|
|
|
|
|
|
|
|
if (res.body[stateKey] === !prevState) {
|
|
|
|
return Promise.resolve()
|
|
|
|
} else {
|
|
|
|
return Promise.reject()
|
|
|
|
}
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
2020-11-22 00:46:23 +01:00
|
|
|
|
|
|
|
export interface Props {
|
2020-12-18 00:00:45 +01:00
|
|
|
accountDispatch?: Dispatch<AccountAction>
|
2020-11-22 00:46:23 +01:00
|
|
|
account: Mastodon.Account | undefined
|
|
|
|
}
|
|
|
|
|
2020-12-18 00:00:45 +01:00
|
|
|
const AccountInformation: React.FC<Props> = ({ accountDispatch, account }) => {
|
2020-12-21 21:47:15 +01:00
|
|
|
const navigation = useNavigation()
|
2020-11-30 00:24:53 +01:00
|
|
|
const { t } = useTranslation('sharedAccount')
|
2020-11-23 00:07:32 +01:00
|
|
|
const { theme } = useTheme()
|
2020-11-22 00:46:23 +01:00
|
|
|
const [avatarLoaded, setAvatarLoaded] = useState(false)
|
|
|
|
|
2020-12-21 21:47:15 +01:00
|
|
|
const relationshipQueryKey = ['Relationship', { id: account?.id }]
|
|
|
|
const { status, data, refetch } = useQuery(
|
|
|
|
relationshipQueryKey,
|
|
|
|
relationshipFetch,
|
|
|
|
{
|
|
|
|
enabled: false
|
|
|
|
}
|
|
|
|
)
|
|
|
|
useEffect(() => {
|
|
|
|
if (account?.id) {
|
|
|
|
refetch()
|
|
|
|
}
|
|
|
|
}, [account])
|
|
|
|
const queryClient = useQueryClient()
|
|
|
|
const { mutate, status: mutateStatus } = useMutation(fireMutation, {
|
|
|
|
onMutate: () => {
|
|
|
|
queryClient.cancelQueries(relationshipQueryKey)
|
|
|
|
const oldData = queryClient.getQueryData(relationshipQueryKey)
|
|
|
|
|
|
|
|
queryClient.setQueryData(relationshipQueryKey, (old: any) => {
|
|
|
|
old && (old.following = !old?.following)
|
|
|
|
return old
|
|
|
|
})
|
|
|
|
|
|
|
|
return oldData
|
|
|
|
},
|
|
|
|
onError: (err, _, oldData) => {
|
|
|
|
queryClient.setQueryData(relationshipQueryKey, oldData)
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
2020-12-17 09:44:03 +01:00
|
|
|
const ShimmerPlaceholder = createShimmerPlaceholder(LinearGradient)
|
|
|
|
const shimmerAvatarRef = createRef<any>()
|
|
|
|
const shimmerNameRef = createRef<any>()
|
|
|
|
const shimmerAccountRef = createRef<any>()
|
|
|
|
const shimmerCreatedRef = createRef<any>()
|
|
|
|
const shimmerStatTootRef = createRef<any>()
|
|
|
|
const shimmerStatFolloingRef = createRef<any>()
|
|
|
|
const shimmerStatFollowerRef = createRef<any>()
|
2020-12-14 23:44:57 +01:00
|
|
|
useEffect(() => {
|
|
|
|
const informationAnimated = Animated.stagger(400, [
|
|
|
|
Animated.parallel([
|
|
|
|
shimmerAvatarRef.current!.getAnimated(),
|
|
|
|
shimmerNameRef.current!.getAnimated(),
|
|
|
|
shimmerAccountRef.current!.getAnimated(),
|
|
|
|
shimmerCreatedRef.current!.getAnimated(),
|
|
|
|
shimmerStatTootRef.current!.getAnimated(),
|
|
|
|
shimmerStatFolloingRef.current!.getAnimated(),
|
|
|
|
shimmerStatFollowerRef.current!.getAnimated()
|
|
|
|
])
|
|
|
|
])
|
|
|
|
Animated.loop(informationAnimated).start()
|
|
|
|
}, [])
|
|
|
|
|
2020-12-21 21:47:15 +01:00
|
|
|
const followingButton = useMemo(
|
|
|
|
() => (
|
|
|
|
<ButtonRow
|
|
|
|
{...(data
|
|
|
|
? status !== 'success' ||
|
|
|
|
(mutateStatus !== 'success' && mutateStatus !== 'idle')
|
|
|
|
? { icon: 'loader' }
|
|
|
|
: { text: `${data.following ? '正在' : ''}关注` }
|
|
|
|
: { icon: 'loader' })}
|
|
|
|
onPress={() =>
|
|
|
|
mutate({
|
|
|
|
type: 'follow',
|
|
|
|
id: account!.id,
|
|
|
|
stateKey: 'following',
|
|
|
|
prevState: data!.following
|
|
|
|
})
|
|
|
|
}
|
|
|
|
disabled={
|
|
|
|
status !== 'success' ||
|
|
|
|
(mutateStatus !== 'success' && mutateStatus !== 'idle')
|
|
|
|
}
|
|
|
|
/>
|
|
|
|
),
|
|
|
|
[data, status, mutateStatus]
|
|
|
|
)
|
|
|
|
|
2020-11-22 00:46:23 +01:00
|
|
|
return (
|
2020-12-17 09:44:03 +01:00
|
|
|
<View
|
2020-12-21 21:47:15 +01:00
|
|
|
style={styles.base}
|
2020-12-17 09:44:03 +01:00
|
|
|
onLayout={({ nativeEvent }) =>
|
2020-12-18 00:00:45 +01:00
|
|
|
accountDispatch &&
|
2020-12-17 09:44:03 +01:00
|
|
|
accountDispatch({
|
|
|
|
type: 'informationLayout',
|
|
|
|
payload: {
|
|
|
|
y: nativeEvent.layout.y,
|
|
|
|
height: nativeEvent.layout.height
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
>
|
2020-11-22 00:46:23 +01:00
|
|
|
{/* <Text>Moved or not: {account.moved}</Text> */}
|
2020-12-21 21:47:15 +01:00
|
|
|
<View style={styles.avatarAndActions}>
|
|
|
|
<ShimmerPlaceholder
|
|
|
|
ref={shimmerAvatarRef}
|
|
|
|
visible={avatarLoaded}
|
|
|
|
width={StyleConstants.Avatar.L}
|
|
|
|
height={StyleConstants.Avatar.L}
|
|
|
|
>
|
|
|
|
<Image
|
|
|
|
source={{ uri: account?.avatar }}
|
|
|
|
style={styles.avatar}
|
|
|
|
onLoadEnd={() => setAvatarLoaded(true)}
|
|
|
|
/>
|
|
|
|
</ShimmerPlaceholder>
|
|
|
|
<View style={styles.actions}>
|
|
|
|
<ButtonRow
|
|
|
|
icon='mail'
|
|
|
|
onPress={() =>
|
|
|
|
navigation.navigate(getCurrentTab(navigation), {
|
|
|
|
screen: 'Screen-Shared-Compose',
|
|
|
|
params: {
|
|
|
|
type: 'conversation',
|
|
|
|
incomingStatus: { account }
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
style={{ marginRight: StyleConstants.Spacing.S }}
|
|
|
|
/>
|
|
|
|
{followingButton}
|
|
|
|
</View>
|
|
|
|
</View>
|
2020-11-22 00:46:23 +01:00
|
|
|
|
2020-12-14 23:44:57 +01:00
|
|
|
<ShimmerPlaceholder
|
|
|
|
ref={shimmerNameRef}
|
|
|
|
visible={account !== undefined}
|
|
|
|
width={StyleConstants.Font.Size.L * 8}
|
|
|
|
height={StyleConstants.Font.Size.L}
|
|
|
|
style={styles.display_name}
|
|
|
|
>
|
|
|
|
<View>
|
|
|
|
{account?.emojis ? (
|
|
|
|
<Emojis
|
|
|
|
content={account?.display_name || account?.username}
|
|
|
|
emojis={account.emojis}
|
|
|
|
size={StyleConstants.Font.Size.L}
|
|
|
|
fontBold={true}
|
|
|
|
/>
|
|
|
|
) : (
|
|
|
|
<Text
|
|
|
|
style={{
|
|
|
|
color: theme.primary,
|
|
|
|
fontSize: StyleConstants.Font.Size.L,
|
|
|
|
fontWeight: StyleConstants.Font.Weight.Bold
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
{account?.display_name || account?.username}
|
|
|
|
</Text>
|
|
|
|
)}
|
|
|
|
</View>
|
|
|
|
</ShimmerPlaceholder>
|
|
|
|
|
|
|
|
<ShimmerPlaceholder
|
|
|
|
ref={shimmerAccountRef}
|
|
|
|
visible={account !== undefined}
|
|
|
|
width={StyleConstants.Font.Size.M * 8}
|
|
|
|
height={StyleConstants.Font.Size.M}
|
|
|
|
style={{ marginBottom: StyleConstants.Spacing.L }}
|
|
|
|
>
|
|
|
|
<View style={styles.account}>
|
2020-12-01 00:44:28 +01:00
|
|
|
<Text
|
|
|
|
style={{
|
2020-12-14 23:44:57 +01:00
|
|
|
color: theme.secondary,
|
|
|
|
fontSize: StyleConstants.Font.Size.M
|
2020-12-01 00:44:28 +01:00
|
|
|
}}
|
2020-12-14 23:44:57 +01:00
|
|
|
selectable
|
2020-12-01 00:44:28 +01:00
|
|
|
>
|
2020-12-14 23:44:57 +01:00
|
|
|
@{account?.acct}
|
2020-12-01 00:44:28 +01:00
|
|
|
</Text>
|
2020-12-14 23:44:57 +01:00
|
|
|
{account?.locked && (
|
|
|
|
<Feather
|
|
|
|
name='lock'
|
|
|
|
style={styles.account_types}
|
|
|
|
color={theme.secondary}
|
|
|
|
/>
|
|
|
|
)}
|
|
|
|
{account?.bot && (
|
|
|
|
<Feather
|
|
|
|
name='hard-drive'
|
|
|
|
style={styles.account_types}
|
|
|
|
color={theme.secondary}
|
|
|
|
/>
|
|
|
|
)}
|
|
|
|
</View>
|
|
|
|
</ShimmerPlaceholder>
|
2020-11-22 00:46:23 +01:00
|
|
|
|
2020-12-01 00:44:28 +01:00
|
|
|
{account?.fields && account.fields.length > 0 && (
|
|
|
|
<View style={[styles.fields, { borderTopColor: theme.border }]}>
|
2020-11-23 00:07:32 +01:00
|
|
|
{account.fields.map((field, index) => (
|
2020-12-01 00:44:28 +01:00
|
|
|
<View
|
|
|
|
key={index}
|
|
|
|
style={[styles.field, { borderBottomColor: theme.border }]}
|
|
|
|
>
|
|
|
|
<View
|
2020-12-14 23:44:57 +01:00
|
|
|
style={[styles.fieldLeft, { borderRightColor: theme.border }]}
|
2020-11-23 00:07:32 +01:00
|
|
|
>
|
|
|
|
<ParseContent
|
|
|
|
content={field.name}
|
2020-12-13 01:24:25 +01:00
|
|
|
size={'M'}
|
2020-11-23 00:07:32 +01:00
|
|
|
emojis={account.emojis}
|
|
|
|
showFullLink
|
2020-12-01 00:44:28 +01:00
|
|
|
/>
|
|
|
|
{field.verified_at && (
|
|
|
|
<Feather
|
|
|
|
name='check-circle'
|
|
|
|
size={StyleConstants.Font.Size.M}
|
|
|
|
color={theme.primary}
|
2020-12-14 23:44:57 +01:00
|
|
|
style={styles.fieldCheck}
|
2020-12-01 00:44:28 +01:00
|
|
|
/>
|
|
|
|
)}
|
|
|
|
</View>
|
2020-12-14 23:44:57 +01:00
|
|
|
<View style={styles.fieldRight}>
|
2020-11-23 00:07:32 +01:00
|
|
|
<ParseContent
|
|
|
|
content={field.value}
|
2020-12-13 01:24:25 +01:00
|
|
|
size={'M'}
|
2020-11-23 00:07:32 +01:00
|
|
|
emojis={account.emojis}
|
|
|
|
showFullLink
|
|
|
|
/>
|
2020-12-01 00:44:28 +01:00
|
|
|
</View>
|
2020-11-23 00:07:32 +01:00
|
|
|
</View>
|
|
|
|
))}
|
|
|
|
</View>
|
|
|
|
)}
|
|
|
|
|
2020-11-22 00:46:23 +01:00
|
|
|
{account?.note && (
|
2020-11-23 00:07:32 +01:00
|
|
|
<View style={styles.note}>
|
|
|
|
<ParseContent
|
|
|
|
content={account.note}
|
2020-12-13 01:24:25 +01:00
|
|
|
size={'M'}
|
2020-11-23 00:07:32 +01:00
|
|
|
emojis={account.emojis}
|
|
|
|
/>
|
|
|
|
</View>
|
2020-11-22 00:46:23 +01:00
|
|
|
)}
|
2020-11-23 00:07:32 +01:00
|
|
|
|
2020-12-14 23:44:57 +01:00
|
|
|
<ShimmerPlaceholder
|
|
|
|
ref={shimmerCreatedRef}
|
|
|
|
visible={account !== undefined}
|
|
|
|
width={StyleConstants.Font.Size.S * 8}
|
|
|
|
height={StyleConstants.Font.Size.S}
|
|
|
|
style={{ marginBottom: StyleConstants.Spacing.M }}
|
|
|
|
>
|
|
|
|
<View style={styles.created_at}>
|
|
|
|
<Feather
|
|
|
|
name='calendar'
|
|
|
|
size={StyleConstants.Font.Size.S}
|
|
|
|
color={theme.secondary}
|
|
|
|
style={styles.created_at_icon}
|
|
|
|
/>
|
|
|
|
<Text
|
|
|
|
style={{
|
|
|
|
color: theme.secondary,
|
|
|
|
fontSize: StyleConstants.Font.Size.S
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
{t('content.created_at', {
|
2020-12-01 00:44:28 +01:00
|
|
|
date: new Date(account?.created_at!).toLocaleDateString('zh-CN', {
|
2020-11-30 00:24:53 +01:00
|
|
|
year: 'numeric',
|
|
|
|
month: 'long',
|
|
|
|
day: 'numeric'
|
|
|
|
})
|
2020-12-14 23:44:57 +01:00
|
|
|
})}
|
|
|
|
</Text>
|
|
|
|
</View>
|
|
|
|
</ShimmerPlaceholder>
|
2020-11-22 00:46:23 +01:00
|
|
|
|
2020-12-14 23:44:57 +01:00
|
|
|
<View style={styles.stats}>
|
|
|
|
<ShimmerPlaceholder
|
|
|
|
ref={shimmerStatTootRef}
|
|
|
|
visible={account !== undefined}
|
|
|
|
width={StyleConstants.Font.Size.S * 5}
|
|
|
|
height={StyleConstants.Font.Size.S}
|
|
|
|
>
|
|
|
|
<Text style={[styles.stat, { color: theme.primary }]}>
|
|
|
|
{t('content.summary.statuses_count', {
|
|
|
|
count: account?.statuses_count || 0
|
|
|
|
})}
|
|
|
|
</Text>
|
|
|
|
</ShimmerPlaceholder>
|
|
|
|
<ShimmerPlaceholder
|
|
|
|
ref={shimmerStatFolloingRef}
|
|
|
|
visible={account !== undefined}
|
|
|
|
width={StyleConstants.Font.Size.S * 5}
|
|
|
|
height={StyleConstants.Font.Size.S}
|
|
|
|
>
|
|
|
|
<Text
|
|
|
|
style={[styles.stat, { color: theme.primary, textAlign: 'center' }]}
|
|
|
|
>
|
|
|
|
{t('content.summary.followers_count', {
|
|
|
|
count: account?.followers_count || 0
|
|
|
|
})}
|
|
|
|
</Text>
|
|
|
|
</ShimmerPlaceholder>
|
|
|
|
<ShimmerPlaceholder
|
|
|
|
ref={shimmerStatFollowerRef}
|
|
|
|
visible={account !== undefined}
|
|
|
|
width={StyleConstants.Font.Size.S * 5}
|
|
|
|
height={StyleConstants.Font.Size.S}
|
|
|
|
>
|
|
|
|
<Text
|
|
|
|
style={[styles.stat, { color: theme.primary, textAlign: 'right' }]}
|
|
|
|
>
|
|
|
|
{t('content.summary.following_count', {
|
|
|
|
count: account?.following_count || 0
|
|
|
|
})}
|
|
|
|
</Text>
|
|
|
|
</ShimmerPlaceholder>
|
2020-11-23 00:07:32 +01:00
|
|
|
</View>
|
2020-11-22 00:46:23 +01:00
|
|
|
</View>
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
const styles = StyleSheet.create({
|
2020-12-21 21:47:15 +01:00
|
|
|
base: {
|
2020-12-17 09:44:03 +01:00
|
|
|
marginTop: -StyleConstants.Spacing.Global.PagePadding * 3,
|
2020-11-30 00:24:53 +01:00
|
|
|
padding: StyleConstants.Spacing.Global.PagePadding
|
2020-11-23 00:07:32 +01:00
|
|
|
},
|
2020-12-21 21:47:15 +01:00
|
|
|
avatarAndActions: {
|
|
|
|
flexDirection: 'row',
|
|
|
|
justifyContent: 'space-between'
|
|
|
|
},
|
2020-11-22 00:46:23 +01:00
|
|
|
avatar: {
|
2020-11-30 00:24:53 +01:00
|
|
|
width: StyleConstants.Avatar.L,
|
|
|
|
height: StyleConstants.Avatar.L,
|
2020-11-23 00:07:32 +01:00
|
|
|
borderRadius: 8
|
2020-11-22 00:46:23 +01:00
|
|
|
},
|
2020-12-21 21:47:15 +01:00
|
|
|
actions: {
|
|
|
|
alignSelf: 'flex-end',
|
|
|
|
flexDirection: 'row'
|
|
|
|
},
|
2020-11-22 00:46:23 +01:00
|
|
|
display_name: {
|
2020-12-01 00:44:28 +01:00
|
|
|
flexDirection: 'row',
|
2020-11-30 00:24:53 +01:00
|
|
|
marginTop: StyleConstants.Spacing.M,
|
|
|
|
marginBottom: StyleConstants.Spacing.XS
|
2020-11-22 00:46:23 +01:00
|
|
|
},
|
|
|
|
account: {
|
2020-12-01 00:44:28 +01:00
|
|
|
flexDirection: 'row',
|
2020-12-14 23:44:57 +01:00
|
|
|
alignItems: 'center'
|
2020-11-23 00:07:32 +01:00
|
|
|
},
|
2020-12-01 00:44:28 +01:00
|
|
|
account_types: { marginLeft: StyleConstants.Spacing.S },
|
2020-11-23 00:07:32 +01:00
|
|
|
fields: {
|
2020-12-03 22:03:06 +01:00
|
|
|
borderTopWidth: StyleSheet.hairlineWidth,
|
2020-12-01 00:44:28 +01:00
|
|
|
marginBottom: StyleConstants.Spacing.M
|
|
|
|
},
|
|
|
|
field: {
|
|
|
|
flex: 1,
|
|
|
|
flexDirection: 'row',
|
2020-12-03 22:03:06 +01:00
|
|
|
borderBottomWidth: StyleSheet.hairlineWidth,
|
2020-12-01 00:44:28 +01:00
|
|
|
paddingTop: StyleConstants.Spacing.S,
|
|
|
|
paddingBottom: StyleConstants.Spacing.S
|
2020-11-23 00:07:32 +01:00
|
|
|
},
|
2020-12-14 23:44:57 +01:00
|
|
|
fieldLeft: {
|
|
|
|
flexBasis: '30%',
|
|
|
|
flexDirection: 'row',
|
|
|
|
alignItems: 'center',
|
|
|
|
justifyContent: 'center',
|
|
|
|
borderRightWidth: 1,
|
|
|
|
paddingLeft: StyleConstants.Spacing.S,
|
|
|
|
paddingRight: StyleConstants.Spacing.S
|
|
|
|
},
|
|
|
|
fieldCheck: { marginLeft: StyleConstants.Spacing.XS },
|
|
|
|
fieldRight: {
|
|
|
|
flexBasis: '70%',
|
|
|
|
alignItems: 'center',
|
|
|
|
justifyContent: 'center',
|
|
|
|
paddingLeft: StyleConstants.Spacing.S,
|
|
|
|
paddingRight: StyleConstants.Spacing.S
|
|
|
|
},
|
2020-11-23 00:07:32 +01:00
|
|
|
note: {
|
2020-12-01 00:44:28 +01:00
|
|
|
marginBottom: StyleConstants.Spacing.L
|
2020-11-23 00:07:32 +01:00
|
|
|
},
|
|
|
|
created_at: {
|
|
|
|
flexDirection: 'row',
|
2020-12-14 23:44:57 +01:00
|
|
|
alignItems: 'center'
|
2020-11-23 00:07:32 +01:00
|
|
|
},
|
2020-12-01 00:44:28 +01:00
|
|
|
created_at_icon: {
|
|
|
|
marginRight: StyleConstants.Spacing.XS
|
|
|
|
},
|
2020-12-14 23:44:57 +01:00
|
|
|
stats: {
|
2020-12-01 00:44:28 +01:00
|
|
|
flex: 1,
|
2020-11-23 00:07:32 +01:00
|
|
|
flexDirection: 'row',
|
|
|
|
justifyContent: 'space-between'
|
2020-12-14 23:44:57 +01:00
|
|
|
},
|
|
|
|
stat: {
|
|
|
|
fontSize: StyleConstants.Font.Size.S
|
2020-11-22 00:46:23 +01:00
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
export default AccountInformation
|