├── .nvmrc ├── client ├── src │ ├── context │ │ ├── alert │ │ │ ├── alertContext.js │ │ │ ├── alertReducer.js │ │ │ └── AlertState.js │ │ ├── auth │ │ │ ├── authContext.js │ │ │ ├── authReducer.js │ │ │ └── AuthState.js │ │ ├── blog │ │ │ ├── blogContext.js │ │ │ ├── blogReducer.js │ │ │ └── BlogState.js │ │ └── types.js │ ├── components │ │ ├── layout │ │ │ ├── Spinner.js │ │ │ ├── ScrollIndicator.css │ │ │ ├── Alert.css │ │ │ ├── Alert.js │ │ │ ├── ScrollArrow.css │ │ │ ├── ScrollIndicator.js │ │ │ ├── Footer.js │ │ │ ├── ScrollArrow.js │ │ │ ├── Footer.css │ │ │ ├── Navbar.css │ │ │ ├── Navbar.js │ │ │ └── Spinner.css │ │ ├── routing │ │ │ └── PrivateRoute.js │ │ ├── Editor │ │ │ ├── editorStyles.js │ │ │ ├── EditEditor.css │ │ │ ├── viewEditor.css │ │ │ ├── ViewEditor.js │ │ │ ├── DraftEditor.css │ │ │ ├── EditEditor.js │ │ │ ├── DraftEditor.js │ │ │ └── Toolbar │ │ │ │ └── Toolbar.js │ │ ├── auth │ │ │ ├── Register.css │ │ │ ├── Login.js │ │ │ └── Register.js │ │ └── Pages │ │ │ ├── UserBlogs.js │ │ │ ├── BlogItem.css │ │ │ └── Home.js │ ├── utils │ │ └── setAuthToken.js │ ├── index.css │ ├── App.css │ ├── index.js │ └── App.js ├── .gitignore ├── public │ └── index.html └── package.json ├── README.md ├── .gitignore ├── config └── DB.js ├── routes ├── authRoutes.js ├── userRoutes.js └── blogRoutes.js ├── models ├── User.js └── Blog.js ├── package.json ├── server.js ├── controllers ├── userController.js ├── authController.js └── blogController.js ├── middlewares └── authMiddleware.js └── yarn.lock /.nvmrc: -------------------------------------------------------------------------------- 1 | v16.20.0 2 | -------------------------------------------------------------------------------- /client/src/context/alert/alertContext.js: -------------------------------------------------------------------------------- 1 | import { createContext } from "react"; 2 | 3 | const alertContext = createContext(); 4 | 5 | export default alertContext; 6 | -------------------------------------------------------------------------------- /client/src/context/auth/authContext.js: -------------------------------------------------------------------------------- 1 | import { createContext } from "react"; 2 | 3 | const authContext = createContext(); 4 | 5 | export default authContext; 6 | -------------------------------------------------------------------------------- /client/src/context/blog/blogContext.js: -------------------------------------------------------------------------------- 1 | import { createContext } from "react"; 2 | 3 | const blogContext = createContext(); 4 | 5 | export default blogContext; 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BLOGIC 2 | 3 | ## A place where you can write your stories. 4 | 5 | It is a MERN stack web-app for creating and reading blogs. It has a very powerful text-editor built in Draft.js . -------------------------------------------------------------------------------- /client/src/components/layout/Spinner.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import "./Spinner.css"; 3 | 4 | const Spinner = () => { 5 | return ( 6 |
7 |
Loading...
8 |
9 | ); 10 | }; 11 | 12 | export default Spinner; 13 | -------------------------------------------------------------------------------- /client/src/utils/setAuthToken.js: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | 3 | const setAuthToken = async (token) => { 4 | if (token) { 5 | axios.defaults.headers.common["x-auth-token"] = token; 6 | } else { 7 | delete axios.defaults.headers.common["x-auth-token"]; 8 | } 9 | }; 10 | 11 | export default setAuthToken; 12 | -------------------------------------------------------------------------------- /client/src/components/layout/ScrollIndicator.css: -------------------------------------------------------------------------------- 1 | .indicator-wrapper { 2 | height: 6px; 3 | position: sticky; 4 | top: 0; 5 | background-color: transparent; 6 | z-index: 1; 7 | } 8 | 9 | .indicator-content { 10 | background-color: #00cc83; 11 | height: 100%; 12 | } 13 | 14 | @media (max-width: 550px) { 15 | .indicator-wrapper { 16 | height: 5px; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /.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 17 | .env.local 18 | .env.development.local 19 | .env.test.local 20 | .env.production.local 21 | 22 | npm-debug.log* 23 | yarn-debug.log* 24 | yarn-error.log* -------------------------------------------------------------------------------- /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/src/components/layout/Alert.css: -------------------------------------------------------------------------------- 1 | .alert { 2 | width: 100%; 3 | padding: 0.5rem 1rem; 4 | border-radius: 10px; 5 | color: white; 6 | } 7 | 8 | .alert-danger { 9 | background: rgba(200, 10, 10, 0.9); 10 | } 11 | 12 | .alert-warning { 13 | background: hsl(0, 90%, 51%); 14 | } 15 | 16 | .alert-primary { 17 | background-color: #00d84a; 18 | } 19 | 20 | .alert-secondary { 21 | background-color: #1b98f5; 22 | } 23 | -------------------------------------------------------------------------------- /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/context/alert/alertReducer.js: -------------------------------------------------------------------------------- 1 | import { SET_ALERT, CLEAR_ALERT } from "../types"; 2 | 3 | export default (state, action) => { 4 | switch (action.type) { 5 | case SET_ALERT: 6 | return { 7 | ...state, 8 | alert: action.payload, 9 | }; 10 | case CLEAR_ALERT: 11 | return { 12 | ...state, 13 | alert: null, 14 | }; 15 | default: 16 | return state; 17 | } 18 | }; 19 | -------------------------------------------------------------------------------- /client/src/App.css: -------------------------------------------------------------------------------- 1 | @import url("https://fonts.googleapis.com/css2?family=Fira+Mono&display=swap"); 2 | @import url("https://fonts.googleapis.com/css2?family=Montserrat:wght@300;400&display=swap"); 3 | * { 4 | box-sizing: border-box; 5 | } 6 | 7 | .App { 8 | display: flex; 9 | flex-direction: column; 10 | min-height: 100vh; 11 | } 12 | 13 | .main-app { 14 | display: flex; 15 | flex: 1 0 auto; 16 | align-items: center; 17 | } 18 | 19 | .my-3 { 20 | margin: 3rem 0; 21 | } 22 | -------------------------------------------------------------------------------- /client/src/components/layout/Alert.js: -------------------------------------------------------------------------------- 1 | import React, { useContext } from "react"; 2 | import AlertContext from "../../context/alert/alertContext"; 3 | import "./Alert.css"; 4 | 5 | const Alert = () => { 6 | const { alert } = useContext(AlertContext); 7 | 8 | return ( 9 | alert && ( 10 |
11 | {alert.message} 12 |
13 | ) 14 | ); 15 | }; 16 | 17 | export default Alert; 18 | -------------------------------------------------------------------------------- /config/DB.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | 3 | const connectDB = async () => { 4 | try { 5 | const conn = await mongoose.connect(process.env.MONGO_URI, { 6 | useCreateIndex: true, 7 | useFindAndModify: false, 8 | useNewUrlParser: true, 9 | useUnifiedTopology: true, 10 | }); 11 | console.log(`DB Connected at: ${conn.connection.host}`); 12 | } catch (err) { 13 | console.log(`Error: ${err}`); 14 | process.exit(1); 15 | } 16 | }; 17 | 18 | module.exports = connectDB; 19 | -------------------------------------------------------------------------------- /client/src/components/layout/ScrollArrow.css: -------------------------------------------------------------------------------- 1 | .scrollTop { 2 | position: fixed; 3 | bottom: 20px; 4 | right: 30px; 5 | font-size: 2rem; 6 | cursor: pointer; 7 | z-index: 2; 8 | animation: fadeIn 0.3s; 9 | transition: opacity 0.4s; 10 | opacity: 0.5; 11 | color: hsl(159, 100%, 30%); 12 | } 13 | 14 | .scrollTop:hover { 15 | opacity: 1; 16 | } 17 | 18 | @keyframes fadeIn { 19 | 0% { 20 | opacity: 0; 21 | } 22 | 100% { 23 | opacity: 0.5; 24 | } 25 | } 26 | 27 | @media (max-width: 550px) { 28 | .scrollTop { 29 | bottom: 30px; 30 | right: 35px; 31 | font-size: 1.8rem; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /client/src/components/routing/PrivateRoute.js: -------------------------------------------------------------------------------- 1 | import React, { useContext } from "react"; 2 | import { Route, Redirect } from "react-router-dom"; 3 | import AuthContext from "../../context/auth/authContext"; 4 | 5 | const PrivateRoute = ({ component: Component, ...rest }) => { 6 | const { isAuthenticated, loading } = useContext(AuthContext); 7 | 8 | return ( 9 | 12 | isAuthenticated && !loading ? ( 13 | 14 | ) : ( 15 | 16 | ) 17 | } 18 | /> 19 | ); 20 | }; 21 | 22 | export default PrivateRoute; 23 | -------------------------------------------------------------------------------- /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 AuthState from "./context/auth/AuthState"; 6 | import AlertState from "./context/alert/AlertState"; 7 | import BlogState from "./context/blog/BlogState"; 8 | import { BrowserRouter as Router } from "react-router-dom"; 9 | 10 | ReactDOM.render( 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | , 22 | document.getElementById("root") 23 | ); 24 | -------------------------------------------------------------------------------- /routes/authRoutes.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const router = express.Router(); 3 | const { 4 | register, 5 | login, 6 | sendCurrentUser, 7 | } = require("../controllers/authController"); 8 | const { protect } = require("../middlewares/authMiddleware"); 9 | 10 | // @desc Get Current User 11 | // @route GET /api/auth 12 | // @access protect, isLoggedIn 13 | router.get("/", protect, sendCurrentUser); 14 | 15 | // @desc Login User 16 | // @route POST /api/auth/login 17 | // @access public 18 | router.post("/login", login); 19 | 20 | // @desc Register new User 21 | // @route POST /api/auth/register 22 | // @access public 23 | router.post("/register", register); 24 | 25 | module.exports = router; 26 | -------------------------------------------------------------------------------- /models/User.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | 3 | const userSchema = new mongoose.Schema({ 4 | name: { 5 | type: String, 6 | required: [true, "Please Enter your name"], 7 | }, 8 | email: { 9 | type: String, 10 | required: [true, "Please enter your email"], 11 | unique: [true, "E-mail already exists"], 12 | select: false, 13 | match: [ 14 | /[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?/, 15 | "Please fill a valid email address", 16 | ], 17 | }, 18 | password: { 19 | type: String, 20 | required: [true, "Please enter some password"], 21 | select: false, 22 | }, 23 | }); 24 | 25 | module.exports = mongoose.model("User", userSchema); 26 | -------------------------------------------------------------------------------- /client/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 11 | 17 | 📰Blogic | 2021 18 | 19 | 20 | 21 |
22 | 23 | 24 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "blogic", 3 | "version": "1.0.0", 4 | "main": "server.js", 5 | "scripts": { 6 | "start": "node server.js", 7 | "server": "nodemon server.js", 8 | "client": "npm start --prefix client", 9 | "clientinstall": "npm install --prefix client", 10 | "dev": "concurrently \"npm run server\" \"npm run client\"", 11 | "heroku-postbuild": "NPM_CONFIG_PRODUCTION=false npm install --prefix client && npm run build --prefix client" 12 | }, 13 | "license": "MIT", 14 | "dependencies": { 15 | "bcryptjs": "^2.4.3", 16 | "cloudinary": "^1.26.3", 17 | "dotenv": "^8.2.0", 18 | "express": "^4.17.1", 19 | "jsonwebtoken": "^8.5.1", 20 | "mongoose": "^5.12.2", 21 | "multer": "^1.4.2" 22 | }, 23 | "devDependencies": { 24 | "concurrently": "^6.0.0", 25 | "nodemon": "^2.0.7" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /client/src/context/alert/AlertState.js: -------------------------------------------------------------------------------- 1 | import React, { useReducer } from "react"; 2 | import AlertContext from "./alertContext"; 3 | import alertReducer from "./alertReducer"; 4 | 5 | import { SET_ALERT, CLEAR_ALERT } from "../types"; 6 | 7 | const AlertState = (props) => { 8 | const initialState = { 9 | alert: null, 10 | }; 11 | 12 | const [state, dispatch] = useReducer(alertReducer, initialState); 13 | 14 | const setAlert = (message, type, timeout = 5000) => { 15 | dispatch({ 16 | type: SET_ALERT, 17 | payload: { message, type }, 18 | }); 19 | 20 | setTimeout(() => dispatch({ type: CLEAR_ALERT }), timeout); 21 | }; 22 | return ( 23 | 29 | {props.children} 30 | 31 | ); 32 | }; 33 | 34 | export default AlertState; 35 | -------------------------------------------------------------------------------- /routes/userRoutes.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const router = express.Router(); 3 | const { 4 | getAllUsers, 5 | getUserById, 6 | updateUser, 7 | deleteUser, 8 | } = require("../controllers/userController"); 9 | 10 | const { protect, isOwner } = require("../middlewares/authMiddleware"); 11 | 12 | // @desc Get All Users 13 | // @route GET /api/users/ 14 | // @access public 15 | router.get("/", getAllUsers); 16 | 17 | // @desc Get User 18 | // @route GET /api/users/:userId 19 | // @access public 20 | router.get("/:userId", getUserById); 21 | 22 | // @desc Update User 23 | // @route PATCH /api/users/:userId 24 | // @access private 25 | router.patch("/:userId", protect, isOwner, updateUser); 26 | 27 | // @desc Delete User 28 | // @route DELETE /api/users/:userId 29 | // @access private 30 | router.delete("/:userId", protect, isOwner, deleteUser); 31 | 32 | module.exports = router; 33 | -------------------------------------------------------------------------------- /client/src/components/layout/ScrollIndicator.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from "react"; 2 | import "./ScrollIndicator.css"; 3 | 4 | const ScrollIndicator = () => { 5 | const [scrollTop, setScrollTop] = useState(0); 6 | 7 | const checkScoll = () => { 8 | const winScroll = document.documentElement.scrollTop; 9 | const height = 10 | document.documentElement.scrollHeight - 11 | document.documentElement.clientHeight; 12 | 13 | setScrollTop((winScroll / height) * 100); 14 | }; 15 | 16 | useEffect(() => { 17 | window.addEventListener("scroll", checkScoll); 18 | 19 | return () => window.removeEventListener("scroll", checkScoll); 20 | }, []); 21 | 22 | return ( 23 |
24 |
28 |
29 | ); 30 | }; 31 | 32 | export default ScrollIndicator; 33 | -------------------------------------------------------------------------------- /client/src/context/types.js: -------------------------------------------------------------------------------- 1 | export const REGISTER_SUCCESS = "REGISTER_SUCCESS"; 2 | export const REGISTER_FAIL = "REGISTER_FAIL"; 3 | export const LOGIN_SUCCESS = "LOGIN_SUCCESS"; 4 | export const LOGIN_FAIL = "LOGIN_FAIL"; 5 | export const USER_LOADED = "USER_LOADED"; 6 | export const AUTH_FAIL = "AUTH_FAIL"; 7 | export const CLEAR_ERROR = "CLEAR_ERROR"; 8 | export const LOGOUT = "LOGOUT"; 9 | export const SET_ALERT = "SET_ALERT"; 10 | export const CLEAR_ALERT = "CLEAR_ALERT"; 11 | export const CREATE_BLOG = "CREATE_BLOG"; 12 | export const GET_ALL_BLOGS = "GET_ALL_BLOGS"; 13 | export const GET_BLOG = "GET_BLOG"; 14 | export const GET_BLOGS_BY_USER = "GET_BLOGS_BY_USER"; 15 | export const UPDATE_BLOG = "UPDATE_BLOG"; 16 | export const LIKE_BLOG = "LIKE_BLOG"; 17 | export const UNLIKE_BLOG = "UNLIKE_BLOG"; 18 | export const DELETE_BLOG = "DELETE_BLOG"; 19 | export const BLOG_ERROR = "BLOG_ERROR"; 20 | export const CLEAR_BLOG = "CLEAR_BLOG"; 21 | export const SET_LOADING = "SET_LOADING"; 22 | -------------------------------------------------------------------------------- /client/src/components/layout/Footer.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import "./Footer.css"; 3 | 4 | const Footer = () => { 5 | return ( 6 |
7 |
8 |
9 |

10 | Copyright © {new Date().getFullYear()}. All Rights Reserved 11 |

12 |
13 | 29 |
30 |
31 | ); 32 | }; 33 | 34 | export default Footer; 35 | -------------------------------------------------------------------------------- /client/src/components/layout/ScrollArrow.js: -------------------------------------------------------------------------------- 1 | import React, { useState } from "react"; 2 | import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; 3 | import { faArrowCircleUp } from "@fortawesome/free-solid-svg-icons"; 4 | import "./ScrollArrow.css"; 5 | 6 | const ScrollArrow = () => { 7 | const [showScroll, setShowScroll] = useState(false); 8 | 9 | const checkScrollTop = () => { 10 | if (!showScroll && window.pageYOffset > 100) { 11 | setShowScroll(true); 12 | } else if (showScroll && window.pageYOffset <= 100) { 13 | setShowScroll(false); 14 | } 15 | }; 16 | 17 | const scrollTop = () => { 18 | window.scrollTo({ top: 0, behavior: "smooth" }); 19 | }; 20 | 21 | window.addEventListener("scroll", checkScrollTop); 22 | 23 | return ( 24 | 31 | ); 32 | }; 33 | 34 | export default ScrollArrow; 35 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | require("dotenv").config({ path: "./config/config.env" }); 2 | const path = require("path"); 3 | const express = require("express"); 4 | const app = express(); 5 | const cloudinary = require("cloudinary").v2; 6 | 7 | const connectDB = require("./config/DB"); 8 | connectDB(); 9 | 10 | cloudinary.config({ 11 | cloud_name: process.env.CLOUDINARY_CLOUD_NAME, 12 | api_key: process.env.CLOUDINARY_API_KEY, 13 | api_secret: process.env.CLOUDINARY_API_SECRET, 14 | }); 15 | 16 | app.use(express.json()); 17 | // app.use(express.static(path.join(__dirname, "./uploads/"))); 18 | app.use("/api/auth", require("./routes/authRoutes")); 19 | app.use("/api/blogs", require("./routes/blogRoutes")); 20 | app.use("/api/users", require("./routes/userRoutes")); 21 | // app.use("*/uploads", express.static("uploads")); 22 | 23 | if (process.env.NODE_ENV === "production") { 24 | app.use(express.static("client/build")); 25 | 26 | app.get("*", (req, res) => { 27 | res.sendFile(path.resolve(__dirname, "client", "build", "index.html")); 28 | }); 29 | } 30 | 31 | const PORT = process.env.PORT || 8000; 32 | app.listen(PORT, () => console.log(`Server is Running at Port: ${PORT}`)); 33 | -------------------------------------------------------------------------------- /models/Blog.js: -------------------------------------------------------------------------------- 1 | const mongoose = require("mongoose"); 2 | 3 | const blogSchema = new mongoose.Schema({ 4 | title: { 5 | type: String, 6 | required: [true, "Please Enter some blog title"], 7 | }, 8 | image: { 9 | type: String, 10 | required: [true, "Please insert some relevant image"], 11 | }, 12 | body: { 13 | type: String, 14 | default: 15 | '{"blocks":[{"key":"3eesq","text":"A Text-editor with super cool features built in Draft.js.","type":"unstyled","depth":0,"inlineStyleRanges":[{"offset":19,"length":6,"style":"BOLD"},{"offset":25,"length":5,"style":"ITALIC"},{"offset":30,"length":8,"style":"UNDERLINE"}],"entityRanges":[],"data":{}},{"key":"9adb5","text":"Tell us a story!","type":"header-one","depth":0,"inlineStyleRanges":[],"entityRanges":[],"data":{}}],"entityMap":{}}', 16 | }, 17 | owner: { 18 | type: mongoose.Schema.ObjectId, 19 | required: true, 20 | ref: "User", 21 | }, 22 | likes: { 23 | type: [ 24 | { 25 | type: mongoose.Schema.ObjectId, 26 | ref: "User", 27 | }, 28 | ], 29 | default: [], 30 | }, 31 | createdAt: { 32 | type: Date, 33 | default: Date.now, 34 | }, 35 | }); 36 | 37 | module.exports = mongoose.model("Blog", blogSchema); 38 | -------------------------------------------------------------------------------- /client/src/context/auth/authReducer.js: -------------------------------------------------------------------------------- 1 | import { 2 | REGISTER_SUCCESS, 3 | REGISTER_FAIL, 4 | LOGIN_SUCCESS, 5 | LOGIN_FAIL, 6 | USER_LOADED, 7 | AUTH_FAIL, 8 | CLEAR_ERROR, 9 | LOGOUT, 10 | } from "../types"; 11 | 12 | export default (state, action) => { 13 | switch (action.type) { 14 | case USER_LOADED: 15 | return { 16 | ...state, 17 | loading: false, 18 | isAuthenticated: true, 19 | user: action.payload.user, 20 | }; 21 | case REGISTER_SUCCESS: 22 | case LOGIN_SUCCESS: 23 | localStorage.setItem("token", action.payload.token); 24 | return { 25 | ...state, 26 | token: action.payload.token, 27 | isAuthenticated: true, 28 | loading: false, 29 | }; 30 | case REGISTER_FAIL: 31 | case LOGIN_FAIL: 32 | case AUTH_FAIL: 33 | case LOGOUT: 34 | localStorage.removeItem("token"); 35 | return { 36 | ...state, 37 | token: null, 38 | user: null, 39 | loading: true, 40 | error: action.payload, 41 | isAuthenticated: false, 42 | }; 43 | case CLEAR_ERROR: 44 | return { 45 | ...state, 46 | error: null, 47 | }; 48 | default: 49 | return state; 50 | } 51 | }; 52 | -------------------------------------------------------------------------------- /client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "blogic", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@fortawesome/fontawesome-svg-core": "^1.2.35", 7 | "@fortawesome/free-solid-svg-icons": "^5.15.3", 8 | "@fortawesome/react-fontawesome": "^0.1.14", 9 | "@testing-library/jest-dom": "^5.11.4", 10 | "@testing-library/react": "^11.1.0", 11 | "@testing-library/user-event": "^12.1.10", 12 | "axios": "^0.21.1", 13 | "draft-js": "^0.11.7", 14 | "react": "^17.0.2", 15 | "react-dom": "^17.0.2", 16 | "react-router-dom": "^5.2.0", 17 | "react-scripts": "4.0.3", 18 | "web-vitals": "^1.0.1" 19 | }, 20 | "scripts": { 21 | "start": "react-scripts start", 22 | "build": "GENERATE_SOURCEMAP=false react-scripts build", 23 | "test": "react-scripts test", 24 | "eject": "react-scripts eject" 25 | }, 26 | "eslintConfig": { 27 | "extends": [ 28 | "react-app", 29 | "react-app/jest" 30 | ] 31 | }, 32 | "browserslist": { 33 | "production": [ 34 | ">0.2%", 35 | "not dead", 36 | "not op_mini all" 37 | ], 38 | "development": [ 39 | "last 1 chrome version", 40 | "last 1 firefox version", 41 | "last 1 safari version" 42 | ] 43 | }, 44 | "proxy": "http://localhost:8000" 45 | } 46 | -------------------------------------------------------------------------------- /client/src/components/layout/Footer.css: -------------------------------------------------------------------------------- 1 | #main-footer { 2 | margin-top: auto; 3 | background: #333; 4 | color: #fff; 5 | padding: 0.6rem 0; 6 | z-index: 3; 7 | } 8 | 9 | a { 10 | color: #fff; 11 | } 12 | 13 | #main-footer .footer-content { 14 | display: flex; 15 | justify-content: space-between; 16 | align-items: center; 17 | } 18 | 19 | #main-footer .footer-content .social .fab { 20 | font-size: 20px; 21 | margin-right: 1rem; 22 | border: 2px #fff solid; 23 | border-radius: 50%; 24 | width: 40px; 25 | line-height: 30px; 26 | text-align: center; 27 | padding: 0.2rem; 28 | transition: all 0.2s ease-in-out; 29 | } 30 | 31 | #main-footer .footer-content .social .fa-github:hover { 32 | background: #fff; 33 | color: #333; 34 | border-color: steelblue; 35 | } 36 | 37 | #main-footer .footer-content .social .fa-linkedin:hover { 38 | background: #fff; 39 | color: #0072b1; 40 | border-color: steelblue; 41 | } 42 | 43 | @media (max-width: 768px) { 44 | #main-footer .footer-content { 45 | justify-content: space-around; 46 | flex-direction: column; 47 | } 48 | .footer-copyright { 49 | margin: 0.5rem 0; 50 | } 51 | } 52 | 53 | @media (max-width: 400px) { 54 | .footer-copyright { 55 | font-size: 14px; 56 | margin: 0.5rem 0; 57 | } 58 | #main-footer .footer-content .social .fab { 59 | transform: scale(0.8); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /client/src/components/Editor/editorStyles.js: -------------------------------------------------------------------------------- 1 | // FOR INLINE STYLES 2 | export const styleMap = { 3 | CODE: { 4 | backgroundColor: "rgba(0, 0, 0, 0.05)", 5 | fontFamily: '"Inconsolata", "Menlo", "Consolas", monospace', 6 | fontSize: 16, 7 | padding: 2, 8 | }, 9 | HIGHLIGHT: { 10 | backgroundColor: "#F7A5F7", 11 | }, 12 | UPPERCASE: { 13 | textTransform: "uppercase", 14 | }, 15 | LOWERCASE: { 16 | textTransform: "lowercase", 17 | }, 18 | CODEBLOCK: { 19 | fontFamily: '"fira-code", "monospace"', 20 | fontSize: "inherit", 21 | background: "#ffeff0", 22 | fontStyle: "italic", 23 | lineHeight: 1.5, 24 | padding: "0.3rem 0.5rem", 25 | borderRadius: " 0.2rem", 26 | }, 27 | SUPERSCRIPT: { 28 | verticalAlign: "super", 29 | fontSize: "80%", 30 | }, 31 | SUBSCRIPT: { 32 | verticalAlign: "sub", 33 | fontSize: "80%", 34 | }, 35 | // FONT80: { 36 | // fontSize: "80px", 37 | // }, 38 | }; 39 | 40 | // FOR BLOCK LEVEL STYLES(Returns CSS Class From DraftEditor.css) 41 | export const myBlockStyleFn = (contentBlock) => { 42 | const type = contentBlock.getType(); 43 | switch (type) { 44 | case "blockQuote": 45 | return "superFancyBlockquote"; 46 | case "leftAlign": 47 | return "leftAlign"; 48 | case "rightAlign": 49 | return "rightAlign"; 50 | case "centerAlign": 51 | return "centerAlign"; 52 | case "justifyAlign": 53 | return "justifyAlign"; 54 | default: 55 | break; 56 | } 57 | }; 58 | -------------------------------------------------------------------------------- /client/src/components/layout/Navbar.css: -------------------------------------------------------------------------------- 1 | .navbar * { 2 | margin: 0; 3 | padding: 0; 4 | } 5 | 6 | .navbar { 7 | background: hsl(259, 6%, 39%); 8 | color: #fff; 9 | padding: 0.5rem 1.6rem; 10 | } 11 | 12 | .container { 13 | max-width: 1100px; 14 | margin: auto; 15 | height: 100%; 16 | } 17 | 18 | .navbar ul { 19 | list-style: none; 20 | } 21 | 22 | .navbar-content { 23 | display: flex; 24 | justify-content: space-between; 25 | align-items: center; 26 | } 27 | 28 | .logo { 29 | font-weight: bold; 30 | } 31 | 32 | .navbar-content .links { 33 | display: flex; 34 | align-items: center; 35 | } 36 | 37 | .plus-icon { 38 | height: 28px; 39 | width: 28px !important; 40 | } 41 | 42 | .navbar-content .links li { 43 | padding: 0.8rem 1.5rem; 44 | } 45 | 46 | .navbar-content .links a { 47 | text-decoration: none; 48 | color: #fff; 49 | text-transform: uppercase; 50 | border-bottom: 3px transparent solid; 51 | padding-bottom: 0.5rem; 52 | transition: border-color 0.5s; 53 | } 54 | 55 | .temp-style { 56 | text-decoration: none; 57 | color: #fff; 58 | text-transform: uppercase; 59 | border-bottom: 3px transparent solid; 60 | padding-bottom: 0.5rem; 61 | transition: border-color 0.5s; 62 | } 63 | 64 | .navbar-content .links a:hover { 65 | border-color: #ccc; 66 | } 67 | 68 | @media (max-width: 550px) { 69 | .navbar-content { 70 | flex-direction: column; 71 | align-items: center; 72 | } 73 | .plus-icon { 74 | width: 20px !important; 75 | } 76 | .navbar-content .links { 77 | width: 100%; 78 | justify-content: space-around; 79 | } 80 | .navbar-content .links li { 81 | font-size: 1rem; 82 | padding: 0.8rem 0.6rem; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /controllers/userController.js: -------------------------------------------------------------------------------- 1 | const User = require("../models/User"); 2 | 3 | exports.getAllUsers = async (req, res) => { 4 | try { 5 | const users = await User.find(); 6 | res.status(200).json({ 7 | status: "success", 8 | results: users.length, 9 | users, 10 | }); 11 | } catch (err) { 12 | res.status(400).json({ 13 | status: "fail", 14 | message: err.message, 15 | }); 16 | } 17 | }; 18 | 19 | exports.getUserById = async (req, res) => { 20 | try { 21 | const user = await User.findById(req.params.userId); 22 | if (!user) { 23 | return res.status(404).json({ 24 | status: "fail", 25 | message: "User does not exist", 26 | }); 27 | } 28 | 29 | res.status(200).json({ 30 | status: "success", 31 | user, 32 | }); 33 | } catch (err) { 34 | res.status(400).json({ 35 | status: "fail", 36 | message: err.message, 37 | }); 38 | } 39 | }; 40 | 41 | exports.updateUser = async (req, res) => { 42 | try { 43 | const user = await User.findByIdAndUpdate(req.params.userId, req.body, { 44 | new: true, 45 | }); 46 | 47 | res.status(200).json({ 48 | status: "success", 49 | user, 50 | }); 51 | } catch (err) { 52 | res.status(400).json({ 53 | status: "fail", 54 | message: err.message, 55 | }); 56 | } 57 | }; 58 | 59 | exports.deleteUser = async (req, res) => { 60 | try { 61 | await User.findByIdAndDelete(req.params.userId); 62 | res.status(200).json({ 63 | status: "success", 64 | message: "User successfully Deleted", 65 | }); 66 | } catch (err) { 67 | res.status(400).json({ 68 | status: "fail", 69 | message: err.message, 70 | }); 71 | } 72 | }; 73 | -------------------------------------------------------------------------------- /middlewares/authMiddleware.js: -------------------------------------------------------------------------------- 1 | const jwt = require("jsonwebtoken"); 2 | const Blog = require("../models/Blog"); 3 | const User = require("../models/User"); 4 | 5 | // Allow only if user is logged-in 6 | exports.protect = async (req, res, next) => { 7 | const token = req.header("x-auth-token"); 8 | 9 | if (!token) { 10 | return res.status(401).json({ 11 | status: "fail", 12 | message: "You are not logged in!", 13 | }); 14 | } 15 | 16 | try { 17 | const decoded = jwt.verify(token, process.env.JWT_SECRET); 18 | const user = await User.findById(decoded.user.id); 19 | if (!user) { 20 | return res.status(400).json({ 21 | status: "fail", 22 | message: "User does not exist", 23 | }); 24 | } 25 | req.user = user; 26 | next(); 27 | } catch (err) { 28 | res.status(401).json({ 29 | status: "fail", 30 | message: err.message, 31 | }); 32 | } 33 | }; 34 | 35 | exports.isOwner = async (req, res, next) => { 36 | const { userId, blogId } = req.params; 37 | if (userId) { 38 | if (!(req.user._id == userId)) { 39 | return res.status(400).json({ 40 | status: "fail", 41 | message: "You are not authorised to perform this action.", 42 | }); 43 | } 44 | next(); 45 | } else if (blogId) { 46 | try { 47 | const blog = await Blog.findById(blogId); 48 | if (!blog.owner.equals(req.user._id)) { 49 | return res.status(400).json({ 50 | status: "fail", 51 | message: "You are not authorised to perform this action.", 52 | }); 53 | } 54 | next(); 55 | } catch (err) { 56 | res.status(400).json({ 57 | status: "fail", 58 | message: err.message, 59 | }); 60 | } 61 | } 62 | }; 63 | -------------------------------------------------------------------------------- /client/src/components/Editor/EditEditor.css: -------------------------------------------------------------------------------- 1 | .edit-title { 2 | display: block; 3 | width: 100%; 4 | margin: 2rem auto; 5 | height: 3.8rem; 6 | border: none; 7 | border-bottom: 2px solid hsl(0, 0%, 80%); 8 | outline: none; 9 | background: hsl(0, 0%, 90%); 10 | font-size: 2.8rem; 11 | font-family: "Montserrat", "fira-mond"; 12 | transition: all 0.1s ease-in-out; 13 | padding-left: 0.5rem; 14 | letter-spacing: 1px; 15 | } 16 | 17 | .edit-title:focus { 18 | background: #fff; 19 | border-color: hsl(207, 44%, 59%); 20 | } 21 | 22 | .cancel-btn { 23 | position: absolute; 24 | top: -1.6rem; 25 | right: 0; 26 | background: none; 27 | border: none; 28 | font-size: 2rem; 29 | border: 2px solid #333; 30 | border-radius: 50%; 31 | width: 3.2rem; 32 | height: 3.2rem; 33 | color: #fff; 34 | background: hsl(0, 100%, 70%); 35 | cursor: pointer; 36 | font-weight: bold; 37 | transition: all 0.2s ease-in-out; 38 | } 39 | 40 | .cancel-btn:hover { 41 | background: hsl(0, 100%, 50%); 42 | } 43 | 44 | .update-btn { 45 | display: block; 46 | margin: 2rem auto 1rem auto; 47 | padding: 0.8rem 1.5rem; 48 | font-size: 1.8rem; 49 | color: #333; 50 | border: none; 51 | outline: none; 52 | cursor: pointer; 53 | background: hsl(265, 70%, 85%); 54 | border-radius: 0.5rem; 55 | transition: all 0.2s ease-in-out; 56 | } 57 | 58 | .update-btn:hover { 59 | color: #fff; 60 | background: hsl(265, 70%, 50%); 61 | transform: translateY(-0.4rem); 62 | } 63 | 64 | @media (max-width: 900px) { 65 | .edit-title { 66 | font-size: 2.7rem; 67 | margin: 2rem auto; 68 | } 69 | } 70 | 71 | @media (max-width: 768px) { 72 | .edit-title { 73 | font-size: 2.6rem; 74 | } 75 | .update-btn { 76 | font-size: 1.2rem; 77 | } 78 | } 79 | 80 | @media (max-width: 550px) { 81 | .edit-title { 82 | font-size: 2.5rem; 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /client/src/components/layout/Navbar.js: -------------------------------------------------------------------------------- 1 | import React, { useContext, useEffect } from "react"; 2 | import { Link } from "react-router-dom"; 3 | import "./Navbar.css"; 4 | import AuthContext from "../../context/auth/authContext"; 5 | import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; 6 | import { faPlusSquare } from "@fortawesome/free-solid-svg-icons"; 7 | 8 | const Navbar = () => { 9 | const { isAuthenticated, user, loadUser, logout } = useContext(AuthContext); 10 | 11 | useEffect(() => { 12 | loadUser(); 13 | }, []); 14 | 15 | const onLogout = () => { 16 | logout(); 17 | }; 18 | 19 | const authLinks = ( 20 | <> 21 |
  • 22 | 28 | 29 | 30 |
  • 31 |
  • Hello {user && user.name}
  • 32 |
  • 33 | 34 | Logout 35 | 36 |
  • 37 | 38 | ); 39 | 40 | const guestLinks = ( 41 | <> 42 |
  • 43 | Register 44 |
  • 45 |
  • 46 | Login 47 |
  • 48 | 49 | ); 50 | 51 | return ( 52 |
    53 |
    54 | 68 |
    69 |
    70 | ); 71 | }; 72 | 73 | export default Navbar; 74 | -------------------------------------------------------------------------------- /client/src/App.js: -------------------------------------------------------------------------------- 1 | import "./App.css"; 2 | import { Switch, Route } from "react-router-dom"; 3 | import Navbar from "./components/layout/Navbar"; 4 | import Footer from "./components/layout/Footer"; 5 | import Register from "./components/auth/Register"; 6 | import Login from "./components/auth/Login"; 7 | import setAuthToken from "./utils/setAuthToken"; 8 | import DraftEditor from "./components/Editor/DraftEditor"; 9 | import ViewEditor from "./components/Editor/ViewEditor"; 10 | import Home from "./components/Pages/Home"; 11 | import EditEditor from "./components/Editor/EditEditor"; 12 | import PrivateRoute from "./components/routing/PrivateRoute"; 13 | import UserBlogs from "./components/Pages/UserBlogs"; 14 | import ScrollArrow from "./components/layout/ScrollArrow"; 15 | 16 | if (localStorage.token) { 17 | setAuthToken(localStorage.token); 18 | } 19 | 20 | function App() { 21 | return ( 22 |
    23 | 24 | 25 | 26 |
    27 | 28 |
    29 |
    30 | 31 |
    32 | 33 |
    34 |
    35 | 36 | 37 | 38 | } 42 | /> 43 | 44 | } 48 | /> 49 | } 53 | /> 54 |
    55 | 56 |
    57 |
    58 | ); 59 | } 60 | 61 | export default App; 62 | -------------------------------------------------------------------------------- /client/src/components/auth/Register.css: -------------------------------------------------------------------------------- 1 | .flex { 2 | display: flex; 3 | flex-direction: column; 4 | justify-content: center; 5 | align-items: center; 6 | } 7 | 8 | .register, 9 | .login { 10 | width: 100%; 11 | margin: 1rem auto; 12 | } 13 | 14 | .form-container { 15 | width: 65%; 16 | text-align: center; 17 | } 18 | 19 | .form-container h1 { 20 | font-size: 3rem; 21 | font-family: "Courier New", Courier, monospace; 22 | text-transform: uppercase; 23 | text-decoration: underline solid 2px red; 24 | margin: 1rem 0 2rem 0; 25 | } 26 | 27 | .form-group { 28 | margin-bottom: 2rem; 29 | } 30 | 31 | .form-container input:not([type="checkbox"]) { 32 | width: 80%; 33 | font-size: 1rem; 34 | padding: 0.5rem 0.2rem; 35 | border: none; 36 | outline: none; 37 | border-bottom: 1px solid #999; 38 | transition: border 0.1s ease-in-out; 39 | } 40 | 41 | .form-container input:focus { 42 | border-bottom: 2px solid steelblue; 43 | } 44 | 45 | .show-password { 46 | text-align: left; 47 | font-size: 16px; 48 | margin: 10px 10%; 49 | } 50 | 51 | .show-password input { 52 | margin: 0 5px 0 0; 53 | height: 1rem; 54 | width: 1rem; 55 | } 56 | 57 | .form-container button { 58 | width: 50%; 59 | padding: 0.8rem; 60 | outline: none; 61 | border-radius: 10px; 62 | border: none; 63 | cursor: pointer; 64 | font-size: 1.3rem; 65 | background: #32a2d6; 66 | color: #fff; 67 | transition: all 0.2s ease-in-out; 68 | } 69 | 70 | .form-container button:hover { 71 | background: #2a93c1; 72 | } 73 | 74 | .form-container p span a { 75 | text-decoration: none; 76 | color: rgb(38, 145, 217); 77 | } 78 | 79 | @media (max-width: 768px) { 80 | .form-container { 81 | width: 80vw; 82 | } 83 | .form-container h1 { 84 | font-size: 2.4rem; 85 | } 86 | .form-group { 87 | margin-bottom: 1.2rem; 88 | } 89 | .show-password input { 90 | height: 14px; 91 | width: 14px; 92 | } 93 | .show-password { 94 | font-size: 14px; 95 | } 96 | .form-container button { 97 | font-size: 1rem; 98 | padding: 0.6rem 1.4rem; 99 | } 100 | } 101 | 102 | @media (max-width: 550px) { 103 | .form-container { 104 | margin: 0; 105 | width: 90vw; 106 | } 107 | .form-container h1 { 108 | font-size: 40px; 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /routes/blogRoutes.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const router = express.Router(); 3 | const { 4 | getAllBlogs, 5 | getBlogById, 6 | createBlog, 7 | updateBlog, 8 | deleteBlog, 9 | likeBlog, 10 | unlikeBlog, 11 | getAllBlogByUser, 12 | } = require("../controllers/blogController"); 13 | const { protect, isOwner } = require("../middlewares/authMiddleware"); 14 | const multer = require("multer"); 15 | const fs = require("fs"); 16 | 17 | // @desc Get all Blogs 18 | // @route GET /api/blogs 19 | // @access public 20 | router.get("/", getAllBlogs); 21 | 22 | // @desc Get Blog by Id 23 | // @route GET /api/blogs/:blogId 24 | // @access public 25 | router.get("/:blogId", getBlogById); 26 | 27 | const storage = multer.diskStorage({ 28 | // destination: function (req, file, cb) { 29 | // fs.mkdir("./uploads/", (err) => { 30 | // cb(null, "./uploads/"); 31 | // }); 32 | // }, 33 | filename: function (req, file, cb) { 34 | cb(null, new Date().toISOString().replace(/:/g, "-") + file.originalname); 35 | }, 36 | }); 37 | 38 | const fileFilter = (req, file, cb) => { 39 | if ( 40 | file.mimetype === "image/jpeg" || 41 | file.mimetype === "image/png" || 42 | file.mimetype === "image/jpg" 43 | ) { 44 | cb(null, true); 45 | } else { 46 | cb(null, false); 47 | } 48 | }; 49 | 50 | const upload = multer({ 51 | storage: storage, 52 | limits: { 53 | fileSize: 5 * 1024 * 1024, 54 | }, 55 | fileFilter: fileFilter, 56 | }); 57 | 58 | // @desc Create a Blog 59 | // @route POST /api/blogs 60 | // @access private 61 | router.post("/", protect, upload.single("image"), createBlog); 62 | 63 | // @desc Update Blog 64 | // @route PATCH /api/blogs/:blogId 65 | // @access private 66 | router.patch("/:blogId", protect, isOwner, upload.single("image"), updateBlog); 67 | 68 | // @desc Delete a Blog 69 | // @route DELETE /api/blogs/:blogId 70 | // @access private 71 | router.delete("/:blogId", protect, isOwner, deleteBlog); 72 | 73 | // @desc Like a Blog 74 | // @route POST /api/blogs/like/:blogID 75 | // @access private 76 | router.post("/like/:blogId", protect, likeBlog); 77 | 78 | // @desc Unlike a Blog 79 | // @route POST /api/blogs/unlike/:blogId 80 | // @access private 81 | router.post("/unlike/:blogId", protect, unlikeBlog); 82 | 83 | // @desc Get all Blogs by a particular User 84 | // @route GET /api/blogs/by/:userId 85 | // @access public 86 | router.get("/by/:userId", getAllBlogByUser); 87 | 88 | module.exports = router; 89 | -------------------------------------------------------------------------------- /client/src/context/blog/blogReducer.js: -------------------------------------------------------------------------------- 1 | import { 2 | CREATE_BLOG, 3 | GET_ALL_BLOGS, 4 | GET_BLOG, 5 | GET_BLOGS_BY_USER, 6 | UPDATE_BLOG, 7 | DELETE_BLOG, 8 | BLOG_ERROR, 9 | CLEAR_BLOG, 10 | SET_LOADING, 11 | LIKE_BLOG, 12 | UNLIKE_BLOG, 13 | } from "../types"; 14 | 15 | export default (state, action) => { 16 | switch (action.type) { 17 | case CREATE_BLOG: 18 | return { 19 | ...state, 20 | blogs: [action.payload, ...state.blogs], 21 | loading: false, 22 | }; 23 | case GET_BLOG: 24 | return { 25 | ...state, 26 | blog: action.payload, 27 | loading: false, 28 | }; 29 | case GET_ALL_BLOGS: 30 | return { 31 | ...state, 32 | blogs: action.payload, 33 | loading: false, 34 | }; 35 | case GET_BLOGS_BY_USER: 36 | return { 37 | ...state, 38 | blogsByUser: action.payload, 39 | loading: false, 40 | }; 41 | case UPDATE_BLOG: 42 | return { 43 | ...state, 44 | blogs: state.blogs.map((blog) => 45 | blog._id === action.payload._id 46 | ? { ...action.payload, owner: blog.owner } 47 | : blog 48 | ), 49 | blog: action.payload, 50 | loading: false, 51 | }; 52 | case DELETE_BLOG: 53 | return { 54 | ...state, 55 | blogs: state.blogs.filter((blog) => blog._id !== action.payload), 56 | blog: null, 57 | }; 58 | case CLEAR_BLOG: { 59 | return { 60 | ...state, 61 | blogs: [], 62 | blog: null, 63 | error: null, 64 | }; 65 | } 66 | case SET_LOADING: 67 | return { 68 | ...state, 69 | loading: true, 70 | }; 71 | case BLOG_ERROR: 72 | return { 73 | ...state, 74 | error: action.payload, 75 | loading: true, 76 | }; 77 | case LIKE_BLOG: 78 | return { 79 | ...state, 80 | blogs: state.blogs.map((blog) => 81 | blog._id === action.payload.blogId 82 | ? { 83 | ...blog, 84 | likes: [...blog.likes, action.payload.userId], 85 | } 86 | : blog 87 | ), 88 | }; 89 | case UNLIKE_BLOG: 90 | return { 91 | ...state, 92 | blogs: state.blogs.map((blog) => 93 | blog._id === action.payload.blogId 94 | ? { 95 | ...blog, 96 | likes: blog.likes.filter( 97 | (likeUserId) => likeUserId !== action.payload.userId 98 | ), 99 | } 100 | : blog 101 | ), 102 | }; 103 | default: 104 | return state; 105 | } 106 | }; 107 | -------------------------------------------------------------------------------- /client/src/components/Pages/UserBlogs.js: -------------------------------------------------------------------------------- 1 | import React, { useContext, useEffect } from "react"; 2 | import { useHistory } from "react-router"; 3 | import BlogContext from "../../context/blog/blogContext"; 4 | import Spinner from "../layout/Spinner"; 5 | import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; 6 | import { 7 | faArrowRight, 8 | faChevronRight, 9 | } from "@fortawesome/free-solid-svg-icons"; 10 | 11 | const UserBlogs = (props) => { 12 | const history = useHistory(); 13 | const { blogsByUser, loading, getAllBlogsByUser } = useContext(BlogContext); 14 | const months = [ 15 | "Jan", 16 | "Feb", 17 | "Mar", 18 | "Apr", 19 | "May", 20 | "June", 21 | "July", 22 | "Aug", 23 | "Sept", 24 | "Oct", 25 | "Nov", 26 | "Dec", 27 | ]; 28 | useEffect(() => { 29 | const queryParams = new URLSearchParams(props.location.search); 30 | let idCopy; 31 | for (let param of queryParams.entries()) { 32 | if (param[0] === "id") { 33 | idCopy = param[1]; 34 | } 35 | } 36 | getAllBlogsByUser(idCopy); 37 | }, []); 38 | 39 | const viewHandler = (blog) => { 40 | history.push({ 41 | pathname: "/blogs/view", 42 | search: `id=${blog._id}`, 43 | // state: { editorState: blog.body }, 44 | }); 45 | }; 46 | const getDate = (date) => { 47 | const blogDate = new Date(date); 48 | return ( 49 |

    50 | {months[blogDate.getMonth()]} {blogDate.getDate()} 51 |

    52 | ); 53 | }; 54 | if (loading) { 55 | return ; 56 | } else { 57 | return ( 58 |
    59 |
    60 | {blogsByUser && 61 | blogsByUser.map((blog) => ( 62 |
    63 |
    64 |
    65 |
    viewHandler(blog)}> 66 |

    {blog.title}

    67 |
    68 |
    {getDate(blog.createdAt)}
    69 | 76 |
    77 | 78 |
    viewHandler(blog)} 82 | /> 83 |
    84 |
    85 | ))} 86 |
    87 |
    88 | ); 89 | } 90 | }; 91 | 92 | export default UserBlogs; 93 | -------------------------------------------------------------------------------- /client/src/context/auth/AuthState.js: -------------------------------------------------------------------------------- 1 | import React, { useReducer } from "react"; 2 | import axios from "axios"; 3 | import AuthContext from "./authContext"; 4 | import authReducer from "./authReducer"; 5 | import setAuthToken from "../../utils/setAuthToken"; 6 | 7 | import { 8 | REGISTER_SUCCESS, 9 | REGISTER_FAIL, 10 | LOGIN_SUCCESS, 11 | LOGIN_FAIL, 12 | USER_LOADED, 13 | AUTH_FAIL, 14 | CLEAR_ERROR, 15 | LOGOUT, 16 | } from "../types"; 17 | 18 | const AuthState = (props) => { 19 | const initialState = { 20 | token: localStorage.getItem("token"), 21 | isAuthenticated: null, 22 | loading: true, 23 | user: null, 24 | error: null, 25 | }; 26 | 27 | const [state, dispatch] = useReducer(authReducer, initialState); 28 | 29 | const loadUser = async () => { 30 | if (localStorage.token) { 31 | setAuthToken(localStorage.token); 32 | } 33 | try { 34 | const res = await axios.get("/api/auth"); 35 | dispatch({ 36 | type: USER_LOADED, 37 | payload: res.data.data, 38 | }); 39 | } catch (err) { 40 | dispatch({ 41 | type: AUTH_FAIL, 42 | }); 43 | } 44 | }; 45 | 46 | const register = async (formData) => { 47 | const config = { 48 | headers: { 49 | "Content-Type": "application/json", 50 | }, 51 | }; 52 | 53 | try { 54 | const res = await axios.post("/api/auth/register", formData, config); 55 | dispatch({ 56 | type: REGISTER_SUCCESS, 57 | payload: res.data.data, 58 | }); 59 | loadUser(); 60 | } catch (err) { 61 | dispatch({ 62 | type: REGISTER_FAIL, 63 | payload: err.response.data.message, 64 | }); 65 | } 66 | }; 67 | 68 | const login = async (formData) => { 69 | const config = { 70 | headers: { 71 | "Content-Type": "application/json", 72 | }, 73 | }; 74 | 75 | try { 76 | const res = await axios.post("/api/auth/login", formData, config); 77 | dispatch({ 78 | type: LOGIN_SUCCESS, 79 | payload: res.data.data, 80 | }); 81 | loadUser(); 82 | } catch (err) { 83 | dispatch({ 84 | type: LOGIN_FAIL, 85 | payload: err.response.data.message, 86 | }); 87 | } 88 | }; 89 | 90 | const clearError = async () => { 91 | dispatch({ type: CLEAR_ERROR }); 92 | }; 93 | 94 | const logout = async () => { 95 | setAuthToken(); 96 | dispatch({ type: LOGOUT }); 97 | }; 98 | return ( 99 | 113 | {props.children} 114 | 115 | ); 116 | }; 117 | 118 | export default AuthState; 119 | -------------------------------------------------------------------------------- /controllers/authController.js: -------------------------------------------------------------------------------- 1 | const User = require("../models/User"); 2 | const bcrypt = require("bcryptjs"); 3 | const jwt = require("jsonwebtoken"); 4 | 5 | exports.sendCurrentUser = async (req, res) => { 6 | try { 7 | if (req.user) { 8 | res.status(200).json({ 9 | status: "success", 10 | data: { user: req.user }, 11 | }); 12 | } 13 | } catch (err) { 14 | res.status(400).json({ 15 | status: "fail", 16 | message: "You are not logged in", 17 | }); 18 | } 19 | }; 20 | 21 | exports.register = async (req, res) => { 22 | const { name, email, password } = req.body; 23 | 24 | try { 25 | if (!email || !password) { 26 | return res.status(400).json({ 27 | status: "fail", 28 | message: "Please provide both email and password.", 29 | }); 30 | } 31 | 32 | if (password.length < 8) { 33 | return res.status(400).json({ 34 | status: "fail", 35 | message: "Password should be more than 8 characters long", 36 | }); 37 | } 38 | 39 | let user = await User.findOne({ email }); 40 | if (user) { 41 | return res.status(409).json({ 42 | status: "fail", 43 | message: "User already exists.", 44 | }); 45 | } 46 | 47 | const hashedPassword = await bcrypt.hash(password, 12); 48 | 49 | user = await User.create({ 50 | name, 51 | email, 52 | password: hashedPassword, 53 | }); 54 | 55 | const payload = { 56 | user: { 57 | id: user._id, 58 | }, 59 | }; 60 | const token = jwt.sign(payload, process.env.JWT_SECRET, { 61 | expiresIn: 3600, 62 | }); 63 | res.status(201).json({ status: "success", data: { token } }); 64 | } catch (err) { 65 | res.status(400).json({ 66 | status: "fail", 67 | message: err.message, 68 | }); 69 | } 70 | }; 71 | 72 | exports.login = async (req, res) => { 73 | const { email, password } = req.body; 74 | 75 | try { 76 | if (!email || !password) { 77 | return res.status(400).json({ 78 | status: "fail", 79 | message: "Please provide an email and a password.", 80 | }); 81 | } 82 | 83 | const user = await User.findOne({ email }).select("+password"); 84 | 85 | if (!user) { 86 | return res.status(400).json({ 87 | status: "fail", 88 | message: "User does not exists", 89 | }); 90 | } 91 | const isMatch = await bcrypt.compare(password, user.password); 92 | if (!isMatch) { 93 | return res.status(401).json({ 94 | status: "fail", 95 | message: "Invalid Credentials", 96 | }); 97 | } 98 | 99 | const payload = { 100 | user: { 101 | id: user._id, 102 | }, 103 | }; 104 | const token = jwt.sign(payload, process.env.JWT_SECRET, { 105 | expiresIn: 3600, 106 | }); 107 | 108 | res.status(200).json({ 109 | status: "success", 110 | data: { token }, 111 | }); 112 | } catch (err) { 113 | res.status(400).json({ 114 | status: "fail", 115 | message: err.message, 116 | }); 117 | } 118 | }; 119 | -------------------------------------------------------------------------------- /client/src/components/auth/Login.js: -------------------------------------------------------------------------------- 1 | import React, { useContext, useEffect, useRef, useState } from "react"; 2 | import { Link, useHistory } from "react-router-dom"; 3 | import AuthContext from "../../context/auth/authContext"; 4 | import AlertContext from "../../context/alert/alertContext"; 5 | import Alert from "../layout/Alert"; 6 | 7 | const Login = () => { 8 | const [formData, setFormData] = useState({ 9 | email: "", 10 | password: "", 11 | }); 12 | 13 | const history = useHistory(); 14 | const passwordCol = useRef(null); 15 | 16 | const { login, error, isAuthenticated, clearError } = useContext(AuthContext); 17 | const { setAlert } = useContext(AlertContext); 18 | const { email, password } = formData; 19 | 20 | const onChange = (e) => { 21 | setFormData((prevData) => ({ 22 | ...prevData, 23 | [e.target.name]: e.target.value, 24 | })); 25 | }; 26 | 27 | useEffect(() => { 28 | if (isAuthenticated) { 29 | history.push("/"); 30 | } 31 | if (error) { 32 | setAlert(error, "danger"); 33 | clearError(); 34 | } 35 | }, [isAuthenticated, error]); 36 | 37 | const handleSubmit = (e) => { 38 | e.preventDefault(); 39 | login(formData); 40 | }; 41 | 42 | const showPassword = () => { 43 | if (passwordCol.current.type === "password") { 44 | passwordCol.current.type = "text"; 45 | } else { 46 | passwordCol.current.type = "password"; 47 | } 48 | }; 49 | 50 | return ( 51 |
    52 |
    53 |
    54 | 55 |

    Login

    56 |
    57 |
    58 | 67 |
    68 |
    69 | 79 |
    80 | 86 | 87 |
    88 |
    89 |
    90 | 91 |
    92 |
    93 |

    94 | Don't have an account? 95 | 96 | Register Here 97 | 98 |

    99 |
    100 |
    101 |
    102 | ); 103 | }; 104 | 105 | export default Login; 106 | -------------------------------------------------------------------------------- /client/src/components/Editor/viewEditor.css: -------------------------------------------------------------------------------- 1 | .view-blog { 2 | width: 55%; 3 | margin: 2rem auto; 4 | padding: 1rem; 5 | } 6 | 7 | .blogTitle { 8 | font-size: 3rem; 9 | font-family: "Trebuchet MS", "Lucida Sans Unicode", "Lucida Grande"; 10 | margin-bottom: 1rem; 11 | } 12 | 13 | .view-blog img { 14 | width: 100%; 15 | height: 40%; 16 | border-radius: 10px; 17 | } 18 | 19 | .owner { 20 | display: flex; 21 | align-items: center; 22 | margin: 1rem 0; 23 | } 24 | 25 | .owner-icon { 26 | font-size: 2.4rem; 27 | margin-right: 1rem; 28 | } 29 | 30 | .owner-name { 31 | font-size: 1.2rem; 32 | text-transform: uppercase; 33 | background: hsl(160, 70%, 37%); 34 | color: hsl(0, 0%, 100%); 35 | padding: 0.3rem 1rem; 36 | border-radius: 2rem; 37 | cursor: pointer; 38 | font-weight: 600; 39 | } 40 | 41 | .left-icon { 42 | margin-left: 10px; 43 | transition: all 0.2s ease-in-out; 44 | } 45 | 46 | .owner-name:hover .left-icon { 47 | margin-left: 30px; 48 | } 49 | 50 | .view-blog .editor { 51 | font-size: 21px; 52 | font-family: charter, Georgia, Cambria, "Times New Roman", Times, serif; 53 | line-height: 1.8; 54 | } 55 | 56 | .view-blog .buttons .btn { 57 | padding: 0.8rem 1.5rem; 58 | margin: 2rem 1.5rem 0 0; 59 | border-radius: 0.5rem; 60 | outline: none; 61 | border: none; 62 | font-size: 1.3rem; 63 | color: #333; 64 | cursor: pointer; 65 | transition: all 0.2s ease-in-out; 66 | } 67 | 68 | .view-blog .buttons .btn:hover { 69 | color: #fff; 70 | transform: translateY(-0.25rem); 71 | } 72 | 73 | .view-blog .buttons .edit-btn { 74 | background: hsl(120, 100%, 85%); 75 | } 76 | 77 | .view-blog .buttons .edit-btn:hover { 78 | background: hsl(120, 100%, 30%); 79 | } 80 | 81 | .view-blog .buttons .delete-btn { 82 | background: hsl(0, 100%, 85%); 83 | } 84 | 85 | .view-blog .buttons .delete-btn:hover { 86 | background: hsl(0, 100%, 50%); 87 | } 88 | 89 | @media (max-width: 900px) { 90 | .view-blog { 91 | width: 80vw; 92 | padding: 0.8rem; 93 | } 94 | .blogTitle { 95 | font-size: 2rem; 96 | } 97 | .view-blog .editor { 98 | font-size: 20px; 99 | line-height: 1.7; 100 | } 101 | .owner-icon { 102 | font-size: 2rem; 103 | margin-right: 0.7rem; 104 | } 105 | .owner-name { 106 | font-size: 1rem; 107 | padding: 0.3rem 0.7rem; 108 | } 109 | .left-icon { 110 | display: none; 111 | } 112 | } 113 | 114 | @media (max-width: 768px) { 115 | .view-blog { 116 | width: 96vw; 117 | margin-top: 1rem; 118 | } 119 | .blogTitle { 120 | font-size: 1.6rem; 121 | } 122 | .view-blog .editor { 123 | font-size: 19px; 124 | } 125 | .owner-icon { 126 | font-size: 1.8rem; 127 | margin-right: 0.6rem; 128 | } 129 | .owner-name { 130 | font-size: 0.9rem; 131 | } 132 | } 133 | 134 | @media (max-width: 500px) { 135 | .view-blog { 136 | width: 98vw; 137 | } 138 | .blogTitle { 139 | font-size: 1.7rem; 140 | } 141 | .view-blog .editor { 142 | font-size: 18px; 143 | } 144 | .owner-icon { 145 | font-size: 1.8rem; 146 | margin-right: 0.5rem; 147 | } 148 | .owner-name { 149 | font-size: 1rem; 150 | } 151 | .buttons { 152 | text-align: center; 153 | } 154 | .view-blog .buttons .btn { 155 | margin-right: 0rem; 156 | transform: scale(0.9); 157 | } 158 | } 159 | -------------------------------------------------------------------------------- /client/src/components/Pages/BlogItem.css: -------------------------------------------------------------------------------- 1 | .blog-item { 2 | width: 80%; 3 | margin: 1rem 0; 4 | padding: 1rem 1.8rem; 5 | border: 2px solid #333; 6 | background: hsl(0, 0%, 95%); 7 | border-radius: 0.5rem; 8 | } 9 | 10 | .blog-item-content { 11 | display: flex; 12 | } 13 | 14 | .blog-item-content .info { 15 | display: flex; 16 | flex-direction: column; 17 | justify-content: space-between; 18 | align-items: flex-start; 19 | text-transform: capitalize; 20 | font-family: "Montserrat"; 21 | width: 80%; 22 | } 23 | 24 | .blog-item-content .info h1 { 25 | font-size: 1.7rem; 26 | } 27 | .blog-item-content .info h1:hover { 28 | color: hsl(240, 54%, 60%); 29 | cursor: pointer; 30 | } 31 | 32 | .blog-item .blog-item-content div { 33 | margin: 5px 0; 34 | } 35 | 36 | .blog-item .blog-item-content div .blog-author span { 37 | text-transform: uppercase; 38 | background: hsl(120, 50%, 40%); 39 | padding: 0.3rem 0.6rem; 40 | border-radius: 0.5rem; 41 | color: #fff; 42 | cursor: pointer; 43 | } 44 | 45 | .blog-item .blog-item-content div .blog-author span:hover { 46 | background: hsl(120, 50%, 48%); 47 | } 48 | 49 | .read-more-btn { 50 | margin-top: 10px; 51 | padding: 0.8rem 1.5rem; 52 | border-radius: 0.5rem; 53 | border: none; 54 | outline: none; 55 | font-size: 1rem; 56 | background: hsl(0, 0%, 40%); 57 | color: #fff; 58 | cursor: pointer; 59 | transition: all 0.2s ease-in-out; 60 | } 61 | 62 | .read-more-btn:hover { 63 | background: hsl(0, 0%, 45%); 64 | } 65 | 66 | .like_comp { 67 | display: flex; 68 | align-items: center; 69 | } 70 | 71 | .like-btn { 72 | background-color: transparent; 73 | color: #777; 74 | outline: none; 75 | border: none; 76 | font-size: 1.6rem; 77 | } 78 | 79 | .like-btn i { 80 | cursor: pointer; 81 | transition: all 0.1s ease-in; 82 | } 83 | 84 | .like-btn i:hover { 85 | color: hsl(0, 80%, 60%); 86 | } 87 | 88 | .filled { 89 | color: hsl(0, 80%, 60%); 90 | } 91 | 92 | .like-cnt { 93 | font-size: 1.5rem; 94 | } 95 | 96 | .blog-item-content .img { 97 | height: 190px; 98 | width: 280px; 99 | background: center center/cover; 100 | border: 1px grey solid; 101 | border-radius: 1rem; 102 | cursor: pointer; 103 | align-self: center; 104 | } 105 | 106 | @media (max-width: 900px) { 107 | .blog-item-content .info h1 { 108 | font-size: 1.5rem; 109 | overflow-wrap: wrap; 110 | } 111 | .blog-item-content .img { 112 | height: 170px; 113 | width: 240px; 114 | } 115 | } 116 | 117 | @media (max-width: 768px) { 118 | .blog-item { 119 | width: 90vw; 120 | } 121 | .blog-item-content .info h1 { 122 | font-size: 1.3rem; 123 | } 124 | .blog-item-content .blog-date, 125 | .blog-author { 126 | font-size: 0.8rem; 127 | } 128 | .blog-item-content .img { 129 | height: 160px; 130 | width: 230px; 131 | } 132 | .read-more-btn { 133 | padding: 0.6rem 1rem; 134 | font-size: 0.9rem; 135 | } 136 | } 137 | 138 | @media (max-width: 550px) { 139 | .blog-item-content { 140 | align-items: center; 141 | flex-direction: column-reverse; 142 | } 143 | .blog-item-content .img { 144 | height: 170px; 145 | width: 250px; 146 | } 147 | .blog-item-content .info { 148 | text-align: center; 149 | align-items: center; 150 | } 151 | .blog-item-content .info h1 { 152 | font-size: 1.3rem; 153 | } 154 | .read-more-btn { 155 | padding: 0.8rem 1rem; 156 | font-size: 0.8rem; 157 | } 158 | } 159 | 160 | @media (max-width: 400px) { 161 | .blog-item-content .info { 162 | width: 100%; 163 | } 164 | .blog-item-content .info h1 { 165 | font-size: 1rem; 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /client/src/components/auth/Register.js: -------------------------------------------------------------------------------- 1 | import React, { useContext, useEffect, useRef, useState } from "react"; 2 | import "./Register.css"; 3 | import { Link, useHistory } from "react-router-dom"; 4 | import AuthContext from "../../context/auth/authContext"; 5 | import AlertContext from "../../context/alert/alertContext"; 6 | import Alert from "../layout/Alert"; 7 | 8 | const Register = () => { 9 | const [formData, setFormData] = useState({ 10 | name: "", 11 | email: "", 12 | password: "", 13 | }); 14 | const { name, email, password } = formData; 15 | 16 | const { register, error, isAuthenticated, clearError } = 17 | useContext(AuthContext); 18 | const { setAlert } = useContext(AlertContext); 19 | const passwordCol = useRef(null); 20 | 21 | const history = useHistory(); 22 | 23 | useEffect(() => { 24 | if (isAuthenticated) { 25 | history.push("/"); 26 | } 27 | if (error) { 28 | setAlert(error, "danger"); 29 | clearError(); 30 | } 31 | }, [isAuthenticated, error]); 32 | 33 | const onChange = (e) => { 34 | setFormData((prevData) => ({ 35 | ...prevData, 36 | [e.target.name]: e.target.value, 37 | })); 38 | }; 39 | 40 | const handleSubmit = async (e) => { 41 | e.preventDefault(); 42 | register(formData); 43 | }; 44 | 45 | const showPassword = () => { 46 | if (passwordCol.current.type === "password") { 47 | passwordCol.current.type = "text"; 48 | } else { 49 | passwordCol.current.type = "password"; 50 | } 51 | }; 52 | 53 | return ( 54 |
    55 |
    56 |
    57 | 58 |

    Register

    59 |
    60 |
    61 | 70 |
    71 |
    72 | 80 |
    81 |
    82 | 91 |
    92 | 98 | 99 |
    100 |
    101 |
    102 | 103 |
    104 |
    105 |

    106 | Already have an account? 107 | 108 | Login Here 109 | 110 |

    111 |
    112 |
    113 |
    114 | ); 115 | }; 116 | 117 | export default Register; 118 | -------------------------------------------------------------------------------- /client/src/components/Editor/ViewEditor.js: -------------------------------------------------------------------------------- 1 | import React, { useContext, useEffect, useState } from "react"; 2 | import { Editor, convertFromRaw, EditorState } from "draft-js"; 3 | import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; 4 | import BlogContext from "../../context/blog/blogContext"; 5 | import AuthContext from "../../context/auth/authContext"; 6 | import { styleMap, myBlockStyleFn } from "./editorStyles"; 7 | import "./viewEditor.css"; 8 | import Spinner from "../layout/Spinner"; 9 | import { 10 | faChevronRight, 11 | faUserCircle, 12 | } from "@fortawesome/free-solid-svg-icons"; 13 | import ScrollIndicator from "../layout/ScrollIndicator"; 14 | 15 | const ViewEditor = (props) => { 16 | const { blog, getBlog, deleteBlog, loading } = useContext(BlogContext); 17 | const { user } = useContext(AuthContext); 18 | 19 | const [editorState, setEditorState] = useState(EditorState.createEmpty()); 20 | 21 | useEffect(async () => { 22 | const queryParams = new URLSearchParams(props.location.search); 23 | let idCopy; 24 | for (let param of queryParams.entries()) { 25 | if (param[0] === "id") { 26 | idCopy = param[1]; 27 | } 28 | } 29 | const blog1 = await getBlog(idCopy); 30 | const body = JSON.parse(blog1.body); 31 | const data = convertFromRaw(body); 32 | setEditorState(EditorState.createWithContent(data)); 33 | }, []); 34 | 35 | const redirectHandler = (id) => { 36 | props.history.push({ 37 | pathname: "/blogs/user", 38 | search: `id=${id}`, 39 | }); 40 | }; 41 | const editHandler = (id) => { 42 | props.history.push({ 43 | pathname: "/blogs/edit", 44 | search: `id=${id}`, 45 | }); 46 | }; 47 | 48 | const deleteHandler = (id) => { 49 | deleteBlog(id); 50 | props.history.push({ 51 | pathname: "/", 52 | }); 53 | }; 54 | 55 | if (loading) { 56 | return ; 57 | } else { 58 | return ( 59 | blog && ( 60 |
    61 | 62 |
    63 |
    64 |

    {blog.title}

    65 | 66 |
    67 | 68 | redirectHandler(blog.owner._id)} 71 | > 72 | {blog.owner.name}{" "} 73 | 74 | 75 | {" "} 76 | 77 | 78 |
    79 |
    80 | 86 |
    87 | {user && blog.owner._id === user._id && ( 88 |
    89 | 95 | 101 |
    102 | )} 103 |
    104 |
    105 |
    106 | ) 107 | ); 108 | } 109 | }; 110 | 111 | export default ViewEditor; 112 | -------------------------------------------------------------------------------- /client/src/components/Pages/Home.js: -------------------------------------------------------------------------------- 1 | import React, { useContext, useEffect } from "react"; 2 | import { useHistory } from "react-router"; 3 | import "./BlogItem.css"; 4 | import BlogContext from "../../context/blog/blogContext"; 5 | import AuthContext from "../../context/auth/authContext"; 6 | import Spinner from "../layout/Spinner"; 7 | import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; 8 | import { 9 | faArrowRight, 10 | faChevronRight, 11 | } from "@fortawesome/free-solid-svg-icons"; 12 | 13 | const Home = () => { 14 | const history = useHistory(); 15 | const { blogs, getAllBlogs, likeBlog, unLikeBlog, loading } = 16 | useContext(BlogContext); 17 | const { isAuthenticated, user } = useContext(AuthContext); 18 | const months = [ 19 | "Jan", 20 | "Feb", 21 | "Mar", 22 | "Apr", 23 | "May", 24 | "June", 25 | "July", 26 | "Aug", 27 | "Sept", 28 | "Oct", 29 | "Nov", 30 | "Dec", 31 | ]; 32 | useEffect(() => { 33 | // props.location.state ? state.blogs : getAllBlogs(); 34 | window.scrollTo(0, 0); 35 | if (!blogs || blogs.length == 0) { 36 | getAllBlogs(); 37 | } 38 | }, []); 39 | 40 | const redirectHandler = (id) => { 41 | history.push({ 42 | pathname: "/blogs/user", 43 | search: `id=${id}`, 44 | }); 45 | }; 46 | 47 | const viewHandler = (blog) => { 48 | history.push({ 49 | pathname: "blogs/view", 50 | search: `id=${blog._id}`, 51 | // state: { editorState: blog.body }, 52 | }); 53 | }; 54 | const getDate = (date) => { 55 | const blogDate = new Date(date); 56 | return ( 57 |

    58 | {months[blogDate.getMonth()]} {blogDate.getDate()} 59 |

    60 | ); 61 | }; 62 | if (loading) { 63 | return ; 64 | } else { 65 | return ( 66 |
    67 |
    68 | {blogs && 69 | blogs.map((blog) => ( 70 |
    71 |
    72 |
    73 |
    viewHandler(blog)}> 74 |

    {blog.title}

    75 |
    76 |
    {getDate(blog.createdAt)}
    77 |
    78 | By{" "} 79 | redirectHandler(blog.owner._id)}> 80 | {blog.owner.name} 81 | {" "} 82 |
    83 | 90 |
    91 | 108 | {blog.likes.length} 109 |
    110 |
    111 |
    viewHandler(blog)} 115 | /> 116 |
    117 |
    118 | ))} 119 |
    120 |
    121 | ); 122 | } 123 | }; 124 | 125 | export default Home; 126 | -------------------------------------------------------------------------------- /client/src/context/blog/BlogState.js: -------------------------------------------------------------------------------- 1 | import React, { useReducer } from "react"; 2 | import BlogContext from "./blogContext"; 3 | import blogReducer from "./blogReducer"; 4 | import axios from "axios"; 5 | 6 | import { 7 | CREATE_BLOG, 8 | GET_ALL_BLOGS, 9 | GET_BLOG, 10 | GET_BLOGS_BY_USER, 11 | UPDATE_BLOG, 12 | DELETE_BLOG, 13 | BLOG_ERROR, 14 | CLEAR_BLOG, 15 | SET_LOADING, 16 | LIKE_BLOG, 17 | UNLIKE_BLOG, 18 | } from "../types"; 19 | 20 | const BlogState = (props) => { 21 | const initialState = { 22 | blogs: [], 23 | blog: null, 24 | blogsByUser: [], 25 | loading: true, 26 | error: null, 27 | }; 28 | const [state, dispatch] = useReducer(blogReducer, initialState); 29 | 30 | const createBlog = async (blog, currUser) => { 31 | const config = { 32 | headers: { 33 | "Content-Type": "multipart/form-data", 34 | }, 35 | }; 36 | const formData = new FormData(); 37 | formData.append("title", blog.title); 38 | formData.append("body", blog.body); 39 | formData.append("image", blog.image); 40 | try { 41 | const res = await axios.post("/api/blogs", formData, config); 42 | dispatch({ 43 | type: CREATE_BLOG, 44 | payload: { ...res.data.data.blog, owner: currUser }, 45 | }); 46 | } catch (err) { 47 | dispatch({ 48 | type: BLOG_ERROR, 49 | payload: err.response.data.message, 50 | }); 51 | } 52 | }; 53 | 54 | const getAllBlogs = async () => { 55 | setLoading(); 56 | try { 57 | const blogs = await axios.get("/api/blogs"); 58 | dispatch({ 59 | type: GET_ALL_BLOGS, 60 | payload: blogs.data.data.blogs, 61 | }); 62 | } catch (err) { 63 | dispatch({ 64 | type: BLOG_ERROR, 65 | payload: err.response.data.message, 66 | }); 67 | } 68 | }; 69 | 70 | const getBlog = async (id) => { 71 | setLoading(); 72 | 73 | try { 74 | const res = await axios.get(`/api/blogs/${id}`); 75 | dispatch({ 76 | type: GET_BLOG, 77 | payload: res.data.data.blog, 78 | }); 79 | return res.data.data.blog; 80 | } catch (err) { 81 | dispatch({ 82 | type: BLOG_ERROR, 83 | payload: err.response.data.message, 84 | }); 85 | } 86 | }; 87 | 88 | const getAllBlogsByUser = async (id) => { 89 | setLoading(); 90 | 91 | try { 92 | const res = await axios.get(`/api/blogs/by/${id}`); 93 | dispatch({ 94 | type: GET_BLOGS_BY_USER, 95 | payload: res.data.data.blogs, 96 | }); 97 | } catch (err) { 98 | dispatch({ 99 | type: BLOG_ERROR, 100 | payload: err.response.data.message, 101 | }); 102 | } 103 | }; 104 | 105 | const updateBlog = async (id, blog) => { 106 | const config = { 107 | headers: { 108 | "Content-Type": "multipart/form-data", 109 | }, 110 | }; 111 | const formData = new FormData(); 112 | formData.append("title", blog.title); 113 | formData.append("image", blog.image); 114 | formData.append("body", blog.body); 115 | try { 116 | const res = await axios.patch(`/api/blogs/${id}`, formData, config); 117 | dispatch({ 118 | type: UPDATE_BLOG, 119 | payload: res.data.data.blog, 120 | }); 121 | } catch (err) { 122 | dispatch({ 123 | type: BLOG_ERROR, 124 | payload: err.response.data.message, 125 | }); 126 | } 127 | }; 128 | 129 | const deleteBlog = async (id) => { 130 | try { 131 | await axios.delete(`/api/blogs/${id}`); 132 | dispatch({ type: DELETE_BLOG, payload: id }); 133 | } catch (err) { 134 | dispatch({ 135 | type: BLOG_ERROR, 136 | payload: err.response.data.message, 137 | }); 138 | } 139 | }; 140 | 141 | const likeBlog = async (blogId, userId) => { 142 | try { 143 | axios.post(`/api/blogs/like/${blogId}`); 144 | dispatch({ type: LIKE_BLOG, payload: { blogId, userId } }); 145 | } catch (err) { 146 | dispatch({ 147 | type: BLOG_ERROR, 148 | payload: err.response.data.message, 149 | }); 150 | } 151 | }; 152 | 153 | const unLikeBlog = async (blogId, userId) => { 154 | try { 155 | axios.post(`/api/blogs/unlike/${blogId}`); 156 | dispatch({ type: UNLIKE_BLOG, payload: { blogId, userId } }); 157 | } catch (err) { 158 | dispatch({ 159 | type: BLOG_ERROR, 160 | payload: err.response.data.message, 161 | }); 162 | } 163 | }; 164 | 165 | const setLoading = () => { 166 | dispatch({ type: SET_LOADING }); 167 | }; 168 | 169 | const clearBlog = () => { 170 | dispatch({ type: CLEAR_BLOG }); 171 | }; 172 | return ( 173 | 191 | {props.children} 192 | 193 | ); 194 | }; 195 | 196 | export default BlogState; 197 | -------------------------------------------------------------------------------- /client/src/components/Editor/DraftEditor.css: -------------------------------------------------------------------------------- 1 | * { 2 | margin: 0; 3 | box-sizing: border-box; 4 | } 5 | 6 | .create-blog, 7 | .edit-blog { 8 | margin: 3rem auto; 9 | padding: 1rem; 10 | } 11 | 12 | .create-blog-header, 13 | .edit-blog-header { 14 | margin: 0 auto 1rem auto; 15 | width: 75%; 16 | } 17 | 18 | .create-blog-header span, 19 | .edit-blog-header span { 20 | margin-top: 1rem; 21 | } 22 | 23 | .create-blog-header .img, 24 | .edit-blog-header .img { 25 | position: relative; 26 | display: block; 27 | height: 100%; 28 | width: 100%; 29 | } 30 | .create-blog-header .img img, 31 | .edit-blog-header .img img { 32 | width: 100%; 33 | height: 100%; 34 | border-radius: 10px; 35 | filter: drop-shadow(0 0 0.75rem #4444dd); 36 | } 37 | 38 | .title { 39 | display: block; 40 | width: 100%; 41 | margin: 2rem auto; 42 | height: 3.6rem; 43 | border: none; 44 | border-bottom: 2px solid hsl(0, 0%, 80%); 45 | outline: none; 46 | font-size: 2.8rem; 47 | font-family: "Montserrat", "fira-mond"; 48 | letter-spacing: 1px; 49 | } 50 | 51 | .title:focus { 52 | border-color: hsl(207, 44%, 59%); 53 | } 54 | 55 | .title::placeholder { 56 | color: #999; 57 | letter-spacing: 0.4rem; 58 | } 59 | 60 | .create-blog-header .button, 61 | .edit-blog-header .button { 62 | display: block; 63 | margin: auto; 64 | width: 100%; 65 | height: 5rem; 66 | outline: none; 67 | border: none; 68 | background: hsl(0, 0%, 70%); 69 | color: #fff; 70 | cursor: pointer; 71 | font-size: 4rem; 72 | border-radius: 0.5rem; 73 | transition: all 0.2s ease-out; 74 | } 75 | 76 | .create-blog-header .button:hover, 77 | .edit-blog-header .button:hover { 78 | background: hsl(0, 0%, 50%); 79 | } 80 | 81 | .editor-wrapper { 82 | margin: auto; 83 | width: 75%; 84 | background: #fff; 85 | padding: 1rem 0; 86 | } 87 | 88 | .editor-container { 89 | width: 100%; 90 | font-family: "charter", "Georgia", "Cambria", "Times New Roman", "Times", 91 | "serif"; 92 | font-size: 18px !important; 93 | border: 1px solid rgb(205, 233, 205); 94 | line-height: 1.8; 95 | padding: 1rem; 96 | border: 1px solid black; 97 | background: hsl(0, 0%, 96%); 98 | } 99 | 100 | .toolbar-grid { 101 | display: flex; 102 | flex-wrap: wrap; 103 | position: sticky; 104 | top: 0; 105 | padding: 10px; 106 | z-index: 1000; 107 | background-color: #fff; 108 | box-shadow: 0 0 4px 3px hsl(198, 12%, 26%), 0 0 2px 2px hsl(198, 12%, 26%); 109 | } 110 | 111 | .toolbar-grid button { 112 | margin-right: 0.5rem; 113 | font-size: 1rem; 114 | padding: 0.7rem; 115 | border: none; 116 | background: #fff; 117 | cursor: pointer; 118 | outline: none; 119 | } 120 | 121 | .superFancyBlockquote { 122 | color: #999; 123 | background: #fff; 124 | font-family: "Hoefler Text", Georgia, serif; 125 | font-style: italic; 126 | border-left: 2px solid #999; 127 | padding-left: 10px; 128 | } 129 | 130 | .codeBlock { 131 | font-family: fira-code, monospace; 132 | font-size: inherit; 133 | background: #ffeff0; 134 | font-style: italic; 135 | word-wrap: normal; 136 | word-wrap: break-word; 137 | box-decoration-break: slice; 138 | padding: 0.3rem 2rem; 139 | border-radius: 0.2rem; 140 | } 141 | 142 | .leftAlign { 143 | text-align: left; 144 | } 145 | .rightAlign { 146 | text-align: right; 147 | } 148 | .centerAlign { 149 | text-align: center; 150 | } 151 | .justifyAlign { 152 | text-align: justify; 153 | } 154 | 155 | .save-btn { 156 | display: block; 157 | margin: auto; 158 | margin-top: 1rem; 159 | padding: 1rem 2rem; 160 | border: none; 161 | outline: none; 162 | border-radius: 10px; 163 | color: #fff; 164 | background: darkgray; 165 | font-size: 1.4rem; 166 | font-family: "Montserrat", "fira-mond"; 167 | cursor: pointer; 168 | transition: all 0.2s ease-in-out; 169 | } 170 | 171 | .save-btn:hover { 172 | background: grey; 173 | transform: translateY(-5px); 174 | } 175 | 176 | @media (max-width: 900px) { 177 | .create-blog, 178 | .edit-blog { 179 | width: 100vw; 180 | } 181 | .create-blog-header, 182 | .edit-blog-header { 183 | width: 90vw; 184 | } 185 | .editor-wrapper { 186 | width: 90vw; 187 | } 188 | .create-blog-header .button, 189 | .edit-blog-header .button { 190 | font-size: 3.6rem; 191 | } 192 | .title { 193 | font-size: 2.7rem; 194 | margin: 1.5rem auto; 195 | } 196 | .title::placeholder { 197 | letter-spacing: 0.2rem; 198 | } 199 | } 200 | 201 | @media (max-width: 768px) { 202 | .create-blog-header .button, 203 | .edit-blog-header .button { 204 | font-size: 3.4rem; 205 | } 206 | .title { 207 | font-size: 2.6rem; 208 | } 209 | .title::placeholder { 210 | letter-spacing: 0.2rem; 211 | } 212 | .toolbar-grid { 213 | padding: 0.5rem; 214 | } 215 | .toolbar-grid button { 216 | font-size: 0.9rem; 217 | padding: 0.6rem; 218 | } 219 | .save-btn { 220 | font-size: 1.3rem; 221 | } 222 | } 223 | 224 | @media (max-width: 550px) { 225 | .create-blog-header, 226 | .edit-blog-header { 227 | width: 100%; 228 | } 229 | .editor-wrapper { 230 | width: 100%; 231 | } 232 | .editor-container { 233 | line-height: 1.6; 234 | font-size: 16px !important; 235 | } 236 | .create-blog-header .button, 237 | .edit-blog-header .button { 238 | font-size: 3.2rem; 239 | } 240 | .title { 241 | font-size: 2.3rem; 242 | } 243 | .title::placeholder { 244 | letter-spacing: 0.1rem; 245 | } 246 | .toolbar-grid { 247 | padding: 0.4rem; 248 | } 249 | .toolbar-grid button { 250 | font-size: 0.8rem; 251 | padding: 0.5rem; 252 | } 253 | .save-btn { 254 | font-size: 1.2rem; 255 | padding: 0.9rem; 256 | letter-spacing: 1.1px; 257 | } 258 | } 259 | -------------------------------------------------------------------------------- /client/src/components/Editor/EditEditor.js: -------------------------------------------------------------------------------- 1 | import React, { useContext, useEffect, useRef, useState } from "react"; 2 | import { 3 | Editor, 4 | EditorState, 5 | RichUtils, 6 | convertToRaw, 7 | convertFromRaw, 8 | } from "draft-js"; 9 | import Toolbar from "./Toolbar/Toolbar"; 10 | import { styleMap, myBlockStyleFn } from "./editorStyles"; 11 | import "./DraftEditor.css"; 12 | 13 | import AuthContext from "../../context/auth/authContext"; 14 | import BlogContext from "../../context/blog/blogContext"; 15 | import AlertContext from "../../context/alert/alertContext"; 16 | 17 | import Spinner from "../layout/Spinner"; 18 | import Alert from "../layout/Alert"; 19 | 20 | import "./EditEditor.css"; 21 | 22 | const EditEditor = (props) => { 23 | const { user, isAuthenticated } = useContext(AuthContext); 24 | const { blog, loading, getBlog, updateBlog } = useContext(BlogContext); 25 | const { setAlert } = useContext(AlertContext); 26 | 27 | const [title, setTitle] = useState(""); 28 | const [image, setImage] = useState(""); 29 | const [editorState, setEditorState] = useState(EditorState.createEmpty()); 30 | 31 | const preview = useRef(""); 32 | const uploadButton = useRef(""); 33 | 34 | useEffect(async () => { 35 | const queryParams = new URLSearchParams(props.location.search); 36 | let idCopy; 37 | for (let param of queryParams.entries()) { 38 | if (param[0] === "id") { 39 | idCopy = param[1]; 40 | } 41 | } 42 | const blog1 = await getBlog(idCopy); 43 | const body = JSON.parse(blog1.body); 44 | const data = convertFromRaw(body); 45 | setEditorState(EditorState.createWithContent(data)); 46 | setTitle(blog1.title); 47 | setImage(blog1.image); 48 | }, []); 49 | 50 | const uploadImage = () => { 51 | uploadButton.current.click(); 52 | }; 53 | const previewImage = (image) => { 54 | preview.current.style.display = ""; 55 | const imageUrl = URL.createObjectURL(image); 56 | preview.current.src = imageUrl; 57 | }; 58 | 59 | const handleImage = () => { 60 | preview.current.style.display = "none"; 61 | preview.current.src = ""; 62 | setImage(""); 63 | }; 64 | 65 | const updateHandler = (id) => { 66 | if (title === "" || image === "") { 67 | setAlert("Please fill all the fields", "warning"); 68 | } else { 69 | const contentState = editorState.getCurrentContent(); 70 | const body = JSON.stringify(convertToRaw(contentState)); 71 | updateBlog(id, { 72 | title, 73 | image, 74 | body, 75 | }); 76 | props.history.push("/"); 77 | } 78 | }; 79 | 80 | const handleKeyCommand = (command) => { 81 | const newState = RichUtils.handleKeyCommand(editorState, command); 82 | if (newState) { 83 | setEditorState(newState); 84 | return true; 85 | } 86 | return false; 87 | }; 88 | 89 | if (loading) { 90 | return ; 91 | } else if (!loading && !isAuthenticated) { 92 | return ( 93 |
    94 |

    You need to be logged in to visit this page

    95 |
    96 | ); 97 | } else if (blog && user && user._id !== blog.owner._id) { 98 | setTimeout(() => props.history.push("/"), 3000); 99 | return ( 100 |
    101 |

    You are not allowed to edit someone else's Blog!

    102 |

    You will be redirected to homepage in 3s

    103 |
    104 | ); 105 | } else { 106 | return ( 107 |
    108 |
    109 | 110 |
    111 | setTitle(e.target.value)} 117 | /> 118 | 119 | {!image && ( 120 | <> 121 | 127 | { 134 | setImage(e.target.files[0]); 135 | previewImage(e.target.files[0]); 136 | }} 137 | /> 138 | 139 | )} 140 |
    141 | 142 | {image && ( 143 | 146 | )} 147 |
    148 |
    149 |
    150 |
    151 | 155 |
    156 | setEditorState(editorState)} 162 | /> 163 |
    164 |
    165 | 171 |
    172 |
    173 | ); 174 | } 175 | }; 176 | 177 | export default EditEditor; 178 | -------------------------------------------------------------------------------- /client/src/components/Editor/DraftEditor.js: -------------------------------------------------------------------------------- 1 | import React, { useContext, useEffect, useRef, useState } from "react"; 2 | import { 3 | Editor, 4 | EditorState, 5 | RichUtils, 6 | convertToRaw, 7 | convertFromRaw, 8 | } from "draft-js"; 9 | import Toolbar from "./Toolbar/Toolbar"; 10 | import AlertContext from "../../context/alert/alertContext"; 11 | import BlogContext from "../../context/blog/blogContext"; 12 | import AuthContext from "../../context/auth/authContext"; 13 | import "./DraftEditor.css"; 14 | import { useHistory } from "react-router"; 15 | import { styleMap, myBlockStyleFn } from "./editorStyles"; 16 | import Alert from "../layout/Alert"; 17 | 18 | const DraftEditor = (props) => { 19 | const { createBlog } = useContext(BlogContext); 20 | const { setAlert } = useContext(AlertContext); 21 | const { user } = useContext(AuthContext); 22 | 23 | const history = useHistory(); 24 | 25 | const imagePreview = useRef(null); 26 | const imageInput = useRef(null); 27 | 28 | const [title, setTitle] = useState(""); 29 | const [image, setImage] = useState(""); 30 | const [editorState, setEditorState] = useState( 31 | EditorState.createWithContent( 32 | convertFromRaw({ 33 | blocks: [ 34 | { 35 | key: "3eesq", 36 | text: "A Text-editor with super cool features built in Draft.js.", 37 | type: "unstyled", 38 | depth: 0, 39 | inlineStyleRanges: [ 40 | { 41 | offset: 19, 42 | length: 6, 43 | style: "BOLD", 44 | }, 45 | { 46 | offset: 25, 47 | length: 5, 48 | style: "ITALIC", 49 | }, 50 | { 51 | offset: 30, 52 | length: 8, 53 | style: "UNDERLINE", 54 | }, 55 | ], 56 | entityRanges: [], 57 | data: {}, 58 | }, 59 | { 60 | key: "9adb5", 61 | text: "Tell us a story!", 62 | type: "header-one", 63 | depth: 0, 64 | inlineStyleRanges: [], 65 | entityRanges: [], 66 | data: {}, 67 | }, 68 | ], 69 | entityMap: {}, 70 | }) 71 | ) 72 | ); 73 | const editor = useRef(null); 74 | 75 | useEffect(() => { 76 | focusEditor(); 77 | }, []); 78 | 79 | const focusEditor = () => { 80 | editor.current.focus(); 81 | }; 82 | 83 | const handleKeyCommand = (command) => { 84 | const newState = RichUtils.handleKeyCommand(editorState, command); 85 | if (newState) { 86 | setEditorState(newState); 87 | return true; 88 | } 89 | return false; 90 | }; 91 | 92 | const uploadImage = () => { 93 | imageInput.current.click(); 94 | }; 95 | 96 | const preview = (image) => { 97 | imagePreview.current.style.display = ""; 98 | const imageURL = URL.createObjectURL(image); 99 | imagePreview.current.src = imageURL; 100 | }; 101 | 102 | const clearImage = () => { 103 | imagePreview.current.style.display = "none"; 104 | imagePreview.current.src = ""; 105 | setImage(""); 106 | }; 107 | 108 | const saveHandler = () => { 109 | if (title === "" || image === "") { 110 | setAlert("Please fill all the fields", "warning"); 111 | } else { 112 | const contentState = editorState.getCurrentContent(); 113 | createBlog( 114 | { 115 | title, 116 | image, 117 | body: JSON.stringify(convertToRaw(contentState)), 118 | }, 119 | user 120 | ); 121 | history.push({ 122 | pathname: "/", 123 | }); 124 | } 125 | }; 126 | 127 | return ( 128 |
    129 |
    130 | 131 |
    132 | 133 | {!image && ( 134 | 140 | )} 141 | { 149 | setImage(e.target.files[0]); 150 | preview(e.target.files[0]); 151 | }} 152 | /> 153 |
    154 | 155 | {image && ( 156 | 159 | )} 160 |
    161 |
    162 | setTitle(e.target.value)} 170 | /> 171 |
    172 |
    176 | 177 |
    178 | setEditorState(editorState)} 187 | /> 188 |
    189 |
    190 | 193 |
    194 |
    195 | ); 196 | }; 197 | 198 | export default DraftEditor; 199 | -------------------------------------------------------------------------------- /client/src/components/Editor/Toolbar/Toolbar.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; 3 | import { 4 | faAlignCenter, 5 | faAlignLeft, 6 | faAlignRight, 7 | faBold, 8 | faChevronDown, 9 | faChevronUp, 10 | faCode, 11 | faHighlighter, 12 | faItalic, 13 | faListOl, 14 | faListUl, 15 | faQuoteRight, 16 | faStrikethrough, 17 | faSubscript, 18 | faSuperscript, 19 | faTextWidth, 20 | faUnderline, 21 | } from "@fortawesome/free-solid-svg-icons"; 22 | import { RichUtils } from "draft-js"; 23 | 24 | const Toolbar = ({ editorState, setEditorState }) => { 25 | const tools = [ 26 | { 27 | label: "bold", 28 | style: "BOLD", 29 | icon: , 30 | method: "inline", 31 | }, 32 | { 33 | label: "italic", 34 | style: "ITALIC", 35 | icon: , 36 | method: "inline", 37 | }, 38 | { 39 | label: "underline", 40 | style: "UNDERLINE", 41 | icon: , 42 | method: "inline", 43 | }, 44 | { 45 | label: "highlight", 46 | style: "HIGHLIGHT", 47 | icon: , 48 | method: "inline", 49 | }, 50 | { 51 | label: "strike-through", 52 | style: "STRIKETHROUGH", 53 | icon: , 54 | method: "inline", 55 | }, 56 | { 57 | label: "Superscript", 58 | style: "SUPERSCRIPT", 59 | icon: , 60 | method: "inline", 61 | }, 62 | { 63 | label: "Subscript", 64 | style: "SUBSCRIPT", 65 | icon: , 66 | method: "inline", 67 | }, 68 | { 69 | label: "Monospace", 70 | style: "CODE", 71 | icon: , 72 | method: "inline", 73 | }, 74 | { 75 | label: "Blockquote", 76 | style: "blockQuote", 77 | icon: , 78 | method: "block", 79 | }, 80 | { 81 | label: "Unordered-List", 82 | style: "unordered-list-item", 83 | method: "block", 84 | icon: , 85 | }, 86 | { 87 | label: "Ordered-List", 88 | style: "ordered-list-item", 89 | method: "block", 90 | icon: , 91 | }, 92 | { 93 | label: "Code Block", 94 | style: "CODEBLOCK", 95 | icon: , 96 | method: "inline", 97 | }, 98 | { 99 | label: "Uppercase", 100 | style: "UPPERCASE", 101 | icon: , 102 | method: "inline", 103 | }, 104 | { 105 | label: "lowercase", 106 | style: "LOWERCASE", 107 | icon: , 108 | method: "inline", 109 | }, 110 | { 111 | label: "Left", 112 | style: "leftAlign", 113 | icon: , 114 | method: "block", 115 | }, 116 | { 117 | label: "Center", 118 | style: "centerAlign", 119 | icon: , 120 | method: "block", 121 | }, 122 | { 123 | label: "Right", 124 | style: "rightAlign", 125 | icon: , 126 | method: "block", 127 | }, 128 | { label: "H1", style: "header-one", method: "block" }, 129 | { label: "H2", style: "header-two", method: "block" }, 130 | { label: "H3", style: "header-three", method: "block" }, 131 | { label: "H4", style: "header-four", method: "block" }, 132 | { label: "H5", style: "header-five", method: "block" }, 133 | { label: "H6", style: "header-six", method: "block" }, 134 | // { 135 | // label: "FONT", 136 | // style: "FONT", 137 | // method: "inline", 138 | // icon: ( 139 | // 156 | // ), 157 | // }, 158 | ]; 159 | 160 | const applyStyle = (e, style, method) => { 161 | e.preventDefault(); 162 | method === "block" 163 | ? setEditorState(RichUtils.toggleBlockType(editorState, style)) 164 | : setEditorState(RichUtils.toggleInlineStyle(editorState, style)); 165 | }; 166 | 167 | const isActive = (style, method) => { 168 | if (method === "block") { 169 | const selection = editorState.getSelection(); 170 | const blockType = editorState 171 | .getCurrentContent() 172 | .getBlockForKey(selection.getStartKey()) 173 | .getType(); 174 | return blockType === style; 175 | } else { 176 | const currentStyle = editorState.getCurrentInlineStyle(); 177 | return currentStyle.has(style); 178 | } 179 | }; 180 | 181 | return ( 182 |
    183 | {tools.map( 184 | (item, idx) => ( 185 | // item.label !== "FONT80" ? ( 186 | 199 | ) 200 | // ) : ( 201 | // item.icon 202 | // ) 203 | )} 204 |
    205 | ); 206 | }; 207 | 208 | export default Toolbar; 209 | -------------------------------------------------------------------------------- /client/src/components/layout/Spinner.css: -------------------------------------------------------------------------------- 1 | .loader { 2 | margin: 20px auto; 3 | font-size: 16px; 4 | width: 1em; 5 | height: 1em; 6 | border-radius: 50%; 7 | position: relative; 8 | text-indent: -9999em; 9 | -webkit-animation: load5 1.1s infinite ease; 10 | animation: load5 1.1s infinite ease; 11 | -webkit-transform: translateZ(0); 12 | -ms-transform: translateZ(0); 13 | transform: translateZ(0); 14 | } 15 | @-webkit-keyframes load5 { 16 | 0%, 17 | 100% { 18 | box-shadow: 0em -2.6em 0em 0em #c0c0c0, 19 | 1.8em -1.8em 0 0em rgba(192, 192, 192, 0.2), 20 | 2.5em 0em 0 0em rgba(192, 192, 192, 0.2), 21 | 1.75em 1.75em 0 0em rgba(192, 192, 192, 0.2), 22 | 0em 2.5em 0 0em rgba(192, 192, 192, 0.2), 23 | -1.8em 1.8em 0 0em rgba(192, 192, 192, 0.2), 24 | -2.6em 0em 0 0em rgba(192, 192, 192, 0.5), 25 | -1.8em -1.8em 0 0em rgba(192, 192, 192, 0.7); 26 | } 27 | 12.5% { 28 | box-shadow: 0em -2.6em 0em 0em rgba(192, 192, 192, 0.7), 29 | 1.8em -1.8em 0 0em #c0c0c0, 2.5em 0em 0 0em rgba(192, 192, 192, 0.2), 30 | 1.75em 1.75em 0 0em rgba(192, 192, 192, 0.2), 31 | 0em 2.5em 0 0em rgba(192, 192, 192, 0.2), 32 | -1.8em 1.8em 0 0em rgba(192, 192, 192, 0.2), 33 | -2.6em 0em 0 0em rgba(192, 192, 192, 0.2), 34 | -1.8em -1.8em 0 0em rgba(192, 192, 192, 0.5); 35 | } 36 | 25% { 37 | box-shadow: 0em -2.6em 0em 0em rgba(192, 192, 192, 0.5), 38 | 1.8em -1.8em 0 0em rgba(192, 192, 192, 0.7), 2.5em 0em 0 0em #c0c0c0, 39 | 1.75em 1.75em 0 0em rgba(192, 192, 192, 0.2), 40 | 0em 2.5em 0 0em rgba(192, 192, 192, 0.2), 41 | -1.8em 1.8em 0 0em rgba(192, 192, 192, 0.2), 42 | -2.6em 0em 0 0em rgba(192, 192, 192, 0.2), 43 | -1.8em -1.8em 0 0em rgba(192, 192, 192, 0.2); 44 | } 45 | 37.5% { 46 | box-shadow: 0em -2.6em 0em 0em rgba(192, 192, 192, 0.2), 47 | 1.8em -1.8em 0 0em rgba(192, 192, 192, 0.5), 48 | 2.5em 0em 0 0em rgba(192, 192, 192, 0.7), 1.75em 1.75em 0 0em #c0c0c0, 49 | 0em 2.5em 0 0em rgba(192, 192, 192, 0.2), 50 | -1.8em 1.8em 0 0em rgba(192, 192, 192, 0.2), 51 | -2.6em 0em 0 0em rgba(192, 192, 192, 0.2), 52 | -1.8em -1.8em 0 0em rgba(192, 192, 192, 0.2); 53 | } 54 | 50% { 55 | box-shadow: 0em -2.6em 0em 0em rgba(192, 192, 192, 0.2), 56 | 1.8em -1.8em 0 0em rgba(192, 192, 192, 0.2), 57 | 2.5em 0em 0 0em rgba(192, 192, 192, 0.5), 58 | 1.75em 1.75em 0 0em rgba(192, 192, 192, 0.7), 0em 2.5em 0 0em #c0c0c0, 59 | -1.8em 1.8em 0 0em rgba(192, 192, 192, 0.2), 60 | -2.6em 0em 0 0em rgba(192, 192, 192, 0.2), 61 | -1.8em -1.8em 0 0em rgba(192, 192, 192, 0.2); 62 | } 63 | 62.5% { 64 | box-shadow: 0em -2.6em 0em 0em rgba(192, 192, 192, 0.2), 65 | 1.8em -1.8em 0 0em rgba(192, 192, 192, 0.2), 66 | 2.5em 0em 0 0em rgba(192, 192, 192, 0.2), 67 | 1.75em 1.75em 0 0em rgba(192, 192, 192, 0.5), 68 | 0em 2.5em 0 0em rgba(192, 192, 192, 0.7), -1.8em 1.8em 0 0em #c0c0c0, 69 | -2.6em 0em 0 0em rgba(192, 192, 192, 0.2), 70 | -1.8em -1.8em 0 0em rgba(192, 192, 192, 0.2); 71 | } 72 | 75% { 73 | box-shadow: 0em -2.6em 0em 0em rgba(192, 192, 192, 0.2), 74 | 1.8em -1.8em 0 0em rgba(192, 192, 192, 0.2), 75 | 2.5em 0em 0 0em rgba(192, 192, 192, 0.2), 76 | 1.75em 1.75em 0 0em rgba(192, 192, 192, 0.2), 77 | 0em 2.5em 0 0em rgba(192, 192, 192, 0.5), 78 | -1.8em 1.8em 0 0em rgba(192, 192, 192, 0.7), -2.6em 0em 0 0em #c0c0c0, 79 | -1.8em -1.8em 0 0em rgba(192, 192, 192, 0.2); 80 | } 81 | 87.5% { 82 | box-shadow: 0em -2.6em 0em 0em rgba(192, 192, 192, 0.2), 83 | 1.8em -1.8em 0 0em rgba(192, 192, 192, 0.2), 84 | 2.5em 0em 0 0em rgba(192, 192, 192, 0.2), 85 | 1.75em 1.75em 0 0em rgba(192, 192, 192, 0.2), 86 | 0em 2.5em 0 0em rgba(192, 192, 192, 0.2), 87 | -1.8em 1.8em 0 0em rgba(192, 192, 192, 0.5), 88 | -2.6em 0em 0 0em rgba(192, 192, 192, 0.7), -1.8em -1.8em 0 0em #c0c0c0; 89 | } 90 | } 91 | @keyframes load5 { 92 | 0%, 93 | 100% { 94 | box-shadow: 0em -2.6em 0em 0em #c0c0c0, 95 | 1.8em -1.8em 0 0em rgba(192, 192, 192, 0.2), 96 | 2.5em 0em 0 0em rgba(192, 192, 192, 0.2), 97 | 1.75em 1.75em 0 0em rgba(192, 192, 192, 0.2), 98 | 0em 2.5em 0 0em rgba(192, 192, 192, 0.2), 99 | -1.8em 1.8em 0 0em rgba(192, 192, 192, 0.2), 100 | -2.6em 0em 0 0em rgba(192, 192, 192, 0.5), 101 | -1.8em -1.8em 0 0em rgba(192, 192, 192, 0.7); 102 | } 103 | 12.5% { 104 | box-shadow: 0em -2.6em 0em 0em rgba(192, 192, 192, 0.7), 105 | 1.8em -1.8em 0 0em #c0c0c0, 2.5em 0em 0 0em rgba(192, 192, 192, 0.2), 106 | 1.75em 1.75em 0 0em rgba(192, 192, 192, 0.2), 107 | 0em 2.5em 0 0em rgba(192, 192, 192, 0.2), 108 | -1.8em 1.8em 0 0em rgba(192, 192, 192, 0.2), 109 | -2.6em 0em 0 0em rgba(192, 192, 192, 0.2), 110 | -1.8em -1.8em 0 0em rgba(192, 192, 192, 0.5); 111 | } 112 | 25% { 113 | box-shadow: 0em -2.6em 0em 0em rgba(192, 192, 192, 0.5), 114 | 1.8em -1.8em 0 0em rgba(192, 192, 192, 0.7), 2.5em 0em 0 0em #c0c0c0, 115 | 1.75em 1.75em 0 0em rgba(192, 192, 192, 0.2), 116 | 0em 2.5em 0 0em rgba(192, 192, 192, 0.2), 117 | -1.8em 1.8em 0 0em rgba(192, 192, 192, 0.2), 118 | -2.6em 0em 0 0em rgba(192, 192, 192, 0.2), 119 | -1.8em -1.8em 0 0em rgba(192, 192, 192, 0.2); 120 | } 121 | 37.5% { 122 | box-shadow: 0em -2.6em 0em 0em rgba(192, 192, 192, 0.2), 123 | 1.8em -1.8em 0 0em rgba(192, 192, 192, 0.5), 124 | 2.5em 0em 0 0em rgba(192, 192, 192, 0.7), 1.75em 1.75em 0 0em #c0c0c0, 125 | 0em 2.5em 0 0em rgba(192, 192, 192, 0.2), 126 | -1.8em 1.8em 0 0em rgba(192, 192, 192, 0.2), 127 | -2.6em 0em 0 0em rgba(192, 192, 192, 0.2), 128 | -1.8em -1.8em 0 0em rgba(192, 192, 192, 0.2); 129 | } 130 | 50% { 131 | box-shadow: 0em -2.6em 0em 0em rgba(192, 192, 192, 0.2), 132 | 1.8em -1.8em 0 0em rgba(192, 192, 192, 0.2), 133 | 2.5em 0em 0 0em rgba(192, 192, 192, 0.5), 134 | 1.75em 1.75em 0 0em rgba(192, 192, 192, 0.7), 0em 2.5em 0 0em #c0c0c0, 135 | -1.8em 1.8em 0 0em rgba(192, 192, 192, 0.2), 136 | -2.6em 0em 0 0em rgba(192, 192, 192, 0.2), 137 | -1.8em -1.8em 0 0em rgba(192, 192, 192, 0.2); 138 | } 139 | 62.5% { 140 | box-shadow: 0em -2.6em 0em 0em rgba(192, 192, 192, 0.2), 141 | 1.8em -1.8em 0 0em rgba(192, 192, 192, 0.2), 142 | 2.5em 0em 0 0em rgba(192, 192, 192, 0.2), 143 | 1.75em 1.75em 0 0em rgba(192, 192, 192, 0.5), 144 | 0em 2.5em 0 0em rgba(192, 192, 192, 0.7), -1.8em 1.8em 0 0em #c0c0c0, 145 | -2.6em 0em 0 0em rgba(192, 192, 192, 0.2), 146 | -1.8em -1.8em 0 0em rgba(192, 192, 192, 0.2); 147 | } 148 | 75% { 149 | box-shadow: 0em -2.6em 0em 0em rgba(192, 192, 192, 0.2), 150 | 1.8em -1.8em 0 0em rgba(192, 192, 192, 0.2), 151 | 2.5em 0em 0 0em rgba(192, 192, 192, 0.2), 152 | 1.75em 1.75em 0 0em rgba(192, 192, 192, 0.2), 153 | 0em 2.5em 0 0em rgba(192, 192, 192, 0.5), 154 | -1.8em 1.8em 0 0em rgba(192, 192, 192, 0.7), -2.6em 0em 0 0em #c0c0c0, 155 | -1.8em -1.8em 0 0em rgba(192, 192, 192, 0.2); 156 | } 157 | 87.5% { 158 | box-shadow: 0em -2.6em 0em 0em rgba(192, 192, 192, 0.2), 159 | 1.8em -1.8em 0 0em rgba(192, 192, 192, 0.2), 160 | 2.5em 0em 0 0em rgba(192, 192, 192, 0.2), 161 | 1.75em 1.75em 0 0em rgba(192, 192, 192, 0.2), 162 | 0em 2.5em 0 0em rgba(192, 192, 192, 0.2), 163 | -1.8em 1.8em 0 0em rgba(192, 192, 192, 0.5), 164 | -2.6em 0em 0 0em rgba(192, 192, 192, 0.7), -1.8em -1.8em 0 0em #c0c0c0; 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /controllers/blogController.js: -------------------------------------------------------------------------------- 1 | const Blog = require("../models/Blog"); 2 | const fs = require("fs"); 3 | const cloudinary = require("cloudinary").v2; 4 | 5 | exports.getAllBlogs = async (req, res) => { 6 | try { 7 | const blogs = await Blog.find().populate("owner").sort({ createdAt: -1 }); 8 | res.status(200).json({ 9 | status: "success", 10 | results: blogs.length, 11 | data: { 12 | blogs, 13 | }, 14 | }); 15 | } catch (err) { 16 | res.status(400).json({ 17 | status: "fail", 18 | message: err.message, 19 | }); 20 | } 21 | }; 22 | 23 | exports.getBlogById = async (req, res) => { 24 | try { 25 | const blog = await Blog.findById(req.params.blogId).populate("owner"); 26 | if (!blog) { 27 | return res.status(404).json({ 28 | status: "fail", 29 | message: "Blog does not exist", 30 | }); 31 | } 32 | 33 | res.status(200).json({ 34 | status: "success", 35 | data: { 36 | blog, 37 | }, 38 | }); 39 | } catch (err) { 40 | res.status(400).json({ 41 | status: "fail", 42 | message: err.message, 43 | }); 44 | } 45 | }; 46 | 47 | exports.createBlog = async (req, res) => { 48 | try { 49 | const cloudinaryLink = await cloudinary.uploader.upload(req.file.path); 50 | 51 | const blog = await Blog.create({ 52 | ...req.body, 53 | // image: req.file.path.replace(/\\/g, "/"), 54 | image: cloudinaryLink.url, 55 | owner: req.user._id, 56 | }); 57 | res.status(200).json({ 58 | status: "success", 59 | data: { 60 | blog, 61 | }, 62 | }); 63 | } catch (err) { 64 | res.status(400).json({ 65 | status: "fail", 66 | message: err.message, 67 | }); 68 | } 69 | }; 70 | 71 | exports.updateBlog = async (req, res) => { 72 | try { 73 | let updatedBlog; 74 | if (req.file) { 75 | const updatingBlog = await Blog.findById(req.params.blogId); 76 | if (!updatingBlog) { 77 | return res.status(404).json({ 78 | status: "fail", 79 | message: "Blog does not exist", 80 | }); 81 | } 82 | const imageName = updatingBlog.image 83 | .split("/") 84 | .slice(-1)[0] 85 | .split(".")[0]; 86 | 87 | const newImage = await cloudinary.uploader.upload(req.file.path, { 88 | public_id: imageName, 89 | invalidate: true, 90 | }); 91 | 92 | // await fs.unlink(`./${updatingBlog.image}`, (err) => { 93 | // if (err && err.code == "ENOENT") { 94 | // // file doens't exist 95 | // console.info("File doesn't exist, won't remove it."); 96 | // } else if (err) { 97 | // // other errors, e.g. maybe we don't have enough permission 98 | // console.error("Error occurred while trying to remove file"); 99 | // } else { 100 | // console.info(`removed`); 101 | // } 102 | // }); 103 | 104 | updatedBlog = { 105 | ...req.body, 106 | // image: req.file.path.replace(/\\/g, "/"), 107 | image: newImage.url, 108 | }; 109 | } else { 110 | updatedBlog = { 111 | ...req.body, 112 | }; 113 | } 114 | const blog = await Blog.findByIdAndUpdate(req.params.blogId, updatedBlog, { 115 | new: true, 116 | }); 117 | 118 | res.status(200).json({ 119 | status: "success", 120 | data: { 121 | blog, 122 | }, 123 | }); 124 | } catch (err) { 125 | res.status(400).json({ 126 | status: "fail", 127 | message: err.message, 128 | }); 129 | } 130 | }; 131 | 132 | exports.deleteBlog = async (req, res) => { 133 | try { 134 | const deletingBlog = await Blog.findById(req.params.blogId); 135 | if (!deletingBlog) { 136 | return res.status(404).json({ 137 | status: "fail", 138 | message: "Blog does not exist", 139 | }); 140 | } 141 | const imageName = deletingBlog.image.split("/").slice(-1)[0].split(".")[0]; 142 | await cloudinary.uploader.destroy(imageName); 143 | 144 | // await fs.unlink(`./${deletingBlog.image}`, (err) => { 145 | // if (err && err.code == "ENOENT") { 146 | // // file doens't exist 147 | // console.info("File doesn't exist, won't remove it."); 148 | // } else if (err) { 149 | // // other errors, e.g. maybe we don't have enough permission 150 | // console.error("Error occurred while trying to remove file"); 151 | // } else { 152 | // console.info(`removed`); 153 | // } 154 | // }); 155 | 156 | deletingBlog.delete(); 157 | 158 | res.status(200).json({ 159 | status: "success", 160 | message: "Blog Successfully Deleted", 161 | }); 162 | } catch (err) { 163 | res.status(400).json({ 164 | status: "fail", 165 | message: err.message, 166 | }); 167 | } 168 | }; 169 | 170 | exports.likeBlog = async (req, res) => { 171 | try { 172 | const blog = await Blog.findById(req.params.blogId); 173 | const user = req.user; 174 | 175 | if (!blog) { 176 | return res.status(404).json({ 177 | status: "fail", 178 | message: "Blog Does not Exist", 179 | }); 180 | } 181 | 182 | const blogLikes = [...blog.likes]; 183 | 184 | const checkUser = blogLikes.findIndex((likedUserId) => 185 | likedUserId.equals(user._id) 186 | ); 187 | 188 | if (checkUser !== -1) { 189 | return res.status(400).json({ 190 | status: "fail", 191 | message: "You have already liked this blog", 192 | }); 193 | } 194 | 195 | blogLikes.push(user._id); 196 | 197 | const likedBlog = await Blog.findByIdAndUpdate( 198 | req.params.blogId, 199 | { likes: blogLikes }, 200 | { new: true } 201 | ); 202 | 203 | return res.status(200).json({ 204 | status: "success", 205 | data: { 206 | likes: blogLikes.length, 207 | likedBlog, 208 | }, 209 | }); 210 | } catch (err) { 211 | res.status(400).json({ 212 | status: "fail", 213 | message: err.message, 214 | }); 215 | } 216 | }; 217 | 218 | exports.unlikeBlog = async (req, res) => { 219 | try { 220 | const blog = await Blog.findById(req.params.blogId); 221 | const user = req.user; 222 | 223 | if (!blog) { 224 | return res.status(404).json({ 225 | status: "fail", 226 | message: "Blog Does not Exist", 227 | }); 228 | } 229 | 230 | if (!blog.likes || !blog.likes.length) { 231 | return res.status(404).json({ 232 | status: "fail", 233 | message: "This blog has no likes", 234 | }); 235 | } 236 | 237 | const blogLikes = [...blog.likes]; 238 | 239 | const checkUser = blogLikes.findIndex((likedUserId) => 240 | likedUserId.equals(user._id) 241 | ); 242 | 243 | if (checkUser === -1) { 244 | return res.status(400).json({ 245 | status: "fail", 246 | message: "You have not liked this blog.", 247 | }); 248 | } 249 | 250 | blogLikes.splice(checkUser, 1); 251 | 252 | const unlikedBlog = await Blog.findByIdAndUpdate( 253 | req.params.blogId, 254 | { likes: blogLikes }, 255 | { new: true } 256 | ); 257 | 258 | return res.status(200).json({ 259 | status: "success", 260 | data: { 261 | likes: blogLikes.length, 262 | unlikedBlog, 263 | }, 264 | }); 265 | } catch (err) { 266 | res.status(400).json({ 267 | status: "fail", 268 | message: err.message, 269 | }); 270 | } 271 | }; 272 | 273 | exports.getAllBlogByUser = async (req, res) => { 274 | try { 275 | const blogs = await Blog.find({ owner: req.params.userId }) 276 | .populate("owner") 277 | .sort({ createdAt: -1 }); 278 | res.status(200).json({ 279 | status: "success", 280 | results: blogs.length, 281 | data: { 282 | blogs, 283 | }, 284 | }); 285 | } catch (err) { 286 | res.status(400).json({ 287 | status: "fail", 288 | message: err.message, 289 | }); 290 | } 291 | }; 292 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@sindresorhus/is@^0.14.0": 6 | version "0.14.0" 7 | resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-0.14.0.tgz#9fb3a3cf3132328151f353de4632e01e52102bea" 8 | integrity sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ== 9 | 10 | "@szmarczak/http-timer@^1.1.2": 11 | version "1.1.2" 12 | resolved "https://registry.yarnpkg.com/@szmarczak/http-timer/-/http-timer-1.1.2.tgz#b1665e2c461a2cd92f4c1bbf50d5454de0d4b421" 13 | integrity sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA== 14 | dependencies: 15 | defer-to-connect "^1.0.1" 16 | 17 | "@tootallnate/once@1": 18 | version "1.1.2" 19 | resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" 20 | integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== 21 | 22 | "@types/bson@*": 23 | version "4.2.0" 24 | resolved "https://registry.yarnpkg.com/@types/bson/-/bson-4.2.0.tgz#a2f71e933ff54b2c3bf267b67fa221e295a33337" 25 | integrity sha512-ELCPqAdroMdcuxqwMgUpifQyRoTpyYCNr1V9xKyF40VsBobsj+BbWNRvwGchMgBPGqkw655ypkjj2MEF5ywVwg== 26 | dependencies: 27 | bson "*" 28 | 29 | "@types/bson@1.x || 4.0.x": 30 | version "4.0.5" 31 | resolved "https://registry.yarnpkg.com/@types/bson/-/bson-4.0.5.tgz#9e0e1d1a6f8866483f96868a9b33bc804926b1fc" 32 | integrity sha512-vVLwMUqhYJSQ/WKcE60eFqcyuWse5fGH+NMAXHuKrUAPoryq3ATxk5o4bgYNtg5aOM4APVg7Hnb3ASqUYG0PKg== 33 | dependencies: 34 | "@types/node" "*" 35 | 36 | "@types/mongodb@^3.5.27": 37 | version "3.6.20" 38 | resolved "https://registry.yarnpkg.com/@types/mongodb/-/mongodb-3.6.20.tgz#b7c5c580644f6364002b649af1c06c3c0454e1d2" 39 | integrity sha512-WcdpPJCakFzcWWD9juKoZbRtQxKIMYF/JIAM4JrNHrMcnJL6/a2NWjXxW7fo9hxboxxkg+icff8d7+WIEvKgYQ== 40 | dependencies: 41 | "@types/bson" "*" 42 | "@types/node" "*" 43 | 44 | "@types/node@*": 45 | version "17.0.13" 46 | resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.13.tgz#5ed7ed7c662948335fcad6c412bb42d99ea754e3" 47 | integrity sha512-Y86MAxASe25hNzlDbsviXl8jQHb0RDvKt4c40ZJQ1Don0AAL0STLZSs4N+6gLEO55pedy7r2cLwS+ZDxPm/2Bw== 48 | 49 | abbrev@1: 50 | version "1.1.1" 51 | resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" 52 | integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== 53 | 54 | accepts@~1.3.7: 55 | version "1.3.7" 56 | resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" 57 | integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA== 58 | dependencies: 59 | mime-types "~2.1.24" 60 | negotiator "0.6.2" 61 | 62 | agent-base@6, agent-base@^6.0.0, agent-base@^6.0.2: 63 | version "6.0.2" 64 | resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" 65 | integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== 66 | dependencies: 67 | debug "4" 68 | 69 | ansi-align@^3.0.0: 70 | version "3.0.1" 71 | resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-3.0.1.tgz#0cdf12e111ace773a86e9a1fad1225c43cb19a59" 72 | integrity sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w== 73 | dependencies: 74 | string-width "^4.1.0" 75 | 76 | ansi-regex@^5.0.1: 77 | version "5.0.1" 78 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" 79 | integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== 80 | 81 | ansi-styles@^4.0.0, ansi-styles@^4.1.0: 82 | version "4.3.0" 83 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" 84 | integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== 85 | dependencies: 86 | color-convert "^2.0.1" 87 | 88 | anymatch@~3.1.2: 89 | version "3.1.2" 90 | resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" 91 | integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== 92 | dependencies: 93 | normalize-path "^3.0.0" 94 | picomatch "^2.0.4" 95 | 96 | append-field@^1.0.0: 97 | version "1.0.0" 98 | resolved "https://registry.yarnpkg.com/append-field/-/append-field-1.0.0.tgz#1e3440e915f0b1203d23748e78edd7b9b5b43e56" 99 | integrity sha1-HjRA6RXwsSA9I3SOeO3XubW0PlY= 100 | 101 | array-flatten@1.1.1: 102 | version "1.1.1" 103 | resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" 104 | integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= 105 | 106 | ast-types@^0.13.2: 107 | version "0.13.4" 108 | resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.13.4.tgz#ee0d77b343263965ecc3fb62da16e7222b2b6782" 109 | integrity sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w== 110 | dependencies: 111 | tslib "^2.0.1" 112 | 113 | balanced-match@^1.0.0: 114 | version "1.0.2" 115 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" 116 | integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== 117 | 118 | base64-js@^1.3.1: 119 | version "1.5.1" 120 | resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" 121 | integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== 122 | 123 | bcryptjs@^2.4.3: 124 | version "2.4.3" 125 | resolved "https://registry.yarnpkg.com/bcryptjs/-/bcryptjs-2.4.3.tgz#9ab5627b93e60621ff7cdac5da9733027df1d0cb" 126 | integrity sha1-mrVie5PmBiH/fNrF2pczAn3x0Ms= 127 | 128 | binary-extensions@^2.0.0: 129 | version "2.2.0" 130 | resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" 131 | integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== 132 | 133 | bl@^2.2.1: 134 | version "2.2.1" 135 | resolved "https://registry.yarnpkg.com/bl/-/bl-2.2.1.tgz#8c11a7b730655c5d56898cdc871224f40fd901d5" 136 | integrity sha512-6Pesp1w0DEX1N550i/uGV/TqucVL4AM/pgThFSN/Qq9si1/DF9aIHs1BxD8V/QU0HoeHO6cQRTAuYnLPKq1e4g== 137 | dependencies: 138 | readable-stream "^2.3.5" 139 | safe-buffer "^5.1.1" 140 | 141 | bluebird@3.5.1: 142 | version "3.5.1" 143 | resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9" 144 | integrity sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA== 145 | 146 | body-parser@1.19.1: 147 | version "1.19.1" 148 | resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.1.tgz#1499abbaa9274af3ecc9f6f10396c995943e31d4" 149 | integrity sha512-8ljfQi5eBk8EJfECMrgqNGWPEY5jWP+1IzkzkGdFFEwFQZZyaZ21UqdaHktgiMlH0xLHqIFtE/u2OYE5dOtViA== 150 | dependencies: 151 | bytes "3.1.1" 152 | content-type "~1.0.4" 153 | debug "2.6.9" 154 | depd "~1.1.2" 155 | http-errors "1.8.1" 156 | iconv-lite "0.4.24" 157 | on-finished "~2.3.0" 158 | qs "6.9.6" 159 | raw-body "2.4.2" 160 | type-is "~1.6.18" 161 | 162 | boxen@^5.0.0: 163 | version "5.1.2" 164 | resolved "https://registry.yarnpkg.com/boxen/-/boxen-5.1.2.tgz#788cb686fc83c1f486dfa8a40c68fc2b831d2b50" 165 | integrity sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ== 166 | dependencies: 167 | ansi-align "^3.0.0" 168 | camelcase "^6.2.0" 169 | chalk "^4.1.0" 170 | cli-boxes "^2.2.1" 171 | string-width "^4.2.2" 172 | type-fest "^0.20.2" 173 | widest-line "^3.1.0" 174 | wrap-ansi "^7.0.0" 175 | 176 | brace-expansion@^1.1.7: 177 | version "1.1.11" 178 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" 179 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== 180 | dependencies: 181 | balanced-match "^1.0.0" 182 | concat-map "0.0.1" 183 | 184 | braces@~3.0.2: 185 | version "3.0.2" 186 | resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" 187 | integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== 188 | dependencies: 189 | fill-range "^7.0.1" 190 | 191 | bson@*: 192 | version "4.6.1" 193 | resolved "https://registry.yarnpkg.com/bson/-/bson-4.6.1.tgz#2b5da517539bb0f7f3ffb54ac70a384ca899641c" 194 | integrity sha512-I1LQ7Hz5zgwR4QquilLNZwbhPw0Apx7i7X9kGMBTsqPdml/03Q9NBtD9nt/19ahjlphktQImrnderxqpzeVDjw== 195 | dependencies: 196 | buffer "^5.6.0" 197 | 198 | bson@^1.1.4: 199 | version "1.1.6" 200 | resolved "https://registry.yarnpkg.com/bson/-/bson-1.1.6.tgz#fb819be9a60cd677e0853aee4ca712a785d6618a" 201 | integrity sha512-EvVNVeGo4tHxwi8L6bPj3y3itEvStdwvvlojVxxbyYfoaxJ6keLgrTuKdyfEAszFK+H3olzBuafE0yoh0D1gdg== 202 | 203 | buffer-equal-constant-time@1.0.1: 204 | version "1.0.1" 205 | resolved "https://registry.yarnpkg.com/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz#f8e71132f7ffe6e01a5c9697a4c6f3e48d5cc819" 206 | integrity sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk= 207 | 208 | buffer-from@^1.0.0: 209 | version "1.1.2" 210 | resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" 211 | integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== 212 | 213 | buffer@^5.6.0: 214 | version "5.7.1" 215 | resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" 216 | integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== 217 | dependencies: 218 | base64-js "^1.3.1" 219 | ieee754 "^1.1.13" 220 | 221 | busboy@^0.2.11: 222 | version "0.2.14" 223 | resolved "https://registry.yarnpkg.com/busboy/-/busboy-0.2.14.tgz#6c2a622efcf47c57bbbe1e2a9c37ad36c7925453" 224 | integrity sha1-bCpiLvz0fFe7vh4qnDetNseSVFM= 225 | dependencies: 226 | dicer "0.2.5" 227 | readable-stream "1.1.x" 228 | 229 | bytes@3.1.1: 230 | version "3.1.1" 231 | resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.1.tgz#3f018291cb4cbad9accb6e6970bca9c8889e879a" 232 | integrity sha512-dWe4nWO/ruEOY7HkUJ5gFt1DCFV9zPRoJr8pV0/ASQermOZjtq8jMjOprC0Kd10GLN+l7xaUPvxzJFWtxGu8Fg== 233 | 234 | cacheable-request@^6.0.0: 235 | version "6.1.0" 236 | resolved "https://registry.yarnpkg.com/cacheable-request/-/cacheable-request-6.1.0.tgz#20ffb8bd162ba4be11e9567d823db651052ca912" 237 | integrity sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg== 238 | dependencies: 239 | clone-response "^1.0.2" 240 | get-stream "^5.1.0" 241 | http-cache-semantics "^4.0.0" 242 | keyv "^3.0.0" 243 | lowercase-keys "^2.0.0" 244 | normalize-url "^4.1.0" 245 | responselike "^1.0.2" 246 | 247 | camelcase@^6.2.0: 248 | version "6.3.0" 249 | resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" 250 | integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== 251 | 252 | chalk@^4.1.0: 253 | version "4.1.2" 254 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" 255 | integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== 256 | dependencies: 257 | ansi-styles "^4.1.0" 258 | supports-color "^7.1.0" 259 | 260 | chokidar@^3.5.2: 261 | version "3.5.3" 262 | resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" 263 | integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== 264 | dependencies: 265 | anymatch "~3.1.2" 266 | braces "~3.0.2" 267 | glob-parent "~5.1.2" 268 | is-binary-path "~2.1.0" 269 | is-glob "~4.0.1" 270 | normalize-path "~3.0.0" 271 | readdirp "~3.6.0" 272 | optionalDependencies: 273 | fsevents "~2.3.2" 274 | 275 | ci-info@^2.0.0: 276 | version "2.0.0" 277 | resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" 278 | integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== 279 | 280 | cli-boxes@^2.2.1: 281 | version "2.2.1" 282 | resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-2.2.1.tgz#ddd5035d25094fce220e9cab40a45840a440318f" 283 | integrity sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw== 284 | 285 | cliui@^7.0.2: 286 | version "7.0.4" 287 | resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" 288 | integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== 289 | dependencies: 290 | string-width "^4.2.0" 291 | strip-ansi "^6.0.0" 292 | wrap-ansi "^7.0.0" 293 | 294 | clone-response@^1.0.2: 295 | version "1.0.2" 296 | resolved "https://registry.yarnpkg.com/clone-response/-/clone-response-1.0.2.tgz#d1dc973920314df67fbeb94223b4ee350239e96b" 297 | integrity sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws= 298 | dependencies: 299 | mimic-response "^1.0.0" 300 | 301 | cloudinary-core@^2.10.2: 302 | version "2.12.3" 303 | resolved "https://registry.yarnpkg.com/cloudinary-core/-/cloudinary-core-2.12.3.tgz#6482e472944214ff905c4852da0a4afce14dec2b" 304 | integrity sha512-Ll4eDzcrIVn4zCttMh3Mdi+KNz07p5EEjBT2PQSRx8Eok1lKPt3uBBenOk/w88RKK3B8SFIWcEe/mN4BHQ0p8A== 305 | 306 | cloudinary@^1.26.3: 307 | version "1.28.1" 308 | resolved "https://registry.yarnpkg.com/cloudinary/-/cloudinary-1.28.1.tgz#84846c6499213c5a034000cf229aa9c00b12a6c5" 309 | integrity sha512-iCSgX/GjyNRYUf/1kQgyLl8UdhPKUWIxsAvCD0qjUcnnIZqHk5tJQmCt5YpGh/r1tVdKa4TV/iDB12S33Zjy0w== 310 | dependencies: 311 | cloudinary-core "^2.10.2" 312 | core-js "3.6.5" 313 | lodash "^4.17.11" 314 | q "^1.5.1" 315 | optionalDependencies: 316 | proxy-agent "^5.0.0" 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 | concat-stream@^1.5.2: 336 | version "1.6.2" 337 | resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" 338 | integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== 339 | dependencies: 340 | buffer-from "^1.0.0" 341 | inherits "^2.0.3" 342 | readable-stream "^2.2.2" 343 | typedarray "^0.0.6" 344 | 345 | concurrently@^6.0.0: 346 | version "6.5.1" 347 | resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-6.5.1.tgz#4518c67f7ac680cf5c34d5adf399a2a2047edc8c" 348 | integrity sha512-FlSwNpGjWQfRwPLXvJ/OgysbBxPkWpiVjy1042b0U7on7S7qwwMIILRj7WTN1mTgqa582bG6NFuScOoh6Zgdag== 349 | dependencies: 350 | chalk "^4.1.0" 351 | date-fns "^2.16.1" 352 | lodash "^4.17.21" 353 | rxjs "^6.6.3" 354 | spawn-command "^0.0.2-1" 355 | supports-color "^8.1.0" 356 | tree-kill "^1.2.2" 357 | yargs "^16.2.0" 358 | 359 | configstore@^5.0.1: 360 | version "5.0.1" 361 | resolved "https://registry.yarnpkg.com/configstore/-/configstore-5.0.1.tgz#d365021b5df4b98cdd187d6a3b0e3f6a7cc5ed96" 362 | integrity sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA== 363 | dependencies: 364 | dot-prop "^5.2.0" 365 | graceful-fs "^4.1.2" 366 | make-dir "^3.0.0" 367 | unique-string "^2.0.0" 368 | write-file-atomic "^3.0.0" 369 | xdg-basedir "^4.0.0" 370 | 371 | content-disposition@0.5.4: 372 | version "0.5.4" 373 | resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.4.tgz#8b82b4efac82512a02bb0b1dcec9d2c5e8eb5bfe" 374 | integrity sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ== 375 | dependencies: 376 | safe-buffer "5.2.1" 377 | 378 | content-type@~1.0.4: 379 | version "1.0.4" 380 | resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" 381 | integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== 382 | 383 | cookie-signature@1.0.6: 384 | version "1.0.6" 385 | resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" 386 | integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= 387 | 388 | cookie@0.4.1: 389 | version "0.4.1" 390 | resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.1.tgz#afd713fe26ebd21ba95ceb61f9a8116e50a537d1" 391 | integrity sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA== 392 | 393 | core-js@3.6.5: 394 | version "3.6.5" 395 | resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.6.5.tgz#7395dc273af37fb2e50e9bd3d9fe841285231d1a" 396 | integrity sha512-vZVEEwZoIsI+vPEuoF9Iqf5H7/M3eeQqWlQnYa8FSKKePuYTf5MWnxb5SDAzCa60b3JBRS5g9b+Dq7b1y/RCrA== 397 | 398 | core-util-is@~1.0.0: 399 | version "1.0.3" 400 | resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" 401 | integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== 402 | 403 | crypto-random-string@^2.0.0: 404 | version "2.0.0" 405 | resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-2.0.0.tgz#ef2a7a966ec11083388369baa02ebead229b30d5" 406 | integrity sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA== 407 | 408 | data-uri-to-buffer@3: 409 | version "3.0.1" 410 | resolved "https://registry.yarnpkg.com/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz#594b8973938c5bc2c33046535785341abc4f3636" 411 | integrity sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og== 412 | 413 | date-fns@^2.16.1: 414 | version "2.28.0" 415 | resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.28.0.tgz#9570d656f5fc13143e50c975a3b6bbeb46cd08b2" 416 | integrity sha512-8d35hViGYx/QH0icHYCeLmsLmMUheMmTyV9Fcm6gvNwdw31yXXH+O85sOBJ+OLnLQMKZowvpKb6FgMIQjcpvQw== 417 | 418 | debug@2.6.9: 419 | version "2.6.9" 420 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" 421 | integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== 422 | dependencies: 423 | ms "2.0.0" 424 | 425 | debug@3.1.0: 426 | version "3.1.0" 427 | resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" 428 | integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== 429 | dependencies: 430 | ms "2.0.0" 431 | 432 | debug@4: 433 | version "4.3.3" 434 | resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" 435 | integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== 436 | dependencies: 437 | ms "2.1.2" 438 | 439 | debug@^3.2.7: 440 | version "3.2.7" 441 | resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" 442 | integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== 443 | dependencies: 444 | ms "^2.1.1" 445 | 446 | decompress-response@^3.3.0: 447 | version "3.3.0" 448 | resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" 449 | integrity sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M= 450 | dependencies: 451 | mimic-response "^1.0.0" 452 | 453 | deep-extend@^0.6.0: 454 | version "0.6.0" 455 | resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" 456 | integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== 457 | 458 | deep-is@~0.1.3: 459 | version "0.1.4" 460 | resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" 461 | integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== 462 | 463 | defer-to-connect@^1.0.1: 464 | version "1.1.3" 465 | resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-1.1.3.tgz#331ae050c08dcf789f8c83a7b81f0ed94f4ac591" 466 | integrity sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ== 467 | 468 | degenerator@^3.0.1: 469 | version "3.0.1" 470 | resolved "https://registry.yarnpkg.com/degenerator/-/degenerator-3.0.1.tgz#7ef78ec0c8577a544477308ddf1d2d6e88d51f5b" 471 | integrity sha512-LFsIFEeLPlKvAKXu7j3ssIG6RT0TbI7/GhsqrI0DnHASEQjXQ0LUSYcjJteGgRGmZbl1TnMSxpNQIAiJ7Du5TQ== 472 | dependencies: 473 | ast-types "^0.13.2" 474 | escodegen "^1.8.1" 475 | esprima "^4.0.0" 476 | vm2 "^3.9.3" 477 | 478 | denque@^1.4.1: 479 | version "1.5.1" 480 | resolved "https://registry.yarnpkg.com/denque/-/denque-1.5.1.tgz#07f670e29c9a78f8faecb2566a1e2c11929c5cbf" 481 | integrity sha512-XwE+iZ4D6ZUB7mfYRMb5wByE8L74HCn30FBN7sWnXksWc1LO1bPDl67pBR9o/kC4z/xSNAwkMYcGgqDV3BE3Hw== 482 | 483 | depd@~1.1.2: 484 | version "1.1.2" 485 | resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" 486 | integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= 487 | 488 | destroy@~1.0.4: 489 | version "1.0.4" 490 | resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" 491 | integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= 492 | 493 | dicer@0.2.5: 494 | version "0.2.5" 495 | resolved "https://registry.yarnpkg.com/dicer/-/dicer-0.2.5.tgz#5996c086bb33218c812c090bddc09cd12facb70f" 496 | integrity sha1-WZbAhrszIYyBLAkL3cCc0S+stw8= 497 | dependencies: 498 | readable-stream "1.1.x" 499 | streamsearch "0.1.2" 500 | 501 | dot-prop@^5.2.0: 502 | version "5.3.0" 503 | resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88" 504 | integrity sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q== 505 | dependencies: 506 | is-obj "^2.0.0" 507 | 508 | dotenv@^8.2.0: 509 | version "8.6.0" 510 | resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.6.0.tgz#061af664d19f7f4d8fc6e4ff9b584ce237adcb8b" 511 | integrity sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g== 512 | 513 | duplexer3@^0.1.4: 514 | version "0.1.4" 515 | resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2" 516 | integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI= 517 | 518 | ecdsa-sig-formatter@1.0.11: 519 | version "1.0.11" 520 | resolved "https://registry.yarnpkg.com/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz#ae0f0fa2d85045ef14a817daa3ce9acd0489e5bf" 521 | integrity sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ== 522 | dependencies: 523 | safe-buffer "^5.0.1" 524 | 525 | ee-first@1.1.1: 526 | version "1.1.1" 527 | resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" 528 | integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= 529 | 530 | emoji-regex@^8.0.0: 531 | version "8.0.0" 532 | resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" 533 | integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== 534 | 535 | encodeurl@~1.0.2: 536 | version "1.0.2" 537 | resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" 538 | integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= 539 | 540 | end-of-stream@^1.1.0: 541 | version "1.4.4" 542 | resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" 543 | integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== 544 | dependencies: 545 | once "^1.4.0" 546 | 547 | escalade@^3.1.1: 548 | version "3.1.1" 549 | resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" 550 | integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== 551 | 552 | escape-goat@^2.0.0: 553 | version "2.1.1" 554 | resolved "https://registry.yarnpkg.com/escape-goat/-/escape-goat-2.1.1.tgz#1b2dc77003676c457ec760b2dc68edb648188675" 555 | integrity sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q== 556 | 557 | escape-html@~1.0.3: 558 | version "1.0.3" 559 | resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" 560 | integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= 561 | 562 | escodegen@^1.8.1: 563 | version "1.14.3" 564 | resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.14.3.tgz#4e7b81fba61581dc97582ed78cab7f0e8d63f503" 565 | integrity sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw== 566 | dependencies: 567 | esprima "^4.0.1" 568 | estraverse "^4.2.0" 569 | esutils "^2.0.2" 570 | optionator "^0.8.1" 571 | optionalDependencies: 572 | source-map "~0.6.1" 573 | 574 | esprima@^4.0.0, esprima@^4.0.1: 575 | version "4.0.1" 576 | resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" 577 | integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== 578 | 579 | estraverse@^4.2.0: 580 | version "4.3.0" 581 | resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" 582 | integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== 583 | 584 | esutils@^2.0.2: 585 | version "2.0.3" 586 | resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" 587 | integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== 588 | 589 | etag@~1.8.1: 590 | version "1.8.1" 591 | resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" 592 | integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= 593 | 594 | express@^4.17.1: 595 | version "4.17.2" 596 | resolved "https://registry.yarnpkg.com/express/-/express-4.17.2.tgz#c18369f265297319beed4e5558753cc8c1364cb3" 597 | integrity sha512-oxlxJxcQlYwqPWKVJJtvQiwHgosH/LrLSPA+H4UxpyvSS6jC5aH+5MoHFM+KABgTOt0APue4w66Ha8jCUo9QGg== 598 | dependencies: 599 | accepts "~1.3.7" 600 | array-flatten "1.1.1" 601 | body-parser "1.19.1" 602 | content-disposition "0.5.4" 603 | content-type "~1.0.4" 604 | cookie "0.4.1" 605 | cookie-signature "1.0.6" 606 | debug "2.6.9" 607 | depd "~1.1.2" 608 | encodeurl "~1.0.2" 609 | escape-html "~1.0.3" 610 | etag "~1.8.1" 611 | finalhandler "~1.1.2" 612 | fresh "0.5.2" 613 | merge-descriptors "1.0.1" 614 | methods "~1.1.2" 615 | on-finished "~2.3.0" 616 | parseurl "~1.3.3" 617 | path-to-regexp "0.1.7" 618 | proxy-addr "~2.0.7" 619 | qs "6.9.6" 620 | range-parser "~1.2.1" 621 | safe-buffer "5.2.1" 622 | send "0.17.2" 623 | serve-static "1.14.2" 624 | setprototypeof "1.2.0" 625 | statuses "~1.5.0" 626 | type-is "~1.6.18" 627 | utils-merge "1.0.1" 628 | vary "~1.1.2" 629 | 630 | fast-levenshtein@~2.0.6: 631 | version "2.0.6" 632 | resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" 633 | integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= 634 | 635 | file-uri-to-path@2: 636 | version "2.0.0" 637 | resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-2.0.0.tgz#7b415aeba227d575851e0a5b0c640d7656403fba" 638 | integrity sha512-hjPFI8oE/2iQPVe4gbrJ73Pp+Xfub2+WI2LlXDbsaJBwT5wuMh35WNWVYYTpnz895shtwfyutMFLFywpQAFdLg== 639 | 640 | fill-range@^7.0.1: 641 | version "7.0.1" 642 | resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" 643 | integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== 644 | dependencies: 645 | to-regex-range "^5.0.1" 646 | 647 | finalhandler@~1.1.2: 648 | version "1.1.2" 649 | resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" 650 | integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== 651 | dependencies: 652 | debug "2.6.9" 653 | encodeurl "~1.0.2" 654 | escape-html "~1.0.3" 655 | on-finished "~2.3.0" 656 | parseurl "~1.3.3" 657 | statuses "~1.5.0" 658 | unpipe "~1.0.0" 659 | 660 | forwarded@0.2.0: 661 | version "0.2.0" 662 | resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" 663 | integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== 664 | 665 | fresh@0.5.2: 666 | version "0.5.2" 667 | resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" 668 | integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= 669 | 670 | fs-extra@^8.1.0: 671 | version "8.1.0" 672 | resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" 673 | integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== 674 | dependencies: 675 | graceful-fs "^4.2.0" 676 | jsonfile "^4.0.0" 677 | universalify "^0.1.0" 678 | 679 | fsevents@~2.3.2: 680 | version "2.3.2" 681 | resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" 682 | integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== 683 | 684 | ftp@^0.3.10: 685 | version "0.3.10" 686 | resolved "https://registry.yarnpkg.com/ftp/-/ftp-0.3.10.tgz#9197d861ad8142f3e63d5a83bfe4c59f7330885d" 687 | integrity sha1-kZfYYa2BQvPmPVqDv+TFn3MwiF0= 688 | dependencies: 689 | readable-stream "1.1.x" 690 | xregexp "2.0.0" 691 | 692 | get-caller-file@^2.0.5: 693 | version "2.0.5" 694 | resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" 695 | integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== 696 | 697 | get-stream@^4.1.0: 698 | version "4.1.0" 699 | resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" 700 | integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== 701 | dependencies: 702 | pump "^3.0.0" 703 | 704 | get-stream@^5.1.0: 705 | version "5.2.0" 706 | resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" 707 | integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA== 708 | dependencies: 709 | pump "^3.0.0" 710 | 711 | get-uri@3: 712 | version "3.0.2" 713 | resolved "https://registry.yarnpkg.com/get-uri/-/get-uri-3.0.2.tgz#f0ef1356faabc70e1f9404fa3b66b2ba9bfc725c" 714 | integrity sha512-+5s0SJbGoyiJTZZ2JTpFPLMPSch72KEqGOTvQsBqg0RBWvwhWUSYZFAtz3TPW0GXJuLBJPts1E241iHg+VRfhg== 715 | dependencies: 716 | "@tootallnate/once" "1" 717 | data-uri-to-buffer "3" 718 | debug "4" 719 | file-uri-to-path "2" 720 | fs-extra "^8.1.0" 721 | ftp "^0.3.10" 722 | 723 | glob-parent@~5.1.2: 724 | version "5.1.2" 725 | resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" 726 | integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== 727 | dependencies: 728 | is-glob "^4.0.1" 729 | 730 | global-dirs@^3.0.0: 731 | version "3.0.0" 732 | resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-3.0.0.tgz#70a76fe84ea315ab37b1f5576cbde7d48ef72686" 733 | integrity sha512-v8ho2DS5RiCjftj1nD9NmnfaOzTdud7RRnVd9kFNOjqZbISlx5DQ+OrTkywgd0dIt7oFCvKetZSHoHcP3sDdiA== 734 | dependencies: 735 | ini "2.0.0" 736 | 737 | got@^9.6.0: 738 | version "9.6.0" 739 | resolved "https://registry.yarnpkg.com/got/-/got-9.6.0.tgz#edf45e7d67f99545705de1f7bbeeeb121765ed85" 740 | integrity sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q== 741 | dependencies: 742 | "@sindresorhus/is" "^0.14.0" 743 | "@szmarczak/http-timer" "^1.1.2" 744 | cacheable-request "^6.0.0" 745 | decompress-response "^3.3.0" 746 | duplexer3 "^0.1.4" 747 | get-stream "^4.1.0" 748 | lowercase-keys "^1.0.1" 749 | mimic-response "^1.0.1" 750 | p-cancelable "^1.0.0" 751 | to-readable-stream "^1.0.0" 752 | url-parse-lax "^3.0.0" 753 | 754 | graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0: 755 | version "4.2.9" 756 | resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.9.tgz#041b05df45755e587a24942279b9d113146e1c96" 757 | integrity sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ== 758 | 759 | has-flag@^3.0.0: 760 | version "3.0.0" 761 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" 762 | integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= 763 | 764 | has-flag@^4.0.0: 765 | version "4.0.0" 766 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" 767 | integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== 768 | 769 | has-yarn@^2.1.0: 770 | version "2.1.0" 771 | resolved "https://registry.yarnpkg.com/has-yarn/-/has-yarn-2.1.0.tgz#137e11354a7b5bf11aa5cb649cf0c6f3ff2b2e77" 772 | integrity sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw== 773 | 774 | http-cache-semantics@^4.0.0: 775 | version "4.1.0" 776 | resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390" 777 | integrity sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ== 778 | 779 | http-errors@1.8.1: 780 | version "1.8.1" 781 | resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.8.1.tgz#7c3f28577cbc8a207388455dbd62295ed07bd68c" 782 | integrity sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g== 783 | dependencies: 784 | depd "~1.1.2" 785 | inherits "2.0.4" 786 | setprototypeof "1.2.0" 787 | statuses ">= 1.5.0 < 2" 788 | toidentifier "1.0.1" 789 | 790 | http-proxy-agent@^4.0.0, http-proxy-agent@^4.0.1: 791 | version "4.0.1" 792 | resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a" 793 | integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg== 794 | dependencies: 795 | "@tootallnate/once" "1" 796 | agent-base "6" 797 | debug "4" 798 | 799 | https-proxy-agent@5, https-proxy-agent@^5.0.0: 800 | version "5.0.0" 801 | resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2" 802 | integrity sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA== 803 | dependencies: 804 | agent-base "6" 805 | debug "4" 806 | 807 | iconv-lite@0.4.24: 808 | version "0.4.24" 809 | resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" 810 | integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== 811 | dependencies: 812 | safer-buffer ">= 2.1.2 < 3" 813 | 814 | ieee754@^1.1.13: 815 | version "1.2.1" 816 | resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" 817 | integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== 818 | 819 | ignore-by-default@^1.0.1: 820 | version "1.0.1" 821 | resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09" 822 | integrity sha1-SMptcvbGo68Aqa1K5odr44ieKwk= 823 | 824 | import-lazy@^2.1.0: 825 | version "2.1.0" 826 | resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43" 827 | integrity sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM= 828 | 829 | imurmurhash@^0.1.4: 830 | version "0.1.4" 831 | resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" 832 | integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= 833 | 834 | inherits@2.0.4, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3: 835 | version "2.0.4" 836 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" 837 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== 838 | 839 | ini@2.0.0: 840 | version "2.0.0" 841 | resolved "https://registry.yarnpkg.com/ini/-/ini-2.0.0.tgz#e5fd556ecdd5726be978fa1001862eacb0a94bc5" 842 | integrity sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA== 843 | 844 | ini@~1.3.0: 845 | version "1.3.8" 846 | resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" 847 | integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== 848 | 849 | ip@^1.1.5: 850 | version "1.1.5" 851 | resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" 852 | integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo= 853 | 854 | ipaddr.js@1.9.1: 855 | version "1.9.1" 856 | resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" 857 | integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== 858 | 859 | is-binary-path@~2.1.0: 860 | version "2.1.0" 861 | resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" 862 | integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== 863 | dependencies: 864 | binary-extensions "^2.0.0" 865 | 866 | is-ci@^2.0.0: 867 | version "2.0.0" 868 | resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" 869 | integrity sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w== 870 | dependencies: 871 | ci-info "^2.0.0" 872 | 873 | is-extglob@^2.1.1: 874 | version "2.1.1" 875 | resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" 876 | integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= 877 | 878 | is-fullwidth-code-point@^3.0.0: 879 | version "3.0.0" 880 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" 881 | integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== 882 | 883 | is-glob@^4.0.1, is-glob@~4.0.1: 884 | version "4.0.3" 885 | resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" 886 | integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== 887 | dependencies: 888 | is-extglob "^2.1.1" 889 | 890 | is-installed-globally@^0.4.0: 891 | version "0.4.0" 892 | resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.4.0.tgz#9a0fd407949c30f86eb6959ef1b7994ed0b7b520" 893 | integrity sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ== 894 | dependencies: 895 | global-dirs "^3.0.0" 896 | is-path-inside "^3.0.2" 897 | 898 | is-npm@^5.0.0: 899 | version "5.0.0" 900 | resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-5.0.0.tgz#43e8d65cc56e1b67f8d47262cf667099193f45a8" 901 | integrity sha512-WW/rQLOazUq+ST/bCAVBp/2oMERWLsR7OrKyt052dNDk4DHcDE0/7QSXITlmi+VBcV13DfIbysG3tZJm5RfdBA== 902 | 903 | is-number@^7.0.0: 904 | version "7.0.0" 905 | resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" 906 | integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== 907 | 908 | is-obj@^2.0.0: 909 | version "2.0.0" 910 | resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" 911 | integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== 912 | 913 | is-path-inside@^3.0.2: 914 | version "3.0.3" 915 | resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" 916 | integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== 917 | 918 | is-typedarray@^1.0.0: 919 | version "1.0.0" 920 | resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" 921 | integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= 922 | 923 | is-yarn-global@^0.3.0: 924 | version "0.3.0" 925 | resolved "https://registry.yarnpkg.com/is-yarn-global/-/is-yarn-global-0.3.0.tgz#d502d3382590ea3004893746754c89139973e232" 926 | integrity sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw== 927 | 928 | isarray@0.0.1: 929 | version "0.0.1" 930 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" 931 | integrity sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8= 932 | 933 | isarray@~1.0.0: 934 | version "1.0.0" 935 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" 936 | integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= 937 | 938 | json-buffer@3.0.0: 939 | version "3.0.0" 940 | resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.0.tgz#5b1f397afc75d677bde8bcfc0e47e1f9a3d9a898" 941 | integrity sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg= 942 | 943 | jsonfile@^4.0.0: 944 | version "4.0.0" 945 | resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" 946 | integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= 947 | optionalDependencies: 948 | graceful-fs "^4.1.6" 949 | 950 | jsonwebtoken@^8.5.1: 951 | version "8.5.1" 952 | resolved "https://registry.yarnpkg.com/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz#00e71e0b8df54c2121a1f26137df2280673bcc0d" 953 | integrity sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w== 954 | dependencies: 955 | jws "^3.2.2" 956 | lodash.includes "^4.3.0" 957 | lodash.isboolean "^3.0.3" 958 | lodash.isinteger "^4.0.4" 959 | lodash.isnumber "^3.0.3" 960 | lodash.isplainobject "^4.0.6" 961 | lodash.isstring "^4.0.1" 962 | lodash.once "^4.0.0" 963 | ms "^2.1.1" 964 | semver "^5.6.0" 965 | 966 | jwa@^1.4.1: 967 | version "1.4.1" 968 | resolved "https://registry.yarnpkg.com/jwa/-/jwa-1.4.1.tgz#743c32985cb9e98655530d53641b66c8645b039a" 969 | integrity sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA== 970 | dependencies: 971 | buffer-equal-constant-time "1.0.1" 972 | ecdsa-sig-formatter "1.0.11" 973 | safe-buffer "^5.0.1" 974 | 975 | jws@^3.2.2: 976 | version "3.2.2" 977 | resolved "https://registry.yarnpkg.com/jws/-/jws-3.2.2.tgz#001099f3639468c9414000e99995fa52fb478304" 978 | integrity sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA== 979 | dependencies: 980 | jwa "^1.4.1" 981 | safe-buffer "^5.0.1" 982 | 983 | kareem@2.3.2: 984 | version "2.3.2" 985 | resolved "https://registry.yarnpkg.com/kareem/-/kareem-2.3.2.tgz#78c4508894985b8d38a0dc15e1a8e11078f2ca93" 986 | integrity sha512-STHz9P7X2L4Kwn72fA4rGyqyXdmrMSdxqHx9IXon/FXluXieaFA6KJ2upcHAHxQPQ0LeM/OjLrhFxifHewOALQ== 987 | 988 | keyv@^3.0.0: 989 | version "3.1.0" 990 | resolved "https://registry.yarnpkg.com/keyv/-/keyv-3.1.0.tgz#ecc228486f69991e49e9476485a5be1e8fc5c4d9" 991 | integrity sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA== 992 | dependencies: 993 | json-buffer "3.0.0" 994 | 995 | latest-version@^5.1.0: 996 | version "5.1.0" 997 | resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-5.1.0.tgz#119dfe908fe38d15dfa43ecd13fa12ec8832face" 998 | integrity sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA== 999 | dependencies: 1000 | package-json "^6.3.0" 1001 | 1002 | levn@~0.3.0: 1003 | version "0.3.0" 1004 | resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" 1005 | integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= 1006 | dependencies: 1007 | prelude-ls "~1.1.2" 1008 | type-check "~0.3.2" 1009 | 1010 | lodash.includes@^4.3.0: 1011 | version "4.3.0" 1012 | resolved "https://registry.yarnpkg.com/lodash.includes/-/lodash.includes-4.3.0.tgz#60bb98a87cb923c68ca1e51325483314849f553f" 1013 | integrity sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8= 1014 | 1015 | lodash.isboolean@^3.0.3: 1016 | version "3.0.3" 1017 | resolved "https://registry.yarnpkg.com/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz#6c2e171db2a257cd96802fd43b01b20d5f5870f6" 1018 | integrity sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY= 1019 | 1020 | lodash.isinteger@^4.0.4: 1021 | version "4.0.4" 1022 | resolved "https://registry.yarnpkg.com/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz#619c0af3d03f8b04c31f5882840b77b11cd68343" 1023 | integrity sha1-YZwK89A/iwTDH1iChAt3sRzWg0M= 1024 | 1025 | lodash.isnumber@^3.0.3: 1026 | version "3.0.3" 1027 | resolved "https://registry.yarnpkg.com/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz#3ce76810c5928d03352301ac287317f11c0b1ffc" 1028 | integrity sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w= 1029 | 1030 | lodash.isplainobject@^4.0.6: 1031 | version "4.0.6" 1032 | resolved "https://registry.yarnpkg.com/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz#7c526a52d89b45c45cc690b88163be0497f550cb" 1033 | integrity sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs= 1034 | 1035 | lodash.isstring@^4.0.1: 1036 | version "4.0.1" 1037 | resolved "https://registry.yarnpkg.com/lodash.isstring/-/lodash.isstring-4.0.1.tgz#d527dfb5456eca7cc9bb95d5daeaf88ba54a5451" 1038 | integrity sha1-1SfftUVuynzJu5XV2ur4i6VKVFE= 1039 | 1040 | lodash.once@^4.0.0: 1041 | version "4.1.1" 1042 | resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" 1043 | integrity sha1-DdOXEhPHxW34gJd9UEyI+0cal6w= 1044 | 1045 | lodash@^4.17.11, lodash@^4.17.21: 1046 | version "4.17.21" 1047 | resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" 1048 | integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== 1049 | 1050 | lowercase-keys@^1.0.0, lowercase-keys@^1.0.1: 1051 | version "1.0.1" 1052 | resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" 1053 | integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA== 1054 | 1055 | lowercase-keys@^2.0.0: 1056 | version "2.0.0" 1057 | resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-2.0.0.tgz#2603e78b7b4b0006cbca2fbcc8a3202558ac9479" 1058 | integrity sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA== 1059 | 1060 | lru-cache@^5.1.1: 1061 | version "5.1.1" 1062 | resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" 1063 | integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== 1064 | dependencies: 1065 | yallist "^3.0.2" 1066 | 1067 | lru-cache@^6.0.0: 1068 | version "6.0.0" 1069 | resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" 1070 | integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== 1071 | dependencies: 1072 | yallist "^4.0.0" 1073 | 1074 | make-dir@^3.0.0: 1075 | version "3.1.0" 1076 | resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" 1077 | integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== 1078 | dependencies: 1079 | semver "^6.0.0" 1080 | 1081 | media-typer@0.3.0: 1082 | version "0.3.0" 1083 | resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" 1084 | integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= 1085 | 1086 | memory-pager@^1.0.2: 1087 | version "1.5.0" 1088 | resolved "https://registry.yarnpkg.com/memory-pager/-/memory-pager-1.5.0.tgz#d8751655d22d384682741c972f2c3d6dfa3e66b5" 1089 | integrity sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg== 1090 | 1091 | merge-descriptors@1.0.1: 1092 | version "1.0.1" 1093 | resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" 1094 | integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= 1095 | 1096 | methods@~1.1.2: 1097 | version "1.1.2" 1098 | resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" 1099 | integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= 1100 | 1101 | mime-db@1.51.0: 1102 | version "1.51.0" 1103 | resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.51.0.tgz#d9ff62451859b18342d960850dc3cfb77e63fb0c" 1104 | integrity sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g== 1105 | 1106 | mime-types@~2.1.24: 1107 | version "2.1.34" 1108 | resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.34.tgz#5a712f9ec1503511a945803640fafe09d3793c24" 1109 | integrity sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A== 1110 | dependencies: 1111 | mime-db "1.51.0" 1112 | 1113 | mime@1.6.0: 1114 | version "1.6.0" 1115 | resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" 1116 | integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== 1117 | 1118 | mimic-response@^1.0.0, mimic-response@^1.0.1: 1119 | version "1.0.1" 1120 | resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" 1121 | integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== 1122 | 1123 | minimatch@^3.0.4: 1124 | version "3.0.4" 1125 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" 1126 | integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== 1127 | dependencies: 1128 | brace-expansion "^1.1.7" 1129 | 1130 | minimist@^1.2.0, minimist@^1.2.5: 1131 | version "1.2.5" 1132 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" 1133 | integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== 1134 | 1135 | mkdirp@^0.5.4: 1136 | version "0.5.5" 1137 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" 1138 | integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== 1139 | dependencies: 1140 | minimist "^1.2.5" 1141 | 1142 | mongodb@3.7.3: 1143 | version "3.7.3" 1144 | resolved "https://registry.yarnpkg.com/mongodb/-/mongodb-3.7.3.tgz#b7949cfd0adc4cc7d32d3f2034214d4475f175a5" 1145 | integrity sha512-Psm+g3/wHXhjBEktkxXsFMZvd3nemI0r3IPsE0bU+4//PnvNWKkzhZcEsbPcYiWqe8XqXJJEg4Tgtr7Raw67Yw== 1146 | dependencies: 1147 | bl "^2.2.1" 1148 | bson "^1.1.4" 1149 | denque "^1.4.1" 1150 | optional-require "^1.1.8" 1151 | safe-buffer "^5.1.2" 1152 | optionalDependencies: 1153 | saslprep "^1.0.0" 1154 | 1155 | mongoose-legacy-pluralize@1.0.2: 1156 | version "1.0.2" 1157 | resolved "https://registry.yarnpkg.com/mongoose-legacy-pluralize/-/mongoose-legacy-pluralize-1.0.2.tgz#3ba9f91fa507b5186d399fb40854bff18fb563e4" 1158 | integrity sha512-Yo/7qQU4/EyIS8YDFSeenIvXxZN+ld7YdV9LqFVQJzTLye8unujAWPZ4NWKfFA+RNjh+wvTWKY9Z3E5XM6ZZiQ== 1159 | 1160 | mongoose@^5.12.2: 1161 | version "5.13.14" 1162 | resolved "https://registry.yarnpkg.com/mongoose/-/mongoose-5.13.14.tgz#ffc9704bd022dd018fbddcbe27dc802c77719fb4" 1163 | integrity sha512-j+BlQjjxgZg0iWn42kLeZTB91OejcxWpY2Z50bsZTiKJ7HHcEtcY21Godw496GMkBqJMTzmW7G/kZ04mW+Cb7Q== 1164 | dependencies: 1165 | "@types/bson" "1.x || 4.0.x" 1166 | "@types/mongodb" "^3.5.27" 1167 | bson "^1.1.4" 1168 | kareem "2.3.2" 1169 | mongodb "3.7.3" 1170 | mongoose-legacy-pluralize "1.0.2" 1171 | mpath "0.8.4" 1172 | mquery "3.2.5" 1173 | ms "2.1.2" 1174 | optional-require "1.0.x" 1175 | regexp-clone "1.0.0" 1176 | safe-buffer "5.2.1" 1177 | sift "13.5.2" 1178 | sliced "1.0.1" 1179 | 1180 | mpath@0.8.4: 1181 | version "0.8.4" 1182 | resolved "https://registry.yarnpkg.com/mpath/-/mpath-0.8.4.tgz#6b566d9581621d9e931dd3b142ed3618e7599313" 1183 | integrity sha512-DTxNZomBcTWlrMW76jy1wvV37X/cNNxPW1y2Jzd4DZkAaC5ZGsm8bfGfNOthcDuRJujXLqiuS6o3Tpy0JEoh7g== 1184 | 1185 | mquery@3.2.5: 1186 | version "3.2.5" 1187 | resolved "https://registry.yarnpkg.com/mquery/-/mquery-3.2.5.tgz#8f2305632e4bb197f68f60c0cffa21aaf4060c51" 1188 | integrity sha512-VjOKHHgU84wij7IUoZzFRU07IAxd5kWJaDmyUzQlbjHjyoeK5TNeeo8ZsFDtTYnSgpW6n/nMNIHvE3u8Lbrf4A== 1189 | dependencies: 1190 | bluebird "3.5.1" 1191 | debug "3.1.0" 1192 | regexp-clone "^1.0.0" 1193 | safe-buffer "5.1.2" 1194 | sliced "1.0.1" 1195 | 1196 | ms@2.0.0: 1197 | version "2.0.0" 1198 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" 1199 | integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= 1200 | 1201 | ms@2.1.2: 1202 | version "2.1.2" 1203 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" 1204 | integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== 1205 | 1206 | ms@2.1.3, ms@^2.1.1: 1207 | version "2.1.3" 1208 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" 1209 | integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== 1210 | 1211 | multer@^1.4.2: 1212 | version "1.4.4" 1213 | resolved "https://registry.yarnpkg.com/multer/-/multer-1.4.4.tgz#e2bc6cac0df57a8832b858d7418ccaa8ebaf7d8c" 1214 | integrity sha512-2wY2+xD4udX612aMqMcB8Ws2Voq6NIUPEtD1be6m411T4uDH/VtL9i//xvcyFlTVfRdaBsk7hV5tgrGQqhuBiw== 1215 | dependencies: 1216 | append-field "^1.0.0" 1217 | busboy "^0.2.11" 1218 | concat-stream "^1.5.2" 1219 | mkdirp "^0.5.4" 1220 | object-assign "^4.1.1" 1221 | on-finished "^2.3.0" 1222 | type-is "^1.6.4" 1223 | xtend "^4.0.0" 1224 | 1225 | negotiator@0.6.2: 1226 | version "0.6.2" 1227 | resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" 1228 | integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== 1229 | 1230 | netmask@^2.0.1: 1231 | version "2.0.2" 1232 | resolved "https://registry.yarnpkg.com/netmask/-/netmask-2.0.2.tgz#8b01a07644065d536383835823bc52004ebac5e7" 1233 | integrity sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg== 1234 | 1235 | nodemon@^2.0.7: 1236 | version "2.0.15" 1237 | resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-2.0.15.tgz#504516ce3b43d9dc9a955ccd9ec57550a31a8d4e" 1238 | integrity sha512-gdHMNx47Gw7b3kWxJV64NI+Q5nfl0y5DgDbiVtShiwa7Z0IZ07Ll4RLFo6AjrhzMtoEZn5PDE3/c2AbVsiCkpA== 1239 | dependencies: 1240 | chokidar "^3.5.2" 1241 | debug "^3.2.7" 1242 | ignore-by-default "^1.0.1" 1243 | minimatch "^3.0.4" 1244 | pstree.remy "^1.1.8" 1245 | semver "^5.7.1" 1246 | supports-color "^5.5.0" 1247 | touch "^3.1.0" 1248 | undefsafe "^2.0.5" 1249 | update-notifier "^5.1.0" 1250 | 1251 | nopt@~1.0.10: 1252 | version "1.0.10" 1253 | resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee" 1254 | integrity sha1-bd0hvSoxQXuScn3Vhfim83YI6+4= 1255 | dependencies: 1256 | abbrev "1" 1257 | 1258 | normalize-path@^3.0.0, normalize-path@~3.0.0: 1259 | version "3.0.0" 1260 | resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" 1261 | integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== 1262 | 1263 | normalize-url@^4.1.0: 1264 | version "4.5.1" 1265 | resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-4.5.1.tgz#0dd90cf1288ee1d1313b87081c9a5932ee48518a" 1266 | integrity sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA== 1267 | 1268 | object-assign@^4.1.1: 1269 | version "4.1.1" 1270 | resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" 1271 | integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= 1272 | 1273 | on-finished@^2.3.0, on-finished@~2.3.0: 1274 | version "2.3.0" 1275 | resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" 1276 | integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= 1277 | dependencies: 1278 | ee-first "1.1.1" 1279 | 1280 | once@^1.3.1, once@^1.4.0: 1281 | version "1.4.0" 1282 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 1283 | integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= 1284 | dependencies: 1285 | wrappy "1" 1286 | 1287 | optional-require@1.0.x: 1288 | version "1.0.3" 1289 | resolved "https://registry.yarnpkg.com/optional-require/-/optional-require-1.0.3.tgz#275b8e9df1dc6a17ad155369c2422a440f89cb07" 1290 | integrity sha512-RV2Zp2MY2aeYK5G+B/Sps8lW5NHAzE5QClbFP15j+PWmP+T9PxlJXBOOLoSAdgwFvS4t0aMR4vpedMkbHfh0nA== 1291 | 1292 | optional-require@^1.1.8: 1293 | version "1.1.8" 1294 | resolved "https://registry.yarnpkg.com/optional-require/-/optional-require-1.1.8.tgz#16364d76261b75d964c482b2406cb824d8ec44b7" 1295 | integrity sha512-jq83qaUb0wNg9Krv1c5OQ+58EK+vHde6aBPzLvPPqJm89UQWsvSuFy9X/OSNJnFeSOKo7btE0n8Nl2+nE+z5nA== 1296 | dependencies: 1297 | require-at "^1.0.6" 1298 | 1299 | optionator@^0.8.1: 1300 | version "0.8.3" 1301 | resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" 1302 | integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== 1303 | dependencies: 1304 | deep-is "~0.1.3" 1305 | fast-levenshtein "~2.0.6" 1306 | levn "~0.3.0" 1307 | prelude-ls "~1.1.2" 1308 | type-check "~0.3.2" 1309 | word-wrap "~1.2.3" 1310 | 1311 | p-cancelable@^1.0.0: 1312 | version "1.1.0" 1313 | resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-1.1.0.tgz#d078d15a3af409220c886f1d9a0ca2e441ab26cc" 1314 | integrity sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw== 1315 | 1316 | pac-proxy-agent@^5.0.0: 1317 | version "5.0.0" 1318 | resolved "https://registry.yarnpkg.com/pac-proxy-agent/-/pac-proxy-agent-5.0.0.tgz#b718f76475a6a5415c2efbe256c1c971c84f635e" 1319 | integrity sha512-CcFG3ZtnxO8McDigozwE3AqAw15zDvGH+OjXO4kzf7IkEKkQ4gxQ+3sdF50WmhQ4P/bVusXcqNE2S3XrNURwzQ== 1320 | dependencies: 1321 | "@tootallnate/once" "1" 1322 | agent-base "6" 1323 | debug "4" 1324 | get-uri "3" 1325 | http-proxy-agent "^4.0.1" 1326 | https-proxy-agent "5" 1327 | pac-resolver "^5.0.0" 1328 | raw-body "^2.2.0" 1329 | socks-proxy-agent "5" 1330 | 1331 | pac-resolver@^5.0.0: 1332 | version "5.0.0" 1333 | resolved "https://registry.yarnpkg.com/pac-resolver/-/pac-resolver-5.0.0.tgz#1d717a127b3d7a9407a16d6e1b012b13b9ba8dc0" 1334 | integrity sha512-H+/A6KitiHNNW+bxBKREk2MCGSxljfqRX76NjummWEYIat7ldVXRU3dhRIE3iXZ0nvGBk6smv3nntxKkzRL8NA== 1335 | dependencies: 1336 | degenerator "^3.0.1" 1337 | ip "^1.1.5" 1338 | netmask "^2.0.1" 1339 | 1340 | package-json@^6.3.0: 1341 | version "6.5.0" 1342 | resolved "https://registry.yarnpkg.com/package-json/-/package-json-6.5.0.tgz#6feedaca35e75725876d0b0e64974697fed145b0" 1343 | integrity sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ== 1344 | dependencies: 1345 | got "^9.6.0" 1346 | registry-auth-token "^4.0.0" 1347 | registry-url "^5.0.0" 1348 | semver "^6.2.0" 1349 | 1350 | parseurl@~1.3.3: 1351 | version "1.3.3" 1352 | resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" 1353 | integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== 1354 | 1355 | path-to-regexp@0.1.7: 1356 | version "0.1.7" 1357 | resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" 1358 | integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= 1359 | 1360 | picomatch@^2.0.4, picomatch@^2.2.1: 1361 | version "2.3.1" 1362 | resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" 1363 | integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== 1364 | 1365 | prelude-ls@~1.1.2: 1366 | version "1.1.2" 1367 | resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" 1368 | integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= 1369 | 1370 | prepend-http@^2.0.0: 1371 | version "2.0.0" 1372 | resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-2.0.0.tgz#e92434bfa5ea8c19f41cdfd401d741a3c819d897" 1373 | integrity sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc= 1374 | 1375 | process-nextick-args@~2.0.0: 1376 | version "2.0.1" 1377 | resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" 1378 | integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== 1379 | 1380 | proxy-addr@~2.0.7: 1381 | version "2.0.7" 1382 | resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" 1383 | integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== 1384 | dependencies: 1385 | forwarded "0.2.0" 1386 | ipaddr.js "1.9.1" 1387 | 1388 | proxy-agent@^5.0.0: 1389 | version "5.0.0" 1390 | resolved "https://registry.yarnpkg.com/proxy-agent/-/proxy-agent-5.0.0.tgz#d31405c10d6e8431fde96cba7a0c027ce01d633b" 1391 | integrity sha512-gkH7BkvLVkSfX9Dk27W6TyNOWWZWRilRfk1XxGNWOYJ2TuedAv1yFpCaU9QSBmBe716XOTNpYNOzhysyw8xn7g== 1392 | dependencies: 1393 | agent-base "^6.0.0" 1394 | debug "4" 1395 | http-proxy-agent "^4.0.0" 1396 | https-proxy-agent "^5.0.0" 1397 | lru-cache "^5.1.1" 1398 | pac-proxy-agent "^5.0.0" 1399 | proxy-from-env "^1.0.0" 1400 | socks-proxy-agent "^5.0.0" 1401 | 1402 | proxy-from-env@^1.0.0: 1403 | version "1.1.0" 1404 | resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" 1405 | integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== 1406 | 1407 | pstree.remy@^1.1.8: 1408 | version "1.1.8" 1409 | resolved "https://registry.yarnpkg.com/pstree.remy/-/pstree.remy-1.1.8.tgz#c242224f4a67c21f686839bbdb4ac282b8373d3a" 1410 | integrity sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w== 1411 | 1412 | pump@^3.0.0: 1413 | version "3.0.0" 1414 | resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" 1415 | integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== 1416 | dependencies: 1417 | end-of-stream "^1.1.0" 1418 | once "^1.3.1" 1419 | 1420 | pupa@^2.1.1: 1421 | version "2.1.1" 1422 | resolved "https://registry.yarnpkg.com/pupa/-/pupa-2.1.1.tgz#f5e8fd4afc2c5d97828faa523549ed8744a20d62" 1423 | integrity sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A== 1424 | dependencies: 1425 | escape-goat "^2.0.0" 1426 | 1427 | q@^1.5.1: 1428 | version "1.5.1" 1429 | resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" 1430 | integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= 1431 | 1432 | qs@6.9.6: 1433 | version "6.9.6" 1434 | resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.6.tgz#26ed3c8243a431b2924aca84cc90471f35d5a0ee" 1435 | integrity sha512-TIRk4aqYLNoJUbd+g2lEdz5kLWIuTMRagAXxl78Q0RiVjAOugHmeKNGdd3cwo/ktpf9aL9epCfFqWDEKysUlLQ== 1436 | 1437 | range-parser@~1.2.1: 1438 | version "1.2.1" 1439 | resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" 1440 | integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== 1441 | 1442 | raw-body@2.4.2, raw-body@^2.2.0: 1443 | version "2.4.2" 1444 | resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.2.tgz#baf3e9c21eebced59dd6533ac872b71f7b61cb32" 1445 | integrity sha512-RPMAFUJP19WIet/99ngh6Iv8fzAbqum4Li7AD6DtGaW2RpMB/11xDoalPiJMTbu6I3hkbMVkATvZrqb9EEqeeQ== 1446 | dependencies: 1447 | bytes "3.1.1" 1448 | http-errors "1.8.1" 1449 | iconv-lite "0.4.24" 1450 | unpipe "1.0.0" 1451 | 1452 | rc@^1.2.8: 1453 | version "1.2.8" 1454 | resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" 1455 | integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== 1456 | dependencies: 1457 | deep-extend "^0.6.0" 1458 | ini "~1.3.0" 1459 | minimist "^1.2.0" 1460 | strip-json-comments "~2.0.1" 1461 | 1462 | readable-stream@1.1.x: 1463 | version "1.1.14" 1464 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" 1465 | integrity sha1-fPTFTvZI44EwhMY23SB54WbAgdk= 1466 | dependencies: 1467 | core-util-is "~1.0.0" 1468 | inherits "~2.0.1" 1469 | isarray "0.0.1" 1470 | string_decoder "~0.10.x" 1471 | 1472 | readable-stream@^2.2.2, readable-stream@^2.3.5: 1473 | version "2.3.7" 1474 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" 1475 | integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== 1476 | dependencies: 1477 | core-util-is "~1.0.0" 1478 | inherits "~2.0.3" 1479 | isarray "~1.0.0" 1480 | process-nextick-args "~2.0.0" 1481 | safe-buffer "~5.1.1" 1482 | string_decoder "~1.1.1" 1483 | util-deprecate "~1.0.1" 1484 | 1485 | readdirp@~3.6.0: 1486 | version "3.6.0" 1487 | resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" 1488 | integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== 1489 | dependencies: 1490 | picomatch "^2.2.1" 1491 | 1492 | regexp-clone@1.0.0, regexp-clone@^1.0.0: 1493 | version "1.0.0" 1494 | resolved "https://registry.yarnpkg.com/regexp-clone/-/regexp-clone-1.0.0.tgz#222db967623277056260b992626354a04ce9bf63" 1495 | integrity sha512-TuAasHQNamyyJ2hb97IuBEif4qBHGjPHBS64sZwytpLEqtBQ1gPJTnOaQ6qmpET16cK14kkjbazl6+p0RRv0yw== 1496 | 1497 | registry-auth-token@^4.0.0: 1498 | version "4.2.1" 1499 | resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-4.2.1.tgz#6d7b4006441918972ccd5fedcd41dc322c79b250" 1500 | integrity sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw== 1501 | dependencies: 1502 | rc "^1.2.8" 1503 | 1504 | registry-url@^5.0.0: 1505 | version "5.1.0" 1506 | resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-5.1.0.tgz#e98334b50d5434b81136b44ec638d9c2009c5009" 1507 | integrity sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw== 1508 | dependencies: 1509 | rc "^1.2.8" 1510 | 1511 | require-at@^1.0.6: 1512 | version "1.0.6" 1513 | resolved "https://registry.yarnpkg.com/require-at/-/require-at-1.0.6.tgz#9eb7e3c5e00727f5a4744070a7f560d4de4f6e6a" 1514 | integrity sha512-7i1auJbMUrXEAZCOQ0VNJgmcT2VOKPRl2YGJwgpHpC9CE91Mv4/4UYIUm4chGJaI381ZDq1JUicFii64Hapd8g== 1515 | 1516 | require-directory@^2.1.1: 1517 | version "2.1.1" 1518 | resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" 1519 | integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= 1520 | 1521 | responselike@^1.0.2: 1522 | version "1.0.2" 1523 | resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7" 1524 | integrity sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec= 1525 | dependencies: 1526 | lowercase-keys "^1.0.0" 1527 | 1528 | rxjs@^6.6.3: 1529 | version "6.6.7" 1530 | resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" 1531 | integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ== 1532 | dependencies: 1533 | tslib "^1.9.0" 1534 | 1535 | safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: 1536 | version "5.1.2" 1537 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" 1538 | integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== 1539 | 1540 | safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@^5.1.2: 1541 | version "5.2.1" 1542 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" 1543 | integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== 1544 | 1545 | "safer-buffer@>= 2.1.2 < 3": 1546 | version "2.1.2" 1547 | resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" 1548 | integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== 1549 | 1550 | saslprep@^1.0.0: 1551 | version "1.0.3" 1552 | resolved "https://registry.yarnpkg.com/saslprep/-/saslprep-1.0.3.tgz#4c02f946b56cf54297e347ba1093e7acac4cf226" 1553 | integrity sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag== 1554 | dependencies: 1555 | sparse-bitfield "^3.0.3" 1556 | 1557 | semver-diff@^3.1.1: 1558 | version "3.1.1" 1559 | resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-3.1.1.tgz#05f77ce59f325e00e2706afd67bb506ddb1ca32b" 1560 | integrity sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg== 1561 | dependencies: 1562 | semver "^6.3.0" 1563 | 1564 | semver@^5.6.0, semver@^5.7.1: 1565 | version "5.7.1" 1566 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" 1567 | integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== 1568 | 1569 | semver@^6.0.0, semver@^6.2.0, semver@^6.3.0: 1570 | version "6.3.0" 1571 | resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" 1572 | integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== 1573 | 1574 | semver@^7.3.4: 1575 | version "7.3.5" 1576 | resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" 1577 | integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== 1578 | dependencies: 1579 | lru-cache "^6.0.0" 1580 | 1581 | send@0.17.2: 1582 | version "0.17.2" 1583 | resolved "https://registry.yarnpkg.com/send/-/send-0.17.2.tgz#926622f76601c41808012c8bf1688fe3906f7820" 1584 | integrity sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww== 1585 | dependencies: 1586 | debug "2.6.9" 1587 | depd "~1.1.2" 1588 | destroy "~1.0.4" 1589 | encodeurl "~1.0.2" 1590 | escape-html "~1.0.3" 1591 | etag "~1.8.1" 1592 | fresh "0.5.2" 1593 | http-errors "1.8.1" 1594 | mime "1.6.0" 1595 | ms "2.1.3" 1596 | on-finished "~2.3.0" 1597 | range-parser "~1.2.1" 1598 | statuses "~1.5.0" 1599 | 1600 | serve-static@1.14.2: 1601 | version "1.14.2" 1602 | resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.2.tgz#722d6294b1d62626d41b43a013ece4598d292bfa" 1603 | integrity sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ== 1604 | dependencies: 1605 | encodeurl "~1.0.2" 1606 | escape-html "~1.0.3" 1607 | parseurl "~1.3.3" 1608 | send "0.17.2" 1609 | 1610 | setprototypeof@1.2.0: 1611 | version "1.2.0" 1612 | resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" 1613 | integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== 1614 | 1615 | sift@13.5.2: 1616 | version "13.5.2" 1617 | resolved "https://registry.yarnpkg.com/sift/-/sift-13.5.2.tgz#24a715e13c617b086166cd04917d204a591c9da6" 1618 | integrity sha512-+gxdEOMA2J+AI+fVsCqeNn7Tgx3M9ZN9jdi95939l1IJ8cZsqS8sqpJyOkic2SJk+1+98Uwryt/gL6XDaV+UZA== 1619 | 1620 | signal-exit@^3.0.2: 1621 | version "3.0.6" 1622 | resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.6.tgz#24e630c4b0f03fea446a2bd299e62b4a6ca8d0af" 1623 | integrity sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ== 1624 | 1625 | sliced@1.0.1: 1626 | version "1.0.1" 1627 | resolved "https://registry.yarnpkg.com/sliced/-/sliced-1.0.1.tgz#0b3a662b5d04c3177b1926bea82b03f837a2ef41" 1628 | integrity sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E= 1629 | 1630 | smart-buffer@^4.1.0: 1631 | version "4.2.0" 1632 | resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae" 1633 | integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== 1634 | 1635 | socks-proxy-agent@5, socks-proxy-agent@^5.0.0: 1636 | version "5.0.1" 1637 | resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-5.0.1.tgz#032fb583048a29ebffec2e6a73fca0761f48177e" 1638 | integrity sha512-vZdmnjb9a2Tz6WEQVIurybSwElwPxMZaIc7PzqbJTrezcKNznv6giT7J7tZDZ1BojVaa1jvO/UiUdhDVB0ACoQ== 1639 | dependencies: 1640 | agent-base "^6.0.2" 1641 | debug "4" 1642 | socks "^2.3.3" 1643 | 1644 | socks@^2.3.3: 1645 | version "2.6.1" 1646 | resolved "https://registry.yarnpkg.com/socks/-/socks-2.6.1.tgz#989e6534a07cf337deb1b1c94aaa44296520d30e" 1647 | integrity sha512-kLQ9N5ucj8uIcxrDwjm0Jsqk06xdpBjGNQtpXy4Q8/QY2k+fY7nZH8CARy+hkbG+SGAovmzzuauCpBlb8FrnBA== 1648 | dependencies: 1649 | ip "^1.1.5" 1650 | smart-buffer "^4.1.0" 1651 | 1652 | source-map@~0.6.1: 1653 | version "0.6.1" 1654 | resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" 1655 | integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== 1656 | 1657 | sparse-bitfield@^3.0.3: 1658 | version "3.0.3" 1659 | resolved "https://registry.yarnpkg.com/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz#ff4ae6e68656056ba4b3e792ab3334d38273ca11" 1660 | integrity sha1-/0rm5oZWBWuks+eSqzM004JzyhE= 1661 | dependencies: 1662 | memory-pager "^1.0.2" 1663 | 1664 | spawn-command@^0.0.2-1: 1665 | version "0.0.2-1" 1666 | resolved "https://registry.yarnpkg.com/spawn-command/-/spawn-command-0.0.2-1.tgz#62f5e9466981c1b796dc5929937e11c9c6921bd0" 1667 | integrity sha1-YvXpRmmBwbeW3Fkpk34RycaSG9A= 1668 | 1669 | "statuses@>= 1.5.0 < 2", statuses@~1.5.0: 1670 | version "1.5.0" 1671 | resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" 1672 | integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= 1673 | 1674 | streamsearch@0.1.2: 1675 | version "0.1.2" 1676 | resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-0.1.2.tgz#808b9d0e56fc273d809ba57338e929919a1a9f1a" 1677 | integrity sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo= 1678 | 1679 | string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2: 1680 | version "4.2.3" 1681 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" 1682 | integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== 1683 | dependencies: 1684 | emoji-regex "^8.0.0" 1685 | is-fullwidth-code-point "^3.0.0" 1686 | strip-ansi "^6.0.1" 1687 | 1688 | string_decoder@~0.10.x: 1689 | version "0.10.31" 1690 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" 1691 | integrity sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ= 1692 | 1693 | string_decoder@~1.1.1: 1694 | version "1.1.1" 1695 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" 1696 | integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== 1697 | dependencies: 1698 | safe-buffer "~5.1.0" 1699 | 1700 | strip-ansi@^6.0.0, strip-ansi@^6.0.1: 1701 | version "6.0.1" 1702 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" 1703 | integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== 1704 | dependencies: 1705 | ansi-regex "^5.0.1" 1706 | 1707 | strip-json-comments@~2.0.1: 1708 | version "2.0.1" 1709 | resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" 1710 | integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= 1711 | 1712 | supports-color@^5.5.0: 1713 | version "5.5.0" 1714 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" 1715 | integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== 1716 | dependencies: 1717 | has-flag "^3.0.0" 1718 | 1719 | supports-color@^7.1.0: 1720 | version "7.2.0" 1721 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" 1722 | integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== 1723 | dependencies: 1724 | has-flag "^4.0.0" 1725 | 1726 | supports-color@^8.1.0: 1727 | version "8.1.1" 1728 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" 1729 | integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== 1730 | dependencies: 1731 | has-flag "^4.0.0" 1732 | 1733 | to-readable-stream@^1.0.0: 1734 | version "1.0.0" 1735 | resolved "https://registry.yarnpkg.com/to-readable-stream/-/to-readable-stream-1.0.0.tgz#ce0aa0c2f3df6adf852efb404a783e77c0475771" 1736 | integrity sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q== 1737 | 1738 | to-regex-range@^5.0.1: 1739 | version "5.0.1" 1740 | resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" 1741 | integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== 1742 | dependencies: 1743 | is-number "^7.0.0" 1744 | 1745 | toidentifier@1.0.1: 1746 | version "1.0.1" 1747 | resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" 1748 | integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== 1749 | 1750 | touch@^3.1.0: 1751 | version "3.1.0" 1752 | resolved "https://registry.yarnpkg.com/touch/-/touch-3.1.0.tgz#fe365f5f75ec9ed4e56825e0bb76d24ab74af83b" 1753 | integrity sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA== 1754 | dependencies: 1755 | nopt "~1.0.10" 1756 | 1757 | tree-kill@^1.2.2: 1758 | version "1.2.2" 1759 | resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" 1760 | integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== 1761 | 1762 | tslib@^1.9.0: 1763 | version "1.14.1" 1764 | resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" 1765 | integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== 1766 | 1767 | tslib@^2.0.1: 1768 | version "2.3.1" 1769 | resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" 1770 | integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== 1771 | 1772 | type-check@~0.3.2: 1773 | version "0.3.2" 1774 | resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" 1775 | integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= 1776 | dependencies: 1777 | prelude-ls "~1.1.2" 1778 | 1779 | type-fest@^0.20.2: 1780 | version "0.20.2" 1781 | resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" 1782 | integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== 1783 | 1784 | type-is@^1.6.4, type-is@~1.6.18: 1785 | version "1.6.18" 1786 | resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" 1787 | integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== 1788 | dependencies: 1789 | media-typer "0.3.0" 1790 | mime-types "~2.1.24" 1791 | 1792 | typedarray-to-buffer@^3.1.5: 1793 | version "3.1.5" 1794 | resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" 1795 | integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== 1796 | dependencies: 1797 | is-typedarray "^1.0.0" 1798 | 1799 | typedarray@^0.0.6: 1800 | version "0.0.6" 1801 | resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" 1802 | integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= 1803 | 1804 | undefsafe@^2.0.5: 1805 | version "2.0.5" 1806 | resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.5.tgz#38733b9327bdcd226db889fb723a6efd162e6e2c" 1807 | integrity sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA== 1808 | 1809 | unique-string@^2.0.0: 1810 | version "2.0.0" 1811 | resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-2.0.0.tgz#39c6451f81afb2749de2b233e3f7c5e8843bd89d" 1812 | integrity sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg== 1813 | dependencies: 1814 | crypto-random-string "^2.0.0" 1815 | 1816 | universalify@^0.1.0: 1817 | version "0.1.2" 1818 | resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" 1819 | integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== 1820 | 1821 | unpipe@1.0.0, unpipe@~1.0.0: 1822 | version "1.0.0" 1823 | resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" 1824 | integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= 1825 | 1826 | update-notifier@^5.1.0: 1827 | version "5.1.0" 1828 | resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-5.1.0.tgz#4ab0d7c7f36a231dd7316cf7729313f0214d9ad9" 1829 | integrity sha512-ItnICHbeMh9GqUy31hFPrD1kcuZ3rpxDZbf4KUDavXwS0bW5m7SLbDQpGX3UYr072cbrF5hFUs3r5tUsPwjfHw== 1830 | dependencies: 1831 | boxen "^5.0.0" 1832 | chalk "^4.1.0" 1833 | configstore "^5.0.1" 1834 | has-yarn "^2.1.0" 1835 | import-lazy "^2.1.0" 1836 | is-ci "^2.0.0" 1837 | is-installed-globally "^0.4.0" 1838 | is-npm "^5.0.0" 1839 | is-yarn-global "^0.3.0" 1840 | latest-version "^5.1.0" 1841 | pupa "^2.1.1" 1842 | semver "^7.3.4" 1843 | semver-diff "^3.1.1" 1844 | xdg-basedir "^4.0.0" 1845 | 1846 | url-parse-lax@^3.0.0: 1847 | version "3.0.0" 1848 | resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-3.0.0.tgz#16b5cafc07dbe3676c1b1999177823d6503acb0c" 1849 | integrity sha1-FrXK/Afb42dsGxmZF3gj1lA6yww= 1850 | dependencies: 1851 | prepend-http "^2.0.0" 1852 | 1853 | util-deprecate@~1.0.1: 1854 | version "1.0.2" 1855 | resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" 1856 | integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= 1857 | 1858 | utils-merge@1.0.1: 1859 | version "1.0.1" 1860 | resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" 1861 | integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= 1862 | 1863 | vary@~1.1.2: 1864 | version "1.1.2" 1865 | resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" 1866 | integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= 1867 | 1868 | vm2@^3.9.3: 1869 | version "3.9.5" 1870 | resolved "https://registry.yarnpkg.com/vm2/-/vm2-3.9.5.tgz#5288044860b4bbace443101fcd3bddb2a0aa2496" 1871 | integrity sha512-LuCAHZN75H9tdrAiLFf030oW7nJV5xwNMuk1ymOZwopmuK3d2H4L1Kv4+GFHgarKiLfXXLFU+7LDABHnwOkWng== 1872 | 1873 | widest-line@^3.1.0: 1874 | version "3.1.0" 1875 | resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-3.1.0.tgz#8292333bbf66cb45ff0de1603b136b7ae1496eca" 1876 | integrity sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg== 1877 | dependencies: 1878 | string-width "^4.0.0" 1879 | 1880 | word-wrap@~1.2.3: 1881 | version "1.2.3" 1882 | resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" 1883 | integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== 1884 | 1885 | wrap-ansi@^7.0.0: 1886 | version "7.0.0" 1887 | resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" 1888 | integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== 1889 | dependencies: 1890 | ansi-styles "^4.0.0" 1891 | string-width "^4.1.0" 1892 | strip-ansi "^6.0.0" 1893 | 1894 | wrappy@1: 1895 | version "1.0.2" 1896 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 1897 | integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= 1898 | 1899 | write-file-atomic@^3.0.0: 1900 | version "3.0.3" 1901 | resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8" 1902 | integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q== 1903 | dependencies: 1904 | imurmurhash "^0.1.4" 1905 | is-typedarray "^1.0.0" 1906 | signal-exit "^3.0.2" 1907 | typedarray-to-buffer "^3.1.5" 1908 | 1909 | xdg-basedir@^4.0.0: 1910 | version "4.0.0" 1911 | resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13" 1912 | integrity sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q== 1913 | 1914 | xregexp@2.0.0: 1915 | version "2.0.0" 1916 | resolved "https://registry.yarnpkg.com/xregexp/-/xregexp-2.0.0.tgz#52a63e56ca0b84a7f3a5f3d61872f126ad7a5943" 1917 | integrity sha1-UqY+VsoLhKfzpfPWGHLxJq16WUM= 1918 | 1919 | xtend@^4.0.0: 1920 | version "4.0.2" 1921 | resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" 1922 | integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== 1923 | 1924 | y18n@^5.0.5: 1925 | version "5.0.8" 1926 | resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" 1927 | integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== 1928 | 1929 | yallist@^3.0.2: 1930 | version "3.1.1" 1931 | resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" 1932 | integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== 1933 | 1934 | yallist@^4.0.0: 1935 | version "4.0.0" 1936 | resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" 1937 | integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== 1938 | 1939 | yargs-parser@^20.2.2: 1940 | version "20.2.9" 1941 | resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" 1942 | integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== 1943 | 1944 | yargs@^16.2.0: 1945 | version "16.2.0" 1946 | resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" 1947 | integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== 1948 | dependencies: 1949 | cliui "^7.0.2" 1950 | escalade "^3.1.1" 1951 | get-caller-file "^2.0.5" 1952 | require-directory "^2.1.1" 1953 | string-width "^4.2.0" 1954 | y18n "^5.0.5" 1955 | yargs-parser "^20.2.2" 1956 | --------------------------------------------------------------------------------