@thecb/components 11.2.6-beta.0 → 11.2.6-beta.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/index.cjs.js +98 -79
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.esm.js +98 -79
- package/dist/index.esm.js.map +1 -1
- package/package.json +1 -1
- package/src/components/atoms/layouts/Center.styled.js +2 -0
- package/src/components/atoms/link/ExternalLink.js +4 -2
- package/src/components/atoms/link/ExternalLink.styled.js +1 -2
- package/src/components/atoms/link/InternalLink.js +4 -2
- package/src/components/atoms/link/InternalLink.styled.js +1 -2
- package/src/components/molecules/contact-card/ContactCard.js +2 -4
- package/src/components/molecules/hero-image/HeroImage.js +67 -54
- package/src/components/molecules/hero-image/HeroImage.stories.js +22 -8
- package/src/components/molecules/hero-image/HeroImage.styled.js +18 -10
- package/src/components/molecules/hero-image/HeroImage.theme.js +6 -6
- package/src/components/molecules/registration-banner/RegistrationBanner.js +10 -5
- package/src/components/molecules/registration-banner/RegistrationBanner.styled.js +6 -4
- package/src/components/molecules/tab-sidebar/TabSidebar.js +1 -0
- package/src/util/general.js +12 -0
package/package.json
CHANGED
|
@@ -4,6 +4,7 @@ export const CenterWrapper = styled.div`
|
|
|
4
4
|
box-sizing: content-box;
|
|
5
5
|
margin-left: auto;
|
|
6
6
|
margin-right: auto;
|
|
7
|
+
width: ${({ width }) => width || "auto"};
|
|
7
8
|
max-width: ${({ maxWidth }) => maxWidth};
|
|
8
9
|
padding-left: ${({ gutters }) => gutters};
|
|
9
10
|
padding-right: ${({ gutters }) => gutters};
|
|
@@ -15,4 +16,5 @@ export const CenterWrapper = styled.div`
|
|
|
15
16
|
align-items: center;
|
|
16
17
|
`
|
|
17
18
|
: ``};
|
|
19
|
+
${({ extraStyles }) => extraStyles}
|
|
18
20
|
`;
|
|
@@ -6,6 +6,7 @@ import { StyledExternalLink } from "./ExternalLink.styled";
|
|
|
6
6
|
import { FONT_WEIGHT_REGULAR } from "../../../constants/style_constants";
|
|
7
7
|
import { safeChildren } from "../../../util/general";
|
|
8
8
|
import { Box } from "../layouts";
|
|
9
|
+
import { LINK_TEXT_DECORATION } from "../../../constants/style_constants";
|
|
9
10
|
|
|
10
11
|
const ExternalLink = forwardRef(
|
|
11
12
|
(
|
|
@@ -57,11 +58,12 @@ const ExternalLink = forwardRef(
|
|
|
57
58
|
activeColor={themeValues.activeColor}
|
|
58
59
|
fontFamily={themeValues.fontFamily}
|
|
59
60
|
tabIndex={tabIndex}
|
|
60
|
-
extrastyles={
|
|
61
|
+
extrastyles={`text-decoration: ${
|
|
62
|
+
isUnderlined ? LINK_TEXT_DECORATION : "none"
|
|
63
|
+
}; ${extraStyles}`}
|
|
61
64
|
rel={newTab ? "noopener" : ""}
|
|
62
65
|
data-qa={dataQa}
|
|
63
66
|
aria-label={ariaLabel}
|
|
64
|
-
isUnderlined={isUnderlined}
|
|
65
67
|
ref={ref}
|
|
66
68
|
>
|
|
67
69
|
{safeChildren(children, <span />)}
|
|
@@ -22,8 +22,7 @@ export const StyledExternalLink = styled(
|
|
|
22
22
|
font-weight: ${({ weight }) => weight};
|
|
23
23
|
font-family: ${({ fontFamily }) => fontFamily};
|
|
24
24
|
line-height: ${({ lineheight }) => lineheight};
|
|
25
|
-
text-decoration: ${
|
|
26
|
-
isUnderlined ? LINK_TEXT_DECORATION : "none"};
|
|
25
|
+
text-decoration: ${LINK_TEXT_DECORATION};
|
|
27
26
|
|
|
28
27
|
&:hover {
|
|
29
28
|
color: ${({ hoverColor }) => hoverColor};
|
|
@@ -4,6 +4,7 @@ import { fallbackValues } from "./Link.theme";
|
|
|
4
4
|
import { createThemeValues } from "../../../util/themeUtils";
|
|
5
5
|
import { StyledInternalLink } from "./InternalLink.styled";
|
|
6
6
|
import { safeChildren } from "../../../util/general";
|
|
7
|
+
import { LINK_TEXT_DECORATION } from "../../../constants/style_constants";
|
|
7
8
|
|
|
8
9
|
const InternalLink = forwardRef(
|
|
9
10
|
(
|
|
@@ -45,9 +46,10 @@ const InternalLink = forwardRef(
|
|
|
45
46
|
hoverColor={themeValues.hoverColor}
|
|
46
47
|
activeColor={themeValues.activeColor}
|
|
47
48
|
tabIndex={tabIndex}
|
|
48
|
-
extrastyles={
|
|
49
|
+
extrastyles={`text-decoration: ${
|
|
50
|
+
isUnderlined ? LINK_TEXT_DECORATION : "none"
|
|
51
|
+
}; ${extraStyles}`}
|
|
49
52
|
data-qa={dataQa}
|
|
50
|
-
isUnderlined={isUnderlined}
|
|
51
53
|
ref={ref}
|
|
52
54
|
>
|
|
53
55
|
{safeChildren(children, <span />)}
|
|
@@ -28,8 +28,7 @@ export const StyledInternalLink = styled(
|
|
|
28
28
|
font-size: ${({ fontSize }) => fontSize};
|
|
29
29
|
font-family: ${({ fontFamily }) => fontFamily};
|
|
30
30
|
margin: ${({ margin }) => margin};
|
|
31
|
-
text-decoration: ${
|
|
32
|
-
isUnderlined ? LINK_TEXT_DECORATION : "none"};
|
|
31
|
+
text-decoration: ${LINK_TEXT_DECORATION};
|
|
33
32
|
|
|
34
33
|
&:hover {
|
|
35
34
|
color: ${({ hoverColor }) => hoverColor};
|
|
@@ -101,10 +101,9 @@ const ContactCard = ({
|
|
|
101
101
|
"contact-card-link"
|
|
102
102
|
);
|
|
103
103
|
return (
|
|
104
|
-
|
|
104
|
+
<React.Fragment key={linkID}>
|
|
105
105
|
{R.test(URL_TEST, link.link) ? (
|
|
106
106
|
<ExternalLink
|
|
107
|
-
key={linkID}
|
|
108
107
|
dataQa={linkID}
|
|
109
108
|
href={link.link}
|
|
110
109
|
newTab={true}
|
|
@@ -129,7 +128,6 @@ const ContactCard = ({
|
|
|
129
128
|
</ExternalLink>
|
|
130
129
|
) : (
|
|
131
130
|
<InternalLink
|
|
132
|
-
key={linkID}
|
|
133
131
|
to={link.link}
|
|
134
132
|
dataQa={linkID}
|
|
135
133
|
fontSize={FONT_SIZE.SM}
|
|
@@ -145,7 +143,7 @@ const ContactCard = ({
|
|
|
145
143
|
{link.text}
|
|
146
144
|
</InternalLink>
|
|
147
145
|
)}
|
|
148
|
-
|
|
146
|
+
</React.Fragment>
|
|
149
147
|
);
|
|
150
148
|
})}
|
|
151
149
|
</Stack>
|
|
@@ -1,82 +1,95 @@
|
|
|
1
1
|
import React, { useContext } from "react";
|
|
2
2
|
import { ThemeContext } from "styled-components";
|
|
3
|
-
import { Box,
|
|
4
|
-
import BoxWithShadow from "../../atoms/box-with-shadow";
|
|
3
|
+
import { Box, Center, Stack } from "../../atoms/layouts";
|
|
5
4
|
import { themeComponent } from "../../../util/themeUtils";
|
|
6
5
|
import Paragraph from "../../atoms/paragraph";
|
|
7
6
|
import Title from "../../atoms/title";
|
|
8
7
|
import { fallbackValues } from "./HeroImage.theme";
|
|
9
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
FONT_WEIGHT_BOLD,
|
|
10
|
+
FONT_WEIGHT_SEMIBOLD
|
|
11
|
+
} from "../../../constants/style_constants";
|
|
10
12
|
import * as Styled from "./HeroImage.styled";
|
|
13
|
+
import { getNextHeading } from "../../../util/general";
|
|
11
14
|
|
|
12
15
|
const HeroImage = ({
|
|
13
16
|
themeValues,
|
|
14
17
|
heading,
|
|
18
|
+
headingVariant = "h2",
|
|
15
19
|
subheading,
|
|
16
20
|
description,
|
|
17
21
|
imageUrl,
|
|
18
22
|
variant = "v1",
|
|
19
|
-
padding = "4rem",
|
|
20
23
|
minWidth = "100%",
|
|
21
24
|
minHeight = "auto",
|
|
22
|
-
contentSpacing = "0.5rem"
|
|
25
|
+
contentSpacing = "0.5rem",
|
|
26
|
+
paddingOverride
|
|
23
27
|
}) => {
|
|
24
28
|
const { isMobile } = useContext(ThemeContext);
|
|
29
|
+
const secondaryHeadingVariant = getNextHeading(headingVariant);
|
|
25
30
|
|
|
26
31
|
return (
|
|
27
32
|
<>
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
33
|
+
<Styled.HeroImageContainer
|
|
34
|
+
minWidth={minWidth}
|
|
35
|
+
minHeight={minHeight}
|
|
36
|
+
padding={paddingOverride ?? (isMobile ? "2rem" : "3rem 5.75rem")}
|
|
37
|
+
extraStyles={Styled.getHeroImageVariantStyles({
|
|
38
|
+
imageUrl,
|
|
39
|
+
isMobile,
|
|
40
|
+
variant,
|
|
41
|
+
heroPrimaryColor: themeValues.heroPrimaryColor,
|
|
42
|
+
heroSecondaryColor: themeValues.heroSecondaryColor
|
|
43
|
+
})}
|
|
44
|
+
>
|
|
45
|
+
<Center
|
|
46
|
+
maxWidth={"78.5rem"}
|
|
47
|
+
width={"100%"}
|
|
48
|
+
intrinsic
|
|
49
|
+
extraStyles={`
|
|
50
|
+
flex-flow: unset;
|
|
51
|
+
justify-content: flex-start;
|
|
52
|
+
flex-wrap: nowrap;"
|
|
53
|
+
`}
|
|
39
54
|
>
|
|
40
|
-
<
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
extraStyles={"display: flex; align-items: center;"}
|
|
55
|
+
<Stack
|
|
56
|
+
childGap={contentSpacing}
|
|
57
|
+
extraStyles={`max-width: ${isMobile ? "100%" : "50%"};`}
|
|
44
58
|
>
|
|
45
|
-
<Stack childGap=
|
|
46
|
-
<
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
</Title>
|
|
66
|
-
</Stack>
|
|
67
|
-
<Box padding="0">
|
|
68
|
-
<Paragraph
|
|
69
|
-
color={themeValues.textColor}
|
|
70
|
-
extraStyles={`line-height: 150%; ${!isMobile &&
|
|
71
|
-
`font-size: 1.125rem;`}`}
|
|
72
|
-
>
|
|
73
|
-
{description}
|
|
74
|
-
</Paragraph>
|
|
75
|
-
</Box>
|
|
59
|
+
<Stack childGap="0">
|
|
60
|
+
<Title
|
|
61
|
+
variant="hero"
|
|
62
|
+
as={headingVariant}
|
|
63
|
+
weight={FONT_WEIGHT_BOLD}
|
|
64
|
+
color={themeValues.heroTextColor}
|
|
65
|
+
extraStyles={`line-height: ${isMobile ? "125%" : "115%"};`}
|
|
66
|
+
>
|
|
67
|
+
{heading}
|
|
68
|
+
</Title>
|
|
69
|
+
<Title
|
|
70
|
+
variant={"large"}
|
|
71
|
+
as={secondaryHeadingVariant}
|
|
72
|
+
weight={FONT_WEIGHT_SEMIBOLD}
|
|
73
|
+
fontSize={isMobile ? "1.5rem" : "2rem"}
|
|
74
|
+
color={themeValues.heroTextColor}
|
|
75
|
+
extraStyles={`line-height: ${isMobile ? "150%" : "115%"};`}
|
|
76
|
+
>
|
|
77
|
+
{subheading}
|
|
78
|
+
</Title>
|
|
76
79
|
</Stack>
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
+
<Box padding="0">
|
|
81
|
+
<Paragraph
|
|
82
|
+
color={themeValues.heroTextColor}
|
|
83
|
+
extraStyles={`line-height: ${
|
|
84
|
+
isMobile ? "150%" : "115%"
|
|
85
|
+
}; ${!isMobile && `font-size: 1.125rem;`}`}
|
|
86
|
+
>
|
|
87
|
+
{description}
|
|
88
|
+
</Paragraph>
|
|
89
|
+
</Box>
|
|
90
|
+
</Stack>
|
|
91
|
+
</Center>
|
|
92
|
+
</Styled.HeroImageContainer>
|
|
80
93
|
</>
|
|
81
94
|
);
|
|
82
95
|
};
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { variants } from "styled-theming";
|
|
2
1
|
import HeroImage from "./HeroImage";
|
|
3
2
|
|
|
4
3
|
const meta = {
|
|
@@ -12,10 +11,7 @@ const meta = {
|
|
|
12
11
|
heading: "Cityville",
|
|
13
12
|
subheading: "Payment Center",
|
|
14
13
|
description:
|
|
15
|
-
"Find and make payments quickly and conveniently from your computer or phone."
|
|
16
|
-
imageUrl:
|
|
17
|
-
"https://thecitybase.wpenginepowered.com/wp-content/uploads/2020/02/homepage-hero2.jpg",
|
|
18
|
-
contentSpacing: "0.5rem"
|
|
14
|
+
"Find and make payments quickly and conveniently from your computer or phone."
|
|
19
15
|
},
|
|
20
16
|
argTypes: {
|
|
21
17
|
heading: {
|
|
@@ -25,6 +21,13 @@ const meta = {
|
|
|
25
21
|
defaultValue: { summary: undefined }
|
|
26
22
|
}
|
|
27
23
|
},
|
|
24
|
+
headingVariant: {
|
|
25
|
+
description: "Heading variant for the hero image heading",
|
|
26
|
+
table: {
|
|
27
|
+
type: { summary: "string" },
|
|
28
|
+
defaultValue: { summary: undefined }
|
|
29
|
+
}
|
|
30
|
+
},
|
|
28
31
|
subheading: {
|
|
29
32
|
description: "Hero image sub-heading",
|
|
30
33
|
table: {
|
|
@@ -46,8 +49,8 @@ const meta = {
|
|
|
46
49
|
defaultValue: { summary: undefined }
|
|
47
50
|
}
|
|
48
51
|
},
|
|
49
|
-
|
|
50
|
-
description: "
|
|
52
|
+
paddingOverride: {
|
|
53
|
+
description: "padding override around the HeroImage content (desktop)",
|
|
51
54
|
table: {
|
|
52
55
|
type: { summary: "string" },
|
|
53
56
|
defaultValue: { summary: "0.5rem 1.5rem" }
|
|
@@ -86,6 +89,17 @@ export const DesktopV1 = {
|
|
|
86
89
|
args: {
|
|
87
90
|
variant: "v1",
|
|
88
91
|
minWidth: "1000px",
|
|
89
|
-
minHeight: "274px"
|
|
92
|
+
minHeight: "274px",
|
|
93
|
+
imageUrl:
|
|
94
|
+
"https://cb-public-assets.s3-us-west-2.amazonaws.com/cityville/hero.png"
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
export const NoImage = {
|
|
99
|
+
args: {
|
|
100
|
+
variant: "v1",
|
|
101
|
+
minWidth: "1000px",
|
|
102
|
+
minHeight: "274px",
|
|
103
|
+
imageUrl: undefined
|
|
90
104
|
}
|
|
91
105
|
};
|
|
@@ -1,20 +1,28 @@
|
|
|
1
1
|
import styled, { css } from "styled-components";
|
|
2
2
|
import { Box } from "../../atoms";
|
|
3
|
+
import { rgba } from "polished";
|
|
3
4
|
|
|
4
5
|
export const getHeroImageVariantStyles = ({
|
|
5
6
|
imageUrl,
|
|
7
|
+
isMobile,
|
|
6
8
|
variant,
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
}) =>
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
9
|
+
heroPrimaryColor,
|
|
10
|
+
heroSecondaryColor
|
|
11
|
+
}) => {
|
|
12
|
+
return css`
|
|
13
|
+
background: ${!isMobile
|
|
14
|
+
? `linear-gradient(
|
|
15
|
+
90deg,
|
|
16
|
+
${heroPrimaryColor} 33%,
|
|
17
|
+
transparent 100%
|
|
18
|
+
)`
|
|
19
|
+
: `linear-gradient(
|
|
20
|
+
${rgba(heroPrimaryColor, 0.8)},
|
|
21
|
+
${rgba(heroPrimaryColor, 0.8)}
|
|
22
|
+
)`},
|
|
23
|
+
url(${imageUrl}) center / cover no-repeat, ${heroPrimaryColor};
|
|
17
24
|
`;
|
|
25
|
+
};
|
|
18
26
|
|
|
19
27
|
export const HeroImageContainer = styled(Box)`
|
|
20
28
|
display: flex;
|
|
@@ -4,12 +4,12 @@ import {
|
|
|
4
4
|
WHITE
|
|
5
5
|
} from "../../../constants/colors";
|
|
6
6
|
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const
|
|
7
|
+
const heroPrimaryColor = ROYAL_BLUE_VIVID;
|
|
8
|
+
const heroSecondaryColor = MATISSE_BLUE;
|
|
9
|
+
const heroTextColor = WHITE;
|
|
10
10
|
|
|
11
11
|
export const fallbackValues = {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
heroPrimaryColor,
|
|
13
|
+
heroSecondaryColor,
|
|
14
|
+
heroTextColor
|
|
15
15
|
};
|
|
@@ -37,6 +37,7 @@ const RegistrationBanner = ({
|
|
|
37
37
|
justify="space-between"
|
|
38
38
|
overflow="visible"
|
|
39
39
|
isMobile={isMobile}
|
|
40
|
+
nowrap
|
|
40
41
|
>
|
|
41
42
|
<Box padding="0" textAlign="left">
|
|
42
43
|
<Heading
|
|
@@ -46,18 +47,18 @@ const RegistrationBanner = ({
|
|
|
46
47
|
variant={titleVariant}
|
|
47
48
|
weight={FONT_WEIGHT_SEMIBOLD}
|
|
48
49
|
>
|
|
49
|
-
Register for a {clientName} Wallet
|
|
50
|
+
Register for a {clientName} Wallet
|
|
50
51
|
</Heading>
|
|
51
52
|
<Text
|
|
52
53
|
extraStyles={`
|
|
53
54
|
display: block;
|
|
54
55
|
padding: ${isMobile ? ".125rem 0 1rem" : "0"}
|
|
55
56
|
`}
|
|
56
|
-
fontSize={isMobile ? FONT_SIZE.
|
|
57
|
+
fontSize={isMobile ? FONT_SIZE.MD : FONT_SIZE.LG}
|
|
57
58
|
color={themeValues.secondaryColor}
|
|
58
59
|
>
|
|
59
|
-
Save payment methods and information for fast, easy, and
|
|
60
|
-
payments with {clientName}
|
|
60
|
+
Save payment methods and billing information for fast, easy, and
|
|
61
|
+
safe payments with {clientName}
|
|
61
62
|
</Text>
|
|
62
63
|
</Box>
|
|
63
64
|
<Styled.ButtonContainer
|
|
@@ -73,7 +74,11 @@ const RegistrationBanner = ({
|
|
|
73
74
|
fontWeight={FONT_WEIGHT_SEMIBOLD}
|
|
74
75
|
url={registrationLink}
|
|
75
76
|
>
|
|
76
|
-
<Cluster
|
|
77
|
+
<Cluster
|
|
78
|
+
justify="center"
|
|
79
|
+
align="center"
|
|
80
|
+
extraStyles="min-width: 100%"
|
|
81
|
+
>
|
|
77
82
|
<Text
|
|
78
83
|
extraStyles="margin-right: 0.5rem"
|
|
79
84
|
fontSize={isMobile ? FONT_SIZE.MD : FONT_SIZE.LG}
|
|
@@ -6,12 +6,12 @@ import { adjustHexColor } from "../../../util/general";
|
|
|
6
6
|
export const BannerContainer = styled(Cluster)`
|
|
7
7
|
background: ${({ themeValues }) =>
|
|
8
8
|
adjustHexColor(themeValues.background, 10, "lighten")};
|
|
9
|
-
padding:
|
|
9
|
+
padding: 2rem;
|
|
10
10
|
`;
|
|
11
11
|
|
|
12
12
|
export const ContentContainer = styled(Cluster)`
|
|
13
13
|
padding: 0;
|
|
14
|
-
width: ${({ isMobile }) => (isMobile ? "
|
|
14
|
+
width: ${({ isMobile }) => (isMobile ? "100%" : " 1224px")};
|
|
15
15
|
> div {
|
|
16
16
|
flex-direction: ${({ isMobile }) => (isMobile ? "column" : "row")};
|
|
17
17
|
}
|
|
@@ -19,8 +19,10 @@ export const ContentContainer = styled(Cluster)`
|
|
|
19
19
|
|
|
20
20
|
export const ButtonContainer = styled(Stack)`
|
|
21
21
|
align-items: center;
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
width: ${({ isMobile }) => (isMobile ? "100%" : "222px")};
|
|
23
|
+
padding-left: ${({ isMobile }) => (isMobile ? "0" : "2rem")};
|
|
24
|
+
> * {
|
|
25
|
+
width: inherit;
|
|
24
26
|
}
|
|
25
27
|
`;
|
|
26
28
|
|
package/src/util/general.js
CHANGED
|
@@ -213,3 +213,15 @@ export const adjustHexColor = (hex, percent, action) => {
|
|
|
213
213
|
.slice(1)
|
|
214
214
|
.padStart(6, "0")}`;
|
|
215
215
|
};
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Gets the next heading level in the sequence.
|
|
219
|
+
*
|
|
220
|
+
* @param {string} heading - The current heading level (e.g., "h1").
|
|
221
|
+
* @returns {string} - The next heading level in the sequence.
|
|
222
|
+
*/
|
|
223
|
+
const headingOrder = ["h1", "h2", "h3", "h4", "h5", "h6"];
|
|
224
|
+
export const getNextHeading = heading => {
|
|
225
|
+
const index = headingOrder.indexOf(heading);
|
|
226
|
+
return index >= 0 && index < 5 ? headingOrder[index + 1] : headingOrder[5];
|
|
227
|
+
};
|