diff --git a/gatsby-config.js b/gatsby-config.js index 631da01..34cbc33 100644 --- a/gatsby-config.js +++ b/gatsby-config.js @@ -77,5 +77,6 @@ module.exports = { 'gatsby-plugin-sitemap', 'gatsby-plugin-offline', 'gatsby-plugin-webpack-size' + // 'gatsby-plugin-webpack-bundle-analyser-v2' ] } diff --git a/jest/__fixtures__/project.json b/jest/__fixtures__/project.json new file mode 100644 index 0000000..df011ee --- /dev/null +++ b/jest/__fixtures__/project.json @@ -0,0 +1,110 @@ +{ + "projectsYaml": { + "title": "Ocean Protocol", + "slug": "/oceanprotocol/", + "fields": { + "descriptionHtml": "

Since 2017 I'm leading the UI design & development of Ocean Protocol, iterating on a components-based UI design system spanning all of Ocean Protocol's web properties. Additionally, I conceptualize, execute and iterate on the creative and visual direction of the Ocean Protocol brand.

\n

Most web interfaces are single-page JavaScript applications built with React, pulling their data from JSON files and various micro services. All design & development is embedded in a continuous deployment process via GitHub & Travis.

\n

Initial website in collaboration with Balance. Key visuals in collaboration with Wojciech Hupert.

\n", + "excerpt": "Since 2017 I'm leading the UI design & development of Ocean Protocol, iterating on a components-based UI design system spanning all of Ocean Protocol's web properties. Additionally, I conceptualize, execute and iterate on the creative and visual direction of the Ocean Protocol brand.\nMost web interfaces are..." + }, + "links": [ + { + "title": "oceanprotocol.com", + "url": "https://oceanprotocol.com", + "icon": "Compass" + }, + { + "title": "Styleguide", + "url": "https://oceanprotocol.com/art", + "icon": null + }, + { + "title": "docs.oceanprotocol.com", + "url": "https://docs.oceanprotocol.com", + "icon": "Compass" + }, + { + "title": "commons.oceanprotocol.com", + "url": "https://commons.oceanprotocol.com", + "icon": "Compass" + }, + { + "title": "@oceanprotocol/art", + "url": "https://github.com/oceanprotocol/art", + "icon": "GitHub" + }, + { + "title": "@oceanprotocol/docs", + "url": "https://github.com/oceanprotocol/docs", + "icon": "GitHub" + }, + { + "title": "@oceanprotocol/commons", + "url": "https://github.com/oceanprotocol/commons", + "icon": "GitHub" + } + ], + "techstack": [ + "Sketch", + "Affinity Designer", + "React", + "Gatsby", + "HTML", + "SCSS", + "JavaScript", + "TypeScript", + "Travis", + "AWS S3", + "Cloudflare", + "Ethereum", + "Docker", + "Kubernetes", + "Cypress", + "IPFS" + ], + "img": { + "childImageSharp": { + "twitterImage": { + "src": "/static/674f679841915ed59da7394e937f8f8f/c7e19/oceanprotocol-01.png" + } + } + } + }, + "projectImages": { + "edges": [ + { + "node": { + "id": "790521d3-05e7-5ab7-a499-86687637475b", + "fluid": { + "aspectRatio": 1.8, + "src": "/static/674f679841915ed59da7394e937f8f8f/af144/oceanprotocol-01.png", + "srcSet": "/static/674f679841915ed59da7394e937f8f8f/7c0ed/oceanprotocol-01.png 200w,\n/static/674f679841915ed59da7394e937f8f8f/647de/oceanprotocol-01.png 400w,\n/static/674f679841915ed59da7394e937f8f8f/af144/oceanprotocol-01.png 800w,\n/static/674f679841915ed59da7394e937f8f8f/ba299/oceanprotocol-01.png 1200w,\n/static/674f679841915ed59da7394e937f8f8f/9ecf6/oceanprotocol-01.png 1600w,\n/static/674f679841915ed59da7394e937f8f8f/7347c/oceanprotocol-01.png 2880w", + "srcWebp": "/static/674f679841915ed59da7394e937f8f8f/c6096/oceanprotocol-01.webp", + "srcSetWebp": "/static/674f679841915ed59da7394e937f8f8f/1932c/oceanprotocol-01.webp 200w,\n/static/674f679841915ed59da7394e937f8f8f/f4957/oceanprotocol-01.webp 400w,\n/static/674f679841915ed59da7394e937f8f8f/c6096/oceanprotocol-01.webp 800w,\n/static/674f679841915ed59da7394e937f8f8f/b6424/oceanprotocol-01.webp 1200w,\n/static/674f679841915ed59da7394e937f8f8f/7a72d/oceanprotocol-01.webp 1600w,\n/static/674f679841915ed59da7394e937f8f8f/b5fcc/oceanprotocol-01.webp 2880w", + "sizes": "(max-width: 800px) 100vw, 800px", + "originalImg": "/static/674f679841915ed59da7394e937f8f8f/7347c/oceanprotocol-01.png", + "originalName": "oceanprotocol-01.png", + "presentationWidth": 800, + "presentationHeight": 444 + } + } + }, + { + "node": { + "id": "f49d52dd-60b9-5833-95ad-4428d4032e76", + "fluid": { + "aspectRatio": 1.8, + "src": "/static/32988a616cc5bc2354e02d16149dbcd6/af144/oceanprotocol-02.png", + "srcSet": "/static/32988a616cc5bc2354e02d16149dbcd6/7c0ed/oceanprotocol-02.png 200w,\n/static/32988a616cc5bc2354e02d16149dbcd6/647de/oceanprotocol-02.png 400w,\n/static/32988a616cc5bc2354e02d16149dbcd6/af144/oceanprotocol-02.png 800w,\n/static/32988a616cc5bc2354e02d16149dbcd6/ba299/oceanprotocol-02.png 1200w,\n/static/32988a616cc5bc2354e02d16149dbcd6/9ecf6/oceanprotocol-02.png 1600w,\n/static/32988a616cc5bc2354e02d16149dbcd6/7347c/oceanprotocol-02.png 2880w", + "srcWebp": "/static/32988a616cc5bc2354e02d16149dbcd6/c6096/oceanprotocol-02.webp", + "srcSetWebp": "/static/32988a616cc5bc2354e02d16149dbcd6/1932c/oceanprotocol-02.webp 200w,\n/static/32988a616cc5bc2354e02d16149dbcd6/f4957/oceanprotocol-02.webp 400w,\n/static/32988a616cc5bc2354e02d16149dbcd6/c6096/oceanprotocol-02.webp 800w,\n/static/32988a616cc5bc2354e02d16149dbcd6/b6424/oceanprotocol-02.webp 1200w,\n/static/32988a616cc5bc2354e02d16149dbcd6/7a72d/oceanprotocol-02.webp 1600w,\n/static/32988a616cc5bc2354e02d16149dbcd6/b5fcc/oceanprotocol-02.webp 2880w", + "sizes": "(max-width: 800px) 100vw, 800px", + "originalImg": "/static/32988a616cc5bc2354e02d16149dbcd6/7347c/oceanprotocol-02.png", + "originalName": "oceanprotocol-02.png", + "presentationWidth": 800, + "presentationHeight": 444 + } + } + } + ] + } +} diff --git a/jest/setup-test-env.js b/jest/setup-test-env.js index 184a34c..55202f9 100644 --- a/jest/setup-test-env.js +++ b/jest/setup-test-env.js @@ -4,6 +4,7 @@ import { StaticQuery, useStaticQuery } from 'gatsby' import meta from './__fixtures__/meta.json' import resume from './__fixtures__/resume.json' +import projects from './__fixtures__/projects.json' beforeAll(() => { const photoSrc = resume.contentJson.basics.picture.childImageSharp.fixed.src @@ -11,11 +12,10 @@ beforeAll(() => { ...meta, ...resume, photoSrc, - portfolioJson: { bugs: '' } + portfolioJson: { bugs: '' }, + ...projects } StaticQuery.mockImplementation(({ render }) => render({ ...dataMock })) - useStaticQuery.mockImplementation(() => { - return { ...dataMock } - }) + useStaticQuery.mockImplementation(() => ({ ...dataMock })) }) diff --git a/package-lock.json b/package-lock.json index f4d7650..1560a0b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3098,6 +3098,25 @@ } } }, + "@loadable/component": { + "version": "5.10.3", + "resolved": "https://registry.npmjs.org/@loadable/component/-/component-5.10.3.tgz", + "integrity": "sha512-/aSO+tXw4vFMwZ6fgLaNQgLuEa7bgTpoBE4PxNzf08/ewAjymrCS3J7v3SbGE7IjGmmKL6vVwkpb7S3cYrk+ag==", + "requires": { + "@babel/runtime": "^7.6.0", + "hoist-non-react-statics": "^3.3.0" + }, + "dependencies": { + "@babel/runtime": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.7.4.tgz", + "integrity": "sha512-r24eVUUr0QqNZa+qrImUk8fn5SPhHq+IfYvIoIMg0do3GdK9sMdiLKP3GYVVaxpPKORgm8KRKaNTEhAjgIpLMw==", + "requires": { + "regenerator-runtime": "^0.13.2" + } + } + } + }, "@mapbox/hast-util-table-cell-style": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/@mapbox/hast-util-table-cell-style/-/hast-util-table-cell-style-0.1.3.tgz", @@ -5118,6 +5137,18 @@ "resolved": "https://registry.npmjs.org/better-queue-memory/-/better-queue-memory-1.0.4.tgz", "integrity": "sha512-SWg5wFIShYffEmJpI6LgbL8/3Dqhku7xI1oEiy6FroP9DbcZlG0ZDjxvPdP9t7hTGW40IpIcC6zVoGT1oxjOuA==" }, + "bfj": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/bfj/-/bfj-6.1.2.tgz", + "integrity": "sha512-BmBJa4Lip6BPRINSZ0BPEIfB1wUY/9rwbwvIHQA1KjX9om29B6id0wnWXq7m3bn5JrUVjeOTnVuhPT1FiHwPGw==", + "dev": true, + "requires": { + "bluebird": "^3.5.5", + "check-types": "^8.0.3", + "hoopy": "^0.1.4", + "tryer": "^1.0.1" + } + }, "big.js": { "version": "5.2.2", "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", @@ -6014,6 +6045,12 @@ "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=" }, + "check-types": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/check-types/-/check-types-8.0.3.tgz", + "integrity": "sha512-YpeKZngUmG65rLudJ4taU7VLkOCTMhNl/u4ctNC56LQS/zJTyNH0Lrtwm1tfTsbLlwvlfsA2d1c8vCf/Kh2KwQ==", + "dev": true + }, "cheerio": { "version": "1.0.0-rc.3", "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.3.tgz", @@ -8368,6 +8405,12 @@ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" }, + "ejs": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.7.4.tgz", + "integrity": "sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA==", + "dev": true + }, "electron-to-chromium": { "version": "1.3.191", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.191.tgz", @@ -11911,6 +11954,27 @@ "resolved": "https://registry.npmjs.org/gatsby-plugin-svgr/-/gatsby-plugin-svgr-2.0.2.tgz", "integrity": "sha512-54REIMe79qFBAwpcnWHBkvEE9CKoEVkefF9rDXai0k642r91SZ4UeWFuAmsegPG+sPVub7tHfHu/2LVXK1I9kg==" }, + "gatsby-plugin-webpack-bundle-analyser-v2": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/gatsby-plugin-webpack-bundle-analyser-v2/-/gatsby-plugin-webpack-bundle-analyser-v2-1.1.8.tgz", + "integrity": "sha512-xVC6JYP1n1CaLml9VTBqdrmBEkCUgcAk5jW8hpJVH9gAn3dVQYyOgUxAavi88ZBLN7Ff6M7uZ80COMRWtdlpbA==", + "dev": true, + "requires": { + "@babel/runtime": "^7.7.2", + "webpack-bundle-analyzer": "^3.6.0" + }, + "dependencies": { + "@babel/runtime": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.7.4.tgz", + "integrity": "sha512-r24eVUUr0QqNZa+qrImUk8fn5SPhHq+IfYvIoIMg0do3GdK9sMdiLKP3GYVVaxpPKORgm8KRKaNTEhAjgIpLMw==", + "dev": true, + "requires": { + "regenerator-runtime": "^0.13.2" + } + } + } + }, "gatsby-plugin-webpack-size": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/gatsby-plugin-webpack-size/-/gatsby-plugin-webpack-size-1.0.0.tgz", @@ -12951,6 +13015,12 @@ "parse-passwd": "^1.0.0" } }, + "hoopy": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz", + "integrity": "sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ==", + "dev": true + }, "hosted-git-info": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", @@ -17433,6 +17503,12 @@ } } }, + "opener": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.1.tgz", + "integrity": "sha512-goYSy5c2UXE4Ra1xixabeVh1guIX/ZV/YokJksb6q2lubWu6UbvPQ20p542/sFIll1nl8JnCyK9oBaOcCWXwvA==", + "dev": true + }, "opentracing": { "version": "0.14.4", "resolved": "https://registry.npmjs.org/opentracing/-/opentracing-0.14.4.tgz", @@ -25396,6 +25472,12 @@ "resolved": "https://registry.npmjs.org/true-case-path/-/true-case-path-2.2.1.tgz", "integrity": "sha512-0z3j8R7MCjy10kc/g+qg7Ln3alJTodw9aDuVWZa3uiWqfuBMKeAeP2ocWcxoyM3D73yz3Jt/Pu4qPr4wHSdB/Q==" }, + "tryer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tryer/-/tryer-1.0.1.tgz", + "integrity": "sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA==", + "dev": true + }, "ts-essentials": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/ts-essentials/-/ts-essentials-1.0.4.tgz", @@ -26270,6 +26352,83 @@ } } }, + "webpack-bundle-analyzer": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-3.6.0.tgz", + "integrity": "sha512-orUfvVYEfBMDXgEKAKVvab5iQ2wXneIEorGNsyuOyVYpjYrI7CUOhhXNDd3huMwQ3vNNWWlGP+hzflMFYNzi2g==", + "dev": true, + "requires": { + "acorn": "^6.0.7", + "acorn-walk": "^6.1.1", + "bfj": "^6.1.1", + "chalk": "^2.4.1", + "commander": "^2.18.0", + "ejs": "^2.6.1", + "express": "^4.16.3", + "filesize": "^3.6.1", + "gzip-size": "^5.0.0", + "lodash": "^4.17.15", + "mkdirp": "^0.5.1", + "opener": "^1.5.1", + "ws": "^6.0.0" + }, + "dependencies": { + "acorn": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.3.0.tgz", + "integrity": "sha512-/czfa8BwS88b9gWQVhc8eknunSA2DoJpJyTQkhheIf5E48u1N0R4q/YxxsAeqRrmK9TQ/uYfgLDfZo91UlANIA==", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "filesize": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-3.6.1.tgz", + "integrity": "sha512-7KjR1vv6qnicaPMi1iiTcI85CyYwRO/PSFCu6SvqL8jN2Wjt/NIYQTFtFs7fSDCYOstUkEWIQGFUg5YZQfjlcg==", + "dev": true + }, + "gzip-size": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-5.1.1.tgz", + "integrity": "sha512-FNHi6mmoHvs1mxZAds4PpdCS6QG8B4C1krxJsMutgxl5t3+GlRTzzI3NEkifXx2pVsOvJdOGSmIgDhQ55FwdPA==", + "dev": true, + "requires": { + "duplexer": "^0.1.1", + "pify": "^4.0.1" + } + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + }, + "ws": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz", + "integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0" + } + } + } + }, "webpack-dev-middleware": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-3.7.2.tgz", diff --git a/package.json b/package.json index 76022fb..6778e28 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "lh": "lighthousebot --pwa=90 --perf=90 --a11y=90 --bp=90 --seo 90 --runner=wpt" }, "dependencies": { + "@loadable/component": "^5.10.3", "axios": "^0.19.0", "file-saver": "^2.0.2", "gatsby": "^2.18.3", @@ -76,6 +77,7 @@ "eslint-plugin-prettier": "^3.1.1", "eslint-plugin-react": "^7.16.0", "eslint-plugin-react-hooks": "^2.3.0", + "gatsby-plugin-webpack-bundle-analyser-v2": "^1.1.8", "identity-obj-proxy": "^3.0.0", "jest": "^24.9.0", "jest-canvas-mock": "^2.2.0", diff --git a/src/components/molecules/Networks.jsx b/src/components/molecules/Networks.jsx index a6f08c0..0340a88 100644 --- a/src/components/molecules/Networks.jsx +++ b/src/components/molecules/Networks.jsx @@ -7,7 +7,7 @@ import { useResume } from '../../hooks/use-resume' import styles from './Networks.module.scss' const linkClasses = key => - key === 'Email' ? `u-email ${styles.link}` : `u-url ${styles.link}` + key === 'Mail' ? `u-email ${styles.link}` : `u-url ${styles.link}` const NetworkLink = ({ name, url }) => ( ( +
+ + {node.title} +

{node.title}

+ +
+) + +Project.propTypes = { + node: PropTypes.any.isRequired, + refCurrentItem: PropTypes.any +} + export default class ProjectNav extends PureComponent { static propTypes = { currentSlug: PropTypes.string.isRequired @@ -48,32 +67,18 @@ export default class ProjectNav extends PureComponent { const scrollContainer = this.scrollContainer.current const activeItem = this.currentItem.current const scrollRect = scrollContainer.getBoundingClientRect() - const activeRect = activeItem.getBoundingClientRect() + const activeRect = activeItem && activeItem.getBoundingClientRect() const scrollLeftPosition = + activeRect && activeRect.left - - scrollRect.left - - scrollRect.width / 2 + - activeRect.width / 2 + scrollRect.left - + scrollRect.width / 2 + + activeRect.width / 2 scrollContainer.scrollLeft += this.state.scrollLeftPosition this.setState({ scrollLeftPosition }) } - Project({ node, refCurrentItem }) { - return ( -
- - {node.title} -

{node.title}

- -
- ) - } - render() { const { currentSlug } = this.props return ( @@ -88,8 +93,8 @@ export default class ProjectNav extends PureComponent { const isCurrent = node.slug === currentSlug return ( - diff --git a/src/components/molecules/ProjectNav.test.jsx b/src/components/molecules/ProjectNav.test.jsx new file mode 100644 index 0000000..9efa87b --- /dev/null +++ b/src/components/molecules/ProjectNav.test.jsx @@ -0,0 +1,10 @@ +import React from 'react' +import { render } from '@testing-library/react' +import ProjectNav from './ProjectNav' + +describe('ProjectNav', () => { + it('renders correctly', () => { + const { container } = render() + expect(container.firstChild).toBeInTheDocument() + }) +}) diff --git a/src/components/organisms/Footer.jsx b/src/components/organisms/Footer.jsx index a0208f6..76dd726 100644 --- a/src/components/organisms/Footer.jsx +++ b/src/components/organisms/Footer.jsx @@ -1,12 +1,14 @@ import React from 'react' import PropTypes from 'prop-types' import { graphql, useStaticQuery } from 'gatsby' -import Vcard from '../atoms/Vcard' +import loadable from '@loadable/component' import LogoUnit from '../molecules/LogoUnit' import Networks from '../molecules/Networks' import styles from './Footer.module.scss' import { useMeta } from '../../hooks/use-meta' +const LazyVcard = loadable(() => import('../atoms/Vcard')) + const query = graphql` query { # the package.json file @@ -22,7 +24,7 @@ const FooterMarkup = ({ pkg, meta, year }) => (

- + PGP/GPG key diff --git a/src/templates/Project.test.jsx b/src/templates/Project.test.jsx new file mode 100644 index 0000000..06dc588 --- /dev/null +++ b/src/templates/Project.test.jsx @@ -0,0 +1,16 @@ +import React from 'react' +import { render } from '@testing-library/react' +import { createHistory, createMemorySource } from '@reach/router' +import Project from './Project' +import project from '../../jest/__fixtures__/project.json' + +describe('Project', () => { + const history = createHistory(createMemorySource('/oceanprotocol')) + + it('renders correctly from data file values', async () => { + const { container } = render( + + ) + expect(container.firstChild).toBeInTheDocument() + }) +})