├── .gitignore ├── README.md ├── client ├── .gitignore ├── README.md ├── package.json ├── public │ ├── favicon.ico │ ├── index.html │ ├── logo192.png │ ├── logo512.png │ ├── manifest.json │ └── robots.txt ├── src │ ├── App.css │ ├── App.js │ ├── App.test.js │ ├── assets │ │ ├── landing.jpg │ │ ├── logo.svg │ │ ├── logout.svg │ │ ├── pencil.svg │ │ ├── play-btn.svg │ │ ├── plus-circle-fill.svg │ │ └── trash.svg │ ├── components │ │ ├── auth │ │ │ ├── LoginForm.js │ │ │ └── RegisterForm.js │ │ ├── layout │ │ │ ├── AlertMessage.js │ │ │ ├── Landing.js │ │ │ └── NavbarMenu.js │ │ ├── posts │ │ │ ├── ActionButton.js │ │ │ ├── AddPostModal.js │ │ │ ├── SinglePost.js │ │ │ └── UpdatePostModal.js │ │ └── routing │ │ │ └── ProtectedRoute.js │ ├── contexts │ │ ├── AuthContext.js │ │ ├── PostContext.js │ │ └── constants.js │ ├── index.css │ ├── index.js │ ├── logo.svg │ ├── reducers │ │ ├── authReducer.js │ │ └── postReducer.js │ ├── reportWebVitals.js │ ├── setupTests.js │ ├── utils │ │ └── setAuthToken.js │ └── views │ │ ├── About.js │ │ ├── Auth.js │ │ └── Dashboard.js └── yarn.lock ├── screenshots ├── screenshot_1.png ├── screenshot_2.png ├── screenshot_3.png ├── screenshot_4.png ├── screenshot_5.png └── screenshot_6.png └── server ├── .env ├── package.json ├── request.http ├── src ├── config │ └── db.js ├── index.js ├── middleware │ └── auth.js ├── models │ ├── Post.js │ └── User.js └── routers │ ├── auth.js │ └── post.js └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | server/dist 2 | server/node_modules 3 | # server/.env 4 | 5 | client/node_modules -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | **Follow me:** 2 | - [Facebook](https://www.facebook.com/zendy199x/) 3 | - [Linkedin](https://www.linkedin.com/in/zendy199x/) 4 | - [Github](https://www.github.com/zendy199x/) 5 | 6 | **Contact me:** 7 | - Mail: zendy199x@gmail.com 8 | - Skype: nhokkute.nguyenduc 9 | - Zalo: [Zendy](https://zalo.me/nguyenduc94/) 10 | 11 | ### Setup 12 | 13 | **Server** 14 | ```bash 15 | cd server && yarn server 16 | ``` 17 | 18 | **Client** 19 | ```bash 20 | cd client && yarn start 21 | ``` 22 | 23 | ### Screenshots 24 | 25 |

26 | 27 |
28 |
29 | 30 |
31 |
32 | 33 |
34 |
35 | 36 |
37 |
38 | 39 |
40 |
41 | 42 |

