├── .gitignore
├── public
├── post1.jpg
├── post2.jpg
├── post1_comments.jpg
└── post2-comments.jpg
├── client
├── public
│ ├── robots.txt
│ ├── favicon.ico
│ ├── logo192.png
│ ├── logo512.png
│ ├── manifest.json
│ └── index.html
├── src
│ ├── components
│ │ ├── Slider
│ │ │ ├── index.scss
│ │ │ └── index.js
│ │ ├── Header
│ │ │ ├── index.scss
│ │ │ └── index.js
│ │ ├── Interactions
│ │ │ ├── Interaction
│ │ │ │ ├── index.scss
│ │ │ │ └── index.js
│ │ │ ├── index.scss
│ │ │ └── index.js
│ │ ├── Loader.js
│ │ ├── Menu
│ │ │ ├── index.scss
│ │ │ └── index.js
│ │ ├── Overlay
│ │ │ ├── index.scss
│ │ │ └── index.js
│ │ ├── BottomDrawer
│ │ │ ├── index.scss
│ │ │ └── index.js
│ │ ├── Comments
│ │ │ ├── index.scss
│ │ │ └── index.js
│ │ ├── Display
│ │ │ ├── index.scss
│ │ │ └── index.js
│ │ └── Views
│ │ │ └── Home.js
│ ├── setupTests.js
│ ├── stories
│ │ ├── 3-Menu.stories.js
│ │ ├── 0-Welcome.stories.js
│ │ ├── 4-BottomDrawer.stories.js
│ │ ├── 1-Button.stories.js
│ │ ├── 2-Display.stories.js
│ │ └── 5-Comments.stories.js
│ ├── App.test.js
│ ├── utils
│ │ ├── AppUtils.js
│ │ └── PostUtils.js
│ ├── store.js
│ ├── index.scss
│ ├── index.js
│ ├── App.scss
│ ├── actions
│ │ ├── postsActions.js
│ │ ├── types.js
│ │ └── appActions.js
│ ├── reducers
│ │ ├── appReducer.js
│ │ └── postsReducer.js
│ ├── App.js
│ └── serviceWorker.js
├── .gitignore
├── package.json
└── README.md
├── package.json
├── server.js
├── README.md
└── yarn.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules
2 |
--------------------------------------------------------------------------------
/public/post1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AWash227/reddit-but-its-tiktok/HEAD/public/post1.jpg
--------------------------------------------------------------------------------
/public/post2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AWash227/reddit-but-its-tiktok/HEAD/public/post2.jpg
--------------------------------------------------------------------------------
/client/public/robots.txt:
--------------------------------------------------------------------------------
1 | # https://www.robotstxt.org/robotstxt.html
2 | User-agent: *
3 | Disallow:
4 |
--------------------------------------------------------------------------------
/client/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AWash227/reddit-but-its-tiktok/HEAD/client/public/favicon.ico
--------------------------------------------------------------------------------
/client/public/logo192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AWash227/reddit-but-its-tiktok/HEAD/client/public/logo192.png
--------------------------------------------------------------------------------
/client/public/logo512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AWash227/reddit-but-its-tiktok/HEAD/client/public/logo512.png
--------------------------------------------------------------------------------
/public/post1_comments.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AWash227/reddit-but-its-tiktok/HEAD/public/post1_comments.jpg
--------------------------------------------------------------------------------
/public/post2-comments.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/AWash227/reddit-but-its-tiktok/HEAD/public/post2-comments.jpg
--------------------------------------------------------------------------------
/client/src/components/Slider/index.scss:
--------------------------------------------------------------------------------
1 | .slider {
2 | position: fixed;
3 | top: 0;
4 | bottom: 0;
5 | left: 0;
6 | right: 0;
7 | }
8 |
--------------------------------------------------------------------------------
/client/src/setupTests.js:
--------------------------------------------------------------------------------
1 | // jest-dom adds custom jest matchers for asserting on DOM nodes.
2 | // allows you to do things like:
3 | // expect(element).toHaveTextContent(/react/i)
4 | // learn more: https://github.com/testing-library/jest-dom
5 | import '@testing-library/jest-dom/extend-expect';
6 |
--------------------------------------------------------------------------------
/client/src/stories/3-Menu.stories.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import "../index.scss";
3 | import "tachyons";
4 | import Menu from "../components/Menu";
5 |
6 | export default {
7 | title: "Menu",
8 | component: Menu
9 | };
10 |
11 | export const DefaultMenu = () =>
;
12 |
--------------------------------------------------------------------------------
/client/src/App.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { render } from '@testing-library/react';
3 | import App from './App';
4 |
5 | test('renders learn react link', () => {
6 | const { getByText } = render( );
7 | const linkElement = getByText(/learn react/i);
8 | expect(linkElement).toBeInTheDocument();
9 | });
10 |
--------------------------------------------------------------------------------
/client/src/components/Header/index.scss:
--------------------------------------------------------------------------------
1 | .header {
2 | position: fixed;
3 | display: flex;
4 | top: 0;
5 | right: 0;
6 | left: 0;
7 | z-index: 2;
8 | justify-content: center;
9 | color: white;
10 | margin: 2rem;
11 | div {
12 | text-shadow: 0px 0px 4px rgba(0, 0, 0, 0.4);
13 | padding: 0 0.25rem 0 0.25rem;
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/client/src/components/Interactions/Interaction/index.scss:
--------------------------------------------------------------------------------
1 | .interaction {
2 | box-sizing: border-box;
3 | display: flex;
4 | flex-direction: column;
5 | align-items: center;
6 | cursor: pointer;
7 | .text {
8 | text-shadow: 0px 0px 5px rgba(0, 0, 0, 0.7);
9 | }
10 | svg {
11 | filter: drop-shadow(0px 0px 3px rgba(0, 0, 0, 0.5));
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/client/src/utils/AppUtils.js:
--------------------------------------------------------------------------------
1 | import { formatPost } from "./PostUtils";
2 |
3 | export const formatResponse = data => ({
4 | before: data.data.before,
5 | after: data.data.after,
6 | numPosts: data.data.dist,
7 | posts: data.data.children.map(post => formatPost(post.data))
8 | });
9 |
10 | export const DEV_URL = `http://localhost:5000`;
11 | export const PROD_URL = ``;
12 |
--------------------------------------------------------------------------------
/client/src/components/Interactions/index.scss:
--------------------------------------------------------------------------------
1 | .interactions {
2 | pointer-events: all;
3 | overflow: hidden;
4 | position: fixed;
5 | z-index: 3;
6 | display: flex;
7 | flex-direction: column;
8 | box-sizing: border-box;
9 | top: 50%;
10 | right: 0;
11 | padding: 1rem;
12 | margin: 1rem;
13 | width: 20%;
14 | height: 50%;
15 | overflow: none;
16 | word-wrap: break-word;
17 | }
18 |
--------------------------------------------------------------------------------
/client/src/stories/0-Welcome.stories.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { linkTo } from '@storybook/addon-links';
3 | import { Welcome } from '@storybook/react/demo';
4 |
5 | export default {
6 | title: 'Welcome',
7 | component: Welcome,
8 | };
9 |
10 | export const ToStorybook = () => ;
11 |
12 | ToStorybook.story = {
13 | name: 'to Storybook',
14 | };
15 |
--------------------------------------------------------------------------------
/client/src/stories/4-BottomDrawer.stories.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import "../index.scss";
3 | import "tachyons";
4 | import BottomDrawer from "../components/BottomDrawer";
5 |
6 | export default {
7 | title: "Bottom Drawer",
8 | component: BottomDrawer
9 | };
10 |
11 | export const DefaultMenu = () => (
12 | {}} />
13 | );
14 |
--------------------------------------------------------------------------------
/client/src/components/Interactions/Interaction/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import "./index.scss";
3 |
4 | const Interaction = ({ icon, text, onClick }) => {
5 | return (
6 |
7 |
{icon}
8 |
{text}
9 |
10 | );
11 | };
12 |
13 | export default Interaction;
14 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "server",
3 | "version": "1.0.0",
4 | "main": "index.js",
5 | "license": "MIT",
6 | "dependencies": {
7 | "axios": "^0.19.2",
8 | "cors": "^2.8.5",
9 | "express": "^4.17.1"
10 | },
11 | "devDependencies": {
12 | "nodemon": "^2.0.2"
13 | },
14 | "scripts": {
15 | "start": "node server.js",
16 | "heroku-postbuild": "cd client && npm install && npm run build"
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/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 | /.storybook
14 |
15 | # misc
16 | .DS_Store
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*
25 |
--------------------------------------------------------------------------------
/client/src/components/Slider/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Swipeable } from "react-swipeable";
3 | import "./index.scss";
4 |
5 | const Slider = ({ handleSwipeDown, handleSwipeUp, children }) => {
6 | return (
7 | handleSwipeDown()}
9 | onSwipedUp={() => handleSwipeUp()}
10 | trackMouse
11 | className="slider w-100 h-100"
12 | >
13 | {children}
14 |
15 | );
16 | };
17 |
18 | export default Slider;
19 |
--------------------------------------------------------------------------------
/client/src/stories/1-Button.stories.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import { action } from '@storybook/addon-actions';
3 | import { Button } from '@storybook/react/demo';
4 |
5 | export default {
6 | title: 'Button',
7 | component: Button,
8 | };
9 |
10 | export const Text = () => Hello Button ;
11 |
12 | export const Emoji = () => (
13 |
14 |
15 | 😀 😎 👍 💯
16 |
17 |
18 | );
19 |
--------------------------------------------------------------------------------
/client/src/components/Interactions/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import "./index.scss";
3 | import Interaction from "./Interaction";
4 |
5 | const Interactions = ({ interactions }) => {
6 | return (
7 |
8 | {interactions.map((interaction, i) => (
9 |
15 | ))}
16 |
17 | );
18 | };
19 |
20 | export default Interactions;
21 |
--------------------------------------------------------------------------------
/client/src/store.js:
--------------------------------------------------------------------------------
1 | import { createStore, combineReducers, applyMiddleware, compose } from "redux";
2 | import { postsReducer } from "./reducers/postsReducer";
3 | import thunk from "redux-thunk";
4 | import { appReducer } from "./reducers/appReducer";
5 |
6 | const RootReducer = combineReducers({ posts: postsReducer, app: appReducer });
7 |
8 | const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
9 |
10 | const store = createStore(
11 | RootReducer,
12 | composeEnhancers(applyMiddleware(thunk))
13 | );
14 |
15 | export default store;
16 |
--------------------------------------------------------------------------------
/client/src/index.scss:
--------------------------------------------------------------------------------
1 | html,
2 | #root,
3 | body {
4 | width: 100%;
5 | height: 100%;
6 | background-color: black;
7 | -webkit-tap-highlight-color: transparent;
8 | }
9 | body {
10 | margin: 0;
11 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
12 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
13 | sans-serif;
14 | -webkit-font-smoothing: antialiased;
15 | -moz-osx-font-smoothing: grayscale;
16 | }
17 |
18 | code {
19 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
20 | monospace;
21 | }
22 |
--------------------------------------------------------------------------------
/client/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "rbitt",
3 | "name": "Reddit but it's TikTok",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | },
10 | {
11 | "src": "logo192.png",
12 | "type": "image/png",
13 | "sizes": "192x192"
14 | },
15 | {
16 | "src": "logo512.png",
17 | "type": "image/png",
18 | "sizes": "512x512"
19 | }
20 | ],
21 | "start_url": ".",
22 | "display": "fullscreen",
23 | "theme_color": "#000000",
24 | "background_color": "#000000"
25 | }
26 |
--------------------------------------------------------------------------------
/client/src/components/Loader.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import { Loader } from "react-loaders";
3 |
4 | export const FullScreenLoader = ({ active }) => {
5 | if (active) {
6 | return (
7 |
21 |
22 |
23 | );
24 | }
25 | return null;
26 | };
27 |
--------------------------------------------------------------------------------
/client/src/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import ReactDOM from "react-dom";
3 | import { Provider } from "react-redux";
4 | import "tachyons";
5 | import "loaders.css";
6 | import "./index.scss";
7 | import App from "./App";
8 | import * as serviceWorker from "./serviceWorker";
9 | import store from "./store";
10 |
11 | ReactDOM.render(
12 |
13 |
14 | ,
15 | document.getElementById("root")
16 | );
17 |
18 | // If you want your app to work offline and load faster, you can change
19 | // unregister() to register() below. Note this comes with some pitfalls.
20 | // Learn more about service workers: https://bit.ly/CRA-PWA
21 | serviceWorker.unregister();
22 |
--------------------------------------------------------------------------------
/client/src/components/Menu/index.scss:
--------------------------------------------------------------------------------
1 | .menu {
2 | width: 100%;
3 | height: 4rem;
4 | position: fixed;
5 | z-index: 3;
6 | bottom: 0;
7 | color: white;
8 | display: flex;
9 | flex-direction: row;
10 | justify-content: space-evenly;
11 | align-items: center;
12 | padding: 1rem 0 0.5rem 0;
13 | border-top: 1px solid rgba(255, 255, 255, 0.5);
14 | }
15 | .menu-item {
16 | display: flex;
17 | flex-direction: column;
18 | align-items: center;
19 | svg {
20 | color: rgba(255, 255, 255, 0.9);
21 | filter: drop-shadow(0px 0px 1px rgba(0, 0, 0, 0.45));
22 | }
23 | a {
24 | font-size: 0.7rem;
25 | text-decoration: none;
26 | color: white;
27 | text-shadow: 0px 0px 2px rgba(0, 0, 0, 1);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/client/src/App.scss:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | width: 100%;
4 | height: 100%;
5 | }
6 |
7 | .App-logo {
8 | height: 40vmin;
9 | pointer-events: none;
10 | }
11 |
12 | @media (prefers-reduced-motion: no-preference) {
13 | .App-logo {
14 | animation: App-logo-spin infinite 20s linear;
15 | }
16 | }
17 |
18 | .App-header {
19 | background-color: #282c34;
20 | min-height: 100vh;
21 | display: flex;
22 | flex-direction: column;
23 | align-items: center;
24 | justify-content: center;
25 | font-size: calc(10px + 2vmin);
26 | color: white;
27 | }
28 |
29 | .App-link {
30 | color: #61dafb;
31 | }
32 |
33 | @keyframes App-logo-spin {
34 | from {
35 | transform: rotate(0deg);
36 | }
37 | to {
38 | transform: rotate(360deg);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/client/src/actions/postsActions.js:
--------------------------------------------------------------------------------
1 | import { postTypes as pt, appTypes as at } from "./types";
2 | import axios from "axios";
3 | import { PROD_URL, DEV_URL } from "../utils/AppUtils";
4 |
5 | // Change me to DEV_URL if you are trying to run the app locally
6 | const URL = PROD_URL;
7 |
8 | export const setCount = (count = 0) => ({
9 | type: pt.SET_COUNT,
10 | payload: count
11 | });
12 | export const fetchCommentsFromPost = (postId, query) => dispatch => {
13 | dispatch({type:pt.FETCHING_COMMENTS});
14 | axios
15 | .get(`${URL}/api/comments/${postId}${query}`)
16 | .then(({ data }) => {
17 | let comments = data[1].data.children.map(child => child.data);
18 | dispatch({ type: pt.FETCH_COMMENTS_FROM_POST, payload: comments });
19 | dispatch({type:pt.FINISHED_FETCHING_COMMENTS});
20 | })
21 | .catch(err => console.error(err));
22 | };
23 |
24 | export const nextPost = () => ({
25 | type: pt.LOAD_NEXT_POST
26 | });
27 |
--------------------------------------------------------------------------------
/client/src/components/Overlay/index.scss:
--------------------------------------------------------------------------------
1 | .overlay {
2 | position: fixed;
3 | z-index: 4;
4 | top: 0;
5 | bottom: 0;
6 | left: 0;
7 | right: 0;
8 | pointer-events: none;
9 | &-title {
10 | overflow: inherit;
11 | padding: 1rem;
12 | padding-top: 2rem;
13 | color: white;
14 | text-shadow: 0px 0px 2px rgba(0, 0, 0, 0.8);
15 | position: absolute;
16 | bottom: 4rem;
17 | left: 0;
18 | background: rgb(0, 0, 0);
19 | background: linear-gradient(
20 | 180deg,
21 | rgba(0, 0, 0, 0) 0%,
22 | rgba(0, 0, 0, 0.2) 20%,
23 | rgba(0, 0, 0, 0.5) 50%,
24 | rgba(0, 0, 0, 0.8) 100%
25 | );
26 | z-index: 4;
27 | }
28 | &-enter {
29 | opacity: 0;
30 | background-color: blue;
31 | }
32 | &-enter-active {
33 | opacity: 1;
34 | transition: opacity 200ms;
35 | }
36 | &-exit {
37 | opacity: 1;
38 | transition: opacity 200ms;
39 | }
40 | &-exit-active {
41 | opacity: 0;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/client/src/actions/types.js:
--------------------------------------------------------------------------------
1 | export const postTypes = (() => {
2 | const SET_POST = "SET_POST";
3 | const SET_POSTS = "SET_POSTS";
4 | const SET_COUNT = "SET_COUNT";
5 | const FETCH_COMMENTS_FROM_POST = "FETCH_COMMENTS_FROM_POST";
6 | const FETCHING_COMMENTS = "FETCHING_COMMENTS";
7 | const FINISHED_FETCHING_COMMENTS = "FINISHED_FETCHING_COMMENTS";
8 | const LOAD_NEXT_POST = "LOAD_NEXT_POST";
9 | return {
10 | SET_POST,
11 | SET_POSTS,
12 | SET_COUNT,
13 | FETCH_COMMENTS_FROM_POST,
14 | FETCHING_COMMENTS,
15 | FINISHED_FETCHING_COMMENTS,
16 | LOAD_NEXT_POST
17 | };
18 | })();
19 |
20 | export const appTypes = (() => {
21 | const FETCH_POSTS_FROM_SUBREDDIT = "FETCH_POSTS_FROM_SUBREDDIT";
22 | const FETCHING_POSTS = "FETCHING_POSTS";
23 | const FINISHED_FETCHING_POSTS = "FINISHED_FETCHING_POSTS";
24 | const SET_SUBREDDIT = "SET_SUBREDDIT";
25 | return {
26 | FETCH_POSTS_FROM_SUBREDDIT,
27 | SET_SUBREDDIT,
28 | FETCHING_POSTS,
29 | FINISHED_FETCHING_POSTS
30 | };
31 | })();
32 |
--------------------------------------------------------------------------------
/client/src/reducers/appReducer.js:
--------------------------------------------------------------------------------
1 | import { appTypes as at, postTypes as pt } from "../actions/types";
2 | import { formatResponse } from "../utils/AppUtils";
3 | import { postsReducer } from "./postsReducer";
4 | const initialState = {
5 | subreddit: "all",
6 | fetchingPosts: false,
7 | data: {}
8 | };
9 |
10 | export const appReducer = (state = initialState, action) => {
11 | switch (action.type) {
12 | case at.FETCHING_POSTS:
13 | return {
14 | ...state,
15 | fetchingPosts: true
16 | };
17 | case at.FINISHED_FETCHING_POSTS:
18 | return {
19 | ...state,
20 | fetchingPosts: false
21 | };
22 | case at.FETCH_POSTS_FROM_SUBREDDIT:
23 | console.log("FETCHING", action.payload);
24 | return {
25 | ...state,
26 | data: action.payload
27 | };
28 |
29 | case at.SET_SUBREDDIT:
30 | return {
31 | ...state,
32 | subreddit: action.payload
33 | };
34 |
35 | default:
36 | return state;
37 | }
38 | };
39 |
--------------------------------------------------------------------------------
/client/src/components/BottomDrawer/index.scss:
--------------------------------------------------------------------------------
1 | .bottom-drawer {
2 | z-index: 10;
3 | position: fixed;
4 | bottom: 0;
5 | background-color: white;
6 | border-top-left-radius: 10px;
7 | border-top-right-radius: 10px;
8 | width: 100%;
9 | pointer-events: all;
10 | .bottom-drawer-header {
11 | display: flex;
12 | align-items: center;
13 | justify-content: center;
14 | height: 2rem;
15 | font-size: 0.9rem;
16 | color: black;
17 | .close {
18 | position: absolute;
19 | right: 0.5rem;
20 | top: 0.25rem;
21 | }
22 | }
23 | .body {
24 | background-color: white;
25 | height: 27.5rem;
26 | max-height: 60%;
27 | overflow-y: scroll;
28 | -webkit-overflow-scrolling: touch;
29 | }
30 | }
31 |
32 | .bottom-drawer-enter {
33 | bottom: -100%;
34 | }
35 |
36 | .bottom-drawer-enter-active {
37 | bottom: 0;
38 | transition: all 0.25s;
39 | }
40 | .bottom-drawer-exit {
41 | bottom: 0;
42 | }
43 | .bottom-drawer-exit-active {
44 | bottom: -100%;
45 | transition: all 0.25s;
46 | }
47 |
--------------------------------------------------------------------------------
/client/src/components/Menu/index.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import "./index.scss";
3 | import {
4 | IoIosHome,
5 | IoIosSearch,
6 | IoIosAddCircle,
7 | IoIosChatboxes,
8 | IoIosPerson
9 | } from "react-icons/io";
10 |
11 | const menuItems = [
12 | { icon: , text: "Home", link: "/home" },
13 | { icon: , text: "Discover", link: "/discover" },
14 | { icon: , text: "", link: "/add" },
15 | { icon: , text: "Inbox", link: "/inbox" },
16 | { icon: , text: "Me", link: "/me" }
17 | ];
18 |
19 | const MenuItem = ({ selected, icon, text, link }) => {
20 | return (
21 |
25 | );
26 | };
27 |
28 | const Menu = () => {
29 | return (
30 |
31 | {menuItems.map(item => (
32 |
39 | ))}
40 |
41 | );
42 | };
43 |
44 | export default Menu;
45 |
--------------------------------------------------------------------------------
/client/src/components/Comments/index.scss:
--------------------------------------------------------------------------------
1 | .comments {
2 | width: 100%;
3 | height: 100%;
4 | background-color: white;
5 | padding: 0.5rem;
6 |
7 | .comment-thread {
8 | margin: 0.5rem 0 0 0;
9 | }
10 | }
11 |
12 | .comment {
13 | font-size: 0.9rem;
14 | background-color: white;
15 | padding: 0.5rem 0 0 0.5rem;
16 | text-align: left;
17 | color: black;
18 | .comment-header {
19 | height: 1rem;
20 | font-size: 0.7rem;
21 | color: black;
22 | .comment-collapse {
23 | display: inline-flex;
24 | border-radius: 999px;
25 | width: 0.75rem;
26 | height: 0.75rem;
27 | justify-content: center;
28 | align-items: center;
29 | padding: 0.15rem;
30 | margin-right: 0.25rem;
31 | &:hover {
32 | background-color: rgba(0, 0, 0, 0.2);
33 | }
34 | }
35 | .comment-author {
36 | &:hover {
37 | text-decoration: underline;
38 | cursor: pointer;
39 | }
40 | }
41 | .comment-score {
42 | color: rgba(0, 0, 0, 0.5);
43 | }
44 | }
45 | .comment-body {
46 | margin: 0 0 0.25rem 0;
47 | padding: 0.5rem 0 0 0.5rem;
48 | line-height: 1.5;
49 | p {
50 | padding: 0;
51 | margin: 0;
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/client/src/actions/appActions.js:
--------------------------------------------------------------------------------
1 | import { appTypes as at, postTypes as pt } from "./types";
2 | import axios from "axios";
3 | import { formatResponse } from "../utils/AppUtils";
4 | import { PROD_URL, DEV_URL } from "../utils/AppUtils";
5 |
6 | // Change me to DEV_URL if you are trying to run the app locally
7 | const URL = PROD_URL;
8 |
9 | export const fetchPostsFromSubreddit = (
10 | subreddit = "pics",
11 | query = ""
12 | ) => dispatch => {
13 | dispatch({ type: at.FETCHING_POSTS });
14 | axios
15 | .get(`${URL}/api/r/${subreddit}${query}`)
16 | .then(res => {
17 | const data = formatResponse(res.data);
18 | let bOA = "";
19 | if (query.includes("before")) {
20 | bOA = "BEFORE";
21 | } else if (query.includes("after")) {
22 | bOA = "AFTER";
23 | } else {
24 | bOA = "";
25 | }
26 | dispatch({ type: at.FETCH_POSTS_FROM_SUBREDDIT, payload: data });
27 | dispatch({
28 | type: pt.SET_POSTS,
29 | payload: { posts: data.posts, numPosts: data.numPosts - 1, query: bOA }
30 | });
31 | dispatch({ type: at.FINISHED_FETCHING_POSTS });
32 | })
33 | .catch(err => console.error(err));
34 | };
35 |
36 | export const setSubreddit = (sub = "") => ({
37 | type: at.SET_SUBREDDIT,
38 | payload: sub
39 | });
40 |
--------------------------------------------------------------------------------
/client/src/components/Display/index.scss:
--------------------------------------------------------------------------------
1 | .display {
2 | overflow: hidden;
3 | height: 100%;
4 | width: 100%;
5 | &-img {
6 | display: flex;
7 | justify-content: center;
8 | align-items: center;
9 | align-content: center;
10 | overflow: inherit;
11 | position: relative;
12 | height: 100%;
13 | width: 100%;
14 | z-index: 2;
15 | img,
16 | video,
17 | p {
18 | max-height: 100vh;
19 | max-width: 100vw;
20 | }
21 | img {
22 | border-radius: 5px;
23 | pointer-events: none;
24 | box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.2),
25 | 0px 0px 15px rgba(0, 0, 0, 0.5);
26 | }
27 | .text {
28 | padding: 1rem;
29 | margin: 2rem;
30 | border: 1px solid white;
31 | text-shadow: 0px 0px 2px rgba(0, 0, 0, 0.5);
32 | background-color: rgba(0, 0, 0, 0.35);
33 | border-radius: 5px;
34 | }
35 | }
36 | &-bg {
37 | position: fixed;
38 | top: 0;
39 | bottom: 0;
40 | left: 0;
41 | right: 0;
42 | overflow: inherit;
43 | pointer-events: none;
44 | filter: blur(10px) opacity(0.5);
45 | -webkit-filter: blur(10px);
46 | background-position: center;
47 | background-repeat: no-repeat;
48 | background-size: cover;
49 | border-radius: 10px;
50 | z-index: 0;
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/client/src/components/Views/Home.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import Header from "../Header";
3 | import Display from "../Display";
4 | import Menu from "../Menu";
5 | import Slider from "../Slider";
6 |
7 | const Home = ({
8 | subreddit,
9 | post,
10 | nextPost,
11 | prevPost,
12 | fetchPosts,
13 | loadNextPost,
14 | loadPrevPost
15 | }) => {
16 | const [overlayActive, setOverlayActive] = useState(false);
17 | return (
18 |
19 |
20 | {/*
21 |
28 |
29 | */}
30 |
36 | {/*
37 |
45 |
46 | */}
47 |
48 |
49 | );
50 | };
51 |
52 | export default Home;
53 |
--------------------------------------------------------------------------------
/client/src/components/BottomDrawer/index.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from "react";
2 | import "./index.scss";
3 | import { IoIosClose } from "react-icons/io";
4 | import { Swipeable } from "react-swipeable";
5 | import { CSSTransition, Transition } from "react-transition-group";
6 |
7 | const BottomDrawer = ({ active, title, setActive, children }) => {
8 | const [isAtTop, setIsAtTop] = useState(false);
9 | const handleClose = () => {
10 | setActive(false);
11 | };
12 |
13 | return (
14 |
17 |
23 |
24 |
25 | {title}
26 | handleClose()}
28 | className="close"
29 | size={25}
30 | />
31 |
32 |
{
35 | if (e.currentTarget.scrollTop > 5) {
36 | setIsAtTop(false);
37 | } else {
38 | setIsAtTop(true);
39 | }
40 | }}
41 | >
42 | {isAtTop}
43 | {children}
44 |
45 |
46 |
47 |
48 | );
49 | };
50 |
51 | export default BottomDrawer;
52 |
--------------------------------------------------------------------------------
/client/src/components/Header/index.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import "./index.scss";
3 | import { connect } from "react-redux";
4 | import { setSubreddit } from "../../actions/appActions";
5 |
6 | const Header = ({ subreddit, setSubreddit, fetchPosts }) => {
7 | const links = [
8 | "Following",
9 | | ,
10 | `/r/${subreddit}`
11 | ];
12 | const [sub, setSub] = useState("");
13 | return (
14 |
15 |
16 | {links.map((link, i) =>
17 | i === 2 ? (
18 |
19 | {link}
20 |
21 | ) : (
22 |
23 | {link}
24 |
25 | )
26 | )}
27 |
28 |
49 |
50 | );
51 | };
52 |
53 | export default connect(null, { setSubreddit })(Header);
54 |
--------------------------------------------------------------------------------
/server.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 | const server = express();
3 | const cors = require("cors");
4 | const axios = require("axios").default;
5 | const port = process.env.PORT || 5000;
6 | const router = express.Router();
7 |
8 | const BASE_URL = "https://reddit.com";
9 |
10 | const isEmptyObject = object => {
11 | for (let key in object) {
12 | if (object.hasOwnProperty(key)) {
13 | return false;
14 | }
15 | return true;
16 | }
17 | };
18 |
19 | const queryToString = query => {
20 | console.log(JSON.stringify(query));
21 | if (query && !isEmptyObject(query)) {
22 | return Object.keys(query)
23 | .map((key, i) =>
24 | i === 0 ? `?${key}=${query[key]}` : `&${key}=${query[key]}`
25 | )
26 | .reduce((prev, curr) => prev + curr, "");
27 | }
28 | };
29 |
30 | router.route("/r/:subreddit").get((req, res) => {
31 | axios
32 | .get(
33 | `${BASE_URL}/r/${req.params.subreddit}.json${queryToString(req.query)}`
34 | )
35 | .then(posts => {
36 | res.json(posts.data);
37 | })
38 | .catch(err => console.log(err));
39 | });
40 |
41 | router.route("/comments/:id").get((req, res) => {
42 | axios
43 | .get(
44 | `${BASE_URL}/comments/${req.params.id}.json${queryToString(req.query)}`
45 | )
46 | .then(comments => {
47 | res.json(comments.data);
48 | })
49 | .catch(err => console.error(err));
50 | });
51 |
52 | server.use(express.json());
53 | server.use(cors());
54 | server.use("/api", router);
55 | server.use(express.static("./client/build/"));
56 | if (process.env.NODE_ENV === "production") {
57 | server.get("/", (req, res) => {
58 | res.sendFile(path.resolve(__dirname, "client", "build", "index.html"));
59 | });
60 | }
61 |
62 | server.listen(port, () => console.log(`Reddit CORS fixer : Port ${port}`));
63 |
--------------------------------------------------------------------------------
/client/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
12 |
13 |
17 |
18 |
27 | rbitt
28 |
29 |
30 | You need to enable JavaScript to run this app.
31 |
32 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/client/src/stories/2-Display.stories.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import "../index.scss";
3 | import "tachyons";
4 | import Display from "../components/Display";
5 |
6 | export default {
7 | title: "Display",
8 | component: Display
9 | };
10 |
11 | export const FullImagePost = () => (
12 |
25 | );
26 |
27 | export const FullGIFPost = () => (
28 |
40 | );
41 |
42 | export const FullVideoEmbedPost = () => (
43 |
56 | );
57 |
--------------------------------------------------------------------------------
/client/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "client",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "@testing-library/jest-dom": "^4.2.4",
7 | "@testing-library/react": "^9.3.2",
8 | "@testing-library/user-event": "^7.1.2",
9 | "axios": "^0.19.2",
10 | "blurhash": "^1.1.3",
11 | "cors": "^2.8.5",
12 | "express": "^4.17.1",
13 | "loaders.css": "^0.1.2",
14 | "node-sass": "^4.13.1",
15 | "react": "^16.13.0",
16 | "react-blurhash": "^0.1.2",
17 | "react-dom": "^16.13.0",
18 | "react-icons": "^3.9.0",
19 | "react-loaders": "^3.0.1",
20 | "react-redux": "^7.2.0",
21 | "react-scripts": "3.4.0",
22 | "react-swipeable": "^5.5.1",
23 | "react-transition-group": "^4.3.0",
24 | "redux": "^4.0.5",
25 | "redux-thunk": "^2.3.0",
26 | "storybook": "^5.3.17",
27 | "tachyons": "^4.11.1"
28 | },
29 | "scripts": {
30 | "start": "react-scripts start",
31 | "build": "react-scripts build",
32 | "test": "react-scripts test",
33 | "eject": "react-scripts eject",
34 | "storybook": "start-storybook -p 9009 -s public",
35 | "build-storybook": "build-storybook -s public"
36 | },
37 | "eslintConfig": {
38 | "extends": "react-app"
39 | },
40 | "browserslist": {
41 | "production": [
42 | ">0.2%",
43 | "not dead",
44 | "not op_mini all"
45 | ],
46 | "development": [
47 | "last 1 chrome version",
48 | "last 1 firefox version",
49 | "last 1 safari version"
50 | ]
51 | },
52 | "devDependencies": {
53 | "@storybook/addon-actions": "^5.3.17",
54 | "@storybook/addon-links": "^5.3.17",
55 | "@storybook/addons": "^5.3.17",
56 | "@storybook/preset-create-react-app": "^2.1.1",
57 | "@storybook/preset-scss": "^1.0.2",
58 | "@storybook/react": "^5.3.17",
59 | "css-loader": "^3.4.2",
60 | "sass-loader": "^8.0.2",
61 | "style-loader": "^1.1.3"
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/client/src/components/Overlay/index.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect } from "react";
2 | import { IoIosHeart, IoIosChatbubbles, IoIosRedo } from "react-icons/io";
3 | import { comments } from "../../stories/5-Comments.stories";
4 | import { useSelector, useDispatch } from "react-redux";
5 | import { numToString, getChildren } from "../../utils/PostUtils";
6 | import Interactions from "../Interactions";
7 | import BottomDrawer from "../BottomDrawer";
8 | import "./index.scss";
9 | import Comments from "../Comments";
10 | import { fetchCommentsFromPost } from "../../actions/postsActions";
11 |
12 | const Overlay = ({ post, active }) => {
13 | const [commentsActive, setCommentsActive] = useState(false);
14 | const {count, posts, fetchingComment} = useSelector((state)=>state.posts);
15 | const dispatch = useDispatch();
16 | const interactions = [
17 | { icon: , stat: numToString(post.score) },
18 | {
19 | icon: ,
20 | stat: numToString(post.num_comments),
21 | onClick: () => setCommentsActive(true)
22 | },
23 | { icon: , stat: "4763" }
24 | ];
25 |
26 | useEffect(() => {
27 | if(commentsActive){
28 | if (posts.length) {
29 | dispatch(fetchCommentsFromPost(posts[count].id, ""));
30 | }
31 | }
32 | }, [dispatch, commentsActive]);
33 |
34 | if (active) {
35 | return (
36 |
37 |
38 |
43 | {fetchingComment ? Loading
: }
44 |
45 | {post.type !== "TEXT" ? (
46 |
{post.title}
47 | ) : null}
48 |
49 | );
50 | } else {
51 | return null;
52 | }
53 | };
54 |
55 | export default Overlay;
56 |
--------------------------------------------------------------------------------
/client/src/reducers/postsReducer.js:
--------------------------------------------------------------------------------
1 | import { postTypes as pt } from "../actions/types";
2 | import { formatResponse } from "../utils/AppUtils";
3 | import { fetchPostsFromSubreddit } from "../actions/appActions";
4 | import {
5 | mapOutChildren,
6 | recursiveMapOutChildren,
7 | getAllChildren
8 | } from "../utils/PostUtils";
9 |
10 | const initialState = {
11 | data: {},
12 | count: 3,
13 | posts: [],
14 | numPosts: 0,
15 | post: {},
16 | fetchingComment: false,
17 | };
18 |
19 | export const postsReducer = (state = initialState, action) => {
20 | switch (action.type) {
21 | case pt.SET_POSTS:
22 | console.log(`Setting posts to: `, action.payload);
23 | switch (action.payload.query) {
24 | case "BEFORE":
25 | return {
26 | ...state,
27 | posts: action.payload.posts,
28 | count: action.payload.posts.length - 1
29 | };
30 | case "AFTER":
31 | return {
32 | ...state,
33 | posts: action.payload.posts,
34 | count: 0
35 | };
36 | default:
37 | return {
38 | ...state,
39 | posts: action.payload.posts,
40 | count: 0
41 | };
42 | }
43 | case pt.SET_COUNT:
44 | console.log(state.posts[state.count]);
45 | return {
46 | ...state,
47 | count: action.payload
48 | };
49 | case pt.FETCHING_COMMENTS:
50 | return {
51 | ...state,
52 | fetchingComment: true
53 | }
54 | case pt.FETCH_COMMENTS_FROM_POST:
55 | // console.log("COMMENTS:", action.payload);
56 | let newPosts = [...state.posts];
57 | newPosts[state.count] = {
58 | ...newPosts[state.count],
59 | comments: action.payload
60 | };
61 | return {
62 | ...state,
63 | posts: newPosts
64 | };
65 | case pt.FINISHED_FETCHING_COMMENTS:
66 | return {
67 | ...state,
68 | fetchingComment: false
69 | }
70 | case pt.LOAD_NEXT_POST:
71 | default:
72 | return state;
73 | }
74 | };
75 |
--------------------------------------------------------------------------------
/client/src/App.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect, useCallback } from "react";
2 | import "./App.scss";
3 | import { setCount } from "./actions/postsActions";
4 | import { fetchPostsFromSubreddit } from "./actions/appActions";
5 | import { nextPost, fetchCommentsFromPost } from "./actions/postsActions";
6 | import Home from "./components/Views/Home";
7 | import { connect } from "react-redux";
8 | import { FullScreenLoader } from "./components/Loader";
9 | import { getMediaSrc } from "./utils/PostUtils";
10 |
11 | function App({
12 | app,
13 | data,
14 | posts,
15 | count,
16 | fetchPostsFromSubreddit,
17 | fetchCommentsFromPost,
18 | setCount
19 | }) {
20 | const loadNextPost = useCallback(() => {
21 | if (count === posts.length - 1) {
22 | fetchPostsFromSubreddit(
23 | app.subreddit,
24 | `?limit=25&after=${app.data.after}&count=${count}`
25 | );
26 | } else if (count < posts.length) {
27 | setCount(count + 1);
28 | }
29 | }, [count, app.subreddit]);
30 |
31 | const loadPreviousPost = useCallback(() => {
32 | if (count === 0) {
33 | if (app.data.before) {
34 | fetchPostsFromSubreddit(
35 | app.subreddit,
36 | `?limit=25&before=${app.data.before}&count=${posts.length -
37 | 1}`
38 | );
39 | }
40 | } else if (count > 0) {
41 | setCount(count - 1);
42 | }
43 | }, [count, app.subreddit]);
44 | // Initial Load
45 | useEffect(() => {
46 | fetchPostsFromSubreddit(app.subreddit);
47 | }, []);
48 |
49 | useEffect(() => {
50 | // Preload all posts
51 | posts.map(post => {
52 | new Image().src = post.thumbnail;
53 | });
54 | }, [posts]);
55 |
56 | // useEffect(() => {
57 | // if (posts.length) {
58 | // fetchCommentsFromPost(posts[count].id, "");
59 | // }
60 | // }, [count]);
61 |
62 | console.log(app.subreddit);
63 | return (
64 |
65 |
66 | loadNextPost()}
71 | loadPrevPost={() => loadPreviousPost()}
72 | />
73 |
74 | );
75 | }
76 |
77 | const mapStateToProps = state => ({
78 | posts: state.posts.posts,
79 | post: state.posts.post,
80 | count: state.posts.count,
81 | data: state.posts.data,
82 | app: state.app
83 | });
84 |
85 | const mapDispatchToProps = {
86 | fetchPostsFromSubreddit,
87 | fetchCommentsFromPost,
88 | setCount,
89 | nextPost
90 | };
91 |
92 | export default connect(mapStateToProps, mapDispatchToProps)(App);
93 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Reddit (but it's TikTok)
2 |
3 | I have long been a viewer of Reddit content. But now there is a new Social Media out there: TikTok. Now, I am not a fan of the content on there, but the app layout is not bad.
4 | So I did what anyone would do and took all of the content on Reddit and put it into Tiktok.
5 |
6 |
7 |
8 |
9 |
10 |
11 | ## How it works
12 |
13 | Client: React, Redux, Axios
14 | Server: Express
15 |
16 | The client side has been custom-made (and programmed) to look as close to TikTok as possible with some features altered to be more user-friendly w/ Reddit content.
17 | Currently, not every feature has been implemented. I'm not sure I intend to continue working on it but on the plus side you have the two most important features working (sorta).
18 |
19 | - Viewing Posts!
20 | - You also have the ability to switch subreddits using the search bar. (You have to click enter twice for some reason though...)
21 | - Comments!
22 |
23 | The server side is essentially just a wrapper over the Reddit API w/ two endpoints that enables you to fetch posts and comments. That's all I need right now.
24 | You're probably wondering why we need a wrapper if we're just doing API requests to reddit in the end anyways... Well, it's because of default browser rules on different devices.
25 | They seem to not like it when a website automatically sends requests to another server (it's a CORS error) which is solved by just fetching the data from a server that can disable that rule.
26 | So, the client needs to be bundled with the server to work on any device that is not a development machine.
27 |
28 | ## Further Improvements
29 |
30 | There is a lot more that can be done with this. Right now, the comments system only displays my username right now (this would be the first thing to fix).
31 | Here are some potential further improvements:
32 |
33 | - Sign in with your reddit account
34 | - Like posts
35 | - Comment on posts
36 | - Actually post something
37 | - Themes
38 | - Caching and pre-fetching content to make infinite scroll better.
39 | - Fixing the bug where swiping backwards on a post messes up the ordering of posts
40 | - Making the site design desktop friendly (please only use it on mobile right now :) )
41 |
42 | ## How to run?
43 |
44 | 1. Clone the repo into a directory
45 | 2. Run npm install on both the client and root folders
46 | 3. Then execute 'npm start' on both folders (root first, then client)
47 | 4. Navigate to appActions.js and postActions.js and change the URL variable in each to DEV_URL
48 | 5. Navigate to localhost:5000 and it should be working!
49 |
--------------------------------------------------------------------------------
/client/src/components/Display/index.js:
--------------------------------------------------------------------------------
1 | import React, { useState, useEffect, useCallback } from "react";
2 | import "./index.scss";
3 | import { removeEncoding } from "../../utils/PostUtils";
4 | import Overlay from "../Overlay";
5 | import Slider from "../Slider";
6 |
7 | const Display = ({ post, autoplay, loadPrevPost, loadNextPost }) => {
8 | const [active, setActive] = useState(true);
9 |
10 | const handleKeyPress = useCallback(event => {
11 | const { key } = event;
12 | if(key === 'ArrowDown'){
13 | loadNextPost();
14 | }
15 | if(key === 'ArrowUp'){
16 | loadPrevPost();
17 | }
18 | }, [post]);
19 |
20 | useEffect(() => {
21 | window.addEventListener('keydown', handleKeyPress);
22 | return () => {
23 | window.removeEventListener('keydown', handleKeyPress);
24 | }
25 | }, [handleKeyPress])
26 |
27 | return (
28 | {}}>
29 |
30 |
34 |
35 |
36 |
37 |
44 |
45 |
46 |
47 | );
48 | };
49 |
50 | const MediaDisplay = ({ type, src, thumbSrc, title, autoplay }) => {
51 | const [fullSrc, setFullSrc] = useState(thumbSrc);
52 | useEffect(() => {
53 | setFullSrc(thumbSrc);
54 | if (type === "IMAGE") {
55 | let image = new Image();
56 | image.src = src;
57 | // Ensure it is loading the correct image for the post
58 | if (image.src === src) {
59 | image.onload = () => setFullSrc(src);
60 | }
61 | }
62 | }, [src]);
63 | switch (type) {
64 | case "VIDEO":
65 | return (
66 |
73 | );
74 | case "IMAGE":
75 | return (
76 |
88 | );
89 | case "TEXT":
90 | return {removeEncoding(title)}
;
91 | default:
92 | return {removeEncoding(title)}
;
93 | }
94 | };
95 |
96 | export default Display;
97 |
--------------------------------------------------------------------------------
/client/README.md:
--------------------------------------------------------------------------------
1 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
2 |
3 | ## Available Scripts
4 |
5 | In the project directory, you can run:
6 |
7 | ### `yarn start`
8 |
9 | Runs the app in the development mode.
10 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
11 |
12 | The page will reload if you make edits.
13 | You will also see any lint errors in the console.
14 |
15 | ### `yarn test`
16 |
17 | Launches the test runner in the interactive watch mode.
18 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.
19 |
20 | ### `yarn build`
21 |
22 | Builds the app for production to the `build` folder.
23 | It correctly bundles React in production mode and optimizes the build for the best performance.
24 |
25 | The build is minified and the filenames include the hashes.
26 | Your app is ready to be deployed!
27 |
28 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.
29 |
30 | ### `yarn eject`
31 |
32 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!**
33 |
34 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
35 |
36 | Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own.
37 |
38 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it.
39 |
40 | ## Learn More
41 |
42 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).
43 |
44 | To learn React, check out the [React documentation](https://reactjs.org/).
45 |
46 | ### Code Splitting
47 |
48 | This section has moved here: https://facebook.github.io/create-react-app/docs/code-splitting
49 |
50 | ### Analyzing the Bundle Size
51 |
52 | This section has moved here: https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size
53 |
54 | ### Making a Progressive Web App
55 |
56 | This section has moved here: https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app
57 |
58 | ### Advanced Configuration
59 |
60 | This section has moved here: https://facebook.github.io/create-react-app/docs/advanced-configuration
61 |
62 | ### Deployment
63 |
64 | This section has moved here: https://facebook.github.io/create-react-app/docs/deployment
65 |
66 | ### `yarn build` fails to minify
67 |
68 | This section has moved here: https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify
69 |
--------------------------------------------------------------------------------
/client/src/utils/PostUtils.js:
--------------------------------------------------------------------------------
1 | export const removeEncoding = str => {
2 | let fixedStr = str;
3 | while (fixedStr.includes("&")) {
4 | fixedStr = fixedStr.replace("&", "&");
5 | }
6 | return fixedStr;
7 | };
8 |
9 | export const getEmbedFromContent = (content = "") => {
10 | let startPos = content.indexOf("src=");
11 | let sliced = content.slice(startPos);
12 | let endPos = sliced.indexOf('"');
13 | sliced = sliced.slice(0, endPos);
14 | return sliced;
15 | };
16 |
17 | export const getMediaSrc = post => {
18 | switch (post.type) {
19 | case "VIDEO_EMBED":
20 | if (post.secure_media_embed.content) {
21 | return getEmbedFromContent(post.secure_media_embed.content);
22 | } else if (post.media_embed.content) {
23 | return getEmbedFromContent(post.media_embed.content);
24 | }
25 | case "VIDEO":
26 | if (post.preview.reddit_video_preview) {
27 | return post.preview.reddit_video_preview.fallback_url;
28 | } else if (post.secure_media) {
29 | if (post.secure_media.reddit_video) {
30 | return post.secure_media.reddit_video.fallback_url;
31 | }
32 | }
33 | case "IMAGE":
34 | if (post.preview.images[0].source.url) {
35 | return removeEncoding(post.preview.images[0].source.url);
36 | } else if (post.thumbnail) {
37 | return post.thumbnail;
38 | }
39 | default:
40 | return "No image sources found";
41 | }
42 | };
43 |
44 | export const getChildren = replies =>
45 | replies.data.children.map(child => child.data);
46 |
47 | export const getPostType = post => {
48 | if (post.media_embed.content || post.secure_media_embed.content) {
49 | return "VIDEO_EMBED";
50 | } else if (post.is_video) {
51 | return "VIDEO";
52 | } else if (post.preview) {
53 | if (post.preview.reddit_video_preview) {
54 | return "VIDEO";
55 | } else if (post.preview.images[0].source.url) {
56 | return "IMAGE";
57 | }
58 | } else if (post.secure_media) {
59 | if (post.secure_media.reddit_video) {
60 | return "VIDEO";
61 | }
62 | } else {
63 | return "TEXT";
64 | }
65 | };
66 | export const numToString = value => {
67 | var suffixes = ["", "k", "m", "b", "t"];
68 | var suffixNum = Math.floor(("" + value).length / 3);
69 | var shortValue = parseFloat(
70 | (suffixNum != 0 ? value / Math.pow(1000, suffixNum) : value).toPrecision(4)
71 | );
72 | if (shortValue % 1 != 0) {
73 | shortValue = shortValue.toFixed(1);
74 | }
75 | return shortValue + suffixes[suffixNum];
76 | };
77 |
78 | export const getThumbnailSrc = post => {
79 | if (post.preview) {
80 | if (post.preview.images[0].resolutions[0]) {
81 | return removeEncoding(post.preview.images[0].resolutions[0].url);
82 | } else if (post.thumbnail) {
83 | return removeEncoding(post.thumbnail);
84 | } else {
85 | return "There was no suitable image";
86 | }
87 | }
88 | };
89 |
90 | export const formatPost = post => {
91 | let formattedPost = { ...post };
92 | formattedPost.type = getPostType(post);
93 | formattedPost.media = getMediaSrc(formattedPost);
94 | formattedPost.thumbnail = getThumbnailSrc(formattedPost);
95 | return formattedPost;
96 | };
97 |
--------------------------------------------------------------------------------
/client/src/components/Comments/index.js:
--------------------------------------------------------------------------------
1 | import React, { useState } from "react";
2 | import "./index.scss";
3 | import { IoIosArrowDown, IoIosArrowUp } from "react-icons/io";
4 | import { getChildren } from "../../utils/PostUtils";
5 |
6 | const COLOR_SCHEME = ["#1fab89", "#62d2a2", "#9df3c4", "#d7fbe8"];
7 | const COLOR_SCHEME_ALT = ["#fffcca", "#55e9bc", "#11d3bc", "#537780"];
8 | const COLOR_SCHEME_ALT_2 = ["#394a6d", "#3c9d9b", "#52de97", "#c0ffb3"];
9 |
10 | const Comment = ({ text, score, comments, colorScheme, author, depth = 0 }) => {
11 | const [collapsed, setCollapsed] = useState(depth % 3 === 0 ? false : true);
12 | const [bodyCollapsed, setBodyCollapsed] = useState(true);
13 | const handleCollapse = () => {
14 | setCollapsed(!collapsed);
15 | };
16 | return (
17 |
21 |
22 |
handleCollapse()}>
23 | handleCollapse()}>
24 | {collapsed ? : }
25 |
26 | {author} {" "}
27 | {score} points
28 | {collapsed && comments ? (
29 | comments.length === 0 ? null : (
30 | {`${comments.length} ${
31 | comments.length === 1 ? "comment" : "comments"
32 | }`}
33 | )
34 | ) : null}
35 |
36 | {!collapsed ? (
37 |
38 |
setBodyCollapsed(!bodyCollapsed)}>
39 | {bodyCollapsed && text ? text.slice(0, 256) + "..." : text}
40 |
41 | {comments
42 | ? comments.map(comment => (
43 |
60 | ) : null}
61 |
62 |
63 | );
64 | };
65 |
66 | const Comments = ({ comments }) => {
67 | return comments ? (
68 |
69 | {comments.map(comment => (
70 |
85 | ) : null;
86 | };
87 |
88 | export default Comments;
89 |
90 |
--------------------------------------------------------------------------------
/client/src/stories/5-Comments.stories.js:
--------------------------------------------------------------------------------
1 | import React from "react";
2 | import Comments from "../components/Comments";
3 | import "tachyons";
4 |
5 | export default {
6 | title: "Comments",
7 | component: Comments
8 | };
9 |
10 | export const comments = [
11 | {
12 | text:
13 | "I worked for a group home. We had a difficult group of residents, but the company things so much worse.\
14 | Every resident was 14-22 years old. They had moderate mental development delays (65-75 IQ range), they all had a psychiatric disorder (from severe ADHD to schizophrenia), and they had also all been convicted of a violent sexual crime.\
15 | \
16 | I worked 3rd shift. My normal hours were 10:30pm to 9am. Four days a week.\
17 | About six months into bareworking there, they did a massive layoff.\
18 | They went down to minimum staff to student ratio each shift, with nobody extra to call in if needed. That meant if someone called out, a person on the previous shift was forced.\
19 | It got to the point, where I was being forced 3 out of 4 shifts per week. And not just a few hours. I was working 10:30 pm to around 4:30 pm the next day, and still having to come in for my following shift. I had an hour commute each way.\
20 | So I'd get home at 5:30 pm from a 16 hour shift, and have to leave the house again four hours later.\
21 | Managed that for about a month. Then one morning I was told last minute I was being forced. Told them I was fucking done and walked out.\
22 | That month took a huge toll on my mental health. Swear it took me like a year to recover.",
23 | comments: [
24 | {
25 | text:
26 | "I feel you on this one. I worked at a similar type of facility. The violent incidents that got them housed there weren't all sex-related, but the residents were all diminished capacity in varying degrees. You can only get into a wrestling match, without backup, so many times before you realize your own safety is slightly more important than the facility's administrative annual bonuses.",
27 | score: 800,
28 | comments: [
29 | {
30 | text:
31 | "I feel you on this one. I worked at a similar type of facility. The violent incidents that got them housed there weren't all sex-related, but the residents were all diminished capacity in varying degrees. You can only get into a wrestling match, without backup, so many times before you realize your own safety is slightly more important than the facility's administrative annual bonuses."
32 | },
33 | {
34 | text:
35 | "Not to mention if you used just a little too much force you were in deep shit. Most people would end up going a week unpaid every few months because there was a complaint that had to be investigated.\
36 | Lost one of our best employees while I was there because one kid bit into his arm and he basically just responded naturally and backhanded the kid. Had a chunk of skin ripped off his arm, but fired immediately."
37 | }
38 | ]
39 | },
40 | {
41 | text:
42 | "Not to mention if you used just a little too much force you were in deep shit. Most people would end up going a week unpaid every few months because there was a complaint that had to be investigated.\
43 | Lost one of our best employees while I was there because one kid bit into his arm and he basically just responded naturally and backhanded the kid. Had a chunk of skin ripped off his arm, but fired immediately."
44 | }
45 | ]
46 | },
47 | {
48 | text:
49 | "I feel you on this one. I worked at a similar type of facility. The violent incidents that got them housed there weren't all sex-related, but the residents were all diminished capacity in varying degrees. You can only get into a wrestling match, without backup, so many times before you realize your own safety is slightly more important than the facility's administrative annual bonuses."
50 | },
51 | {
52 | text:
53 | "Not to mention if you used just a little too much force you were in deep shit. Most people would end up going a week unpaid every few months because there was a complaint that had to be investigated.\
54 | Lost one of our best employees while I was there because one kid bit into his arm and he basically just responded naturally and backhanded the kid. Had a chunk of skin ripped off his arm, but fired immediately.\
55 | "
56 | }
57 | ];
58 |
59 | export const DefaultComments = () => ;
60 |
--------------------------------------------------------------------------------
/client/src/serviceWorker.js:
--------------------------------------------------------------------------------
1 | // This optional code is used to register a service worker.
2 | // register() is not called by default.
3 |
4 | // This lets the app load faster on subsequent visits in production, and gives
5 | // it offline capabilities. However, it also means that developers (and users)
6 | // will only see deployed updates on subsequent visits to a page, after all the
7 | // existing tabs open on the page have been closed, since previously cached
8 | // resources are updated in the background.
9 |
10 | // To learn more about the benefits of this model and instructions on how to
11 | // opt-in, read https://bit.ly/CRA-PWA
12 |
13 | const isLocalhost = Boolean(
14 | window.location.hostname === 'localhost' ||
15 | // [::1] is the IPv6 localhost address.
16 | window.location.hostname === '[::1]' ||
17 | // 127.0.0.0/8 are considered localhost for IPv4.
18 | window.location.hostname.match(
19 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
20 | )
21 | );
22 |
23 | export function register(config) {
24 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
25 | // The URL constructor is available in all browsers that support SW.
26 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);
27 | if (publicUrl.origin !== window.location.origin) {
28 | // Our service worker won't work if PUBLIC_URL is on a different origin
29 | // from what our page is served on. This might happen if a CDN is used to
30 | // serve assets; see https://github.com/facebook/create-react-app/issues/2374
31 | return;
32 | }
33 |
34 | window.addEventListener('load', () => {
35 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
36 |
37 | if (isLocalhost) {
38 | // This is running on localhost. Let's check if a service worker still exists or not.
39 | checkValidServiceWorker(swUrl, config);
40 |
41 | // Add some additional logging to localhost, pointing developers to the
42 | // service worker/PWA documentation.
43 | navigator.serviceWorker.ready.then(() => {
44 | console.log(
45 | 'This web app is being served cache-first by a service ' +
46 | 'worker. To learn more, visit https://bit.ly/CRA-PWA'
47 | );
48 | });
49 | } else {
50 | // Is not localhost. Just register service worker
51 | registerValidSW(swUrl, config);
52 | }
53 | });
54 | }
55 | }
56 |
57 | function registerValidSW(swUrl, config) {
58 | navigator.serviceWorker
59 | .register(swUrl)
60 | .then(registration => {
61 | registration.onupdatefound = () => {
62 | const installingWorker = registration.installing;
63 | if (installingWorker == null) {
64 | return;
65 | }
66 | installingWorker.onstatechange = () => {
67 | if (installingWorker.state === 'installed') {
68 | if (navigator.serviceWorker.controller) {
69 | // At this point, the updated precached content has been fetched,
70 | // but the previous service worker will still serve the older
71 | // content until all client tabs are closed.
72 | console.log(
73 | 'New content is available and will be used when all ' +
74 | 'tabs for this page are closed. See https://bit.ly/CRA-PWA.'
75 | );
76 |
77 | // Execute callback
78 | if (config && config.onUpdate) {
79 | config.onUpdate(registration);
80 | }
81 | } else {
82 | // At this point, everything has been precached.
83 | // It's the perfect time to display a
84 | // "Content is cached for offline use." message.
85 | console.log('Content is cached for offline use.');
86 |
87 | // Execute callback
88 | if (config && config.onSuccess) {
89 | config.onSuccess(registration);
90 | }
91 | }
92 | }
93 | };
94 | };
95 | })
96 | .catch(error => {
97 | console.error('Error during service worker registration:', error);
98 | });
99 | }
100 |
101 | function checkValidServiceWorker(swUrl, config) {
102 | // Check if the service worker can be found. If it can't reload the page.
103 | fetch(swUrl, {
104 | headers: { 'Service-Worker': 'script' }
105 | })
106 | .then(response => {
107 | // Ensure service worker exists, and that we really are getting a JS file.
108 | const contentType = response.headers.get('content-type');
109 | if (
110 | response.status === 404 ||
111 | (contentType != null && contentType.indexOf('javascript') === -1)
112 | ) {
113 | // No service worker found. Probably a different app. Reload the page.
114 | navigator.serviceWorker.ready.then(registration => {
115 | registration.unregister().then(() => {
116 | window.location.reload();
117 | });
118 | });
119 | } else {
120 | // Service worker found. Proceed as normal.
121 | registerValidSW(swUrl, config);
122 | }
123 | })
124 | .catch(() => {
125 | console.log(
126 | 'No internet connection found. App is running in offline mode.'
127 | );
128 | });
129 | }
130 |
131 | export function unregister() {
132 | if ('serviceWorker' in navigator) {
133 | navigator.serviceWorker.ready
134 | .then(registration => {
135 | registration.unregister();
136 | })
137 | .catch(error => {
138 | console.error(error.message);
139 | });
140 | }
141 | }
142 |
--------------------------------------------------------------------------------
/yarn.lock:
--------------------------------------------------------------------------------
1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2 | # yarn lockfile v1
3 |
4 |
5 | abbrev@1:
6 | version "1.1.1"
7 | resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
8 | integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==
9 |
10 | accepts@~1.3.7:
11 | version "1.3.7"
12 | resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd"
13 | integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==
14 | dependencies:
15 | mime-types "~2.1.24"
16 | negotiator "0.6.2"
17 |
18 | ansi-align@^2.0.0:
19 | version "2.0.0"
20 | resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-2.0.0.tgz#c36aeccba563b89ceb556f3690f0b1d9e3547f7f"
21 | integrity sha1-w2rsy6VjuJzrVW82kPCx2eNUf38=
22 | dependencies:
23 | string-width "^2.0.0"
24 |
25 | ansi-regex@^3.0.0:
26 | version "3.0.0"
27 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
28 | integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=
29 |
30 | ansi-styles@^3.2.1:
31 | version "3.2.1"
32 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
33 | integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
34 | dependencies:
35 | color-convert "^1.9.0"
36 |
37 | anymatch@~3.1.1:
38 | version "3.1.1"
39 | resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.1.tgz#c55ecf02185e2469259399310c173ce31233b142"
40 | integrity sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==
41 | dependencies:
42 | normalize-path "^3.0.0"
43 | picomatch "^2.0.4"
44 |
45 | array-flatten@1.1.1:
46 | version "1.1.1"
47 | resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
48 | integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=
49 |
50 | axios@^0.19.2:
51 | version "0.19.2"
52 | resolved "https://registry.yarnpkg.com/axios/-/axios-0.19.2.tgz#3ea36c5d8818d0d5f8a8a97a6d36b86cdc00cb27"
53 | integrity sha512-fjgm5MvRHLhx+osE2xoekY70AhARk3a6hkN+3Io1jc00jtquGvxYlKlsFUhmUET0V5te6CcZI7lcv2Ym61mjHA==
54 | dependencies:
55 | follow-redirects "1.5.10"
56 |
57 | balanced-match@^1.0.0:
58 | version "1.0.0"
59 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
60 | integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
61 |
62 | binary-extensions@^2.0.0:
63 | version "2.0.0"
64 | resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.0.0.tgz#23c0df14f6a88077f5f986c0d167ec03c3d5537c"
65 | integrity sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==
66 |
67 | body-parser@1.19.0:
68 | version "1.19.0"
69 | resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a"
70 | integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==
71 | dependencies:
72 | bytes "3.1.0"
73 | content-type "~1.0.4"
74 | debug "2.6.9"
75 | depd "~1.1.2"
76 | http-errors "1.7.2"
77 | iconv-lite "0.4.24"
78 | on-finished "~2.3.0"
79 | qs "6.7.0"
80 | raw-body "2.4.0"
81 | type-is "~1.6.17"
82 |
83 | boxen@^1.2.1:
84 | version "1.3.0"
85 | resolved "https://registry.yarnpkg.com/boxen/-/boxen-1.3.0.tgz#55c6c39a8ba58d9c61ad22cd877532deb665a20b"
86 | integrity sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw==
87 | dependencies:
88 | ansi-align "^2.0.0"
89 | camelcase "^4.0.0"
90 | chalk "^2.0.1"
91 | cli-boxes "^1.0.0"
92 | string-width "^2.0.0"
93 | term-size "^1.2.0"
94 | widest-line "^2.0.0"
95 |
96 | brace-expansion@^1.1.7:
97 | version "1.1.11"
98 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
99 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
100 | dependencies:
101 | balanced-match "^1.0.0"
102 | concat-map "0.0.1"
103 |
104 | braces@~3.0.2:
105 | version "3.0.2"
106 | resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
107 | integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
108 | dependencies:
109 | fill-range "^7.0.1"
110 |
111 | bytes@3.1.0:
112 | version "3.1.0"
113 | resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6"
114 | integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==
115 |
116 | camelcase@^4.0.0:
117 | version "4.1.0"
118 | resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd"
119 | integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=
120 |
121 | capture-stack-trace@^1.0.0:
122 | version "1.0.1"
123 | resolved "https://registry.yarnpkg.com/capture-stack-trace/-/capture-stack-trace-1.0.1.tgz#a6c0bbe1f38f3aa0b92238ecb6ff42c344d4135d"
124 | integrity sha512-mYQLZnx5Qt1JgB1WEiMCf2647plpGeQ2NMR/5L0HNZzGQo4fuSPnK+wjfPnKZV0aiJDgzmWqqkV/g7JD+DW0qw==
125 |
126 | chalk@^2.0.1:
127 | version "2.4.2"
128 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
129 | integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
130 | dependencies:
131 | ansi-styles "^3.2.1"
132 | escape-string-regexp "^1.0.5"
133 | supports-color "^5.3.0"
134 |
135 | chokidar@^3.2.2:
136 | version "3.3.1"
137 | resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.3.1.tgz#c84e5b3d18d9a4d77558fef466b1bf16bbeb3450"
138 | integrity sha512-4QYCEWOcK3OJrxwvyyAOxFuhpvOVCYkr33LPfFNBjAD/w3sEzWsp2BUOkI4l9bHvWioAd0rc6NlHUOEaWkTeqg==
139 | dependencies:
140 | anymatch "~3.1.1"
141 | braces "~3.0.2"
142 | glob-parent "~5.1.0"
143 | is-binary-path "~2.1.0"
144 | is-glob "~4.0.1"
145 | normalize-path "~3.0.0"
146 | readdirp "~3.3.0"
147 | optionalDependencies:
148 | fsevents "~2.1.2"
149 |
150 | ci-info@^1.5.0:
151 | version "1.6.0"
152 | resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.6.0.tgz#2ca20dbb9ceb32d4524a683303313f0304b1e497"
153 | integrity sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==
154 |
155 | cli-boxes@^1.0.0:
156 | version "1.0.0"
157 | resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-1.0.0.tgz#4fa917c3e59c94a004cd61f8ee509da651687143"
158 | integrity sha1-T6kXw+WclKAEzWH47lCdplFocUM=
159 |
160 | color-convert@^1.9.0:
161 | version "1.9.3"
162 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
163 | integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
164 | dependencies:
165 | color-name "1.1.3"
166 |
167 | color-name@1.1.3:
168 | version "1.1.3"
169 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
170 | integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
171 |
172 | concat-map@0.0.1:
173 | version "0.0.1"
174 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
175 | integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
176 |
177 | configstore@^3.0.0:
178 | version "3.1.2"
179 | resolved "https://registry.yarnpkg.com/configstore/-/configstore-3.1.2.tgz#c6f25defaeef26df12dd33414b001fe81a543f8f"
180 | integrity sha512-vtv5HtGjcYUgFrXc6Kx747B83MRRVS5R1VTEQoXvuP+kMI+if6uywV0nDGoiydJRy4yk7h9od5Og0kxx4zUXmw==
181 | dependencies:
182 | dot-prop "^4.1.0"
183 | graceful-fs "^4.1.2"
184 | make-dir "^1.0.0"
185 | unique-string "^1.0.0"
186 | write-file-atomic "^2.0.0"
187 | xdg-basedir "^3.0.0"
188 |
189 | content-disposition@0.5.3:
190 | version "0.5.3"
191 | resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd"
192 | integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==
193 | dependencies:
194 | safe-buffer "5.1.2"
195 |
196 | content-type@~1.0.4:
197 | version "1.0.4"
198 | resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b"
199 | integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==
200 |
201 | cookie-signature@1.0.6:
202 | version "1.0.6"
203 | resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
204 | integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw=
205 |
206 | cookie@0.4.0:
207 | version "0.4.0"
208 | resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba"
209 | integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==
210 |
211 | cors@^2.8.5:
212 | version "2.8.5"
213 | resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29"
214 | integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==
215 | dependencies:
216 | object-assign "^4"
217 | vary "^1"
218 |
219 | create-error-class@^3.0.0:
220 | version "3.0.2"
221 | resolved "https://registry.yarnpkg.com/create-error-class/-/create-error-class-3.0.2.tgz#06be7abef947a3f14a30fd610671d401bca8b7b6"
222 | integrity sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=
223 | dependencies:
224 | capture-stack-trace "^1.0.0"
225 |
226 | cross-spawn@^5.0.1:
227 | version "5.1.0"
228 | resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449"
229 | integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=
230 | dependencies:
231 | lru-cache "^4.0.1"
232 | shebang-command "^1.2.0"
233 | which "^1.2.9"
234 |
235 | crypto-random-string@^1.0.0:
236 | version "1.0.0"
237 | resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e"
238 | integrity sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=
239 |
240 | debug@2.6.9, debug@^2.2.0:
241 | version "2.6.9"
242 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
243 | integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
244 | dependencies:
245 | ms "2.0.0"
246 |
247 | debug@=3.1.0:
248 | version "3.1.0"
249 | resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
250 | integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==
251 | dependencies:
252 | ms "2.0.0"
253 |
254 | debug@^3.2.6:
255 | version "3.2.6"
256 | resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
257 | integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==
258 | dependencies:
259 | ms "^2.1.1"
260 |
261 | deep-extend@^0.6.0:
262 | version "0.6.0"
263 | resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac"
264 | integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==
265 |
266 | depd@~1.1.2:
267 | version "1.1.2"
268 | resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
269 | integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=
270 |
271 | destroy@~1.0.4:
272 | version "1.0.4"
273 | resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80"
274 | integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=
275 |
276 | dot-prop@^4.1.0:
277 | version "4.2.0"
278 | resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57"
279 | integrity sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==
280 | dependencies:
281 | is-obj "^1.0.0"
282 |
283 | duplexer3@^0.1.4:
284 | version "0.1.4"
285 | resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2"
286 | integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=
287 |
288 | ee-first@1.1.1:
289 | version "1.1.1"
290 | resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
291 | integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=
292 |
293 | encodeurl@~1.0.2:
294 | version "1.0.2"
295 | resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
296 | integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=
297 |
298 | escape-html@~1.0.3:
299 | version "1.0.3"
300 | resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
301 | integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=
302 |
303 | escape-string-regexp@^1.0.5:
304 | version "1.0.5"
305 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
306 | integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
307 |
308 | etag@~1.8.1:
309 | version "1.8.1"
310 | resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
311 | integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=
312 |
313 | execa@^0.7.0:
314 | version "0.7.0"
315 | resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777"
316 | integrity sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=
317 | dependencies:
318 | cross-spawn "^5.0.1"
319 | get-stream "^3.0.0"
320 | is-stream "^1.1.0"
321 | npm-run-path "^2.0.0"
322 | p-finally "^1.0.0"
323 | signal-exit "^3.0.0"
324 | strip-eof "^1.0.0"
325 |
326 | express@^4.17.1:
327 | version "4.17.1"
328 | resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134"
329 | integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==
330 | dependencies:
331 | accepts "~1.3.7"
332 | array-flatten "1.1.1"
333 | body-parser "1.19.0"
334 | content-disposition "0.5.3"
335 | content-type "~1.0.4"
336 | cookie "0.4.0"
337 | cookie-signature "1.0.6"
338 | debug "2.6.9"
339 | depd "~1.1.2"
340 | encodeurl "~1.0.2"
341 | escape-html "~1.0.3"
342 | etag "~1.8.1"
343 | finalhandler "~1.1.2"
344 | fresh "0.5.2"
345 | merge-descriptors "1.0.1"
346 | methods "~1.1.2"
347 | on-finished "~2.3.0"
348 | parseurl "~1.3.3"
349 | path-to-regexp "0.1.7"
350 | proxy-addr "~2.0.5"
351 | qs "6.7.0"
352 | range-parser "~1.2.1"
353 | safe-buffer "5.1.2"
354 | send "0.17.1"
355 | serve-static "1.14.1"
356 | setprototypeof "1.1.1"
357 | statuses "~1.5.0"
358 | type-is "~1.6.18"
359 | utils-merge "1.0.1"
360 | vary "~1.1.2"
361 |
362 | fill-range@^7.0.1:
363 | version "7.0.1"
364 | resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
365 | integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
366 | dependencies:
367 | to-regex-range "^5.0.1"
368 |
369 | finalhandler@~1.1.2:
370 | version "1.1.2"
371 | resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d"
372 | integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==
373 | dependencies:
374 | debug "2.6.9"
375 | encodeurl "~1.0.2"
376 | escape-html "~1.0.3"
377 | on-finished "~2.3.0"
378 | parseurl "~1.3.3"
379 | statuses "~1.5.0"
380 | unpipe "~1.0.0"
381 |
382 | follow-redirects@1.5.10:
383 | version "1.5.10"
384 | resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.5.10.tgz#7b7a9f9aea2fdff36786a94ff643ed07f4ff5e2a"
385 | integrity sha512-0V5l4Cizzvqt5D44aTXbFZz+FtyXV1vrDN6qrelxtfYQKW0KO0W2T/hkE8xvGa/540LkZlkaUjO4ailYTFtHVQ==
386 | dependencies:
387 | debug "=3.1.0"
388 |
389 | forwarded@~0.1.2:
390 | version "0.1.2"
391 | resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84"
392 | integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=
393 |
394 | fresh@0.5.2:
395 | version "0.5.2"
396 | resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
397 | integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=
398 |
399 | fsevents@~2.1.2:
400 | version "2.1.2"
401 | resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.2.tgz#4c0a1fb34bc68e543b4b82a9ec392bfbda840805"
402 | integrity sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA==
403 |
404 | get-stream@^3.0.0:
405 | version "3.0.0"
406 | resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14"
407 | integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=
408 |
409 | glob-parent@~5.1.0:
410 | version "5.1.0"
411 | resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.0.tgz#5f4c1d1e748d30cd73ad2944b3577a81b081e8c2"
412 | integrity sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==
413 | dependencies:
414 | is-glob "^4.0.1"
415 |
416 | global-dirs@^0.1.0:
417 | version "0.1.1"
418 | resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-0.1.1.tgz#b319c0dd4607f353f3be9cca4c72fc148c49f445"
419 | integrity sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=
420 | dependencies:
421 | ini "^1.3.4"
422 |
423 | got@^6.7.1:
424 | version "6.7.1"
425 | resolved "https://registry.yarnpkg.com/got/-/got-6.7.1.tgz#240cd05785a9a18e561dc1b44b41c763ef1e8db0"
426 | integrity sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=
427 | dependencies:
428 | create-error-class "^3.0.0"
429 | duplexer3 "^0.1.4"
430 | get-stream "^3.0.0"
431 | is-redirect "^1.0.0"
432 | is-retry-allowed "^1.0.0"
433 | is-stream "^1.0.0"
434 | lowercase-keys "^1.0.0"
435 | safe-buffer "^5.0.1"
436 | timed-out "^4.0.0"
437 | unzip-response "^2.0.1"
438 | url-parse-lax "^1.0.0"
439 |
440 | graceful-fs@^4.1.11, graceful-fs@^4.1.2:
441 | version "4.2.3"
442 | resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423"
443 | integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==
444 |
445 | has-flag@^3.0.0:
446 | version "3.0.0"
447 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
448 | integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0=
449 |
450 | http-errors@1.7.2:
451 | version "1.7.2"
452 | resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f"
453 | integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==
454 | dependencies:
455 | depd "~1.1.2"
456 | inherits "2.0.3"
457 | setprototypeof "1.1.1"
458 | statuses ">= 1.5.0 < 2"
459 | toidentifier "1.0.0"
460 |
461 | http-errors@~1.7.2:
462 | version "1.7.3"
463 | resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06"
464 | integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==
465 | dependencies:
466 | depd "~1.1.2"
467 | inherits "2.0.4"
468 | setprototypeof "1.1.1"
469 | statuses ">= 1.5.0 < 2"
470 | toidentifier "1.0.0"
471 |
472 | iconv-lite@0.4.24:
473 | version "0.4.24"
474 | resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
475 | integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
476 | dependencies:
477 | safer-buffer ">= 2.1.2 < 3"
478 |
479 | ignore-by-default@^1.0.1:
480 | version "1.0.1"
481 | resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09"
482 | integrity sha1-SMptcvbGo68Aqa1K5odr44ieKwk=
483 |
484 | import-lazy@^2.1.0:
485 | version "2.1.0"
486 | resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43"
487 | integrity sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=
488 |
489 | imurmurhash@^0.1.4:
490 | version "0.1.4"
491 | resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
492 | integrity sha1-khi5srkoojixPcT7a21XbyMUU+o=
493 |
494 | inherits@2.0.3:
495 | version "2.0.3"
496 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
497 | integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
498 |
499 | inherits@2.0.4:
500 | version "2.0.4"
501 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
502 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
503 |
504 | ini@^1.3.4, ini@~1.3.0:
505 | version "1.3.5"
506 | resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927"
507 | integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==
508 |
509 | ipaddr.js@1.9.1:
510 | version "1.9.1"
511 | resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3"
512 | integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==
513 |
514 | is-binary-path@~2.1.0:
515 | version "2.1.0"
516 | resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09"
517 | integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==
518 | dependencies:
519 | binary-extensions "^2.0.0"
520 |
521 | is-ci@^1.0.10:
522 | version "1.2.1"
523 | resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.2.1.tgz#e3779c8ee17fccf428488f6e281187f2e632841c"
524 | integrity sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==
525 | dependencies:
526 | ci-info "^1.5.0"
527 |
528 | is-extglob@^2.1.1:
529 | version "2.1.1"
530 | resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
531 | integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=
532 |
533 | is-fullwidth-code-point@^2.0.0:
534 | version "2.0.0"
535 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f"
536 | integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=
537 |
538 | is-glob@^4.0.1, is-glob@~4.0.1:
539 | version "4.0.1"
540 | resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc"
541 | integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==
542 | dependencies:
543 | is-extglob "^2.1.1"
544 |
545 | is-installed-globally@^0.1.0:
546 | version "0.1.0"
547 | resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.1.0.tgz#0dfd98f5a9111716dd535dda6492f67bf3d25a80"
548 | integrity sha1-Df2Y9akRFxbdU13aZJL2e/PSWoA=
549 | dependencies:
550 | global-dirs "^0.1.0"
551 | is-path-inside "^1.0.0"
552 |
553 | is-npm@^1.0.0:
554 | version "1.0.0"
555 | resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-1.0.0.tgz#f2fb63a65e4905b406c86072765a1a4dc793b9f4"
556 | integrity sha1-8vtjpl5JBbQGyGBydloaTceTufQ=
557 |
558 | is-number@^7.0.0:
559 | version "7.0.0"
560 | resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
561 | integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
562 |
563 | is-obj@^1.0.0:
564 | version "1.0.1"
565 | resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f"
566 | integrity sha1-PkcprB9f3gJc19g6iW2rn09n2w8=
567 |
568 | is-path-inside@^1.0.0:
569 | version "1.0.1"
570 | resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036"
571 | integrity sha1-jvW33lBDej/cprToZe96pVy0gDY=
572 | dependencies:
573 | path-is-inside "^1.0.1"
574 |
575 | is-redirect@^1.0.0:
576 | version "1.0.0"
577 | resolved "https://registry.yarnpkg.com/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24"
578 | integrity sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=
579 |
580 | is-retry-allowed@^1.0.0:
581 | version "1.2.0"
582 | resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz#d778488bd0a4666a3be8a1482b9f2baafedea8b4"
583 | integrity sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==
584 |
585 | is-stream@^1.0.0, is-stream@^1.1.0:
586 | version "1.1.0"
587 | resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
588 | integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ=
589 |
590 | isexe@^2.0.0:
591 | version "2.0.0"
592 | resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
593 | integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=
594 |
595 | latest-version@^3.0.0:
596 | version "3.1.0"
597 | resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-3.1.0.tgz#a205383fea322b33b5ae3b18abee0dc2f356ee15"
598 | integrity sha1-ogU4P+oyKzO1rjsYq+4NwvNW7hU=
599 | dependencies:
600 | package-json "^4.0.0"
601 |
602 | lowercase-keys@^1.0.0:
603 | version "1.0.1"
604 | resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f"
605 | integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==
606 |
607 | lru-cache@^4.0.1:
608 | version "4.1.5"
609 | resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd"
610 | integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==
611 | dependencies:
612 | pseudomap "^1.0.2"
613 | yallist "^2.1.2"
614 |
615 | make-dir@^1.0.0:
616 | version "1.3.0"
617 | resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c"
618 | integrity sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==
619 | dependencies:
620 | pify "^3.0.0"
621 |
622 | media-typer@0.3.0:
623 | version "0.3.0"
624 | resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
625 | integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=
626 |
627 | merge-descriptors@1.0.1:
628 | version "1.0.1"
629 | resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61"
630 | integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=
631 |
632 | methods@~1.1.2:
633 | version "1.1.2"
634 | resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
635 | integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=
636 |
637 | mime-db@1.43.0:
638 | version "1.43.0"
639 | resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.43.0.tgz#0a12e0502650e473d735535050e7c8f4eb4fae58"
640 | integrity sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==
641 |
642 | mime-types@~2.1.24:
643 | version "2.1.26"
644 | resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.26.tgz#9c921fc09b7e149a65dfdc0da4d20997200b0a06"
645 | integrity sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==
646 | dependencies:
647 | mime-db "1.43.0"
648 |
649 | mime@1.6.0:
650 | version "1.6.0"
651 | resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
652 | integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
653 |
654 | minimatch@^3.0.4:
655 | version "3.0.4"
656 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
657 | integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
658 | dependencies:
659 | brace-expansion "^1.1.7"
660 |
661 | minimist@^1.2.0:
662 | version "1.2.5"
663 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
664 | integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
665 |
666 | ms@2.0.0:
667 | version "2.0.0"
668 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
669 | integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
670 |
671 | ms@2.1.1:
672 | version "2.1.1"
673 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a"
674 | integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==
675 |
676 | ms@^2.1.1:
677 | version "2.1.2"
678 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
679 | integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
680 |
681 | negotiator@0.6.2:
682 | version "0.6.2"
683 | resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb"
684 | integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==
685 |
686 | nodemon@^2.0.2:
687 | version "2.0.2"
688 | resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-2.0.2.tgz#9c7efeaaf9b8259295a97e5d4585ba8f0cbe50b0"
689 | integrity sha512-GWhYPMfde2+M0FsHnggIHXTqPDHXia32HRhh6H0d75Mt9FKUoCBvumNHr7LdrpPBTKxsWmIEOjoN+P4IU6Hcaw==
690 | dependencies:
691 | chokidar "^3.2.2"
692 | debug "^3.2.6"
693 | ignore-by-default "^1.0.1"
694 | minimatch "^3.0.4"
695 | pstree.remy "^1.1.7"
696 | semver "^5.7.1"
697 | supports-color "^5.5.0"
698 | touch "^3.1.0"
699 | undefsafe "^2.0.2"
700 | update-notifier "^2.5.0"
701 |
702 | nopt@~1.0.10:
703 | version "1.0.10"
704 | resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee"
705 | integrity sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=
706 | dependencies:
707 | abbrev "1"
708 |
709 | normalize-path@^3.0.0, normalize-path@~3.0.0:
710 | version "3.0.0"
711 | resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
712 | integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
713 |
714 | npm-run-path@^2.0.0:
715 | version "2.0.2"
716 | resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f"
717 | integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=
718 | dependencies:
719 | path-key "^2.0.0"
720 |
721 | object-assign@^4:
722 | version "4.1.1"
723 | resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
724 | integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
725 |
726 | on-finished@~2.3.0:
727 | version "2.3.0"
728 | resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947"
729 | integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=
730 | dependencies:
731 | ee-first "1.1.1"
732 |
733 | p-finally@^1.0.0:
734 | version "1.0.0"
735 | resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae"
736 | integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=
737 |
738 | package-json@^4.0.0:
739 | version "4.0.1"
740 | resolved "https://registry.yarnpkg.com/package-json/-/package-json-4.0.1.tgz#8869a0401253661c4c4ca3da6c2121ed555f5eed"
741 | integrity sha1-iGmgQBJTZhxMTKPabCEh7VVfXu0=
742 | dependencies:
743 | got "^6.7.1"
744 | registry-auth-token "^3.0.1"
745 | registry-url "^3.0.3"
746 | semver "^5.1.0"
747 |
748 | parseurl@~1.3.3:
749 | version "1.3.3"
750 | resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
751 | integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==
752 |
753 | path-is-inside@^1.0.1:
754 | version "1.0.2"
755 | resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53"
756 | integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=
757 |
758 | path-key@^2.0.0:
759 | version "2.0.1"
760 | resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40"
761 | integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=
762 |
763 | path-to-regexp@0.1.7:
764 | version "0.1.7"
765 | resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
766 | integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=
767 |
768 | picomatch@^2.0.4, picomatch@^2.0.7:
769 | version "2.2.1"
770 | resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.1.tgz#21bac888b6ed8601f831ce7816e335bc779f0a4a"
771 | integrity sha512-ISBaA8xQNmwELC7eOjqFKMESB2VIqt4PPDD0nsS95b/9dZXvVKOlz9keMSnoGGKcOHXfTvDD6WMaRoSc9UuhRA==
772 |
773 | pify@^3.0.0:
774 | version "3.0.0"
775 | resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176"
776 | integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=
777 |
778 | prepend-http@^1.0.1:
779 | version "1.0.4"
780 | resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc"
781 | integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=
782 |
783 | proxy-addr@~2.0.5:
784 | version "2.0.6"
785 | resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.6.tgz#fdc2336505447d3f2f2c638ed272caf614bbb2bf"
786 | integrity sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==
787 | dependencies:
788 | forwarded "~0.1.2"
789 | ipaddr.js "1.9.1"
790 |
791 | pseudomap@^1.0.2:
792 | version "1.0.2"
793 | resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3"
794 | integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM=
795 |
796 | pstree.remy@^1.1.7:
797 | version "1.1.7"
798 | resolved "https://registry.yarnpkg.com/pstree.remy/-/pstree.remy-1.1.7.tgz#c76963a28047ed61542dc361aa26ee55a7fa15f3"
799 | integrity sha512-xsMgrUwRpuGskEzBFkH8NmTimbZ5PcPup0LA8JJkHIm2IMUbQcpo3yeLNWVrufEYjh8YwtSVh0xz6UeWc5Oh5A==
800 |
801 | qs@6.7.0:
802 | version "6.7.0"
803 | resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc"
804 | integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==
805 |
806 | range-parser@~1.2.1:
807 | version "1.2.1"
808 | resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
809 | integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==
810 |
811 | raw-body@2.4.0:
812 | version "2.4.0"
813 | resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332"
814 | integrity sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==
815 | dependencies:
816 | bytes "3.1.0"
817 | http-errors "1.7.2"
818 | iconv-lite "0.4.24"
819 | unpipe "1.0.0"
820 |
821 | rc@^1.0.1, rc@^1.1.6:
822 | version "1.2.8"
823 | resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed"
824 | integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==
825 | dependencies:
826 | deep-extend "^0.6.0"
827 | ini "~1.3.0"
828 | minimist "^1.2.0"
829 | strip-json-comments "~2.0.1"
830 |
831 | readdirp@~3.3.0:
832 | version "3.3.0"
833 | resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.3.0.tgz#984458d13a1e42e2e9f5841b129e162f369aff17"
834 | integrity sha512-zz0pAkSPOXXm1viEwygWIPSPkcBYjW1xU5j/JBh5t9bGCJwa6f9+BJa6VaB2g+b55yVrmXzqkyLf4xaWYM0IkQ==
835 | dependencies:
836 | picomatch "^2.0.7"
837 |
838 | registry-auth-token@^3.0.1:
839 | version "3.4.0"
840 | resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-3.4.0.tgz#d7446815433f5d5ed6431cd5dca21048f66b397e"
841 | integrity sha512-4LM6Fw8eBQdwMYcES4yTnn2TqIasbXuwDx3um+QRs7S55aMKCBKBxvPXl2RiUjHwuJLTyYfxSpmfSAjQpcuP+A==
842 | dependencies:
843 | rc "^1.1.6"
844 | safe-buffer "^5.0.1"
845 |
846 | registry-url@^3.0.3:
847 | version "3.1.0"
848 | resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-3.1.0.tgz#3d4ef870f73dde1d77f0cf9a381432444e174942"
849 | integrity sha1-PU74cPc93h138M+aOBQyRE4XSUI=
850 | dependencies:
851 | rc "^1.0.1"
852 |
853 | safe-buffer@5.1.2:
854 | version "5.1.2"
855 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
856 | integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
857 |
858 | safe-buffer@^5.0.1:
859 | version "5.2.0"
860 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519"
861 | integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==
862 |
863 | "safer-buffer@>= 2.1.2 < 3":
864 | version "2.1.2"
865 | resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
866 | integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
867 |
868 | semver-diff@^2.0.0:
869 | version "2.1.0"
870 | resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36"
871 | integrity sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY=
872 | dependencies:
873 | semver "^5.0.3"
874 |
875 | semver@^5.0.3, semver@^5.1.0, semver@^5.7.1:
876 | version "5.7.1"
877 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
878 | integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
879 |
880 | send@0.17.1:
881 | version "0.17.1"
882 | resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8"
883 | integrity sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==
884 | dependencies:
885 | debug "2.6.9"
886 | depd "~1.1.2"
887 | destroy "~1.0.4"
888 | encodeurl "~1.0.2"
889 | escape-html "~1.0.3"
890 | etag "~1.8.1"
891 | fresh "0.5.2"
892 | http-errors "~1.7.2"
893 | mime "1.6.0"
894 | ms "2.1.1"
895 | on-finished "~2.3.0"
896 | range-parser "~1.2.1"
897 | statuses "~1.5.0"
898 |
899 | serve-static@1.14.1:
900 | version "1.14.1"
901 | resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9"
902 | integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==
903 | dependencies:
904 | encodeurl "~1.0.2"
905 | escape-html "~1.0.3"
906 | parseurl "~1.3.3"
907 | send "0.17.1"
908 |
909 | setprototypeof@1.1.1:
910 | version "1.1.1"
911 | resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683"
912 | integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==
913 |
914 | shebang-command@^1.2.0:
915 | version "1.2.0"
916 | resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"
917 | integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=
918 | dependencies:
919 | shebang-regex "^1.0.0"
920 |
921 | shebang-regex@^1.0.0:
922 | version "1.0.0"
923 | resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3"
924 | integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=
925 |
926 | signal-exit@^3.0.0, signal-exit@^3.0.2:
927 | version "3.0.2"
928 | resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
929 | integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=
930 |
931 | "statuses@>= 1.5.0 < 2", statuses@~1.5.0:
932 | version "1.5.0"
933 | resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
934 | integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=
935 |
936 | string-width@^2.0.0, string-width@^2.1.1:
937 | version "2.1.1"
938 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e"
939 | integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==
940 | dependencies:
941 | is-fullwidth-code-point "^2.0.0"
942 | strip-ansi "^4.0.0"
943 |
944 | strip-ansi@^4.0.0:
945 | version "4.0.0"
946 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f"
947 | integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8=
948 | dependencies:
949 | ansi-regex "^3.0.0"
950 |
951 | strip-eof@^1.0.0:
952 | version "1.0.0"
953 | resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"
954 | integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=
955 |
956 | strip-json-comments@~2.0.1:
957 | version "2.0.1"
958 | resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
959 | integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo=
960 |
961 | supports-color@^5.3.0, supports-color@^5.5.0:
962 | version "5.5.0"
963 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
964 | integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
965 | dependencies:
966 | has-flag "^3.0.0"
967 |
968 | term-size@^1.2.0:
969 | version "1.2.0"
970 | resolved "https://registry.yarnpkg.com/term-size/-/term-size-1.2.0.tgz#458b83887f288fc56d6fffbfad262e26638efa69"
971 | integrity sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk=
972 | dependencies:
973 | execa "^0.7.0"
974 |
975 | timed-out@^4.0.0:
976 | version "4.0.1"
977 | resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f"
978 | integrity sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=
979 |
980 | to-regex-range@^5.0.1:
981 | version "5.0.1"
982 | resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
983 | integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
984 | dependencies:
985 | is-number "^7.0.0"
986 |
987 | toidentifier@1.0.0:
988 | version "1.0.0"
989 | resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553"
990 | integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==
991 |
992 | touch@^3.1.0:
993 | version "3.1.0"
994 | resolved "https://registry.yarnpkg.com/touch/-/touch-3.1.0.tgz#fe365f5f75ec9ed4e56825e0bb76d24ab74af83b"
995 | integrity sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==
996 | dependencies:
997 | nopt "~1.0.10"
998 |
999 | type-is@~1.6.17, type-is@~1.6.18:
1000 | version "1.6.18"
1001 | resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131"
1002 | integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==
1003 | dependencies:
1004 | media-typer "0.3.0"
1005 | mime-types "~2.1.24"
1006 |
1007 | undefsafe@^2.0.2:
1008 | version "2.0.3"
1009 | resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.3.tgz#6b166e7094ad46313b2202da7ecc2cd7cc6e7aae"
1010 | integrity sha512-nrXZwwXrD/T/JXeygJqdCO6NZZ1L66HrxM/Z7mIq2oPanoN0F1nLx3lwJMu6AwJY69hdixaFQOuoYsMjE5/C2A==
1011 | dependencies:
1012 | debug "^2.2.0"
1013 |
1014 | unique-string@^1.0.0:
1015 | version "1.0.0"
1016 | resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-1.0.0.tgz#9e1057cca851abb93398f8b33ae187b99caec11a"
1017 | integrity sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo=
1018 | dependencies:
1019 | crypto-random-string "^1.0.0"
1020 |
1021 | unpipe@1.0.0, unpipe@~1.0.0:
1022 | version "1.0.0"
1023 | resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
1024 | integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=
1025 |
1026 | unzip-response@^2.0.1:
1027 | version "2.0.1"
1028 | resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-2.0.1.tgz#d2f0f737d16b0615e72a6935ed04214572d56f97"
1029 | integrity sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c=
1030 |
1031 | update-notifier@^2.5.0:
1032 | version "2.5.0"
1033 | resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-2.5.0.tgz#d0744593e13f161e406acb1d9408b72cad08aff6"
1034 | integrity sha512-gwMdhgJHGuj/+wHJJs9e6PcCszpxR1b236igrOkUofGhqJuG+amlIKwApH1IW1WWl7ovZxsX49lMBWLxSdm5Dw==
1035 | dependencies:
1036 | boxen "^1.2.1"
1037 | chalk "^2.0.1"
1038 | configstore "^3.0.0"
1039 | import-lazy "^2.1.0"
1040 | is-ci "^1.0.10"
1041 | is-installed-globally "^0.1.0"
1042 | is-npm "^1.0.0"
1043 | latest-version "^3.0.0"
1044 | semver-diff "^2.0.0"
1045 | xdg-basedir "^3.0.0"
1046 |
1047 | url-parse-lax@^1.0.0:
1048 | version "1.0.0"
1049 | resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73"
1050 | integrity sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=
1051 | dependencies:
1052 | prepend-http "^1.0.1"
1053 |
1054 | utils-merge@1.0.1:
1055 | version "1.0.1"
1056 | resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
1057 | integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=
1058 |
1059 | vary@^1, vary@~1.1.2:
1060 | version "1.1.2"
1061 | resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
1062 | integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=
1063 |
1064 | which@^1.2.9:
1065 | version "1.3.1"
1066 | resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
1067 | integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
1068 | dependencies:
1069 | isexe "^2.0.0"
1070 |
1071 | widest-line@^2.0.0:
1072 | version "2.0.1"
1073 | resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-2.0.1.tgz#7438764730ec7ef4381ce4df82fb98a53142a3fc"
1074 | integrity sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA==
1075 | dependencies:
1076 | string-width "^2.1.1"
1077 |
1078 | write-file-atomic@^2.0.0:
1079 | version "2.4.3"
1080 | resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.4.3.tgz#1fd2e9ae1df3e75b8d8c367443c692d4ca81f481"
1081 | integrity sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==
1082 | dependencies:
1083 | graceful-fs "^4.1.11"
1084 | imurmurhash "^0.1.4"
1085 | signal-exit "^3.0.2"
1086 |
1087 | xdg-basedir@^3.0.0:
1088 | version "3.0.0"
1089 | resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4"
1090 | integrity sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=
1091 |
1092 | yallist@^2.1.2:
1093 | version "2.1.2"
1094 | resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"
1095 | integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=
1096 |
--------------------------------------------------------------------------------