diff --git a/client/src/components/helpers/ImageLoader.js b/client/src/components/helpers/ImageLoader.js
new file mode 100644
index 0000000000..7a4342ef9d
--- /dev/null
+++ b/client/src/components/helpers/ImageLoader.js
@@ -0,0 +1,65 @@
+import React from 'react';
+
+import './image-loader.css';
+import LazyLoad from 'react-lazy-load';
+import PropTypes from 'prop-types';
+
+const propTypes = {
+ alt: PropTypes.string,
+ className: PropTypes.string,
+ height: PropTypes.number,
+ loadedClassName: PropTypes.string,
+ loadingClassName: PropTypes.string,
+ src: PropTypes.string,
+ width: PropTypes.number
+};
+
+class ImageLoader extends React.Component {
+ // initial state: image loaded stage
+ state = {
+ loaded: false
+ };
+
+ // define our loading and loaded image classes
+ static defaultProps = {
+ className: '',
+ loadingClassName: 'img-loading',
+ loadedClassName: 'img-loaded'
+ };
+
+ // image onLoad handler to update state to loaded
+ onLoad = () => {
+ this.setState(() => ({ loaded: true }));
+ };
+
+ render() {
+ let {
+ className,
+ loadedClassName,
+ loadingClassName,
+ alt,
+ src,
+ width,
+ height
+ } = this.props;
+
+ className = `${className} ${
+ this.state.loaded ? loadedClassName : loadingClassName
+ }`;
+
+ return (
+
+ {/* eslint-disable jsx-a11y/no-noninteractive-element-interactions */}
+
+ {/* eslint-enable jsx-a11y/no-noninteractive-element-interactions */}
+
+ );
+ }
+}
+ImageLoader.propTypes = propTypes;
+export default ImageLoader;
diff --git a/client/src/components/helpers/image-loader.css b/client/src/components/helpers/image-loader.css
new file mode 100644
index 0000000000..127e71b8b1
--- /dev/null
+++ b/client/src/components/helpers/image-loader.css
@@ -0,0 +1,23 @@
+@keyframes fadeInImg {
+ from {
+ opacity: 0;
+ }
+ to {
+ opacity: 1;
+ }
+}
+
+.img-loading {
+ opacity: 0;
+ width: 100%;
+ height: auto;
+}
+
+.img-loaded {
+ animation: fadeInImg cubic-bezier(0.23, 1, 0.32, 1) 1;
+ position: relative;
+ opacity: 0;
+ animation-fill-mode: forwards;
+ animation-duration: 0.7s;
+ animation-delay: 0.1s;
+}
diff --git a/client/src/components/helpers/index.js b/client/src/components/helpers/index.js
index da9b95ca94..ac6353802b 100644
--- a/client/src/components/helpers/index.js
+++ b/client/src/components/helpers/index.js
@@ -6,3 +6,4 @@ export { default as SkeletonSprite } from './SkeletonSprite';
export { default as Spacer } from './Spacer';
export { default as Link } from './Link';
export { default as CurrentChallengeLink } from './CurrentChallengeLink';
+export { default as ImageLoader } from './ImageLoader';
diff --git a/client/src/components/landing/components/AsSeenIn.js b/client/src/components/landing/components/AsSeenIn.js
new file mode 100644
index 0000000000..36db0e5e45
--- /dev/null
+++ b/client/src/components/landing/components/AsSeenIn.js
@@ -0,0 +1,18 @@
+import React from 'react';
+import { Col, Row } from '@freecodecamp/react-bootstrap';
+
+import { AsFeatureLogo } from '../../../assets/images/components';
+
+const AsSeenIn = () => (
+
+
+
+
+
+);
+
+AsSeenIn.displayName = 'AsSeenIn';
+export default AsSeenIn;
diff --git a/client/src/components/landing/components/BigCallToAction.js b/client/src/components/landing/components/BigCallToAction.js
new file mode 100644
index 0000000000..b233fa8931
--- /dev/null
+++ b/client/src/components/landing/components/BigCallToAction.js
@@ -0,0 +1,19 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import Login from '../../Header/components/Login';
+
+const propTypes = {
+ page: PropTypes.string
+};
+
+const BigCallToAction = ({ page }) => (
+
+ {page === 'landing'
+ ? "Get started (it's free)"
+ : "Sign in to save your progress (it's free)"}
+
+);
+
+BigCallToAction.displayName = 'BigCallToAction';
+BigCallToAction.propTypes = propTypes;
+export default BigCallToAction;
diff --git a/client/src/components/landing/components/Certifications.js b/client/src/components/landing/components/Certifications.js
new file mode 100644
index 0000000000..eaf154af30
--- /dev/null
+++ b/client/src/components/landing/components/Certifications.js
@@ -0,0 +1,47 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { Col, Row } from '@freecodecamp/react-bootstrap';
+import { uniq } from 'lodash';
+import { Spacer, Link } from '../../helpers';
+import LinkButton from '../../../assets/icons/LinkButton';
+import BigCallToAction from './BigCallToAction';
+
+const propTypes = {
+ nodes: PropTypes.array,
+ page: PropTypes.string
+};
+
+const Certifications = ({ nodes, page }) => {
+ const superBlocks = uniq(nodes.map(node => node.superBlock)).filter(
+ cert => cert !== 'Coding Interview Prep'
+ );
+
+ return (
+
+
+ Earn free verified certifications in:
+
+ {superBlocks.map((superBlock, i) => (
+ -
+
+ {superBlock}
+
+
+
+ ))}
+
+
+
+
+
+
+ );
+};
+
+Certifications.displayName = 'Certifications';
+Certifications.propTypes = propTypes;
+export default Certifications;
diff --git a/client/src/components/landing/components/CompanyLogos.js b/client/src/components/landing/components/CompanyLogos.js
deleted file mode 100644
index 64ace2dd66..0000000000
--- a/client/src/components/landing/components/CompanyLogos.js
+++ /dev/null
@@ -1,26 +0,0 @@
-import React from 'react';
-
-import {
- AmazonLogo,
- AppleLogo,
- MicrosoftLogo,
- SpotifyLogo,
- GoogleLogo
-} from '../../../assets/images';
-
-import './companyLogos.css';
-
-export const CompanyLogos = () => {
- return (
-
- );
-};
-
-CompanyLogos.displayName = 'CompanyLogos';
-export default CompanyLogos;
diff --git a/client/src/components/landing/components/LandingTop.js b/client/src/components/landing/components/LandingTop.js
new file mode 100644
index 0000000000..12ef44a9c7
--- /dev/null
+++ b/client/src/components/landing/components/LandingTop.js
@@ -0,0 +1,78 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import Media from 'react-responsive';
+import { Col, Row } from '@freecodecamp/react-bootstrap';
+import { Spacer, ImageLoader } from '../../helpers';
+import wideImg from '../../../assets/images/landing/wide-image.png';
+import Login from '../../Header/components/Login';
+import {
+ AmazonLogo,
+ AppleLogo,
+ MicrosoftLogo,
+ SpotifyLogo,
+ GoogleLogo
+} from '../../../assets/images/components';
+
+const propTypes = {
+ page: PropTypes.string
+};
+
+const LARGE_SCREEN_SIZE = 1200;
+
+function landingTop({ page }) {
+ const landingImageSection = (
+
+
+
+
+ freeCodeCamp students at a local study group in South Korea.
+
+
+ );
+ const BigCallToAction = (
+
+ {page === 'landing'
+ ? "Get started (it's free)"
+ : "Sign in to save your progress (it's free)"}
+
+ );
+ return (
+
+
+
+
+
+ Learn to code at home.
+
+ Build projects.
+ Earn certifications.
+
+ Since 2014, more than 40,000 freeCodeCamp.org graduates have gotten
+ jobs at tech companies including:
+
+
+
+ {BigCallToAction}
+ {landingImageSection}
+
+
+
+
+ );
+}
+
+landingTop.displayName = 'LandingTop';
+landingTop.propTypes = propTypes;
+export default landingTop;
diff --git a/client/src/components/landing/components/Testimonials.js b/client/src/components/landing/components/Testimonials.js
new file mode 100644
index 0000000000..e8b83e2ed5
--- /dev/null
+++ b/client/src/components/landing/components/Testimonials.js
@@ -0,0 +1,61 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+import { ImageLoader } from '../../helpers';
+import testimonialsMeta from '../landingMeta';
+
+const propTypes = {
+ page: PropTypes.string
+};
+
+const Testimonials = () => {
+ const campers = Object.keys(testimonialsMeta);
+
+ return (
+
+
+ Here is what our alumini say about freeCodeCamp:
+
+
+ {campers.map((camper, i) => {
+ let {
+ name,
+ country,
+ position,
+ company,
+ testimony
+ } = testimonialsMeta[camper];
+ let imageSource = require(`../../../assets/images/landing/${camper}.png`);
+ return (
+
+
+
+
+
+
+
+
+ {' '}
+ {name} in {country}
+
+
+ {position} at {company}
+
+
+
{testimony}
+
+
+ );
+ })}
+
+
+ );
+};
+
+Testimonials.displayName = 'Testimonals';
+Testimonials.propTypes = propTypes;
+export default Testimonials;
diff --git a/client/src/components/landing/components/companyLogos.css b/client/src/components/landing/components/companyLogos.css
deleted file mode 100644
index a09f398e74..0000000000
--- a/client/src/components/landing/components/companyLogos.css
+++ /dev/null
@@ -1,32 +0,0 @@
-.logo-row svg {
- height: 25px;
- margin: 10px;
-}
-
-@media (min-width: 343px) {
- .logo-row svg {
- height: 35px;
- }
-}
-
-@media (min-width: 380px) {
- .logo-row svg {
- height: 40px;
- }
-}
-
-@media (min-width: 480px) {
- .logo-row svg {
- height: 25px;
- }
-}
-
-@media (min-width: 600px) {
- .logo-row svg {
- height: 40px;
- margin: 10px;
- }
- .logo-row #apple-logo {
- height: 35px;
- }
-}
diff --git a/client/src/components/landing/index.js b/client/src/components/landing/index.js
index 05e0217302..294539c29f 100644
--- a/client/src/components/landing/index.js
+++ b/client/src/components/landing/index.js
@@ -1,108 +1,49 @@
import React, { Fragment } from 'react';
-
-import { Grid, Row, Col } from '@freecodecamp/react-bootstrap';
+import { Grid } from '@freecodecamp/react-bootstrap';
import Helmet from 'react-helmet';
import PropTypes from 'prop-types';
-import { Link } from 'gatsby';
-import { uniq, partition } from 'lodash';
-import { Spacer } from '../helpers';
-import Login from '../Header/components/Login';
-import CompanyLogos from './components/CompanyLogos';
-import { AsFeatureLogo } from '../../assets/images';
+import { graphql, useStaticQuery } from 'gatsby';
+
+import Testimonials from './components/Testimonials';
+import LandingTop from './components/LandingTop';
+import Certifications from './components/Certifications';
+import AsSeenIn from './components/AsSeenIn';
import './landing.css';
-import '../Map/map.css';
const propTypes = {
- nodes: PropTypes.array
+ page: PropTypes.string
};
-const BigCallToAction = () => (
-
-
-
- Get started (it's free)
-
-
-
-);
+export const Landing = ({ page = 'landing' }) => {
+ const data = useStaticQuery(graphql`
+ query certifications {
+ challenges: allChallengeNode(
+ filter: { isHidden: { eq: false } }
+ sort: { fields: [superOrder, order, challengeOrder] }
+ ) {
+ nodes {
+ superBlock
+ }
+ }
+ }
+ `);
-const AsFeaturedSection = () => (
-
-
-
-
-
-);
-
-export const Landing = ({ nodes }) => {
- const [superBlocks, rest] = partition(
- uniq(nodes.map(node => node.superBlock)),
- name => name !== 'Coding Interview Prep'
- );
- const interviewPrep = rest[0];
return (
Learn to code at home | freeCodeCamp.org
-
-
-
-
- Welcome to freeCodeCamp.org
-
-
-
- Learn to code at home.
-
- Build projects.
-
- Earn certifications.
-
-
- Since 2014, more than 40,000 freeCodeCamp.org graduates have
- gotten jobs at tech companies including:
-
-
-
-
-
-
-
-
-
-
- Certifications:
-
- {superBlocks.map((superBlock, i) => (
- -
-
-
{superBlock}
-
-
- ))}
-
-
- Additional Learning:
-
- -
-
-
{interviewPrep}
-
-
-
-
-
-
+
+
+
+
+
+
+
+
diff --git a/client/src/components/landing/landing.css b/client/src/components/landing/landing.css
index c286027be3..10b72c58bf 100644
--- a/client/src/components/landing/landing.css
+++ b/client/src/components/landing/landing.css
@@ -9,21 +9,203 @@
white-space: pre-line;
}
-.logo-row {
- display: flex;
- flex-direction: row;
- flex-wrap: wrap;
- justify-content: space-around;
- align-content: center;
- margin-bottom: 10px;
-}
-
.landing-page ul {
list-style: none;
padding-left: 0px;
}
#featured-logos {
- margin-top: 10px;
max-width: 600px;
}
+.landing-top h1:first-child {
+ margin-top: 0px;
+}
+
+.landing-page h1,
+.landing-page h2,
+.landing-page p {
+ font-family: 'Lato', sans-serif;
+}
+
+p.caption {
+ margin: 10px 0 0 0;
+ font-size: 0.8rem;
+ color: var(--quaternary-color);
+}
+
+.as-seen-in {
+ background-color: var(--gray-75);
+ color: var(--gray-15);
+}
+
+.as-seen-in h1 {
+ color: var(--gray-15);
+}
+
+.landing-page h1 {
+ margin-bottom: 40px;
+}
+
+.campers-images {
+ display: none !important;
+}
+
+@media (min-width: 1200px) {
+ .campers-images {
+ display: inline-block !important;
+ width: 100%;
+ height: 100%;
+ }
+}
+
+.logo-row {
+ display: flex;
+ flex-direction: row;
+ flex-wrap: wrap;
+ justify-content: space-around;
+ align-content: center;
+ margin: 10px 0;
+}
+
+.logo-row svg {
+ height: 40px;
+}
+
+@media (min-width: 370px) {
+ .logo-row svg {
+ margin: 5px 15px;
+ }
+}
+
+@media (min-width: 480px) {
+ .logo-row svg {
+ height: 25px;
+ margin: 5px;
+ }
+}
+
+@media (min-width: 550px) {
+ .logo-row {
+ justify-content: space-between;
+ }
+
+ .logo-row svg {
+ height: 40px;
+ }
+}
+
+.cta-landing-section h2 {
+ font-size: 1.3rem;
+ font-weight: 400;
+}
+
+/* testimonials */
+
+.testimonials-row {
+ display: flex;
+ flex-direction: column;
+ justify-content: space-around;
+ flex-wrap: wrap;
+ align-items: center;
+}
+
+.testimonials p,
+.testimonials strong {
+ font-family: 'Lato', sans-serif;
+ font-size: 1.1rem;
+ margin: 0;
+ color: var(--gray-75);
+}
+.testimonial-meta p:last-child {
+ margin-top: 15px;
+}
+
+.testimonial-card {
+ max-width: 350px;
+ display: flex;
+ flex-direction: column;
+ margin: 10px 10px 50px 10px;
+ background: var(--gray-00);
+ -webkit-box-shadow: 0 3px 13px 1px rgba(0, 0, 0, 0.09);
+ box-shadow: 0 3px 13px 1px rgba(0, 0, 0, 0.09);
+}
+
+.testimonial-image,
+.landing-page-image {
+ width: 100%;
+}
+
+.testimonial-meta {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ text-align: center;
+ padding: 10px 0px 30px 0px;
+}
+
+.testimonial-meta p,
+.testimonial-meta strong {
+ font-size: 1.2rem;
+}
+
+.testimonial-card-header {
+ height: 100%;
+ padding-bottom: 100%;
+ position: relative;
+}
+
+.testimonial-image {
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: auto;
+}
+
+.testimonials-footer {
+ display: flex;
+ flex-direction: column;
+ padding: 25px;
+ text-align: justify;
+ justify-content: center;
+}
+.landing-top,
+.as-seen-in,
+.certification-section,
+.testimonials {
+ padding: 4vw 0;
+}
+
+@media (min-width: 500px) {
+ .cta-landing-section h2 {
+ font-size: 1.5rem;
+ }
+}
+
+@media (min-width: 992px) {
+ .testimonial-card {
+ flex-direction: row;
+ width: auto;
+ max-width: none;
+ }
+ .testimonial-image {
+ width: auto;
+ height: 100%;
+ }
+ .testimonial-meta {
+ padding: 0px 0px 30px;
+ }
+ .testimonial-meta p,
+ .testimonial-meta strong {
+ font-size: 1.3rem;
+ }
+ .testimonials-footer {
+ padding: 40px;
+ }
+ .testimonial-card-header {
+ height: 350px;
+ min-width: 350px;
+ padding-bottom: 0;
+ }
+}
diff --git a/client/src/components/landing/landingMeta.js b/client/src/components/landing/landingMeta.js
new file mode 100644
index 0000000000..4a8ad26481
--- /dev/null
+++ b/client/src/components/landing/landingMeta.js
@@ -0,0 +1,48 @@
+import React from 'react';
+
+export default {
+ Shawn: {
+ name: 'Shawn Wang',
+ country: 'Singapore',
+ position: 'Software Engineer',
+ company: 'Amazon',
+ testimony: (
+
+ "It's scary to change careers. I only gained confidence that I could
+ code by working through the hundreds of hours of free lessons on
+ freeCodeCamp. Within a year I had a six-figure job as a Software
+ Engineer.
+ freeCodeCamp changed my life."
+
+ )
+ },
+ Sarah: {
+ name: 'Sarah Chima',
+ country: 'Nigeria',
+ position: 'Software Engineer',
+ company: 'ChatDesk',
+ testimony: (
+
+ “freeCodeCamp was the gateway to my career
+ as a software developer. The well-structured curriculum took my coding
+ knowledge from a total beginner level to a very confident level. It was
+ everything I needed to land my first dev job at an amazing company."
+
+ )
+ },
+ Emma: {
+ name: 'Emma Bostian',
+ country: 'Sweden',
+ position: 'Software Engineer',
+ company: 'Spotify',
+ testimony: (
+
+ "I've always struggled with learning JavaScript. I've taken many courses
+ but freeCodeCamp's course was the one which stuck. Studying JavaScript
+ as well as data structures and algorithms on{' '}
+ freeCodeCamp gave me the skills and confidence I needed
+ to land my dream job as a software engineer at Spotify."
+
+ )
+ }
+};
diff --git a/client/src/components/layouts/global.css b/client/src/components/layouts/global.css
index b64835343c..12fd545e55 100644
--- a/client/src/components/layouts/global.css
+++ b/client/src/components/layouts/global.css
@@ -11,7 +11,7 @@ body {
.btn-cta-big {
max-height: 100%;
- font-size: 1.3rem;
+ font-size: 1.5rem;
white-space: normal;
width: 100%;
}
@@ -64,25 +64,13 @@ p {
}
.big-heading {
- font-size: 1.5rem !important;
+ font-size: 2.5rem !important;
overflow-wrap: break-word;
}
-.medium-heading {
- font-size: 1.25rem !important;
- font-weight: normal;
-}
-
-.medium-heading.text-center {
- margin-bottom: 50px;
-}
-
@media (max-width: 500px) {
.big-heading {
- font-size: 1.2rem !important;
- }
- .medium-heading {
- font-size: 1.1rem !important;
+ font-size: 1.5rem !important;
}
h1 {
font-size: 1.3rem;
@@ -99,6 +87,12 @@ p {
}
}
+@media (max-width: 1199px) {
+ .btn-cta-big {
+ font-size: 1.3rem;
+ }
+}
+
.text-center {
text-align: center !important;
}
@@ -160,6 +154,7 @@ input[type='submit'],
color: var(--secondary-color);
border-radius: 0px;
text-decoration: none;
+ white-space: pre-line;
}
button:hover,
@@ -257,6 +252,33 @@ fieldset[disabled] .btn-primary.focus {
color: inherit;
}
+.link-btn {
+ margin-bottom: 10px;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ width: 100%;
+ font-size: 1rem;
+ text-align: left;
+}
+
+.link-btn.btn-lg svg {
+ height: 100%;
+ min-height: 20px;
+ min-width: 16px;
+ margin-left: 5px;
+}
+
+.link-btn:hover svg {
+ fill: var(--quaternary-background);
+}
+
+@media (min-width: 700px) {
+ .link-btn {
+ font-size: 1.1rem;
+ }
+}
+
.button-group .btn:not(:last-child) {
margin-bottom: 10px;
}
@@ -494,27 +516,3 @@ blockquote .small {
#search::placeholder {
color: var(--secondary-color);
}
-
-/* checkbox */
-
-.checkbox-inline input[type='checkbox'] {
- margin-left: -30px;
-}
-
-.checkbox-inline {
- padding-left: 30px;
-}
-
-input[type='checkbox'] {
- height: 21px;
- width: 21px;
-}
-
-/* general page styling */
-.default-page-wrapper {
- min-height: 100vh;
- display: flex;
- flex-direction: column;
- justify-content: center;
- padding: 20px;
-}
diff --git a/client/src/pages/index.js b/client/src/pages/index.js
index 6d78449a82..2450a048ce 100644
--- a/client/src/pages/index.js
+++ b/client/src/pages/index.js
@@ -1,16 +1,11 @@
import React from 'react';
import PropTypes from 'prop-types';
-import { graphql } from 'gatsby';
import Landing from '../components/landing';
import { AllChallengeNode } from '../redux/propTypes';
-export const IndexPage = ({
- data: {
- allChallengeNode: { nodes }
- }
-}) => {
- return ;
+export const IndexPage = () => {
+ return ;
};
const propTypes = {
@@ -23,16 +18,3 @@ IndexPage.propTypes = propTypes;
IndexPage.displayName = 'IndexPage';
export default IndexPage;
-
-export const query = graphql`
- query MyQuery {
- allChallengeNode(
- filter: { isHidden: { eq: false } }
- sort: { fields: [superOrder, order, challengeOrder] }
- ) {
- nodes {
- superBlock
- }
- }
- }
-`;
diff --git a/client/utils/gatsby/layoutSelector.js b/client/utils/gatsby/layoutSelector.js
index 4130fb4ca1..6fa4a90c9b 100644
--- a/client/utils/gatsby/layoutSelector.js
+++ b/client/utils/gatsby/layoutSelector.js
@@ -32,7 +32,7 @@ export default function layoutSelector({ element, props }) {
);
}
- if (/^\/donation(\/.*)*|^\/donate(\/.*)*/.test(pathname)) {
+ if (/^\/donation(\/.*)*|^\/$|^\/donate(\/.*)*/.test(pathname)) {
return (
{element}
diff --git a/cypress/integration/landing.js b/cypress/integration/landing.js
index c09f5ca268..2b9d20892c 100644
--- a/cypress/integration/landing.js
+++ b/cypress/integration/landing.js
@@ -1,16 +1,41 @@
/* global cy */
const selectors = {
heading: "[data-test-label='landing-header']",
- callToAction: "[data-test-label='landing-big-cta']"
+ callToAction: "[data-test-label='landing-big-cta']",
+ certifications: "[data-test-label='certifications']",
+ testimonials: "[data-test-label='testimonial-cards']",
+ landingPageImage: '.landing-page-image'
};
describe('Landing page', function() {
it('renders', function() {
cy.visit('/');
-
cy.title().should('eq', 'Learn to code at home | freeCodeCamp.org');
-
- cy.contains(selectors.heading, 'Welcome to freeCodeCamp.org');
+ cy.contains(selectors.heading, 'Learn to code at home.');
cy.contains(selectors.callToAction, "Get started (it's free)");
+ cy.get(selectors.callToAction).should('have.length', 2);
+ });
+
+ it('has a visible large image on large viewports', function() {
+ cy.viewport(1200, 660)
+ .get(selectors.landingPageImage)
+ .should('be.visible');
+
+ cy.viewport(1199, 660)
+ .get(selectors.landingPageImage)
+ .should('not.be.visible');
+ });
+
+ it('has 10 certifications', function() {
+ cy.get(selectors.certifications)
+ .children()
+ .its('length')
+ .should('eq', 10);
+ });
+ it('has 3 testimonial cards', function() {
+ cy.get(selectors.testimonials)
+ .children()
+ .its('length')
+ .should('eq', 3);
});
});