-------------------------------------------------------------------------------- /client/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /client/README.md: -------------------------------------------------------------------------------- 1 | # Getting Started with Create React App 2 | 3 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). 4 | 5 | ## Available Scripts 6 | 7 | In the project directory, you can run: 8 | 9 | ### `yarn start` 10 | 11 | Runs the app in the development mode.\ 12 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser. 13 | 14 | The page will reload if you make edits.\ 15 | You will also see any lint errors in the console. 16 | 17 | ### `yarn test` 18 | 19 | Launches the test runner in the interactive watch mode.\ 20 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. 21 | 22 | ### `yarn build` 23 | 24 | Builds the app for production to the `build` folder.\ 25 | It correctly bundles React in production mode and optimizes the build for the best performance. 26 | 27 | The build is minified and the filenames include the hashes.\ 28 | Your app is ready to be deployed! 29 | 30 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. 31 | 32 | ### `yarn eject` 33 | 34 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!** 35 | 36 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. 37 | 38 | Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. 39 | 40 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. 41 | 42 | ## Learn More 43 | 44 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). 45 | 46 | To learn React, check out the [React documentation](https://reactjs.org/). 47 | 48 | ### Code Splitting 49 | 50 | This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting) 51 | 52 | ### Analyzing the Bundle Size 53 | 54 | This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size) 55 | 56 | ### Making a Progressive Web App 57 | 58 | This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app) 59 | 60 | ### Advanced Configuration 61 | 62 | This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration) 63 | 64 | ### Deployment 65 | 66 | This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment) 67 | 68 | ### `yarn build` fails to minify 69 | 70 | This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify) 71 | -------------------------------------------------------------------------------- /client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "client", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "axios": "^0.21.1", 7 | "cra-template": "1.1.2", 8 | "react": "^17.0.2", 9 | "react-bootstrap": "^1.6.1", 10 | "react-dom": "^17.0.2", 11 | "react-router-dom": "^5.2.1", 12 | "react-scripts": "4.0.3", 13 | "web-vitals": "^2.1.0" 14 | }, 15 | "scripts": { 16 | "start": "react-scripts start", 17 | "build": "react-scripts build", 18 | "test": "react-scripts test", 19 | "eject": "react-scripts eject" 20 | }, 21 | "eslintConfig": { 22 | "extends": [ 23 | "react-app", 24 | "react-app/jest" 25 | ] 26 | }, 27 | "browserslist": { 28 | "production": [ 29 | ">0.2%", 30 | "not dead", 31 | "not op_mini all" 32 | ], 33 | "development": [ 34 | "last 1 chrome version", 35 | "last 1 firefox version", 36 | "last 1 safari version" 37 | ] 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /client/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zendy199x/MERN-Stack/a459fe84ed7723c3b37fcedc77ea2ec411e0eec6/client/public/favicon.ico -------------------------------------------------------------------------------- /client/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 24 | 33 | MERN Stack 34 | 35 | 36 | 37 |
38 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /client/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zendy199x/MERN-Stack/a459fe84ed7723c3b37fcedc77ea2ec411e0eec6/client/public/logo192.png -------------------------------------------------------------------------------- /client/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zendy199x/MERN-Stack/a459fe84ed7723c3b37fcedc77ea2ec411e0eec6/client/public/logo512.png -------------------------------------------------------------------------------- /client/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /client/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /client/src/App.css: -------------------------------------------------------------------------------- 1 | .landing { 2 | position: relative; 3 | background: url('./assets/landing.jpg') no-repeat center center/cover; 4 | height: 100vh; 5 | } 6 | 7 | .dark-overlay { 8 | background-color: rgba(0, 0, 0, 0.5); 9 | height: 100%; 10 | } 11 | 12 | .landing-inner { 13 | height: 100%; 14 | margin: auto; 15 | display: flex; 16 | flex-direction: column; 17 | justify-content: center; 18 | align-items: center; 19 | text-align: center; 20 | } 21 | 22 | .landing-inner form { 23 | width: 30%; 24 | } 25 | 26 | .landing-inner h1, 27 | .landing-inner h4, 28 | .landing-inner p { 29 | color: white; 30 | } 31 | 32 | .spinner-container { 33 | position: absolute; 34 | top: 50%; 35 | left: 50%; 36 | -moz-transform: translateX(-50%) translateY(-50%); 37 | -webkit-transform: translateX(-50%) translateY(-50%); 38 | transform: translateX(-50%) translateY(-50%); 39 | } 40 | 41 | /* Post button */ 42 | .post-button { 43 | padding-top: 0; 44 | background: transparent; 45 | border: none; 46 | } 47 | 48 | .post-button:hover { 49 | background: transparent; 50 | } 51 | 52 | a.post-button.btn:focus, 53 | a.post-button.btn:active { 54 | outline: none; 55 | background: transparent; 56 | border: none; 57 | box-shadow: none; 58 | } 59 | 60 | button.post-button.btn:focus, 61 | button.post-button.btn:active { 62 | outline: none; 63 | background: transparent; 64 | border: none; 65 | box-shadow: none; 66 | } 67 | 68 | /* Floating add button */ 69 | .btn-floating { 70 | position: fixed; 71 | right: 3rem; 72 | bottom: 3rem; 73 | background: transparent; 74 | border: none; 75 | } 76 | 77 | .btn-floating:hover { 78 | background: transparent; 79 | } 80 | 81 | .btn-floating:focus, 82 | .btn-floating:active { 83 | outline: none; 84 | background: transparent; 85 | border: none; 86 | box-shadow: none; 87 | } 88 | 89 | /* Add new post tooltip */ 90 | .tooltip { 91 | background: transparent; 92 | } 93 | 94 | .tooltip .arrow::before { 95 | border-left-color: #78c2ad; 96 | } 97 | 98 | .tooltip-inner { 99 | background: #78c2ad; 100 | } 101 | 102 | /* Post border thicker */ 103 | .border-success, 104 | .border-warning, 105 | .border-danger { 106 | border-width: 2px; 107 | } 108 | 109 | /* Post title */ 110 | .post-title { 111 | margin-bottom: 0.5rem; 112 | } -------------------------------------------------------------------------------- /client/src/App.js: -------------------------------------------------------------------------------- 1 | import { BrowserRouter as Router, Route, Switch } from "react-router-dom"; 2 | import "./App.css"; 3 | import Landing from "./components/layout/Landing"; 4 | import ProtectedRoute from "./components/routing/ProtectedRoute"; 5 | import AuthContextProvider from "./contexts/AuthContext"; 6 | import PostContextProvider from "./contexts/PostContext"; 7 | import About from "./views/About"; 8 | import Auth from "./views/Auth"; 9 | import Dashboard from "./views/Dashboard"; 10 | 11 | function App() { 12 | return ( 13 | 14 | 15 | 16 | 17 | 18 | } 22 | /> 23 | } 27 | /> 28 | 29 | 30 | 31 | 32 | 33 | 34 | ); 35 | } 36 | 37 | export default App; 38 | -------------------------------------------------------------------------------- /client/src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import App from './App'; 3 | 4 | test('renders learn react link', () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /client/src/assets/landing.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zendy199x/MERN-Stack/a459fe84ed7723c3b37fcedc77ea2ec411e0eec6/client/src/assets/landing.jpg -------------------------------------------------------------------------------- /client/src/assets/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /client/src/assets/logout.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /client/src/assets/pencil.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /client/src/assets/play-btn.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /client/src/assets/plus-circle-fill.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /client/src/assets/trash.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /client/src/components/auth/LoginForm.js: -------------------------------------------------------------------------------- 1 | import React, { useContext, useState } from "react"; 2 | import { Button, Form } from "react-bootstrap"; 3 | import { Link } from "react-router-dom"; 4 | import { AuthContext } from "../../contexts/AuthContext"; 5 | import AlertMessage from "../layout/AlertMessage"; 6 | 7 | const LoginForm = () => { 8 | // Context 9 | const { loginUser } = useContext(AuthContext); 10 | 11 | // const history = useHistory(); 12 | 13 | const [loginForm, setLoginForm] = useState({ 14 | username: "", 15 | password: "", 16 | }); 17 | 18 | const [alert, setAlert] = useState(null); 19 | 20 | const { username, password } = loginForm; 21 | 22 | const onChangeLoginForm = (event) => 23 | setLoginForm({ ...loginForm, [event.target.name]: event.target.value }); 24 | 25 | const handleLogin = async (event) => { 26 | event.preventDefault(); 27 | 28 | try { 29 | const loginData = await loginUser(loginForm); 30 | if (loginData.success) { 31 | // history.push("/dashboard"); 32 | } else { 33 | setAlert({ type: "danger", message: loginData.message }); 34 | setTimeout(() => setAlert(null), 5000); 35 | } 36 | } catch (error) { 37 | console.log(error); 38 | } 39 | }; 40 | 41 | return ( 42 | <> 43 |
44 | 45 | 46 | 47 | 55 | 56 | 57 | 65 | 66 | 69 | 70 |

71 | Don't have an account?{" "} 72 | 73 | 76 | 77 |

78 | 79 | ); 80 | }; 81 | 82 | export default LoginForm; 83 | -------------------------------------------------------------------------------- /client/src/components/auth/RegisterForm.js: -------------------------------------------------------------------------------- 1 | import React, { useContext, useState } from "react"; 2 | import { Button, Form } from "react-bootstrap"; 3 | import { Link } from "react-router-dom"; 4 | import { AuthContext } from "../../contexts/AuthContext"; 5 | import AlertMessage from "../layout/AlertMessage"; 6 | 7 | const RegisterForm = () => { 8 | // Context 9 | const { registerUser } = useContext(AuthContext); 10 | 11 | const [registerForm, setRegisterForm] = useState({ 12 | username: "", 13 | password: "", 14 | confirmPassword: "", 15 | }); 16 | 17 | const [alert, setAlert] = useState(null); 18 | 19 | const { username, password, confirmPassword } = registerForm; 20 | 21 | const onChangeRegisterForm = (event) => 22 | setRegisterForm({ 23 | ...registerForm, 24 | [event.target.name]: event.target.value, 25 | }); 26 | 27 | const handleRegister = async (event) => { 28 | event.preventDefault(); 29 | 30 | if (password !== confirmPassword) { 31 | setAlert({ type: "danger", message: "Passwords do not match" }); 32 | setTimeout(() => setAlert(null), 5000); 33 | return; 34 | } 35 | 36 | try { 37 | const registerData = await registerUser(registerForm); 38 | if (!registerData.success) { 39 | setAlert({ type: "danger", message: registerData.message }); 40 | setTimeout(() => setAlert(null), 5000); 41 | } 42 | } catch (error) { 43 | console.log(error); 44 | } 45 | }; 46 | 47 | return ( 48 | <> 49 |
50 | 51 | 52 | 53 | 61 | 62 | 63 | 71 | 72 | 73 | 81 | 82 | 85 | 86 |

87 | Don't have an account?{" "} 88 | 89 | 92 | 93 |

94 | 95 | ); 96 | }; 97 | 98 | export default RegisterForm; 99 | -------------------------------------------------------------------------------- /client/src/components/layout/AlertMessage.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Alert } from 'react-bootstrap'; 3 | 4 | const AlertMessage = ({ info }) => { 5 | return info === null ? null : ( 6 | {info.message} 7 | ); 8 | }; 9 | 10 | export default AlertMessage; 11 | -------------------------------------------------------------------------------- /client/src/components/layout/Landing.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Redirect } from "react-router-dom"; 3 | 4 | const Landing = () => { 5 | return ; 6 | }; 7 | 8 | export default Landing; 9 | -------------------------------------------------------------------------------- /client/src/components/layout/NavbarMenu.js: -------------------------------------------------------------------------------- 1 | import React, { useContext } from "react"; 2 | import { Button, Nav, Navbar } from "react-bootstrap"; 3 | import { Link } from "react-router-dom"; 4 | import learnItLogo from "../../assets/logo.svg"; 5 | import logoutIcon from "../../assets/logout.svg"; 6 | import { AuthContext } from "../../contexts/AuthContext"; 7 | 8 | const NavbarMenu = () => { 9 | const { 10 | authState: { 11 | user: { username }, 12 | }, 13 | logoutUser 14 | } = useContext(AuthContext); 15 | 16 | const handleLogout = () => logoutUser(); 17 | 18 | return ( 19 | 20 | 21 | learnItLogo 28 | LearnIt 29 | 30 | 31 | 32 | 33 | 37 | 53 | 54 | 70 | 71 | 72 | ); 73 | }; 74 | 75 | export default NavbarMenu; 76 | -------------------------------------------------------------------------------- /client/src/components/posts/ActionButton.js: -------------------------------------------------------------------------------- 1 | import { useContext } from "react"; 2 | import { Button } from "react-bootstrap"; 3 | import editIcon from "../../assets/pencil.svg"; 4 | import playIcon from "../../assets/play-btn.svg"; 5 | import deleteIcon from "../../assets/trash.svg"; 6 | import { PostContext } from "../../contexts/PostContext"; 7 | 8 | const ActionButtons = ({ url, _id }) => { 9 | const { deletePost, findPost, setShowUpdatePostModal } = 10 | useContext(PostContext); 11 | 12 | const choosePost = (postId) => { 13 | findPost(postId); 14 | setShowUpdatePostModal(true); 15 | }; 16 | 17 | return ( 18 | <> 19 | 22 | 25 | 28 | 29 | ); 30 | }; 31 | 32 | export default ActionButtons; 33 | -------------------------------------------------------------------------------- /client/src/components/posts/AddPostModal.js: -------------------------------------------------------------------------------- 1 | import { useContext, useState } from "react"; 2 | import { Button, Form, Modal } from "react-bootstrap"; 3 | import { PostContext } from "../../contexts/PostContext"; 4 | 5 | const AddPostModal = () => { 6 | // Contexts 7 | const { showAddPostModal, setShowAddPostModal, addPost, setShowToast } = 8 | useContext(PostContext); 9 | 10 | // State 11 | const [newPost, setNewPost] = useState({ 12 | title: "", 13 | description: "", 14 | url: "", 15 | status: "TO LEARN", 16 | }); 17 | 18 | const { title, description, url } = newPost; 19 | 20 | const onChangeNewPostForm = (event) => 21 | setNewPost({ ...newPost, [event.target.name]: event.target.value }); 22 | 23 | const closeDialog = () => { 24 | resetAddPostData(); 25 | }; 26 | 27 | const onSubmit = async (event) => { 28 | event.preventDefault(); 29 | const { success, message } = await addPost(newPost); 30 | resetAddPostData(); 31 | setShowToast({ show: true, message, type: success ? "success" : "danger" }); 32 | }; 33 | 34 | const resetAddPostData = () => { 35 | setNewPost({ title: "", description: "", url: "", status: "TO LEARN" }); 36 | setShowAddPostModal(false); 37 | }; 38 | 39 | return ( 40 | 41 | 42 | What do you want to learn? 43 | 44 |
45 | 46 | 47 | Title 48 | 49 | 50 | 59 | 60 | 61 | Description 62 | 63 | 64 | 72 | 73 | 74 | URL 75 | 76 | 77 | 84 | 85 | 86 | 87 | 90 | 93 | 94 |
95 |
96 | ); 97 | }; 98 | 99 | export default AddPostModal; 100 | -------------------------------------------------------------------------------- /client/src/components/posts/SinglePost.js: -------------------------------------------------------------------------------- 1 | import { Badge, Card, Col, Row } from "react-bootstrap"; 2 | import ActionButtons from "./ActionButton"; 3 | 4 | const SinglePost = ({ post: { _id, status, title, description, url } }) => ( 5 | 15 | 16 | 17 | 18 | 19 |

{title}

20 | 30 | {status} 31 | 32 | 33 | 34 | 35 | 36 |
37 |
38 | {description} 39 |
40 |
41 | ); 42 | 43 | export default SinglePost; 44 | -------------------------------------------------------------------------------- /client/src/components/posts/UpdatePostModal.js: -------------------------------------------------------------------------------- 1 | import React, { useContext, useEffect, useState } from "react"; 2 | import { Button, Form, Modal } from "react-bootstrap"; 3 | import { PostContext } from "../../contexts/PostContext"; 4 | 5 | const UpdatePostModal = () => { 6 | // Contexts 7 | const { 8 | postState: { post }, 9 | showUpdatePostModal, 10 | setShowUpdatePostModal, 11 | updatePost, 12 | setShowToast, 13 | } = useContext(PostContext); 14 | 15 | // State 16 | const [updatedPost, setUpdatedPost] = useState(post); 17 | 18 | useEffect(() => setUpdatedPost(post), [post]); 19 | 20 | const { title, description, url, status } = updatedPost; 21 | 22 | const onChangeUpdatedPostForm = (event) => 23 | setUpdatedPost({ ...updatedPost, [event.target.name]: event.target.value }); 24 | 25 | const closeDialog = () => { 26 | setUpdatedPost(post); 27 | setShowUpdatePostModal(false); 28 | }; 29 | 30 | const onSubmit = async (event) => { 31 | event.preventDefault(); 32 | const { success, message } = await updatePost(updatedPost); 33 | setShowUpdatePostModal(false); 34 | setShowToast({ show: true, message, type: success ? "success" : "danger" }); 35 | }; 36 | 37 | return ( 38 | 39 | 40 | Making progress? 41 | 42 |
43 | 44 | 45 | Title 46 | 47 | 48 | 57 | 58 | 59 | Description 60 | 61 | 62 | 70 | 71 | 72 | URL 73 | 74 | 75 | 82 | 83 | 84 | Status 85 | 86 | 87 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 103 | 106 | 107 |
108 |
109 | ); 110 | }; 111 | 112 | export default UpdatePostModal; 113 | -------------------------------------------------------------------------------- /client/src/components/routing/ProtectedRoute.js: -------------------------------------------------------------------------------- 1 | import React, { useContext } from "react"; 2 | import { Spinner } from "react-bootstrap"; 3 | import { Redirect, Route } from "react-router-dom"; 4 | import { AuthContext } from "../../contexts/AuthContext"; 5 | import NavbarMenu from "../layout/NavbarMenu"; 6 | 7 | const ProtectedRoute = ({ component: Component, ...rest }) => { 8 | const { 9 | authState: { authLoading, isAuthenticated }, 10 | } = useContext(AuthContext); 11 | 12 | if (authLoading) { 13 | return ( 14 |
15 | 16 |
17 | ); 18 | } 19 | 20 | return ( 21 | 24 | isAuthenticated ? ( 25 | <> 26 | 27 | 28 | 29 | ) : ( 30 | 31 | ) 32 | } 33 | /> 34 | ); 35 | }; 36 | 37 | export default ProtectedRoute; 38 | -------------------------------------------------------------------------------- /client/src/contexts/AuthContext.js: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | import { createContext, useEffect, useReducer } from "react"; 3 | import { SET_AUTH } from "../contexts/constants"; 4 | import { authReducer } from "../reducers/authReducer"; 5 | import setAuthToken from "../utils/setAuthToken"; 6 | import { apiUrl, LOCAL_STORAGE_TOKEN_NAME } from "./constants"; 7 | 8 | export const AuthContext = createContext(); 9 | 10 | const AuthContextProvider = ({ children }) => { 11 | const [authState, dispatch] = useReducer(authReducer, { 12 | authLoading: true, 13 | isAuthenticated: false, 14 | user: null, 15 | }); 16 | 17 | // Authenticate user 18 | const loadUser = async () => { 19 | if (localStorage[LOCAL_STORAGE_TOKEN_NAME]) { 20 | setAuthToken(localStorage[LOCAL_STORAGE_TOKEN_NAME]); 21 | } 22 | 23 | try { 24 | const response = await axios.get(`${apiUrl}/auth`); 25 | if (response.data.success) { 26 | dispatch({ 27 | type: SET_AUTH, 28 | payload: { 29 | isAuthenticated: true, 30 | user: response.data.user, 31 | }, 32 | }); 33 | } 34 | } catch (error) { 35 | localStorage.removeItem(LOCAL_STORAGE_TOKEN_NAME); 36 | setAuthToken(null); 37 | dispatch({ 38 | type: SET_AUTH, 39 | payload: { 40 | isAuthenticated: false, 41 | user: null, 42 | }, 43 | }); 44 | } 45 | }; 46 | 47 | useEffect(() => loadUser(), []); 48 | 49 | // Login 50 | const loginUser = async (userForm) => { 51 | try { 52 | const response = await axios.post(`${apiUrl}/auth/login`, userForm); 53 | if (response.data.success) 54 | localStorage.setItem( 55 | LOCAL_STORAGE_TOKEN_NAME, 56 | response.data.accessToken 57 | ); 58 | 59 | await loadUser(); 60 | 61 | return response.data; 62 | } catch (error) { 63 | if (error.response.data) return error.response.data; 64 | else return { success: false, message: error.message }; 65 | } 66 | }; 67 | 68 | // Register 69 | const registerUser = async (userForm) => { 70 | try { 71 | const response = await axios.post(`${apiUrl}/auth/register`, userForm); 72 | if (response.data.success) 73 | localStorage.setItem( 74 | LOCAL_STORAGE_TOKEN_NAME, 75 | response.data.accessToken 76 | ); 77 | 78 | await loadUser(); 79 | 80 | return response.data; 81 | } catch (error) { 82 | if (error.response.data) return error.response.data; 83 | else return { success: false, message: error.message }; 84 | } 85 | }; 86 | 87 | // Logout 88 | const logoutUser = () => { 89 | localStorage.removeItem(LOCAL_STORAGE_TOKEN_NAME); 90 | dispatch({ 91 | type: "SET_AUTH", 92 | payload: { 93 | isAuthenticated: false, 94 | user: null, 95 | }, 96 | }); 97 | }; 98 | 99 | // Context data 100 | const authContextData = { loginUser, registerUser, logoutUser, authState }; 101 | 102 | // Return provider 103 | return ( 104 | 105 | {children} 106 | 107 | ); 108 | }; 109 | 110 | export default AuthContextProvider; 111 | -------------------------------------------------------------------------------- /client/src/contexts/PostContext.js: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | import { createContext, useReducer, useState } from "react"; 3 | import { postReducer } from "../reducers/postReducer"; 4 | import { 5 | ADD_POST, 6 | apiUrl, 7 | DELETE_POST, 8 | FIND_POST, 9 | POSTS_LOADED_FAIL, 10 | POSTS_LOADED_SUCCESS, 11 | UPDATE_POST, 12 | } from "./constants"; 13 | 14 | export const PostContext = createContext(); 15 | 16 | const PostContextProvider = ({ children }) => { 17 | // State 18 | const [postState, dispatch] = useReducer(postReducer, { 19 | post: null, 20 | posts: [], 21 | postsLoading: true, 22 | }); 23 | 24 | const [showAddPostModal, setShowAddPostModal] = useState(false); 25 | const [showUpdatePostModal, setShowUpdatePostModal] = useState(false); 26 | const [showToast, setShowToast] = useState({ 27 | show: false, 28 | message: "", 29 | type: null, 30 | }); 31 | 32 | // Get all posts 33 | const getPosts = async () => { 34 | try { 35 | const response = await axios.get(`${apiUrl}/posts`); 36 | if (response.data.success) { 37 | dispatch({ type: POSTS_LOADED_SUCCESS, payload: response.data.posts }); 38 | } 39 | } catch (error) { 40 | dispatch({ type: POSTS_LOADED_FAIL }); 41 | } 42 | }; 43 | 44 | // Add post 45 | const addPost = async (newPost) => { 46 | try { 47 | const response = await axios.post(`${apiUrl}/posts`, newPost); 48 | if (response.data.success) { 49 | dispatch({ type: ADD_POST, payload: response.data.post }); 50 | return response.data; 51 | } 52 | } catch (error) { 53 | return error.response.data 54 | ? error.response.data 55 | : { success: false, message: "Server error" }; 56 | } 57 | }; 58 | 59 | // Delete post 60 | const deletePost = async (postId) => { 61 | try { 62 | const response = await axios.delete(`${apiUrl}/posts/${postId}`); 63 | if (response.data.success) 64 | dispatch({ type: DELETE_POST, payload: postId }); 65 | } catch (error) { 66 | console.log(error); 67 | } 68 | }; 69 | 70 | // Find post when user is updating post 71 | const findPost = (postId) => { 72 | const post = postState.posts.find((post) => post._id === postId); 73 | dispatch({ type: FIND_POST, payload: post }); 74 | }; 75 | 76 | // Update post 77 | const updatePost = async (updatedPost) => { 78 | try { 79 | const response = await axios.put( 80 | `${apiUrl}/posts/${updatedPost._id}`, 81 | updatedPost 82 | ); 83 | if (response.data.success) { 84 | dispatch({ type: UPDATE_POST, payload: response.data.post }); 85 | return response.data; 86 | } 87 | } catch (error) { 88 | return error.response.data 89 | ? error.response.data 90 | : { success: false, message: "Server error" }; 91 | } 92 | }; 93 | 94 | // Post context data 95 | const postContextData = { 96 | postState, 97 | getPosts, 98 | showAddPostModal, 99 | setShowAddPostModal, 100 | showUpdatePostModal, 101 | setShowUpdatePostModal, 102 | addPost, 103 | showToast, 104 | setShowToast, 105 | deletePost, 106 | findPost, 107 | updatePost, 108 | }; 109 | 110 | return ( 111 | 112 | {children} 113 | 114 | ); 115 | }; 116 | 117 | export default PostContextProvider; 118 | -------------------------------------------------------------------------------- /client/src/contexts/constants.js: -------------------------------------------------------------------------------- 1 | export const apiUrl = 2 | process.env.NODE_ENV !== "production" ? `http://localhost:5000/api` : ``; 3 | 4 | export const LOCAL_STORAGE_TOKEN_NAME = `learnit_mern`; 5 | 6 | export const SET_AUTH = "SET_AUTH"; 7 | export const POSTS_LOADED_SUCCESS = "POSTS_LOADED_SUCCESS"; 8 | export const POSTS_LOADED_FAIL = "POSTS_LOADED_FAIL"; 9 | export const ADD_POST = 'ADD_POST' 10 | export const DELETE_POST = 'DELETE_POST' 11 | export const UPDATE_POST = 'UPDATE_POST' 12 | export const FIND_POST = 'FIND_POST' -------------------------------------------------------------------------------- /client/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /client/src/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import reportWebVitals from './reportWebVitals'; 6 | 7 | ReactDOM.render( 8 | 9 | 10 | , 11 | document.getElementById('root') 12 | ); 13 | 14 | // If you want to start measuring performance in your app, pass a function 15 | // to log results (for example: reportWebVitals(console.log)) 16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 17 | reportWebVitals(); 18 | -------------------------------------------------------------------------------- /client/src/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/src/reducers/authReducer.js: -------------------------------------------------------------------------------- 1 | import { SET_AUTH } from '../contexts/constants' 2 | 3 | export const authReducer = (state, action) => { 4 | const { 5 | type, 6 | payload: { isAuthenticated, user }, 7 | } = action; 8 | 9 | switch (type) { 10 | case SET_AUTH: 11 | return { 12 | ...state, 13 | authLoading: false, 14 | isAuthenticated, 15 | user, 16 | }; 17 | 18 | default: 19 | return state; 20 | } 21 | }; 22 | -------------------------------------------------------------------------------- /client/src/reducers/postReducer.js: -------------------------------------------------------------------------------- 1 | import { 2 | ADD_POST, 3 | DELETE_POST, FIND_POST, POSTS_LOADED_FAIL, POSTS_LOADED_SUCCESS, UPDATE_POST 4 | } from '../contexts/constants'; 5 | 6 | export const postReducer = (state, action) => { 7 | const { type, payload } = action; 8 | 9 | switch (type) { 10 | case POSTS_LOADED_SUCCESS: 11 | return { 12 | ...state, 13 | posts: payload, 14 | postsLoading: false, 15 | }; 16 | 17 | case POSTS_LOADED_FAIL: 18 | return { 19 | ...state, 20 | posts: [], 21 | postsLoading: false, 22 | }; 23 | 24 | case ADD_POST: 25 | return { 26 | ...state, 27 | posts: [...state.posts, payload], 28 | }; 29 | 30 | case DELETE_POST: 31 | return { 32 | ...state, 33 | posts: state.posts.filter((post) => post._id !== payload), 34 | }; 35 | 36 | case FIND_POST: 37 | return { ...state, post: payload }; 38 | 39 | case UPDATE_POST: 40 | const newPosts = state.posts.map((post) => 41 | post._id === payload._id ? payload : post 42 | ); 43 | 44 | return { 45 | ...state, 46 | posts: newPosts, 47 | }; 48 | 49 | default: 50 | return state; 51 | } 52 | }; 53 | -------------------------------------------------------------------------------- /client/src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /client/src/setupTests.js: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /client/src/utils/setAuthToken.js: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | 3 | const setAuthToken = (token) => { 4 | if (token) { 5 | axios.defaults.headers.common["Authorization"] = `Bearer ${token}`; 6 | } else { 7 | delete axios.defaults.headers.common["Authorization"]; 8 | } 9 | }; 10 | 11 | export default setAuthToken; 12 | -------------------------------------------------------------------------------- /client/src/views/About.js: -------------------------------------------------------------------------------- 1 | import Button from "react-bootstrap/Button"; 2 | import Row from "react-bootstrap/Row"; 3 | import Col from "react-bootstrap/Col"; 4 | 5 | const About = () => { 6 | return ( 7 | 8 | 9 | 12 | 13 | 14 | ); 15 | }; 16 | 17 | export default About; 18 | -------------------------------------------------------------------------------- /client/src/views/Auth.js: -------------------------------------------------------------------------------- 1 | import React, { useContext } from "react"; 2 | import { Spinner } from "react-bootstrap"; 3 | import { Redirect } from "react-router"; 4 | import LoginForm from "../components/auth/LoginForm"; 5 | import RegisterForm from "../components/auth/RegisterForm"; 6 | import { AuthContext } from "../contexts/AuthContext"; 7 | 8 | const Auth = ({ authRoute }) => { 9 | const { 10 | authState: { authLoading, isAuthenticated }, 11 | } = useContext(AuthContext); 12 | 13 | let body; 14 | 15 | if (authLoading) { 16 | body = ( 17 |
18 | 19 |
20 | ); 21 | } else if (isAuthenticated) { 22 | return ; 23 | } else { 24 | body = ( 25 | <> 26 | {authRoute === "login" && } 27 | {authRoute === "register" && } 28 | 29 | ); 30 | } 31 | 32 | return ( 33 |
34 |
35 |
36 |

LearnIt

37 |

Keep track of what you are learning

38 | {body} 39 |
40 |
41 |
42 | ); 43 | }; 44 | 45 | export default Auth; 46 | -------------------------------------------------------------------------------- /client/src/views/Dashboard.js: -------------------------------------------------------------------------------- 1 | import { PostContext } from "../contexts/PostContext"; 2 | import { AuthContext } from "../contexts/AuthContext"; 3 | import { useContext, useEffect } from "react"; 4 | import { 5 | Spinner, 6 | Button, 7 | Card, 8 | Row, 9 | Toast, 10 | OverlayTrigger, 11 | Tooltip, 12 | Col, 13 | } from "react-bootstrap"; 14 | import SinglePost from "../components/posts/SinglePost"; 15 | import AddPostModal from "../components/posts/AddPostModal"; 16 | import UpdatePostModal from "../components/posts/UpdatePostModal"; 17 | import addIcon from "../assets/plus-circle-fill.svg"; 18 | 19 | const Dashboard = () => { 20 | // Contexts 21 | const { 22 | authState: { 23 | user: { username }, 24 | }, 25 | } = useContext(AuthContext); 26 | 27 | const { 28 | postState: { post, posts, postsLoading }, 29 | getPosts, 30 | setShowAddPostModal, 31 | showToast: { show, message, type }, 32 | setShowToast, 33 | } = useContext(PostContext); 34 | 35 | // Get all posts 36 | // eslint-disable-next-line react-hooks/exhaustive-deps 37 | useEffect(() => getPosts(), []); 38 | 39 | let body = null; 40 | 41 | if (postsLoading) { 42 | body = ( 43 |
44 | 45 |
46 | ); 47 | } else if (posts.length === 0) { 48 | body = ( 49 | <> 50 | 51 | Hi {username} 52 | 53 | Welcome to LearnIt 54 | 55 | Click the button below to track your first skill to learn 56 | 57 | 63 | 64 | 65 | 66 | ); 67 | } else { 68 | body = ( 69 | <> 70 | 71 | {posts.map((post) => ( 72 | 73 | 74 | 75 | ))} 76 | 77 | 78 | {/* Open Add Post Modal */} 79 | Add a new thing to learn} 82 | > 83 | 89 | 90 | 91 | ); 92 | } 93 | 94 | return ( 95 | <> 96 | {body} 97 | 98 | {post !== null && } 99 | {/* After post is added, show toast */} 100 | 112 | 113 | {message} 114 | 115 | 116 | 117 | ); 118 | }; 119 | 120 | export default Dashboard; 121 | -------------------------------------------------------------------------------- /screenshots/screenshot_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zendy199x/MERN-Stack/a459fe84ed7723c3b37fcedc77ea2ec411e0eec6/screenshots/screenshot_1.png -------------------------------------------------------------------------------- /screenshots/screenshot_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zendy199x/MERN-Stack/a459fe84ed7723c3b37fcedc77ea2ec411e0eec6/screenshots/screenshot_2.png -------------------------------------------------------------------------------- /screenshots/screenshot_3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zendy199x/MERN-Stack/a459fe84ed7723c3b37fcedc77ea2ec411e0eec6/screenshots/screenshot_3.png -------------------------------------------------------------------------------- /screenshots/screenshot_4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zendy199x/MERN-Stack/a459fe84ed7723c3b37fcedc77ea2ec411e0eec6/screenshots/screenshot_4.png -------------------------------------------------------------------------------- /screenshots/screenshot_5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zendy199x/MERN-Stack/a459fe84ed7723c3b37fcedc77ea2ec411e0eec6/screenshots/screenshot_5.png -------------------------------------------------------------------------------- /screenshots/screenshot_6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/zendy199x/MERN-Stack/a459fe84ed7723c3b37fcedc77ea2ec411e0eec6/screenshots/screenshot_6.png -------------------------------------------------------------------------------- /server/.env: -------------------------------------------------------------------------------- 1 | PORT=5000 2 | SESSION_DB_USERNAME=zendy 3 | SESSION_DB_PASSWORD=zendy 4 | ACCESS_TOKEN_SECRET=abcxyz -------------------------------------------------------------------------------- /server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mern-server", 3 | "version": "1.0.0", 4 | "description": "MERN server", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "server": "nodemon src/index" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/zendy199x/MERN-Stack.git" 13 | }, 14 | "author": "Zendy", 15 | "license": "MIT", 16 | "bugs": { 17 | "url": "https://github.com/zendy199x/MERN-Stack/issues" 18 | }, 19 | "homepage": "https://github.com/zendy199x/MERN-Stack#readme", 20 | "dependencies": { 21 | "argon2": "^0.28.2", 22 | "cors": "^2.8.5", 23 | "dotenv": "^10.0.0", 24 | "express": "^4.17.1", 25 | "jsonwebtoken": "^8.5.1", 26 | "mongoose": "5.13.8" 27 | }, 28 | "devDependencies": { 29 | "nodemon": "^2.0.12" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /server/request.http: -------------------------------------------------------------------------------- 1 | # GET http://localhost:5000 2 | 3 | # Register 4 | POST http://localhost:5000/api/auth/register 5 | Content-Type: application/json 6 | 7 | { 8 | "username": "zendy1", 9 | "password": "zendy" 10 | } 11 | 12 | ### 13 | 14 | # Login 15 | POST http://localhost:5000/api/auth/login 16 | Content-Type: application/json 17 | 18 | { 19 | "username": "zendy1", 20 | "password": "zendy" 21 | } 22 | 23 | ### 24 | 25 | # Create post 26 | POST http://localhost:5000/api/posts 27 | Content-Type: application/json 28 | Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiI2MTMyNGFiN2JkNTdiNmNlOWYwYmRjZTgiLCJpYXQiOjE2MzA2ODc0NTN9.riX9Ln4wwMOwF3CheCn4Rw3IsZscgt1SVyx8rqewjYE 29 | 30 | { 31 | "title": "title 2", 32 | "description": "description 2", 33 | "url": "gooogle.com", 34 | "status": "LEARNING" 35 | } 36 | 37 | ### 38 | 39 | # Get post 40 | GET http://localhost:5000/api/posts 41 | Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiI2MTMyNGFiN2JkNTdiNmNlOWYwYmRjZTgiLCJpYXQiOjE2MzA2ODc0NTN9.riX9Ln4wwMOwF3CheCn4Rw3IsZscgt1SVyx8rqewjYE 42 | 43 | 44 | ### 45 | 46 | # Update post 47 | PUT http://localhost:5000/api/posts/61324ac8bd57b6ce9f0bdceb 48 | Content-Type: application/json 49 | Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiI2MTMyNGFiN2JkNTdiNmNlOWYwYmRjZTgiLCJpYXQiOjE2MzA2ODc0NTN9.riX9Ln4wwMOwF3CheCn4Rw3IsZscgt1SVyx8rqewjYE 50 | 51 | { 52 | "title": "Vue", 53 | "description": "Learn Vue", 54 | "url": "youtube.com", 55 | "status": "LEARNING" 56 | } 57 | 58 | 59 | ### 60 | 61 | # Delete post 62 | DELETE http://localhost:5000/api/posts/613252260ae41dd672f5ed36 63 | Content-Type: application/json 64 | Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiI2MTMyNGFiN2JkNTdiNmNlOWYwYmRjZTgiLCJpYXQiOjE2MzA2ODc0NTN9.riX9Ln4wwMOwF3CheCn4Rw3IsZscgt1SVyx8rqewjYE 65 | -------------------------------------------------------------------------------- /server/src/config/db.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | 3 | const mongoUrl = `mongodb+srv://${process.env.SESSION_DB_USERNAME}:${process.env.SESSION_DB_PASSWORD}@cluster0.bbsjh.mongodb.net/myFirstDatabase?retryWrites=true&w=majority` 4 | 5 | const connectDB = async () => { 6 | try { 7 | await mongoose.connect(mongoUrl, { 8 | useCreateIndex: true, 9 | useNewUrlParser: true, 10 | useUnifiedTopology: true, 11 | useFindAndModify: false, 12 | }), 13 | console.log(`MongoDB connected`); 14 | } catch (error) { 15 | console.log(error.message); 16 | process.exit(1); // error code 17 | } 18 | }; 19 | 20 | module.exports = connectDB; 21 | -------------------------------------------------------------------------------- /server/src/index.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const cors = require("cors"); 3 | require("dotenv").config(); 4 | const connectDB = require("./config/db"); 5 | 6 | const authRouter = require("./routers/auth"); 7 | const postRouter = require("./routers/post"); 8 | 9 | // start app 10 | const app = express(); 11 | app.use(express.json()); 12 | app.use(cors()); 13 | 14 | // connect DB 15 | connectDB(); 16 | 17 | app.use("/api/auth", authRouter); 18 | app.use("/api/posts", postRouter); 19 | 20 | const PORT = process.env.PORT || 5000; 21 | 22 | app.listen(PORT, () => console.log(`Server started on port ${PORT}`)); 23 | -------------------------------------------------------------------------------- /server/src/middleware/auth.js: -------------------------------------------------------------------------------- 1 | const jwt = require("jsonwebtoken"); 2 | 3 | // Authorization = Bearer abcxyz 4 | 5 | const verifyToken = (req, res, next) => { 6 | const authHeader = req.header("Authorization"); 7 | const token = authHeader && authHeader.split(" ")[1]; 8 | 9 | if (!token) 10 | return res 11 | .status(401) 12 | .json({ success: false, message: "Access token not found" }); 13 | 14 | try { 15 | const decoded = jwt.verify(token, process.env.ACCESS_TOKEN_SECRET); 16 | 17 | req.userId = decoded.userId; 18 | next(); 19 | } catch (error) { 20 | console.log(error); 21 | return res.status(403).json({ success: false, message: "Invalid token" }); 22 | } 23 | }; 24 | 25 | module.exports = verifyToken; 26 | -------------------------------------------------------------------------------- /server/src/models/Post.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | const Schema = mongoose.Schema; 3 | 4 | const PostSchema = new Schema({ 5 | title: { 6 | type: String, 7 | require: true, 8 | }, 9 | description: { 10 | type: String, 11 | }, 12 | url: { 13 | type: String, 14 | }, 15 | status: { 16 | type: String, 17 | enum: ["TO LEARN", "LEARNING", "LEARNED"], 18 | }, 19 | user: { 20 | type: Schema.Types.ObjectId, 21 | ref: "users", 22 | }, 23 | }); 24 | 25 | module.exports = mongoose.model("posts", PostSchema); 26 | -------------------------------------------------------------------------------- /server/src/models/User.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | const Schema = mongoose.Schema; 3 | 4 | const UserSchema = new Schema({ 5 | username: { 6 | type: String, 7 | required: true, 8 | unique: true, 9 | }, 10 | password: { 11 | type: String, 12 | required: true, 13 | }, 14 | createdAt: { 15 | type: Date, 16 | default: Date.now(), 17 | }, 18 | }); 19 | 20 | module.exports = mongoose.model("users", UserSchema); 21 | -------------------------------------------------------------------------------- /server/src/routers/auth.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const argon2 = require("argon2"); 3 | const jwt = require("jsonwebtoken"); 4 | const verifyToken = require("../middleware/auth"); 5 | 6 | const router = express.Router(); 7 | 8 | const User = require("../models/User"); 9 | 10 | // @route GET api/auth 11 | // @desc Check if user is logged in 12 | // @access Public 13 | router.get("/", verifyToken, async (req, res) => { 14 | try { 15 | const user = await User.findById(req.userId).select("-password"); 16 | if (!user) 17 | return res 18 | .status(400) 19 | .json({ success: false, message: "User not found" }); 20 | 21 | res.json({ success: true, user }); 22 | } catch (error) { 23 | console.log(error); 24 | res.status(500).json({ success: false, message: `Internal server error` }); 25 | } 26 | }); 27 | 28 | // @route POST api/auth/register 29 | // @desc Register user 30 | // @access Public 31 | router.post("/register", async (req, res) => { 32 | const { username, password } = req.body; 33 | 34 | // Simple validation 35 | if (!username || !password) { 36 | return res 37 | .status(400) 38 | .json({ success: false, message: "Missing username and/or password" }); 39 | } 40 | 41 | try { 42 | // Check for existing user 43 | const user = await User.findOne({ username }); 44 | 45 | if (user) 46 | return res 47 | .status(400) 48 | .json({ success: false, message: "User already taken" }); 49 | 50 | // All good 51 | const hashedPassword = await argon2.hash(password); 52 | const newUser = new User({ username, password: hashedPassword }); 53 | 54 | await newUser.save(); 55 | 56 | // Return token 57 | const accessToken = jwt.sign( 58 | { userId: newUser._id }, 59 | process.env.ACCESS_TOKEN_SECRET 60 | ); 61 | 62 | res.json({ 63 | success: true, 64 | message: `User created successfully`, 65 | accessToken, 66 | }); 67 | } catch (error) { 68 | console.log(error); 69 | res.status(500).json({ success: false, message: `Internal server error` }); 70 | } 71 | }); 72 | 73 | // @route POST api/auth/login 74 | // @desc Login user 75 | // @access Public 76 | router.post("/login", async (req, res) => { 77 | const { username, password } = req.body; 78 | if (!username || !password) 79 | return res 80 | .status(400) 81 | .json({ success: false, message: "Missing username and/or password" }); 82 | 83 | try { 84 | // Check for existing user 85 | const user = await User.findOne({ username }); 86 | if (!user) 87 | return res 88 | .status(400) 89 | .json({ success: false, message: "Incorrect username or password" }); 90 | 91 | // Username found 92 | const passwordValid = await argon2.verify(user.password, password); 93 | if (!passwordValid) 94 | return res 95 | .status(400) 96 | .json({ success: false, message: "Incorrect username or password" }); 97 | 98 | // All good 99 | const accessToken = jwt.sign( 100 | { userId: user._id }, 101 | process.env.ACCESS_TOKEN_SECRET 102 | ); 103 | 104 | res.json({ 105 | success: true, 106 | message: `User logged in successfully`, 107 | accessToken, 108 | }); 109 | } catch (error) { 110 | console.log(error); 111 | res.status(500).json({ success: false, message: `Internal server error` }); 112 | } 113 | }); 114 | 115 | module.exports = router; 116 | -------------------------------------------------------------------------------- /server/src/routers/post.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const router = express.Router(); 3 | const verifyToken = require("../middleware/auth"); 4 | 5 | const Post = require("../models/Post"); 6 | 7 | // @routes GET api/posts 8 | // @desc Get post 9 | // @access Private 10 | router.get("/", verifyToken, async (req, res) => { 11 | try { 12 | const posts = await Post.find({ user: req.userId }).populate("user", [ 13 | "username", 14 | ]); 15 | res.json({ success: true, posts }); 16 | } catch (error) { 17 | console.log(error); 18 | res.status(500).json({ success: false, message: `Internal server error` }); 19 | } 20 | }); 21 | 22 | // @routes POST api/posts 23 | // @desc Create post 24 | // @access Private 25 | router.post("/", verifyToken, async (req, res) => { 26 | const { title, description, url, status } = req.body; 27 | 28 | // Simple validation 29 | if (!title) 30 | return res 31 | .status(400) 32 | .json({ success: false, message: "Title is required" }); 33 | 34 | try { 35 | const newPost = new Post({ 36 | title, 37 | description, 38 | url: url.startsWith("https://") ? url : `https://${url}`, 39 | status: status || "TO LEARN", 40 | user: req.userId, 41 | }); 42 | 43 | await newPost.save(); 44 | 45 | res.json({ success: true, message: "Happy learning!", post: newPost }); 46 | } catch (error) { 47 | console.log(error); 48 | res.status(500).json({ success: false, message: `Internal server error` }); 49 | } 50 | }); 51 | 52 | // @routes PUT api/posts 53 | // @desc Update post 54 | // @access Private 55 | router.put("/:id", verifyToken, async (req, res) => { 56 | const { title, description, url, status } = req.body; 57 | 58 | // Simple validation 59 | if (!title) 60 | return res 61 | .status(400) 62 | .json({ success: false, message: "Title is required" }); 63 | 64 | try { 65 | let updatedPost = { 66 | title, 67 | description: description || "", 68 | url: (url.startsWith("https://") ? url : `https://${url}`) || "", 69 | status: status || "TO LEARN", 70 | }; 71 | 72 | const postUpdateCondition = { _id: req.params.id, user: req.userId }; 73 | 74 | updatedPost = await Post.findOneAndUpdate( 75 | postUpdateCondition, 76 | updatedPost, 77 | { new: true } 78 | ); 79 | 80 | // User not authorised to update post or post not found 81 | if (!updatedPost) 82 | return res.status(401).json({ 83 | success: false, 84 | message: "Post not found or user not authorised", 85 | }); 86 | 87 | res.json({ 88 | success: true, 89 | message: "Excellent progress!", 90 | post: updatedPost, 91 | }); 92 | } catch (error) { 93 | console.log(error); 94 | res.status(500).json({ success: false, message: "Internal server error" }); 95 | } 96 | }); 97 | 98 | // @route DELETE api/posts 99 | // @desc Delete post 100 | // @access Private 101 | router.delete("/:id", verifyToken, async (req, res) => { 102 | try { 103 | const postDeleteCondition = { _id: req.params.id, user: req.userId }; 104 | const deletedPost = await Post.findOneAndDelete(postDeleteCondition); 105 | 106 | // User not authorised or post not found 107 | if (!deletedPost) 108 | return res.status(401).json({ 109 | success: false, 110 | message: "Post not found or user not authorised", 111 | }); 112 | 113 | res.json({ success: true, post: deletedPost }); 114 | } catch (error) { 115 | console.log(error); 116 | res.status(500).json({ success: false, message: "Internal server error" }); 117 | } 118 | }); 119 | 120 | module.exports = router; 121 | -------------------------------------------------------------------------------- /server/yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@mapbox/node-pre-gyp@^1.0.1": 6 | version "1.0.5" 7 | resolved "https://registry.yarnpkg.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.5.tgz#2a0b32fcb416fb3f2250fd24cb2a81421a4f5950" 8 | integrity sha512-4srsKPXWlIxp5Vbqz5uLfBN+du2fJChBoYn/f2h991WLdk7jUvcSk/McVLSv/X+xQIPI8eGD5GjrnygdyHnhPA== 9 | dependencies: 10 | detect-libc "^1.0.3" 11 | https-proxy-agent "^5.0.0" 12 | make-dir "^3.1.0" 13 | node-fetch "^2.6.1" 14 | nopt "^5.0.0" 15 | npmlog "^4.1.2" 16 | rimraf "^3.0.2" 17 | semver "^7.3.4" 18 | tar "^6.1.0" 19 | 20 | "@phc/format@^1.0.0": 21 | version "1.0.0" 22 | resolved "https://registry.yarnpkg.com/@phc/format/-/format-1.0.0.tgz#b5627003b3216dc4362125b13f48a4daa76680e4" 23 | integrity sha512-m7X9U6BG2+J+R1lSOdCiITLLrxm+cWlNI3HUFA92oLO77ObGNzaKdh8pMLqdZcshtkKuV84olNNXDfMc4FezBQ== 24 | 25 | "@sindresorhus/is@^0.14.0": 26 | version "0.14.0" 27 | resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" 28 | integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ== 29 | 30 | "@szmarczak/http-timer@^1.1.2": 31 | version "1.1.2" 32 | resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421" 33 | integrity sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA== 34 | dependencies: 35 | defer-to-connect "^1.0.1" 36 | 37 | "@types/bson@*": 38 | version "4.2.0" 39 | resolved "https://registry.yarnpkg.com/@types/bson/-/bson-4.2.0.tgz#a2f71e933ff54b2c3bf267b67fa221e295a33337" 40 | integrity sha512-ELCPqAdroMdcuxqwMgUpifQyRoTpyYCNr1V9xKyF40VsBobsj+BbWNRvwGchMgBPGqkw655ypkjj2MEF5ywVwg== 41 | dependencies: 42 | bson "*" 43 | 44 | "@types/mongodb@^3.5.27": 45 | version "3.6.20" 46 | resolved "https://registry.yarnpkg.com/@types/mongodb/-/mongodb-3.6.20.tgz#b7c5c580644f6364002b649af1c06c3c0454e1d2" 47 | integrity sha512-WcdpPJCakFzcWWD9juKoZbRtQxKIMYF/JIAM4JrNHrMcnJL6/a2NWjXxW7fo9hxboxxkg+icff8d7+WIEvKgYQ== 48 | dependencies: 49 | "@types/bson" "*" 50 | "@types/node" "*" 51 | 52 | "@types/node@*": 53 | version "16.7.10" 54 | resolved "https://registry.yarnpkg.com/@types/node/-/node-16.7.10.tgz#7aa732cc47341c12a16b7d562f519c2383b6d4fc" 55 | integrity sha512-S63Dlv4zIPb8x6MMTgDq5WWRJQe56iBEY0O3SOFA9JrRienkOVDXSXBjjJw6HTNQYSE2JI6GMCR6LVbIMHJVvA== 56 | 57 | abbrev@1: 58 | version "1.1.1" 59 | resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" 60 | integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== 61 | 62 | accepts@~1.3.7: 63 | version "1.3.7" 64 | resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" 65 | integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA== 66 | dependencies: 67 | mime-types "~2.1.24" 68 | negotiator "0.6.2" 69 | 70 | agent-base@6: 71 | version "6.0.2" 72 | resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" 73 | integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== 74 | dependencies: 75 | debug "4" 76 | 77 | ansi-align@^3.0.0: 78 | version "3.0.0" 79 | resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-3.0.0.tgz#b536b371cf687caaef236c18d3e21fe3797467cb" 80 | integrity sha512-ZpClVKqXN3RGBmKibdfWzqCY4lnjEuoNzU5T0oEFpfd/z5qJHVarukridD4juLO2FXMiwUQxr9WqQtaYa8XRYw== 81 | dependencies: 82 | string-width "^3.0.0" 83 | 84 | ansi-regex@^2.0.0: 85 | version "2.1.1" 86 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" 87 | integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= 88 | 89 | ansi-regex@^3.0.0: 90 | version "3.0.0" 91 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" 92 | integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= 93 | 94 | ansi-regex@^4.1.0: 95 | version "4.1.0" 96 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" 97 | integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== 98 | 99 | ansi-regex@^5.0.0: 100 | version "5.0.0" 101 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" 102 | integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== 103 | 104 | ansi-styles@^4.1.0: 105 | version "4.3.0" 106 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" 107 | integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== 108 | dependencies: 109 | color-convert "^2.0.1" 110 | 111 | anymatch@~3.1.2: 112 | version "3.1.2" 113 | resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" 114 | integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== 115 | dependencies: 116 | normalize-path "^3.0.0" 117 | picomatch "^2.0.4" 118 | 119 | aproba@^1.0.3: 120 | version "1.2.0" 121 | resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" 122 | integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== 123 | 124 | are-we-there-yet@~1.1.2: 125 | version "1.1.7" 126 | resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz#b15474a932adab4ff8a50d9adfa7e4e926f21146" 127 | integrity sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g== 128 | dependencies: 129 | delegates "^1.0.0" 130 | readable-stream "^2.0.6" 131 | 132 | argon2@^0.28.2: 133 | version "0.28.2" 134 | resolved "https://registry.yarnpkg.com/argon2/-/argon2-0.28.2.tgz#b583e4ef5b052a83bfe146752844b9fa526dba29" 135 | integrity sha512-8oRk3kPlL0lLletENzhpbF9zoZJqvIHwTkjBseMrg1uD4gBMqhqnjJz1z3lEtwT0oqQAEkEwsEpsjaQBBRHcWw== 136 | dependencies: 137 | "@mapbox/node-pre-gyp" "^1.0.1" 138 | "@phc/format" "^1.0.0" 139 | node-addon-api "^3.0.2" 140 | opencollective-postinstall "^2.0.3" 141 | 142 | array-flatten@1.1.1: 143 | version "1.1.1" 144 | resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" 145 | integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= 146 | 147 | balanced-match@^1.0.0: 148 | version "1.0.2" 149 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" 150 | integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== 151 | 152 | base64-js@^1.3.1: 153 | version "1.5.1" 154 | resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" 155 | integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== 156 | 157 | binary-extensions@^2.0.0: 158 | version "2.2.0" 159 | resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" 160 | integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== 161 | 162 | bl@^2.2.1: 163 | version "2.2.1" 164 | resolved "https://registry.yarnpkg.com/bl/-/bl-2.2.1.tgz#8c11a7b730655c5d56898cdc871224f40fd901d5" 165 | integrity sha512-6Pesp1w0DEX1N550i/uGV/TqucVL4AM/pgThFSN/Qq9si1/DF9aIHs1BxD8V/QU0HoeHO6cQRTAuYnLPKq1e4g== 166 | dependencies: 167 | readable-stream "^2.3.5" 168 | safe-buffer "^5.1.1" 169 | 170 | bluebird@3.5.1: 171 | version "3.5.1" 172 | resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9" 173 | integrity sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA== 174 | 175 | body-parser@1.19.0: 176 | version "1.19.0" 177 | resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" 178 | integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw== 179 | dependencies: 180 | bytes "3.1.0" 181 | content-type "~1.0.4" 182 | debug "2.6.9" 183 | depd "~1.1.2" 184 | http-errors "1.7.2" 185 | iconv-lite "0.4.24" 186 | on-finished "~2.3.0" 187 | qs "6.7.0" 188 | raw-body "2.4.0" 189 | type-is "~1.6.17" 190 | 191 | boxen@^4.2.0: 192 | version "4.2.0" 193 | resolved "https://registry.yarnpkg.com/boxen/-/boxen-4.2.0.tgz#e411b62357d6d6d36587c8ac3d5d974daa070e64" 194 | integrity sha512-eB4uT9RGzg2odpER62bBwSLvUeGC+WbRjjyyFhGsKnc8wp/m0+hQsMUvUe3H2V0D5vw0nBdO1hCJoZo5mKeuIQ== 195 | dependencies: 196 | ansi-align "^3.0.0" 197 | camelcase "^5.3.1" 198 | chalk "^3.0.0" 199 | cli-boxes "^2.2.0" 200 | string-width "^4.1.0" 201 | term-size "^2.1.0" 202 | type-fest "^0.8.1" 203 | widest-line "^3.1.0" 204 | 205 | brace-expansion@^1.1.7: 206 | version "1.1.11" 207 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" 208 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== 209 | dependencies: 210 | balanced-match "^1.0.0" 211 | concat-map "0.0.1" 212 | 213 | braces@~3.0.2: 214 | version "3.0.2" 215 | resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" 216 | integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== 217 | dependencies: 218 | fill-range "^7.0.1" 219 | 220 | bson@*: 221 | version "4.5.1" 222 | resolved "https://registry.yarnpkg.com/bson/-/bson-4.5.1.tgz#02e9d649ce017ab14ed258737756c11809963d6c" 223 | integrity sha512-XqFP74pbTVLyLy5KFxVfTUyRrC1mgOlmu/iXHfXqfCKT59jyP9lwbotGfbN59cHBRbJSamZNkrSopjv+N0SqAA== 224 | dependencies: 225 | buffer "^5.6.0" 226 | 227 | bson@^1.1.4: 228 | version "1.1.6" 229 | resolved "https://registry.yarnpkg.com/bson/-/bson-1.1.6.tgz#fb819be9a60cd677e0853aee4ca712a785d6618a" 230 | integrity sha512-EvVNVeGo4tHxwi8L6bPj3y3itEvStdwvvlojVxxbyYfoaxJ6keLgrTuKdyfEAszFK+H3olzBuafE0yoh0D1gdg== 231 | 232 | buffer-equal-constant-time@1.0.1: 233 | version "1.0.1" 234 | resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" 235 | integrity sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk= 236 | 237 | buffer@^5.6.0: 238 | version "5.7.1" 239 | resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" 240 | integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== 241 | dependencies: 242 | base64-js "^1.3.1" 243 | ieee754 "^1.1.13" 244 | 245 | bytes@3.1.0: 246 | version "3.1.0" 247 | resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" 248 | integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== 249 | 250 | cacheable-request@^6.0.0: 251 | version "6.1.0" 252 | resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-6.1.0.tgz#20ffb8bd162ba4be11e9567d823db651052ca912" 253 | integrity sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg== 254 | dependencies: 255 | clone-response "^1.0.2" 256 | get-stream "^5.1.0" 257 | http-cache-semantics "^4.0.0" 258 | keyv "^3.0.0" 259 | lowercase-keys "^2.0.0" 260 | normalize-url "^4.1.0" 261 | responselike "^1.0.2" 262 | 263 | camelcase@^5.3.1: 264 | version "5.3.1" 265 | resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" 266 | integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== 267 | 268 | chalk@^3.0.0: 269 | version "3.0.0" 270 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4" 271 | integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg== 272 | dependencies: 273 | ansi-styles "^4.1.0" 274 | supports-color "^7.1.0" 275 | 276 | chokidar@^3.2.2: 277 | version "3.5.2" 278 | resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.2.tgz#dba3976fcadb016f66fd365021d91600d01c1e75" 279 | integrity sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ== 280 | dependencies: 281 | anymatch "~3.1.2" 282 | braces "~3.0.2" 283 | glob-parent "~5.1.2" 284 | is-binary-path "~2.1.0" 285 | is-glob "~4.0.1" 286 | normalize-path "~3.0.0" 287 | readdirp "~3.6.0" 288 | optionalDependencies: 289 | fsevents "~2.3.2" 290 | 291 | chownr@^2.0.0: 292 | version "2.0.0" 293 | resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" 294 | integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== 295 | 296 | ci-info@^2.0.0: 297 | version "2.0.0" 298 | resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" 299 | integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== 300 | 301 | cli-boxes@^2.2.0: 302 | version "2.2.1" 303 | resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-2.2.1.tgz#ddd5035d25094fce220e9cab40a45840a440318f" 304 | integrity sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw== 305 | 306 | clone-response@^1.0.2: 307 | version "1.0.2" 308 | resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" 309 | integrity sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws= 310 | dependencies: 311 | mimic-response "^1.0.0" 312 | 313 | code-point-at@^1.0.0: 314 | version "1.1.0" 315 | resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" 316 | integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= 317 | 318 | color-convert@^2.0.1: 319 | version "2.0.1" 320 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" 321 | integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== 322 | dependencies: 323 | color-name "~1.1.4" 324 | 325 | color-name@~1.1.4: 326 | version "1.1.4" 327 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" 328 | integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== 329 | 330 | concat-map@0.0.1: 331 | version "0.0.1" 332 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 333 | integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= 334 | 335 | configstore@^5.0.1: 336 | version "5.0.1" 337 | resolved "https://registry.yarnpkg.com/configstore/-/configstore-5.0.1.tgz#d365021b5df4b98cdd187d6a3b0e3f6a7cc5ed96" 338 | integrity sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA== 339 | dependencies: 340 | dot-prop "^5.2.0" 341 | graceful-fs "^4.1.2" 342 | make-dir "^3.0.0" 343 | unique-string "^2.0.0" 344 | write-file-atomic "^3.0.0" 345 | xdg-basedir "^4.0.0" 346 | 347 | console-control-strings@^1.0.0, console-control-strings@~1.1.0: 348 | version "1.1.0" 349 | resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" 350 | integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= 351 | 352 | content-disposition@0.5.3: 353 | version "0.5.3" 354 | resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" 355 | integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g== 356 | dependencies: 357 | safe-buffer "5.1.2" 358 | 359 | content-type@~1.0.4: 360 | version "1.0.4" 361 | resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" 362 | integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== 363 | 364 | cookie-signature@1.0.6: 365 | version "1.0.6" 366 | resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" 367 | integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= 368 | 369 | cookie@0.4.0: 370 | version "0.4.0" 371 | resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" 372 | integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg== 373 | 374 | core-util-is@~1.0.0: 375 | version "1.0.3" 376 | resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" 377 | integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== 378 | 379 | cors@^2.8.5: 380 | version "2.8.5" 381 | resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" 382 | integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g== 383 | dependencies: 384 | object-assign "^4" 385 | vary "^1" 386 | 387 | crypto-random-string@^2.0.0: 388 | version "2.0.0" 389 | resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5" 390 | integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA== 391 | 392 | debug@2.6.9, debug@^2.2.0: 393 | version "2.6.9" 394 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" 395 | integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== 396 | dependencies: 397 | ms "2.0.0" 398 | 399 | debug@3.1.0: 400 | version "3.1.0" 401 | resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" 402 | integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== 403 | dependencies: 404 | ms "2.0.0" 405 | 406 | debug@4: 407 | version "4.3.2" 408 | resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b" 409 | integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw== 410 | dependencies: 411 | ms "2.1.2" 412 | 413 | debug@^3.2.6: 414 | version "3.2.7" 415 | resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" 416 | integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== 417 | dependencies: 418 | ms "^2.1.1" 419 | 420 | decompress-response@^3.3.0: 421 | version "3.3.0" 422 | resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" 423 | integrity sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M= 424 | dependencies: 425 | mimic-response "^1.0.0" 426 | 427 | deep-extend@^0.6.0: 428 | version "0.6.0" 429 | resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" 430 | integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== 431 | 432 | defer-to-connect@^1.0.1: 433 | version "1.1.3" 434 | resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591" 435 | integrity sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ== 436 | 437 | delegates@^1.0.0: 438 | version "1.0.0" 439 | resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" 440 | integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= 441 | 442 | denque@^1.4.1: 443 | version "1.5.1" 444 | resolved "https://registry.yarnpkg.com/denque/-/denque-1.5.1.tgz#07f670e29c9a78f8faecb2566a1e2c11929c5cbf" 445 | integrity sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw== 446 | 447 | depd@~1.1.2: 448 | version "1.1.2" 449 | resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" 450 | integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= 451 | 452 | destroy@~1.0.4: 453 | version "1.0.4" 454 | resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" 455 | integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= 456 | 457 | detect-libc@^1.0.3: 458 | version "1.0.3" 459 | resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" 460 | integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= 461 | 462 | dot-prop@^5.2.0: 463 | version "5.3.0" 464 | resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88" 465 | integrity sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q== 466 | dependencies: 467 | is-obj "^2.0.0" 468 | 469 | dotenv@^10.0.0: 470 | version "10.0.0" 471 | resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-10.0.0.tgz#3d4227b8fb95f81096cdd2b66653fb2c7085ba81" 472 | integrity sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q== 473 | 474 | duplexer3@^0.1.4: 475 | version "0.1.4" 476 | resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" 477 | integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI= 478 | 479 | ecdsa-sig-formatter@1.0.11: 480 | version "1.0.11" 481 | resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf" 482 | integrity sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ== 483 | dependencies: 484 | safe-buffer "^5.0.1" 485 | 486 | ee-first@1.1.1: 487 | version "1.1.1" 488 | resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" 489 | integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= 490 | 491 | emoji-regex@^7.0.1: 492 | version "7.0.3" 493 | resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" 494 | integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== 495 | 496 | emoji-regex@^8.0.0: 497 | version "8.0.0" 498 | resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" 499 | integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== 500 | 501 | encodeurl@~1.0.2: 502 | version "1.0.2" 503 | resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" 504 | integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= 505 | 506 | end-of-stream@^1.1.0: 507 | version "1.4.4" 508 | resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" 509 | integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== 510 | dependencies: 511 | once "^1.4.0" 512 | 513 | escape-goat@^2.0.0: 514 | version "2.1.1" 515 | resolved "https://registry.yarnpkg.com/escape-goat/-/escape-goat-2.1.1.tgz#1b2dc77003676c457ec760b2dc68edb648188675" 516 | integrity sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q== 517 | 518 | escape-html@~1.0.3: 519 | version "1.0.3" 520 | resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" 521 | integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= 522 | 523 | etag@~1.8.1: 524 | version "1.8.1" 525 | resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" 526 | integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= 527 | 528 | express@^4.17.1: 529 | version "4.17.1" 530 | resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134" 531 | integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g== 532 | dependencies: 533 | accepts "~1.3.7" 534 | array-flatten "1.1.1" 535 | body-parser "1.19.0" 536 | content-disposition "0.5.3" 537 | content-type "~1.0.4" 538 | cookie "0.4.0" 539 | cookie-signature "1.0.6" 540 | debug "2.6.9" 541 | depd "~1.1.2" 542 | encodeurl "~1.0.2" 543 | escape-html "~1.0.3" 544 | etag "~1.8.1" 545 | finalhandler "~1.1.2" 546 | fresh "0.5.2" 547 | merge-descriptors "1.0.1" 548 | methods "~1.1.2" 549 | on-finished "~2.3.0" 550 | parseurl "~1.3.3" 551 | path-to-regexp "0.1.7" 552 | proxy-addr "~2.0.5" 553 | qs "6.7.0" 554 | range-parser "~1.2.1" 555 | safe-buffer "5.1.2" 556 | send "0.17.1" 557 | serve-static "1.14.1" 558 | setprototypeof "1.1.1" 559 | statuses "~1.5.0" 560 | type-is "~1.6.18" 561 | utils-merge "1.0.1" 562 | vary "~1.1.2" 563 | 564 | fill-range@^7.0.1: 565 | version "7.0.1" 566 | resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" 567 | integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== 568 | dependencies: 569 | to-regex-range "^5.0.1" 570 | 571 | finalhandler@~1.1.2: 572 | version "1.1.2" 573 | resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" 574 | integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== 575 | dependencies: 576 | debug "2.6.9" 577 | encodeurl "~1.0.2" 578 | escape-html "~1.0.3" 579 | on-finished "~2.3.0" 580 | parseurl "~1.3.3" 581 | statuses "~1.5.0" 582 | unpipe "~1.0.0" 583 | 584 | forwarded@0.2.0: 585 | version "0.2.0" 586 | resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" 587 | integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== 588 | 589 | fresh@0.5.2: 590 | version "0.5.2" 591 | resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" 592 | integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= 593 | 594 | fs-minipass@^2.0.0: 595 | version "2.1.0" 596 | resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" 597 | integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg== 598 | dependencies: 599 | minipass "^3.0.0" 600 | 601 | fs.realpath@^1.0.0: 602 | version "1.0.0" 603 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 604 | integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= 605 | 606 | fsevents@~2.3.2: 607 | version "2.3.2" 608 | resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" 609 | integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== 610 | 611 | gauge@~2.7.3: 612 | version "2.7.4" 613 | resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" 614 | integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c= 615 | dependencies: 616 | aproba "^1.0.3" 617 | console-control-strings "^1.0.0" 618 | has-unicode "^2.0.0" 619 | object-assign "^4.1.0" 620 | signal-exit "^3.0.0" 621 | string-width "^1.0.1" 622 | strip-ansi "^3.0.1" 623 | wide-align "^1.1.0" 624 | 625 | get-stream@^4.1.0: 626 | version "4.1.0" 627 | resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" 628 | integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== 629 | dependencies: 630 | pump "^3.0.0" 631 | 632 | get-stream@^5.1.0: 633 | version "5.2.0" 634 | resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" 635 | integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA== 636 | dependencies: 637 | pump "^3.0.0" 638 | 639 | glob-parent@~5.1.2: 640 | version "5.1.2" 641 | resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" 642 | integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== 643 | dependencies: 644 | is-glob "^4.0.1" 645 | 646 | glob@^7.1.3: 647 | version "7.1.7" 648 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" 649 | integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== 650 | dependencies: 651 | fs.realpath "^1.0.0" 652 | inflight "^1.0.4" 653 | inherits "2" 654 | minimatch "^3.0.4" 655 | once "^1.3.0" 656 | path-is-absolute "^1.0.0" 657 | 658 | global-dirs@^2.0.1: 659 | version "2.1.0" 660 | resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-2.1.0.tgz#e9046a49c806ff04d6c1825e196c8f0091e8df4d" 661 | integrity sha512-MG6kdOUh/xBnyo9cJFeIKkLEc1AyFq42QTU4XiX51i2NEdxLxLWXIjEjmqKeSuKR7pAZjTqUVoT2b2huxVLgYQ== 662 | dependencies: 663 | ini "1.3.7" 664 | 665 | got@^9.6.0: 666 | version "9.6.0" 667 | resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85" 668 | integrity sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q== 669 | dependencies: 670 | "@sindresorhus/is" "^0.14.0" 671 | "@szmarczak/http-timer" "^1.1.2" 672 | cacheable-request "^6.0.0" 673 | decompress-response "^3.3.0" 674 | duplexer3 "^0.1.4" 675 | get-stream "^4.1.0" 676 | lowercase-keys "^1.0.1" 677 | mimic-response "^1.0.1" 678 | p-cancelable "^1.0.0" 679 | to-readable-stream "^1.0.0" 680 | url-parse-lax "^3.0.0" 681 | 682 | graceful-fs@^4.1.2: 683 | version "4.2.8" 684 | resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.8.tgz#e412b8d33f5e006593cbd3cee6df9f2cebbe802a" 685 | integrity sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg== 686 | 687 | has-flag@^3.0.0: 688 | version "3.0.0" 689 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" 690 | integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= 691 | 692 | has-flag@^4.0.0: 693 | version "4.0.0" 694 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" 695 | integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== 696 | 697 | has-unicode@^2.0.0: 698 | version "2.0.1" 699 | resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" 700 | integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= 701 | 702 | has-yarn@^2.1.0: 703 | version "2.1.0" 704 | resolved "https://registry.yarnpkg.com/has-yarn/-/has-yarn-2.1.0.tgz#137e11354a7b5bf11aa5cb649cf0c6f3ff2b2e77" 705 | integrity sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw== 706 | 707 | http-cache-semantics@^4.0.0: 708 | version "4.1.0" 709 | resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390" 710 | integrity sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ== 711 | 712 | http-errors@1.7.2: 713 | version "1.7.2" 714 | resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f" 715 | integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg== 716 | dependencies: 717 | depd "~1.1.2" 718 | inherits "2.0.3" 719 | setprototypeof "1.1.1" 720 | statuses ">= 1.5.0 < 2" 721 | toidentifier "1.0.0" 722 | 723 | http-errors@~1.7.2: 724 | version "1.7.3" 725 | resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06" 726 | integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw== 727 | dependencies: 728 | depd "~1.1.2" 729 | inherits "2.0.4" 730 | setprototypeof "1.1.1" 731 | statuses ">= 1.5.0 < 2" 732 | toidentifier "1.0.0" 733 | 734 | https-proxy-agent@^5.0.0: 735 | version "5.0.0" 736 | resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2" 737 | integrity sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA== 738 | dependencies: 739 | agent-base "6" 740 | debug "4" 741 | 742 | iconv-lite@0.4.24: 743 | version "0.4.24" 744 | resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" 745 | integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== 746 | dependencies: 747 | safer-buffer ">= 2.1.2 < 3" 748 | 749 | ieee754@^1.1.13: 750 | version "1.2.1" 751 | resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" 752 | integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== 753 | 754 | ignore-by-default@^1.0.1: 755 | version "1.0.1" 756 | resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09" 757 | integrity sha1-SMptcvbGo68Aqa1K5odr44ieKwk= 758 | 759 | import-lazy@^2.1.0: 760 | version "2.1.0" 761 | resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43" 762 | integrity sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM= 763 | 764 | imurmurhash@^0.1.4: 765 | version "0.1.4" 766 | resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" 767 | integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= 768 | 769 | inflight@^1.0.4: 770 | version "1.0.6" 771 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 772 | integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= 773 | dependencies: 774 | once "^1.3.0" 775 | wrappy "1" 776 | 777 | inherits@2, inherits@2.0.4, inherits@~2.0.3: 778 | version "2.0.4" 779 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" 780 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== 781 | 782 | inherits@2.0.3: 783 | version "2.0.3" 784 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" 785 | integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= 786 | 787 | ini@1.3.7: 788 | version "1.3.7" 789 | resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.7.tgz#a09363e1911972ea16d7a8851005d84cf09a9a84" 790 | integrity sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ== 791 | 792 | ini@~1.3.0: 793 | version "1.3.8" 794 | resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" 795 | integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== 796 | 797 | ipaddr.js@1.9.1: 798 | version "1.9.1" 799 | resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" 800 | integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== 801 | 802 | is-binary-path@~2.1.0: 803 | version "2.1.0" 804 | resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" 805 | integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== 806 | dependencies: 807 | binary-extensions "^2.0.0" 808 | 809 | is-ci@^2.0.0: 810 | version "2.0.0" 811 | resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" 812 | integrity sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w== 813 | dependencies: 814 | ci-info "^2.0.0" 815 | 816 | is-extglob@^2.1.1: 817 | version "2.1.1" 818 | resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" 819 | integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= 820 | 821 | is-fullwidth-code-point@^1.0.0: 822 | version "1.0.0" 823 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" 824 | integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= 825 | dependencies: 826 | number-is-nan "^1.0.0" 827 | 828 | is-fullwidth-code-point@^2.0.0: 829 | version "2.0.0" 830 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" 831 | integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= 832 | 833 | is-fullwidth-code-point@^3.0.0: 834 | version "3.0.0" 835 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" 836 | integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== 837 | 838 | is-glob@^4.0.1, is-glob@~4.0.1: 839 | version "4.0.1" 840 | resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" 841 | integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== 842 | dependencies: 843 | is-extglob "^2.1.1" 844 | 845 | is-installed-globally@^0.3.1: 846 | version "0.3.2" 847 | resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.3.2.tgz#fd3efa79ee670d1187233182d5b0a1dd00313141" 848 | integrity sha512-wZ8x1js7Ia0kecP/CHM/3ABkAmujX7WPvQk6uu3Fly/Mk44pySulQpnHG46OMjHGXApINnV4QhY3SWnECO2z5g== 849 | dependencies: 850 | global-dirs "^2.0.1" 851 | is-path-inside "^3.0.1" 852 | 853 | is-npm@^4.0.0: 854 | version "4.0.0" 855 | resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-4.0.0.tgz#c90dd8380696df87a7a6d823c20d0b12bbe3c84d" 856 | integrity sha512-96ECIfh9xtDDlPylNPXhzjsykHsMJZ18ASpaWzQyBr4YRTcVjUvzaHayDAES2oU/3KpljhHUjtSRNiDwi0F0ig== 857 | 858 | is-number@^7.0.0: 859 | version "7.0.0" 860 | resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" 861 | integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== 862 | 863 | is-obj@^2.0.0: 864 | version "2.0.0" 865 | resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" 866 | integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== 867 | 868 | is-path-inside@^3.0.1: 869 | version "3.0.3" 870 | resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" 871 | integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== 872 | 873 | is-typedarray@^1.0.0: 874 | version "1.0.0" 875 | resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" 876 | integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= 877 | 878 | is-yarn-global@^0.3.0: 879 | version "0.3.0" 880 | resolved "https://registry.yarnpkg.com/is-yarn-global/-/is-yarn-global-0.3.0.tgz#d502d3382590ea3004893746754c89139973e232" 881 | integrity sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw== 882 | 883 | isarray@~1.0.0: 884 | version "1.0.0" 885 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" 886 | integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= 887 | 888 | json-buffer@3.0.0: 889 | version "3.0.0" 890 | resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" 891 | integrity sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg= 892 | 893 | jsonwebtoken@^8.5.1: 894 | version "8.5.1" 895 | resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz#00e71e0b8df54c2121a1f26137df2280673bcc0d" 896 | integrity sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w== 897 | dependencies: 898 | jws "^3.2.2" 899 | lodash.includes "^4.3.0" 900 | lodash.isboolean "^3.0.3" 901 | lodash.isinteger "^4.0.4" 902 | lodash.isnumber "^3.0.3" 903 | lodash.isplainobject "^4.0.6" 904 | lodash.isstring "^4.0.1" 905 | lodash.once "^4.0.0" 906 | ms "^2.1.1" 907 | semver "^5.6.0" 908 | 909 | jwa@^1.4.1: 910 | version "1.4.1" 911 | resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.4.1.tgz#743c32985cb9e98655530d53641b66c8645b039a" 912 | integrity sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA== 913 | dependencies: 914 | buffer-equal-constant-time "1.0.1" 915 | ecdsa-sig-formatter "1.0.11" 916 | safe-buffer "^5.0.1" 917 | 918 | jws@^3.2.2: 919 | version "3.2.2" 920 | resolved "https://registry.yarnpkg.com/jws/-/jws-3.2.2.tgz#001099f3639468c9414000e99995fa52fb478304" 921 | integrity sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA== 922 | dependencies: 923 | jwa "^1.4.1" 924 | safe-buffer "^5.0.1" 925 | 926 | kareem@2.3.2: 927 | version "2.3.2" 928 | resolved "https://registry.yarnpkg.com/kareem/-/kareem-2.3.2.tgz#78c4508894985b8d38a0dc15e1a8e11078f2ca93" 929 | integrity sha512-STHz9P7X2L4Kwn72fA4rGyqyXdmrMSdxqHx9IXon/FXluXieaFA6KJ2upcHAHxQPQ0LeM/OjLrhFxifHewOALQ== 930 | 931 | keyv@^3.0.0: 932 | version "3.1.0" 933 | resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9" 934 | integrity sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA== 935 | dependencies: 936 | json-buffer "3.0.0" 937 | 938 | latest-version@^5.0.0: 939 | version "5.1.0" 940 | resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-5.1.0.tgz#119dfe908fe38d15dfa43ecd13fa12ec8832face" 941 | integrity sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA== 942 | dependencies: 943 | package-json "^6.3.0" 944 | 945 | lodash.includes@^4.3.0: 946 | version "4.3.0" 947 | resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" 948 | integrity sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8= 949 | 950 | lodash.isboolean@^3.0.3: 951 | version "3.0.3" 952 | resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" 953 | integrity sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY= 954 | 955 | lodash.isinteger@^4.0.4: 956 | version "4.0.4" 957 | resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343" 958 | integrity sha1-YZwK89A/iwTDH1iChAt3sRzWg0M= 959 | 960 | lodash.isnumber@^3.0.3: 961 | version "3.0.3" 962 | resolved "https://registry.yarnpkg.com/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc" 963 | integrity sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w= 964 | 965 | lodash.isplainobject@^4.0.6: 966 | version "4.0.6" 967 | resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" 968 | integrity sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs= 969 | 970 | lodash.isstring@^4.0.1: 971 | version "4.0.1" 972 | resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" 973 | integrity sha1-1SfftUVuynzJu5XV2ur4i6VKVFE= 974 | 975 | lodash.once@^4.0.0: 976 | version "4.1.1" 977 | resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" 978 | integrity sha1-DdOXEhPHxW34gJd9UEyI+0cal6w= 979 | 980 | lowercase-keys@^1.0.0, lowercase-keys@^1.0.1: 981 | version "1.0.1" 982 | resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" 983 | integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA== 984 | 985 | lowercase-keys@^2.0.0: 986 | version "2.0.0" 987 | resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479" 988 | integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA== 989 | 990 | lru-cache@^6.0.0: 991 | version "6.0.0" 992 | resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" 993 | integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== 994 | dependencies: 995 | yallist "^4.0.0" 996 | 997 | make-dir@^3.0.0, make-dir@^3.1.0: 998 | version "3.1.0" 999 | resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" 1000 | integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== 1001 | dependencies: 1002 | semver "^6.0.0" 1003 | 1004 | media-typer@0.3.0: 1005 | version "0.3.0" 1006 | resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" 1007 | integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= 1008 | 1009 | memory-pager@^1.0.2: 1010 | version "1.5.0" 1011 | resolved "https://registry.yarnpkg.com/memory-pager/-/memory-pager-1.5.0.tgz#d8751655d22d384682741c972f2c3d6dfa3e66b5" 1012 | integrity sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg== 1013 | 1014 | merge-descriptors@1.0.1: 1015 | version "1.0.1" 1016 | resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" 1017 | integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= 1018 | 1019 | methods@~1.1.2: 1020 | version "1.1.2" 1021 | resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" 1022 | integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= 1023 | 1024 | mime-db@1.49.0: 1025 | version "1.49.0" 1026 | resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.49.0.tgz#f3dfde60c99e9cf3bc9701d687778f537001cbed" 1027 | integrity sha512-CIc8j9URtOVApSFCQIF+VBkX1RwXp/oMMOrqdyXSBXq5RWNEsRfyj1kiRnQgmNXmHxPoFIxOroKA3zcU9P+nAA== 1028 | 1029 | mime-types@~2.1.24: 1030 | version "2.1.32" 1031 | resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.32.tgz#1d00e89e7de7fe02008db61001d9e02852670fd5" 1032 | integrity sha512-hJGaVS4G4c9TSMYh2n6SQAGrC4RnfU+daP8G7cSCmaqNjiOoUY0VHCMS42pxnQmVF1GWwFhbHWn3RIxCqTmZ9A== 1033 | dependencies: 1034 | mime-db "1.49.0" 1035 | 1036 | mime@1.6.0: 1037 | version "1.6.0" 1038 | resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" 1039 | integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== 1040 | 1041 | mimic-response@^1.0.0, mimic-response@^1.0.1: 1042 | version "1.0.1" 1043 | resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" 1044 | integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== 1045 | 1046 | minimatch@^3.0.4: 1047 | version "3.0.4" 1048 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" 1049 | integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== 1050 | dependencies: 1051 | brace-expansion "^1.1.7" 1052 | 1053 | minimist@^1.2.0: 1054 | version "1.2.5" 1055 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" 1056 | integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== 1057 | 1058 | minipass@^3.0.0: 1059 | version "3.1.3" 1060 | resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.1.3.tgz#7d42ff1f39635482e15f9cdb53184deebd5815fd" 1061 | integrity sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg== 1062 | dependencies: 1063 | yallist "^4.0.0" 1064 | 1065 | minizlib@^2.1.1: 1066 | version "2.1.2" 1067 | resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" 1068 | integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg== 1069 | dependencies: 1070 | minipass "^3.0.0" 1071 | yallist "^4.0.0" 1072 | 1073 | mkdirp@^1.0.3: 1074 | version "1.0.4" 1075 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" 1076 | integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== 1077 | 1078 | mongodb@3.6.11: 1079 | version "3.6.11" 1080 | resolved "https://registry.yarnpkg.com/mongodb/-/mongodb-3.6.11.tgz#8a59a0491a92b00a8c925f72ed9d9a5b054aebb2" 1081 | integrity sha512-4Y4lTFHDHZZdgMaHmojtNAlqkvddX2QQBEN0K//GzxhGwlI9tZ9R0vhbjr1Decw+TF7qK0ZLjQT292XgHRRQgw== 1082 | dependencies: 1083 | bl "^2.2.1" 1084 | bson "^1.1.4" 1085 | denque "^1.4.1" 1086 | optional-require "^1.0.3" 1087 | safe-buffer "^5.1.2" 1088 | optionalDependencies: 1089 | saslprep "^1.0.0" 1090 | 1091 | mongoose-legacy-pluralize@1.0.2: 1092 | version "1.0.2" 1093 | resolved "https://registry.yarnpkg.com/mongoose-legacy-pluralize/-/mongoose-legacy-pluralize-1.0.2.tgz#3ba9f91fa507b5186d399fb40854bff18fb563e4" 1094 | integrity sha512-Yo/7qQU4/EyIS8YDFSeenIvXxZN+ld7YdV9LqFVQJzTLye8unujAWPZ4NWKfFA+RNjh+wvTWKY9Z3E5XM6ZZiQ== 1095 | 1096 | mongoose@5.13.8: 1097 | version "5.13.8" 1098 | resolved "https://registry.yarnpkg.com/mongoose/-/mongoose-5.13.8.tgz#1477c306b9f1d1c737ad95ce1b4acac9aec4a421" 1099 | integrity sha512-z3d+qei9Dem/LxRcJi0cdGPKzQnYk71oHEsEfYm17JA/vLiAbJiGuBS2hW7vkd9afkPAqu3KsPZh2ax0c5iPQw== 1100 | dependencies: 1101 | "@types/mongodb" "^3.5.27" 1102 | bson "^1.1.4" 1103 | kareem "2.3.2" 1104 | mongodb "3.6.11" 1105 | mongoose-legacy-pluralize "1.0.2" 1106 | mpath "0.8.3" 1107 | mquery "3.2.5" 1108 | ms "2.1.2" 1109 | optional-require "1.0.x" 1110 | regexp-clone "1.0.0" 1111 | safe-buffer "5.2.1" 1112 | sift "13.5.2" 1113 | sliced "1.0.1" 1114 | 1115 | mpath@0.8.3: 1116 | version "0.8.3" 1117 | resolved "https://registry.yarnpkg.com/mpath/-/mpath-0.8.3.tgz#828ac0d187f7f42674839d74921970979abbdd8f" 1118 | integrity sha512-eb9rRvhDltXVNL6Fxd2zM9D4vKBxjVVQNLNijlj7uoXUy19zNDsIif5zR+pWmPCWNKwAtqyo4JveQm4nfD5+eA== 1119 | 1120 | mquery@3.2.5: 1121 | version "3.2.5" 1122 | resolved "https://registry.yarnpkg.com/mquery/-/mquery-3.2.5.tgz#8f2305632e4bb197f68f60c0cffa21aaf4060c51" 1123 | integrity sha512-VjOKHHgU84wij7IUoZzFRU07IAxd5kWJaDmyUzQlbjHjyoeK5TNeeo8ZsFDtTYnSgpW6n/nMNIHvE3u8Lbrf4A== 1124 | dependencies: 1125 | bluebird "3.5.1" 1126 | debug "3.1.0" 1127 | regexp-clone "^1.0.0" 1128 | safe-buffer "5.1.2" 1129 | sliced "1.0.1" 1130 | 1131 | ms@2.0.0: 1132 | version "2.0.0" 1133 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" 1134 | integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= 1135 | 1136 | ms@2.1.1: 1137 | version "2.1.1" 1138 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" 1139 | integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== 1140 | 1141 | ms@2.1.2: 1142 | version "2.1.2" 1143 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" 1144 | integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== 1145 | 1146 | ms@^2.1.1: 1147 | version "2.1.3" 1148 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" 1149 | integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== 1150 | 1151 | negotiator@0.6.2: 1152 | version "0.6.2" 1153 | resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" 1154 | integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== 1155 | 1156 | node-addon-api@^3.0.2: 1157 | version "3.2.1" 1158 | resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.2.1.tgz#81325e0a2117789c0128dab65e7e38f07ceba161" 1159 | integrity sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A== 1160 | 1161 | node-fetch@^2.6.1: 1162 | version "2.6.1" 1163 | resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" 1164 | integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== 1165 | 1166 | nodemon@^2.0.12: 1167 | version "2.0.12" 1168 | resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-2.0.12.tgz#5dae4e162b617b91f1873b3bfea215dd71e144d5" 1169 | integrity sha512-egCTmNZdObdBxUBw6ZNwvZ/xzk24CKRs5K6d+5zbmrMr7rOpPmfPeF6OxM3DDpaRx331CQRFEktn+wrFFfBSOA== 1170 | dependencies: 1171 | chokidar "^3.2.2" 1172 | debug "^3.2.6" 1173 | ignore-by-default "^1.0.1" 1174 | minimatch "^3.0.4" 1175 | pstree.remy "^1.1.7" 1176 | semver "^5.7.1" 1177 | supports-color "^5.5.0" 1178 | touch "^3.1.0" 1179 | undefsafe "^2.0.3" 1180 | update-notifier "^4.1.0" 1181 | 1182 | nopt@^5.0.0: 1183 | version "5.0.0" 1184 | resolved "https://registry.yarnpkg.com/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88" 1185 | integrity sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ== 1186 | dependencies: 1187 | abbrev "1" 1188 | 1189 | nopt@~1.0.10: 1190 | version "1.0.10" 1191 | resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee" 1192 | integrity sha1-bd0hvSoxQXuScn3Vhfim83YI6+4= 1193 | dependencies: 1194 | abbrev "1" 1195 | 1196 | normalize-path@^3.0.0, normalize-path@~3.0.0: 1197 | version "3.0.0" 1198 | resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" 1199 | integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== 1200 | 1201 | normalize-url@^4.1.0: 1202 | version "4.5.1" 1203 | resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.1.tgz#0dd90cf1288ee1d1313b87081c9a5932ee48518a" 1204 | integrity sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA== 1205 | 1206 | npmlog@^4.1.2: 1207 | version "4.1.2" 1208 | resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" 1209 | integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== 1210 | dependencies: 1211 | are-we-there-yet "~1.1.2" 1212 | console-control-strings "~1.1.0" 1213 | gauge "~2.7.3" 1214 | set-blocking "~2.0.0" 1215 | 1216 | number-is-nan@^1.0.0: 1217 | version "1.0.1" 1218 | resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" 1219 | integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= 1220 | 1221 | object-assign@^4, object-assign@^4.1.0: 1222 | version "4.1.1" 1223 | resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" 1224 | integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= 1225 | 1226 | on-finished@~2.3.0: 1227 | version "2.3.0" 1228 | resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" 1229 | integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= 1230 | dependencies: 1231 | ee-first "1.1.1" 1232 | 1233 | once@^1.3.0, once@^1.3.1, once@^1.4.0: 1234 | version "1.4.0" 1235 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 1236 | integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= 1237 | dependencies: 1238 | wrappy "1" 1239 | 1240 | opencollective-postinstall@^2.0.3: 1241 | version "2.0.3" 1242 | resolved "https://registry.yarnpkg.com/opencollective-postinstall/-/opencollective-postinstall-2.0.3.tgz#7a0fff978f6dbfa4d006238fbac98ed4198c3259" 1243 | integrity sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q== 1244 | 1245 | optional-require@1.0.x: 1246 | version "1.0.3" 1247 | resolved "https://registry.yarnpkg.com/optional-require/-/optional-require-1.0.3.tgz#275b8e9df1dc6a17ad155369c2422a440f89cb07" 1248 | integrity sha512-RV2Zp2MY2aeYK5G+B/Sps8lW5NHAzE5QClbFP15j+PWmP+T9PxlJXBOOLoSAdgwFvS4t0aMR4vpedMkbHfh0nA== 1249 | 1250 | optional-require@^1.0.3: 1251 | version "1.1.7" 1252 | resolved "https://registry.yarnpkg.com/optional-require/-/optional-require-1.1.7.tgz#9ab5b254f59534108d4b2201d9ae96a063abc015" 1253 | integrity sha512-cIeRZocXsZnZYn+SevbtSqNlLbeoS4mLzuNn4fvXRMDRNhTGg0sxuKXl0FnZCtnew85LorNxIbZp5OeliILhMw== 1254 | dependencies: 1255 | require-at "^1.0.6" 1256 | 1257 | p-cancelable@^1.0.0: 1258 | version "1.1.0" 1259 | resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc" 1260 | integrity sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw== 1261 | 1262 | package-json@^6.3.0: 1263 | version "6.5.0" 1264 | resolved "https://registry.yarnpkg.com/package-json/-/package-json-6.5.0.tgz#6feedaca35e75725876d0b0e64974697fed145b0" 1265 | integrity sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ== 1266 | dependencies: 1267 | got "^9.6.0" 1268 | registry-auth-token "^4.0.0" 1269 | registry-url "^5.0.0" 1270 | semver "^6.2.0" 1271 | 1272 | parseurl@~1.3.3: 1273 | version "1.3.3" 1274 | resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" 1275 | integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== 1276 | 1277 | path-is-absolute@^1.0.0: 1278 | version "1.0.1" 1279 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 1280 | integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= 1281 | 1282 | path-to-regexp@0.1.7: 1283 | version "0.1.7" 1284 | resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" 1285 | integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= 1286 | 1287 | picomatch@^2.0.4, picomatch@^2.2.1: 1288 | version "2.3.0" 1289 | resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972" 1290 | integrity sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw== 1291 | 1292 | prepend-http@^2.0.0: 1293 | version "2.0.0" 1294 | resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" 1295 | integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc= 1296 | 1297 | process-nextick-args@~2.0.0: 1298 | version "2.0.1" 1299 | resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" 1300 | integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== 1301 | 1302 | proxy-addr@~2.0.5: 1303 | version "2.0.7" 1304 | resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" 1305 | integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== 1306 | dependencies: 1307 | forwarded "0.2.0" 1308 | ipaddr.js "1.9.1" 1309 | 1310 | pstree.remy@^1.1.7: 1311 | version "1.1.8" 1312 | resolved "https://registry.yarnpkg.com/pstree.remy/-/pstree.remy-1.1.8.tgz#c242224f4a67c21f686839bbdb4ac282b8373d3a" 1313 | integrity sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w== 1314 | 1315 | pump@^3.0.0: 1316 | version "3.0.0" 1317 | resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" 1318 | integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== 1319 | dependencies: 1320 | end-of-stream "^1.1.0" 1321 | once "^1.3.1" 1322 | 1323 | pupa@^2.0.1: 1324 | version "2.1.1" 1325 | resolved "https://registry.yarnpkg.com/pupa/-/pupa-2.1.1.tgz#f5e8fd4afc2c5d97828faa523549ed8744a20d62" 1326 | integrity sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A== 1327 | dependencies: 1328 | escape-goat "^2.0.0" 1329 | 1330 | qs@6.7.0: 1331 | version "6.7.0" 1332 | resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" 1333 | integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== 1334 | 1335 | range-parser@~1.2.1: 1336 | version "1.2.1" 1337 | resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" 1338 | integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== 1339 | 1340 | raw-body@2.4.0: 1341 | version "2.4.0" 1342 | resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332" 1343 | integrity sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q== 1344 | dependencies: 1345 | bytes "3.1.0" 1346 | http-errors "1.7.2" 1347 | iconv-lite "0.4.24" 1348 | unpipe "1.0.0" 1349 | 1350 | rc@^1.2.8: 1351 | version "1.2.8" 1352 | resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" 1353 | integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== 1354 | dependencies: 1355 | deep-extend "^0.6.0" 1356 | ini "~1.3.0" 1357 | minimist "^1.2.0" 1358 | strip-json-comments "~2.0.1" 1359 | 1360 | readable-stream@^2.0.6, readable-stream@^2.3.5: 1361 | version "2.3.7" 1362 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" 1363 | integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== 1364 | dependencies: 1365 | core-util-is "~1.0.0" 1366 | inherits "~2.0.3" 1367 | isarray "~1.0.0" 1368 | process-nextick-args "~2.0.0" 1369 | safe-buffer "~5.1.1" 1370 | string_decoder "~1.1.1" 1371 | util-deprecate "~1.0.1" 1372 | 1373 | readdirp@~3.6.0: 1374 | version "3.6.0" 1375 | resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" 1376 | integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== 1377 | dependencies: 1378 | picomatch "^2.2.1" 1379 | 1380 | regexp-clone@1.0.0, regexp-clone@^1.0.0: 1381 | version "1.0.0" 1382 | resolved "https://registry.yarnpkg.com/regexp-clone/-/regexp-clone-1.0.0.tgz#222db967623277056260b992626354a04ce9bf63" 1383 | integrity sha512-TuAasHQNamyyJ2hb97IuBEif4qBHGjPHBS64sZwytpLEqtBQ1gPJTnOaQ6qmpET16cK14kkjbazl6+p0RRv0yw== 1384 | 1385 | registry-auth-token@^4.0.0: 1386 | version "4.2.1" 1387 | resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-4.2.1.tgz#6d7b4006441918972ccd5fedcd41dc322c79b250" 1388 | integrity sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw== 1389 | dependencies: 1390 | rc "^1.2.8" 1391 | 1392 | registry-url@^5.0.0: 1393 | version "5.1.0" 1394 | resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-5.1.0.tgz#e98334b50d5434b81136b44ec638d9c2009c5009" 1395 | integrity sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw== 1396 | dependencies: 1397 | rc "^1.2.8" 1398 | 1399 | require-at@^1.0.6: 1400 | version "1.0.6" 1401 | resolved "https://registry.yarnpkg.com/require-at/-/require-at-1.0.6.tgz#9eb7e3c5e00727f5a4744070a7f560d4de4f6e6a" 1402 | integrity sha512-7i1auJbMUrXEAZCOQ0VNJgmcT2VOKPRl2YGJwgpHpC9CE91Mv4/4UYIUm4chGJaI381ZDq1JUicFii64Hapd8g== 1403 | 1404 | responselike@^1.0.2: 1405 | version "1.0.2" 1406 | resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" 1407 | integrity sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec= 1408 | dependencies: 1409 | lowercase-keys "^1.0.0" 1410 | 1411 | rimraf@^3.0.2: 1412 | version "3.0.2" 1413 | resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" 1414 | integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== 1415 | dependencies: 1416 | glob "^7.1.3" 1417 | 1418 | safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: 1419 | version "5.1.2" 1420 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" 1421 | integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== 1422 | 1423 | safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@^5.1.2: 1424 | version "5.2.1" 1425 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" 1426 | integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== 1427 | 1428 | "safer-buffer@>= 2.1.2 < 3": 1429 | version "2.1.2" 1430 | resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" 1431 | integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== 1432 | 1433 | saslprep@^1.0.0: 1434 | version "1.0.3" 1435 | resolved "https://registry.yarnpkg.com/saslprep/-/saslprep-1.0.3.tgz#4c02f946b56cf54297e347ba1093e7acac4cf226" 1436 | integrity sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag== 1437 | dependencies: 1438 | sparse-bitfield "^3.0.3" 1439 | 1440 | semver-diff@^3.1.1: 1441 | version "3.1.1" 1442 | resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-3.1.1.tgz#05f77ce59f325e00e2706afd67bb506ddb1ca32b" 1443 | integrity sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg== 1444 | dependencies: 1445 | semver "^6.3.0" 1446 | 1447 | semver@^5.6.0, semver@^5.7.1: 1448 | version "5.7.1" 1449 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" 1450 | integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== 1451 | 1452 | semver@^6.0.0, semver@^6.2.0, semver@^6.3.0: 1453 | version "6.3.0" 1454 | resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" 1455 | integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== 1456 | 1457 | semver@^7.3.4: 1458 | version "7.3.5" 1459 | resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" 1460 | integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== 1461 | dependencies: 1462 | lru-cache "^6.0.0" 1463 | 1464 | send@0.17.1: 1465 | version "0.17.1" 1466 | resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" 1467 | integrity sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg== 1468 | dependencies: 1469 | debug "2.6.9" 1470 | depd "~1.1.2" 1471 | destroy "~1.0.4" 1472 | encodeurl "~1.0.2" 1473 | escape-html "~1.0.3" 1474 | etag "~1.8.1" 1475 | fresh "0.5.2" 1476 | http-errors "~1.7.2" 1477 | mime "1.6.0" 1478 | ms "2.1.1" 1479 | on-finished "~2.3.0" 1480 | range-parser "~1.2.1" 1481 | statuses "~1.5.0" 1482 | 1483 | serve-static@1.14.1: 1484 | version "1.14.1" 1485 | resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9" 1486 | integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg== 1487 | dependencies: 1488 | encodeurl "~1.0.2" 1489 | escape-html "~1.0.3" 1490 | parseurl "~1.3.3" 1491 | send "0.17.1" 1492 | 1493 | set-blocking@~2.0.0: 1494 | version "2.0.0" 1495 | resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" 1496 | integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= 1497 | 1498 | setprototypeof@1.1.1: 1499 | version "1.1.1" 1500 | resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" 1501 | integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== 1502 | 1503 | sift@13.5.2: 1504 | version "13.5.2" 1505 | resolved "https://registry.yarnpkg.com/sift/-/sift-13.5.2.tgz#24a715e13c617b086166cd04917d204a591c9da6" 1506 | integrity sha512-+gxdEOMA2J+AI+fVsCqeNn7Tgx3M9ZN9jdi95939l1IJ8cZsqS8sqpJyOkic2SJk+1+98Uwryt/gL6XDaV+UZA== 1507 | 1508 | signal-exit@^3.0.0, signal-exit@^3.0.2: 1509 | version "3.0.3" 1510 | resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" 1511 | integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== 1512 | 1513 | sliced@1.0.1: 1514 | version "1.0.1" 1515 | resolved "https://registry.yarnpkg.com/sliced/-/sliced-1.0.1.tgz#0b3a662b5d04c3177b1926bea82b03f837a2ef41" 1516 | integrity sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E= 1517 | 1518 | sparse-bitfield@^3.0.3: 1519 | version "3.0.3" 1520 | resolved "https://registry.yarnpkg.com/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz#ff4ae6e68656056ba4b3e792ab3334d38273ca11" 1521 | integrity sha1-/0rm5oZWBWuks+eSqzM004JzyhE= 1522 | dependencies: 1523 | memory-pager "^1.0.2" 1524 | 1525 | "statuses@>= 1.5.0 < 2", statuses@~1.5.0: 1526 | version "1.5.0" 1527 | resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" 1528 | integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= 1529 | 1530 | string-width@^1.0.1: 1531 | version "1.0.2" 1532 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" 1533 | integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= 1534 | dependencies: 1535 | code-point-at "^1.0.0" 1536 | is-fullwidth-code-point "^1.0.0" 1537 | strip-ansi "^3.0.0" 1538 | 1539 | "string-width@^1.0.2 || 2": 1540 | version "2.1.1" 1541 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" 1542 | integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== 1543 | dependencies: 1544 | is-fullwidth-code-point "^2.0.0" 1545 | strip-ansi "^4.0.0" 1546 | 1547 | string-width@^3.0.0: 1548 | version "3.1.0" 1549 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" 1550 | integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== 1551 | dependencies: 1552 | emoji-regex "^7.0.1" 1553 | is-fullwidth-code-point "^2.0.0" 1554 | strip-ansi "^5.1.0" 1555 | 1556 | string-width@^4.0.0, string-width@^4.1.0: 1557 | version "4.2.2" 1558 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.2.tgz#dafd4f9559a7585cfba529c6a0a4f73488ebd4c5" 1559 | integrity sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA== 1560 | dependencies: 1561 | emoji-regex "^8.0.0" 1562 | is-fullwidth-code-point "^3.0.0" 1563 | strip-ansi "^6.0.0" 1564 | 1565 | string_decoder@~1.1.1: 1566 | version "1.1.1" 1567 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" 1568 | integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== 1569 | dependencies: 1570 | safe-buffer "~5.1.0" 1571 | 1572 | strip-ansi@^3.0.0, strip-ansi@^3.0.1: 1573 | version "3.0.1" 1574 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" 1575 | integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= 1576 | dependencies: 1577 | ansi-regex "^2.0.0" 1578 | 1579 | strip-ansi@^4.0.0: 1580 | version "4.0.0" 1581 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" 1582 | integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= 1583 | dependencies: 1584 | ansi-regex "^3.0.0" 1585 | 1586 | strip-ansi@^5.1.0: 1587 | version "5.2.0" 1588 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" 1589 | integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== 1590 | dependencies: 1591 | ansi-regex "^4.1.0" 1592 | 1593 | strip-ansi@^6.0.0: 1594 | version "6.0.0" 1595 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" 1596 | integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w== 1597 | dependencies: 1598 | ansi-regex "^5.0.0" 1599 | 1600 | strip-json-comments@~2.0.1: 1601 | version "2.0.1" 1602 | resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" 1603 | integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= 1604 | 1605 | supports-color@^5.5.0: 1606 | version "5.5.0" 1607 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" 1608 | integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== 1609 | dependencies: 1610 | has-flag "^3.0.0" 1611 | 1612 | supports-color@^7.1.0: 1613 | version "7.2.0" 1614 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" 1615 | integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== 1616 | dependencies: 1617 | has-flag "^4.0.0" 1618 | 1619 | tar@^6.1.0: 1620 | version "6.1.11" 1621 | resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.11.tgz#6760a38f003afa1b2ffd0ffe9e9abbd0eab3d621" 1622 | integrity sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA== 1623 | dependencies: 1624 | chownr "^2.0.0" 1625 | fs-minipass "^2.0.0" 1626 | minipass "^3.0.0" 1627 | minizlib "^2.1.1" 1628 | mkdirp "^1.0.3" 1629 | yallist "^4.0.0" 1630 | 1631 | term-size@^2.1.0: 1632 | version "2.2.1" 1633 | resolved "https://registry.yarnpkg.com/term-size/-/term-size-2.2.1.tgz#2a6a54840432c2fb6320fea0f415531e90189f54" 1634 | integrity sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg== 1635 | 1636 | to-readable-stream@^1.0.0: 1637 | version "1.0.0" 1638 | resolved "https://registry.yarnpkg.com/to-readable-stream/-/to-readable-stream-1.0.0.tgz#ce0aa0c2f3df6adf852efb404a783e77c0475771" 1639 | integrity sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q== 1640 | 1641 | to-regex-range@^5.0.1: 1642 | version "5.0.1" 1643 | resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" 1644 | integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== 1645 | dependencies: 1646 | is-number "^7.0.0" 1647 | 1648 | toidentifier@1.0.0: 1649 | version "1.0.0" 1650 | resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" 1651 | integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== 1652 | 1653 | touch@^3.1.0: 1654 | version "3.1.0" 1655 | resolved "https://registry.yarnpkg.com/touch/-/touch-3.1.0.tgz#fe365f5f75ec9ed4e56825e0bb76d24ab74af83b" 1656 | integrity sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA== 1657 | dependencies: 1658 | nopt "~1.0.10" 1659 | 1660 | type-fest@^0.8.1: 1661 | version "0.8.1" 1662 | resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" 1663 | integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== 1664 | 1665 | type-is@~1.6.17, type-is@~1.6.18: 1666 | version "1.6.18" 1667 | resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" 1668 | integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== 1669 | dependencies: 1670 | media-typer "0.3.0" 1671 | mime-types "~2.1.24" 1672 | 1673 | typedarray-to-buffer@^3.1.5: 1674 | version "3.1.5" 1675 | resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" 1676 | integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== 1677 | dependencies: 1678 | is-typedarray "^1.0.0" 1679 | 1680 | undefsafe@^2.0.3: 1681 | version "2.0.3" 1682 | resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.3.tgz#6b166e7094ad46313b2202da7ecc2cd7cc6e7aae" 1683 | integrity sha512-nrXZwwXrD/T/JXeygJqdCO6NZZ1L66HrxM/Z7mIq2oPanoN0F1nLx3lwJMu6AwJY69hdixaFQOuoYsMjE5/C2A== 1684 | dependencies: 1685 | debug "^2.2.0" 1686 | 1687 | unique-string@^2.0.0: 1688 | version "2.0.0" 1689 | resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-2.0.0.tgz#39c6451f81afb2749de2b233e3f7c5e8843bd89d" 1690 | integrity sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg== 1691 | dependencies: 1692 | crypto-random-string "^2.0.0" 1693 | 1694 | unpipe@1.0.0, unpipe@~1.0.0: 1695 | version "1.0.0" 1696 | resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" 1697 | integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= 1698 | 1699 | update-notifier@^4.1.0: 1700 | version "4.1.3" 1701 | resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-4.1.3.tgz#be86ee13e8ce48fb50043ff72057b5bd598e1ea3" 1702 | integrity sha512-Yld6Z0RyCYGB6ckIjffGOSOmHXj1gMeE7aROz4MG+XMkmixBX4jUngrGXNYz7wPKBmtoD4MnBa2Anu7RSKht/A== 1703 | dependencies: 1704 | boxen "^4.2.0" 1705 | chalk "^3.0.0" 1706 | configstore "^5.0.1" 1707 | has-yarn "^2.1.0" 1708 | import-lazy "^2.1.0" 1709 | is-ci "^2.0.0" 1710 | is-installed-globally "^0.3.1" 1711 | is-npm "^4.0.0" 1712 | is-yarn-global "^0.3.0" 1713 | latest-version "^5.0.0" 1714 | pupa "^2.0.1" 1715 | semver-diff "^3.1.1" 1716 | xdg-basedir "^4.0.0" 1717 | 1718 | url-parse-lax@^3.0.0: 1719 | version "3.0.0" 1720 | resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" 1721 | integrity sha1-FrXK/Afb42dsGxmZF3gj1lA6yww= 1722 | dependencies: 1723 | prepend-http "^2.0.0" 1724 | 1725 | util-deprecate@~1.0.1: 1726 | version "1.0.2" 1727 | resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" 1728 | integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= 1729 | 1730 | utils-merge@1.0.1: 1731 | version "1.0.1" 1732 | resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" 1733 | integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= 1734 | 1735 | vary@^1, vary@~1.1.2: 1736 | version "1.1.2" 1737 | resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" 1738 | integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= 1739 | 1740 | wide-align@^1.1.0: 1741 | version "1.1.3" 1742 | resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" 1743 | integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== 1744 | dependencies: 1745 | string-width "^1.0.2 || 2" 1746 | 1747 | widest-line@^3.1.0: 1748 | version "3.1.0" 1749 | resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-3.1.0.tgz#8292333bbf66cb45ff0de1603b136b7ae1496eca" 1750 | integrity sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg== 1751 | dependencies: 1752 | string-width "^4.0.0" 1753 | 1754 | wrappy@1: 1755 | version "1.0.2" 1756 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 1757 | integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= 1758 | 1759 | write-file-atomic@^3.0.0: 1760 | version "3.0.3" 1761 | resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8" 1762 | integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q== 1763 | dependencies: 1764 | imurmurhash "^0.1.4" 1765 | is-typedarray "^1.0.0" 1766 | signal-exit "^3.0.2" 1767 | typedarray-to-buffer "^3.1.5" 1768 | 1769 | xdg-basedir@^4.0.0: 1770 | version "4.0.0" 1771 | resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13" 1772 | integrity sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q== 1773 | 1774 | yallist@^4.0.0: 1775 | version "4.0.0" 1776 | resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" 1777 | integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== 1778 | --------------------------------------------------------------------------------