├── public
├── favicon.ico
├── manifest.json
└── index.html
├── src
├── index.js
├── App.test.js
├── index.css
├── App.css
├── components
│ ├── navbar.component.js
│ ├── create-user.component.js
│ ├── exercises-list.component.js
│ ├── create-exercise.component.js
│ └── edit-exercise.component.js
├── App.js
├── logo.svg
└── serviceWorker.js
├── README.md
├── backend
├── models
│ ├── user.model.js
│ └── exercise.model.js
├── package.json
├── routes
│ ├── users.js
│ └── exercises.js
├── server.js
└── package-lock.json
├── .gitignore
└── package.json
/public/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/beaucarnes/mern-exercise-tracker-mongodb/HEAD/public/favicon.ico
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './App';
4 |
5 | ReactDOM.render(, document.getElementById('root'));
--------------------------------------------------------------------------------
/src/App.test.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import ReactDOM from 'react-dom';
3 | import App from './App';
4 |
5 | it('renders without crashing', () => {
6 | const div = document.createElement('div');
7 | ReactDOM.render(, div);
8 | ReactDOM.unmountComponentAtNode(div);
9 | });
10 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Code for MERN tutorial.
2 |
3 | Video Tutorial: https://www.youtube.com/watch?v=7CqJlxBYj-M
4 |
5 | Article Tutorial: https://medium.com/@beaucarnes/learn-the-mern-stack-by-building-an-exercise-tracker-mern-tutorial-59c13c1237a1
6 |
7 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).
8 |
--------------------------------------------------------------------------------
/public/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "short_name": "React App",
3 | "name": "Create React App Sample",
4 | "icons": [
5 | {
6 | "src": "favicon.ico",
7 | "sizes": "64x64 32x32 24x24 16x16",
8 | "type": "image/x-icon"
9 | }
10 | ],
11 | "start_url": ".",
12 | "display": "standalone",
13 | "theme_color": "#000000",
14 | "background_color": "#ffffff"
15 | }
16 |
--------------------------------------------------------------------------------
/backend/models/user.model.js:
--------------------------------------------------------------------------------
1 | const mongoose = require('mongoose');
2 |
3 | const Schema = mongoose.Schema;
4 |
5 | const userSchema = new Schema({
6 | username: {
7 | type: String,
8 | required: true,
9 | unique: true,
10 | trim: true,
11 | minlength: 3
12 | },
13 | }, {
14 | timestamps: true,
15 | });
16 |
17 | const User = mongoose.model('User', userSchema);
18 |
19 | module.exports = User;
--------------------------------------------------------------------------------
/src/index.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin: 0;
3 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
4 | "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
5 | sans-serif;
6 | -webkit-font-smoothing: antialiased;
7 | -moz-osx-font-smoothing: grayscale;
8 | }
9 |
10 | code {
11 | font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
12 | monospace;
13 | }
14 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2 |
3 | # dependencies
4 | /node_modules
5 | backend/node_modules
6 | /.pnp
7 | .pnp.js
8 |
9 | # testing
10 | /coverage
11 |
12 | # production
13 | /build
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 |
--------------------------------------------------------------------------------
/backend/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "backend",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "keywords": [],
10 | "author": "",
11 | "license": "ISC",
12 | "dependencies": {
13 | "body-parser": "^1.19.0",
14 | "cors": "^2.8.5",
15 | "dotenv": "^8.0.0",
16 | "express": "^4.16.4",
17 | "mongoose": "^5.5.7"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/backend/models/exercise.model.js:
--------------------------------------------------------------------------------
1 | const mongoose = require('mongoose');
2 |
3 | const Schema = mongoose.Schema;
4 |
5 | const exerciseSchema = new Schema({
6 | username: { type: String, required: true },
7 | description: { type: String, required: true },
8 | duration: { type: Number, required: true },
9 | date: { type: Date, required: true },
10 | }, {
11 | timestamps: true,
12 | });
13 |
14 | const Exercise = mongoose.model('Exercise', exerciseSchema);
15 |
16 | module.exports = Exercise;
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | Exercise Tracker
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/backend/routes/users.js:
--------------------------------------------------------------------------------
1 | const router = require('express').Router();
2 | let User = require('../models/user.model');
3 |
4 | router.route('/').get((req, res) => {
5 | User.find()
6 | .then(users => res.json(users))
7 | .catch(err => res.status(400).json('Error: ' + err));
8 | });
9 |
10 | router.route('/add').post((req, res) => {
11 | const username = req.body.username;
12 |
13 | const newUser = new User({username});
14 |
15 | newUser.save()
16 | .then(() => res.json('User added!'))
17 | .catch(err => res.status(400).json('Error: ' + err));
18 | });
19 |
20 | module.exports = router;
--------------------------------------------------------------------------------
/src/App.css:
--------------------------------------------------------------------------------
1 | .App {
2 | text-align: center;
3 | }
4 |
5 | .App-logo {
6 | animation: App-logo-spin infinite 20s linear;
7 | height: 40vmin;
8 | pointer-events: none;
9 | }
10 |
11 | .App-header {
12 | background-color: #282c34;
13 | min-height: 100vh;
14 | display: flex;
15 | flex-direction: column;
16 | align-items: center;
17 | justify-content: center;
18 | font-size: calc(10px + 2vmin);
19 | color: white;
20 | }
21 |
22 | .App-link {
23 | color: #61dafb;
24 | }
25 |
26 | @keyframes App-logo-spin {
27 | from {
28 | transform: rotate(0deg);
29 | }
30 | to {
31 | transform: rotate(360deg);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/backend/server.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const cors = require('cors');
3 | const mongoose = require('mongoose');
4 |
5 | require('dotenv').config();
6 |
7 | const app = express();
8 | const port = process.env.PORT || 5000;
9 |
10 | app.use(cors());
11 | app.use(express.json());
12 |
13 | const uri = process.env.ATLAS_URI;
14 | mongoose.connect(uri, { useNewUrlParser: true, useCreateIndex: true }
15 | );
16 | const connection = mongoose.connection;
17 | connection.once('open', () => {
18 | console.log("MongoDB database connection established successfully");
19 | })
20 |
21 | const exercisesRouter = require('./routes/exercises');
22 | const usersRouter = require('./routes/users');
23 |
24 | app.use('/exercises', exercisesRouter);
25 | app.use('/users', usersRouter);
26 |
27 | app.listen(port, () => {
28 | console.log(`Server is running on port: ${port}`);
29 | });
30 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "mern-tracker",
3 | "version": "0.1.0",
4 | "private": true,
5 | "dependencies": {
6 | "axios": "^0.18.0",
7 | "bootstrap": "^4.3.1",
8 | "react": "^16.8.6",
9 | "react-datepicker": "^2.5.0",
10 | "react-dom": "^16.8.6",
11 | "react-router-dom": "^5.0.0",
12 | "react-scripts": "3.0.1"
13 | },
14 | "scripts": {
15 | "start": "react-scripts start",
16 | "build": "react-scripts build",
17 | "test": "react-scripts test",
18 | "eject": "react-scripts eject"
19 | },
20 | "eslintConfig": {
21 | "extends": "react-app"
22 | },
23 | "browserslist": {
24 | "production": [
25 | ">0.2%",
26 | "not dead",
27 | "not op_mini all"
28 | ],
29 | "development": [
30 | "last 1 chrome version",
31 | "last 1 firefox version",
32 | "last 1 safari version"
33 | ]
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/components/navbar.component.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { Link } from 'react-router-dom';
3 |
4 | export default class Navbar extends Component {
5 |
6 | render() {
7 | return (
8 |
24 | );
25 | }
26 | }
--------------------------------------------------------------------------------
/src/App.js:
--------------------------------------------------------------------------------
1 | import React from 'react';
2 | import "bootstrap/dist/css/bootstrap.min.css";
3 | import { BrowserRouter as Router, Route} from "react-router-dom";
4 |
5 | import Navbar from "./components/navbar.component"
6 | import ExercisesList from "./components/exercises-list.component";
7 | import EditExercise from "./components/edit-exercise.component";
8 | import CreateExercise from "./components/create-exercise.component";
9 | import CreateUser from "./components/create-user.component";
10 |
11 | function App() {
12 | return (
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | );
24 | }
25 |
26 | export default App;
27 |
--------------------------------------------------------------------------------
/src/components/create-user.component.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import axios from 'axios';
3 |
4 | export default class CreateUser extends Component {
5 | constructor(props) {
6 | super(props);
7 |
8 | this.onChangeUsername = this.onChangeUsername.bind(this);
9 | this.onSubmit = this.onSubmit.bind(this);
10 |
11 | this.state = {
12 | username: ''
13 | }
14 | }
15 |
16 | onChangeUsername(e) {
17 | this.setState({
18 | username: e.target.value
19 | })
20 | }
21 |
22 | onSubmit(e) {
23 | e.preventDefault();
24 |
25 | const user = {
26 | username: this.state.username
27 | }
28 |
29 | console.log(user);
30 |
31 | axios.post('http://localhost:5000/users/add', user)
32 | .then(res => console.log(res.data));
33 |
34 | this.setState({
35 | username: ''
36 | })
37 | }
38 |
39 | render() {
40 | return (
41 |
42 |
Create New User
43 |
57 |
58 | )
59 | }
60 | }
--------------------------------------------------------------------------------
/backend/routes/exercises.js:
--------------------------------------------------------------------------------
1 | const router = require('express').Router();
2 | let Exercise = require('../models/exercise.model');
3 |
4 | router.route('/').get((req, res) => {
5 | Exercise.find()
6 | .then(exercises => res.json(exercises))
7 | .catch(err => res.status(400).json('Error: ' + err));
8 | });
9 |
10 | router.route('/add').post((req, res) => {
11 | const username = req.body.username;
12 | const description = req.body.description;
13 | const duration = Number(req.body.duration);
14 | const date = Date.parse(req.body.date);
15 |
16 | const newExercise = new Exercise({
17 | username,
18 | description,
19 | duration,
20 | date,
21 | });
22 |
23 | newExercise.save()
24 | .then(() => res.json('Exercise added!'))
25 | .catch(err => res.status(400).json('Error: ' + err));
26 | });
27 |
28 | router.route('/:id').get((req, res) => {
29 | Exercise.findById(req.params.id)
30 | .then(exercise => res.json(exercise))
31 | .catch(err => res.status(400).json('Error: ' + err));
32 | });
33 |
34 | router.route('/:id').delete((req, res) => {
35 | Exercise.findByIdAndDelete(req.params.id)
36 | .then(() => res.json('Exercise deleted.'))
37 | .catch(err => res.status(400).json('Error: ' + err));
38 | });
39 |
40 | router.route('/update/:id').post((req, res) => {
41 | Exercise.findById(req.params.id)
42 | .then(exercise => {
43 | exercise.username = req.body.username;
44 | exercise.description = req.body.description;
45 | exercise.duration = Number(req.body.duration);
46 | exercise.date = Date.parse(req.body.date);
47 |
48 | exercise.save()
49 | .then(() => res.json('Exercise updated!'))
50 | .catch(err => res.status(400).json('Error: ' + err));
51 | })
52 | .catch(err => res.status(400).json('Error: ' + err));
53 | });
54 |
55 | module.exports = router;
--------------------------------------------------------------------------------
/src/components/exercises-list.component.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import { Link } from 'react-router-dom';
3 | import axios from 'axios';
4 |
5 | const Exercise = props => (
6 |
7 | | {props.exercise.username} |
8 | {props.exercise.description} |
9 | {props.exercise.duration} |
10 | {props.exercise.date.substring(0,10)} |
11 |
12 | edit | { props.deleteExercise(props.exercise._id) }}>delete
13 | |
14 |
15 | )
16 |
17 | export default class ExercisesList extends Component {
18 | constructor(props) {
19 | super(props);
20 |
21 | this.deleteExercise = this.deleteExercise.bind(this)
22 |
23 | this.state = {exercises: []};
24 | }
25 |
26 | componentDidMount() {
27 | axios.get('http://localhost:5000/exercises/')
28 | .then(response => {
29 | this.setState({ exercises: response.data })
30 | })
31 | .catch((error) => {
32 | console.log(error);
33 | })
34 | }
35 |
36 | deleteExercise(id) {
37 | axios.delete('http://localhost:5000/exercises/'+id)
38 | .then(response => { console.log(response.data)});
39 |
40 | this.setState({
41 | exercises: this.state.exercises.filter(el => el._id !== id)
42 | })
43 | }
44 |
45 | exerciseList() {
46 | return this.state.exercises.map(currentexercise => {
47 | return ;
48 | })
49 | }
50 |
51 | render() {
52 | return (
53 |
54 |
Logged Exercises
55 |
56 |
57 |
58 | | Username |
59 | Description |
60 | Duration |
61 | Date |
62 | Actions |
63 |
64 |
65 |
66 | { this.exerciseList() }
67 |
68 |
69 |
70 | )
71 | }
72 | }
--------------------------------------------------------------------------------
/src/logo.svg:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/src/components/create-exercise.component.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import axios from 'axios';
3 | import DatePicker from 'react-datepicker';
4 | import "react-datepicker/dist/react-datepicker.css";
5 |
6 | export default class CreateExercise extends Component {
7 | constructor(props) {
8 | super(props);
9 |
10 | this.onChangeUsername = this.onChangeUsername.bind(this);
11 | this.onChangeDescription = this.onChangeDescription.bind(this);
12 | this.onChangeDuration = this.onChangeDuration.bind(this);
13 | this.onChangeDate = this.onChangeDate.bind(this);
14 | this.onSubmit = this.onSubmit.bind(this);
15 |
16 | this.state = {
17 | username: '',
18 | description: '',
19 | duration: 0,
20 | date: new Date(),
21 | users: []
22 | }
23 | }
24 |
25 | componentDidMount() {
26 | axios.get('http://localhost:5000/users/')
27 | .then(response => {
28 | if (response.data.length > 0) {
29 | this.setState({
30 | users: response.data.map(user => user.username),
31 | username: response.data[0].username
32 | })
33 | }
34 | })
35 | .catch((error) => {
36 | console.log(error);
37 | })
38 |
39 | }
40 |
41 | onChangeUsername(e) {
42 | this.setState({
43 | username: e.target.value
44 | })
45 | }
46 |
47 | onChangeDescription(e) {
48 | this.setState({
49 | description: e.target.value
50 | })
51 | }
52 |
53 | onChangeDuration(e) {
54 | this.setState({
55 | duration: e.target.value
56 | })
57 | }
58 |
59 | onChangeDate(date) {
60 | this.setState({
61 | date: date
62 | })
63 | }
64 |
65 | onSubmit(e) {
66 | e.preventDefault();
67 |
68 | const exercise = {
69 | username: this.state.username,
70 | description: this.state.description,
71 | duration: this.state.duration,
72 | date: this.state.date
73 | }
74 |
75 | console.log(exercise);
76 |
77 | axios.post('http://localhost:5000/exercises/add', exercise)
78 | .then(res => console.log(res.data));
79 |
80 | window.location = '/';
81 | }
82 |
83 | render() {
84 | return (
85 |
86 |
Create New Exercise Log
87 |
137 |
138 | )
139 | }
140 | }
--------------------------------------------------------------------------------
/src/components/edit-exercise.component.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import axios from 'axios';
3 | import DatePicker from 'react-datepicker';
4 | import "react-datepicker/dist/react-datepicker.css";
5 |
6 | export default class EditExercise extends Component {
7 | constructor(props) {
8 | super(props);
9 |
10 | this.onChangeUsername = this.onChangeUsername.bind(this);
11 | this.onChangeDescription = this.onChangeDescription.bind(this);
12 | this.onChangeDuration = this.onChangeDuration.bind(this);
13 | this.onChangeDate = this.onChangeDate.bind(this);
14 | this.onSubmit = this.onSubmit.bind(this);
15 |
16 | this.state = {
17 | username: '',
18 | description: '',
19 | duration: 0,
20 | date: new Date(),
21 | users: []
22 | }
23 | }
24 |
25 | componentDidMount() {
26 | axios.get('http://localhost:5000/exercises/'+this.props.match.params.id)
27 | .then(response => {
28 | this.setState({
29 | username: response.data.username,
30 | description: response.data.description,
31 | duration: response.data.duration,
32 | date: new Date(response.data.date)
33 | })
34 | })
35 | .catch(function (error) {
36 | console.log(error);
37 | })
38 |
39 | axios.get('http://localhost:5000/users/')
40 | .then(response => {
41 | if (response.data.length > 0) {
42 | this.setState({
43 | users: response.data.map(user => user.username),
44 | })
45 | }
46 | })
47 | .catch((error) => {
48 | console.log(error);
49 | })
50 |
51 | }
52 |
53 | onChangeUsername(e) {
54 | this.setState({
55 | username: e.target.value
56 | })
57 | }
58 |
59 | onChangeDescription(e) {
60 | this.setState({
61 | description: e.target.value
62 | })
63 | }
64 |
65 | onChangeDuration(e) {
66 | this.setState({
67 | duration: e.target.value
68 | })
69 | }
70 |
71 | onChangeDate(date) {
72 | this.setState({
73 | date: date
74 | })
75 | }
76 |
77 | onSubmit(e) {
78 | e.preventDefault();
79 |
80 | const exercise = {
81 | username: this.state.username,
82 | description: this.state.description,
83 | duration: this.state.duration,
84 | date: this.state.date
85 | }
86 |
87 | console.log(exercise);
88 |
89 | axios.post('http://localhost:5000/exercises/update/' + this.props.match.params.id, exercise)
90 | .then(res => console.log(res.data));
91 |
92 | window.location = '/';
93 | }
94 |
95 | render() {
96 | return (
97 |
98 |
Edit Exercise Log
99 |
149 |
150 | )
151 | }
152 | }
--------------------------------------------------------------------------------
/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.1/8 is 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 | .then(response => {
105 | // Ensure service worker exists, and that we really are getting a JS file.
106 | const contentType = response.headers.get('content-type');
107 | if (
108 | response.status === 404 ||
109 | (contentType != null && contentType.indexOf('javascript') === -1)
110 | ) {
111 | // No service worker found. Probably a different app. Reload the page.
112 | navigator.serviceWorker.ready.then(registration => {
113 | registration.unregister().then(() => {
114 | window.location.reload();
115 | });
116 | });
117 | } else {
118 | // Service worker found. Proceed as normal.
119 | registerValidSW(swUrl, config);
120 | }
121 | })
122 | .catch(() => {
123 | console.log(
124 | 'No internet connection found. App is running in offline mode.'
125 | );
126 | });
127 | }
128 |
129 | export function unregister() {
130 | if ('serviceWorker' in navigator) {
131 | navigator.serviceWorker.ready.then(registration => {
132 | registration.unregister();
133 | });
134 | }
135 | }
136 |
--------------------------------------------------------------------------------
/backend/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "backend",
3 | "version": "1.0.0",
4 | "lockfileVersion": 1,
5 | "requires": true,
6 | "dependencies": {
7 | "accepts": {
8 | "version": "1.3.7",
9 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
10 | "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
11 | "requires": {
12 | "mime-types": "~2.1.24",
13 | "negotiator": "0.6.2"
14 | }
15 | },
16 | "array-flatten": {
17 | "version": "1.1.1",
18 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
19 | "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
20 | },
21 | "async": {
22 | "version": "2.6.1",
23 | "resolved": "https://registry.npmjs.org/async/-/async-2.6.1.tgz",
24 | "integrity": "sha512-fNEiL2+AZt6AlAw/29Cr0UDe4sRAHCpEHh54WMz+Bb7QfNcFw4h3loofyJpLeQs4Yx7yuqu/2dLgM5hKOs6HlQ==",
25 | "requires": {
26 | "lodash": "^4.17.10"
27 | }
28 | },
29 | "bluebird": {
30 | "version": "3.5.1",
31 | "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz",
32 | "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA=="
33 | },
34 | "body-parser": {
35 | "version": "1.19.0",
36 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
37 | "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==",
38 | "requires": {
39 | "bytes": "3.1.0",
40 | "content-type": "~1.0.4",
41 | "debug": "2.6.9",
42 | "depd": "~1.1.2",
43 | "http-errors": "1.7.2",
44 | "iconv-lite": "0.4.24",
45 | "on-finished": "~2.3.0",
46 | "qs": "6.7.0",
47 | "raw-body": "2.4.0",
48 | "type-is": "~1.6.17"
49 | }
50 | },
51 | "bson": {
52 | "version": "1.1.1",
53 | "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.1.tgz",
54 | "integrity": "sha512-jCGVYLoYMHDkOsbwJZBCqwMHyH4c+wzgI9hG7Z6SZJRXWr+x58pdIbm2i9a/jFGCkRJqRUr8eoI7lDWa0hTkxg=="
55 | },
56 | "bytes": {
57 | "version": "3.1.0",
58 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
59 | "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg=="
60 | },
61 | "content-disposition": {
62 | "version": "0.5.2",
63 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz",
64 | "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ="
65 | },
66 | "content-type": {
67 | "version": "1.0.4",
68 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
69 | "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
70 | },
71 | "cookie": {
72 | "version": "0.3.1",
73 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz",
74 | "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s="
75 | },
76 | "cookie-signature": {
77 | "version": "1.0.6",
78 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
79 | "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
80 | },
81 | "cors": {
82 | "version": "2.8.5",
83 | "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
84 | "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
85 | "requires": {
86 | "object-assign": "^4",
87 | "vary": "^1"
88 | }
89 | },
90 | "debug": {
91 | "version": "2.6.9",
92 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
93 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
94 | "requires": {
95 | "ms": "2.0.0"
96 | }
97 | },
98 | "depd": {
99 | "version": "1.1.2",
100 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
101 | "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
102 | },
103 | "destroy": {
104 | "version": "1.0.4",
105 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
106 | "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
107 | },
108 | "dotenv": {
109 | "version": "8.0.0",
110 | "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.0.0.tgz",
111 | "integrity": "sha512-30xVGqjLjiUOArT4+M5q9sYdvuR4riM6yK9wMcas9Vbp6zZa+ocC9dp6QoftuhTPhFAiLK/0C5Ni2nou/Bk8lg=="
112 | },
113 | "ee-first": {
114 | "version": "1.1.1",
115 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
116 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
117 | },
118 | "encodeurl": {
119 | "version": "1.0.2",
120 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
121 | "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
122 | },
123 | "escape-html": {
124 | "version": "1.0.3",
125 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
126 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
127 | },
128 | "etag": {
129 | "version": "1.8.1",
130 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
131 | "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
132 | },
133 | "express": {
134 | "version": "4.16.4",
135 | "resolved": "https://registry.npmjs.org/express/-/express-4.16.4.tgz",
136 | "integrity": "sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg==",
137 | "requires": {
138 | "accepts": "~1.3.5",
139 | "array-flatten": "1.1.1",
140 | "body-parser": "1.18.3",
141 | "content-disposition": "0.5.2",
142 | "content-type": "~1.0.4",
143 | "cookie": "0.3.1",
144 | "cookie-signature": "1.0.6",
145 | "debug": "2.6.9",
146 | "depd": "~1.1.2",
147 | "encodeurl": "~1.0.2",
148 | "escape-html": "~1.0.3",
149 | "etag": "~1.8.1",
150 | "finalhandler": "1.1.1",
151 | "fresh": "0.5.2",
152 | "merge-descriptors": "1.0.1",
153 | "methods": "~1.1.2",
154 | "on-finished": "~2.3.0",
155 | "parseurl": "~1.3.2",
156 | "path-to-regexp": "0.1.7",
157 | "proxy-addr": "~2.0.4",
158 | "qs": "6.5.2",
159 | "range-parser": "~1.2.0",
160 | "safe-buffer": "5.1.2",
161 | "send": "0.16.2",
162 | "serve-static": "1.13.2",
163 | "setprototypeof": "1.1.0",
164 | "statuses": "~1.4.0",
165 | "type-is": "~1.6.16",
166 | "utils-merge": "1.0.1",
167 | "vary": "~1.1.2"
168 | },
169 | "dependencies": {
170 | "body-parser": {
171 | "version": "1.18.3",
172 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz",
173 | "integrity": "sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=",
174 | "requires": {
175 | "bytes": "3.0.0",
176 | "content-type": "~1.0.4",
177 | "debug": "2.6.9",
178 | "depd": "~1.1.2",
179 | "http-errors": "~1.6.3",
180 | "iconv-lite": "0.4.23",
181 | "on-finished": "~2.3.0",
182 | "qs": "6.5.2",
183 | "raw-body": "2.3.3",
184 | "type-is": "~1.6.16"
185 | }
186 | },
187 | "bytes": {
188 | "version": "3.0.0",
189 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
190 | "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg="
191 | },
192 | "http-errors": {
193 | "version": "1.6.3",
194 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz",
195 | "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=",
196 | "requires": {
197 | "depd": "~1.1.2",
198 | "inherits": "2.0.3",
199 | "setprototypeof": "1.1.0",
200 | "statuses": ">= 1.4.0 < 2"
201 | }
202 | },
203 | "iconv-lite": {
204 | "version": "0.4.23",
205 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz",
206 | "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==",
207 | "requires": {
208 | "safer-buffer": ">= 2.1.2 < 3"
209 | }
210 | },
211 | "qs": {
212 | "version": "6.5.2",
213 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
214 | "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA=="
215 | },
216 | "raw-body": {
217 | "version": "2.3.3",
218 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz",
219 | "integrity": "sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==",
220 | "requires": {
221 | "bytes": "3.0.0",
222 | "http-errors": "1.6.3",
223 | "iconv-lite": "0.4.23",
224 | "unpipe": "1.0.0"
225 | }
226 | },
227 | "setprototypeof": {
228 | "version": "1.1.0",
229 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz",
230 | "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ=="
231 | },
232 | "statuses": {
233 | "version": "1.4.0",
234 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz",
235 | "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew=="
236 | }
237 | }
238 | },
239 | "finalhandler": {
240 | "version": "1.1.1",
241 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz",
242 | "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==",
243 | "requires": {
244 | "debug": "2.6.9",
245 | "encodeurl": "~1.0.2",
246 | "escape-html": "~1.0.3",
247 | "on-finished": "~2.3.0",
248 | "parseurl": "~1.3.2",
249 | "statuses": "~1.4.0",
250 | "unpipe": "~1.0.0"
251 | },
252 | "dependencies": {
253 | "statuses": {
254 | "version": "1.4.0",
255 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz",
256 | "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew=="
257 | }
258 | }
259 | },
260 | "forwarded": {
261 | "version": "0.1.2",
262 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
263 | "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ="
264 | },
265 | "fresh": {
266 | "version": "0.5.2",
267 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
268 | "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
269 | },
270 | "http-errors": {
271 | "version": "1.7.2",
272 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz",
273 | "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==",
274 | "requires": {
275 | "depd": "~1.1.2",
276 | "inherits": "2.0.3",
277 | "setprototypeof": "1.1.1",
278 | "statuses": ">= 1.5.0 < 2",
279 | "toidentifier": "1.0.0"
280 | }
281 | },
282 | "iconv-lite": {
283 | "version": "0.4.24",
284 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
285 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
286 | "requires": {
287 | "safer-buffer": ">= 2.1.2 < 3"
288 | }
289 | },
290 | "inherits": {
291 | "version": "2.0.3",
292 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
293 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
294 | },
295 | "ipaddr.js": {
296 | "version": "1.9.0",
297 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz",
298 | "integrity": "sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA=="
299 | },
300 | "kareem": {
301 | "version": "2.3.0",
302 | "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.3.0.tgz",
303 | "integrity": "sha512-6hHxsp9e6zQU8nXsP+02HGWXwTkOEw6IROhF2ZA28cYbUk4eJ6QbtZvdqZOdD9YPKghG3apk5eOCvs+tLl3lRg=="
304 | },
305 | "lodash": {
306 | "version": "4.17.11",
307 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.11.tgz",
308 | "integrity": "sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg=="
309 | },
310 | "media-typer": {
311 | "version": "0.3.0",
312 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
313 | "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
314 | },
315 | "memory-pager": {
316 | "version": "1.5.0",
317 | "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz",
318 | "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==",
319 | "optional": true
320 | },
321 | "merge-descriptors": {
322 | "version": "1.0.1",
323 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
324 | "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
325 | },
326 | "methods": {
327 | "version": "1.1.2",
328 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
329 | "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
330 | },
331 | "mime": {
332 | "version": "1.4.1",
333 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz",
334 | "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ=="
335 | },
336 | "mime-db": {
337 | "version": "1.40.0",
338 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz",
339 | "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA=="
340 | },
341 | "mime-types": {
342 | "version": "2.1.24",
343 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz",
344 | "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==",
345 | "requires": {
346 | "mime-db": "1.40.0"
347 | }
348 | },
349 | "mongodb": {
350 | "version": "3.2.3",
351 | "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.2.3.tgz",
352 | "integrity": "sha512-jw8UyPsq4QleZ9z+t/pIVy3L++51vKdaJ2Q/XXeYxk/3cnKioAH8H6f5tkkDivrQL4PUgUOHe9uZzkpRFH1XtQ==",
353 | "requires": {
354 | "mongodb-core": "^3.2.3",
355 | "safe-buffer": "^5.1.2"
356 | }
357 | },
358 | "mongodb-core": {
359 | "version": "3.2.3",
360 | "resolved": "https://registry.npmjs.org/mongodb-core/-/mongodb-core-3.2.3.tgz",
361 | "integrity": "sha512-UyI0rmvPPkjOJV8XGWa9VCTq7R4hBVipimhnAXeSXnuAPjuTqbyfA5Ec9RcYJ1Hhu+ISnc8bJ1KfGZd4ZkYARQ==",
362 | "requires": {
363 | "bson": "^1.1.1",
364 | "require_optional": "^1.0.1",
365 | "safe-buffer": "^5.1.2",
366 | "saslprep": "^1.0.0"
367 | }
368 | },
369 | "mongoose": {
370 | "version": "5.5.7",
371 | "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.5.7.tgz",
372 | "integrity": "sha512-Xs4SVuMGkMRdmKZ6ATGVvbp2pjI+KENCNhPZMnksjU3ZerkJHGhWKrUE1A6e/5iZ2lTu6Oz9AOPcfrDgp6BCUw==",
373 | "requires": {
374 | "async": "2.6.1",
375 | "bson": "~1.1.1",
376 | "kareem": "2.3.0",
377 | "mongodb": "3.2.3",
378 | "mongodb-core": "3.2.3",
379 | "mongoose-legacy-pluralize": "1.0.2",
380 | "mpath": "0.6.0",
381 | "mquery": "3.2.0",
382 | "ms": "2.1.1",
383 | "regexp-clone": "0.0.1",
384 | "safe-buffer": "5.1.2",
385 | "sift": "7.0.1",
386 | "sliced": "1.0.1"
387 | },
388 | "dependencies": {
389 | "ms": {
390 | "version": "2.1.1",
391 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
392 | "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
393 | }
394 | }
395 | },
396 | "mongoose-legacy-pluralize": {
397 | "version": "1.0.2",
398 | "resolved": "https://registry.npmjs.org/mongoose-legacy-pluralize/-/mongoose-legacy-pluralize-1.0.2.tgz",
399 | "integrity": "sha512-Yo/7qQU4/EyIS8YDFSeenIvXxZN+ld7YdV9LqFVQJzTLye8unujAWPZ4NWKfFA+RNjh+wvTWKY9Z3E5XM6ZZiQ=="
400 | },
401 | "mpath": {
402 | "version": "0.6.0",
403 | "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.6.0.tgz",
404 | "integrity": "sha512-i75qh79MJ5Xo/sbhxrDrPSEG0H/mr1kcZXJ8dH6URU5jD/knFxCVqVC/gVSW7GIXL/9hHWlT9haLbCXWOll3qw=="
405 | },
406 | "mquery": {
407 | "version": "3.2.0",
408 | "resolved": "https://registry.npmjs.org/mquery/-/mquery-3.2.0.tgz",
409 | "integrity": "sha512-qPJcdK/yqcbQiKoemAt62Y0BAc0fTEKo1IThodBD+O5meQRJT/2HSe5QpBNwaa4CjskoGrYWsEyjkqgiE0qjhg==",
410 | "requires": {
411 | "bluebird": "3.5.1",
412 | "debug": "3.1.0",
413 | "regexp-clone": "0.0.1",
414 | "safe-buffer": "5.1.2",
415 | "sliced": "1.0.1"
416 | },
417 | "dependencies": {
418 | "debug": {
419 | "version": "3.1.0",
420 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
421 | "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
422 | "requires": {
423 | "ms": "2.0.0"
424 | }
425 | }
426 | }
427 | },
428 | "ms": {
429 | "version": "2.0.0",
430 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
431 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
432 | },
433 | "negotiator": {
434 | "version": "0.6.2",
435 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
436 | "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw=="
437 | },
438 | "object-assign": {
439 | "version": "4.1.1",
440 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
441 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
442 | },
443 | "on-finished": {
444 | "version": "2.3.0",
445 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
446 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
447 | "requires": {
448 | "ee-first": "1.1.1"
449 | }
450 | },
451 | "parseurl": {
452 | "version": "1.3.3",
453 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
454 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="
455 | },
456 | "path-to-regexp": {
457 | "version": "0.1.7",
458 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
459 | "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
460 | },
461 | "proxy-addr": {
462 | "version": "2.0.5",
463 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.5.tgz",
464 | "integrity": "sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ==",
465 | "requires": {
466 | "forwarded": "~0.1.2",
467 | "ipaddr.js": "1.9.0"
468 | }
469 | },
470 | "qs": {
471 | "version": "6.7.0",
472 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
473 | "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ=="
474 | },
475 | "range-parser": {
476 | "version": "1.2.0",
477 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz",
478 | "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4="
479 | },
480 | "raw-body": {
481 | "version": "2.4.0",
482 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz",
483 | "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==",
484 | "requires": {
485 | "bytes": "3.1.0",
486 | "http-errors": "1.7.2",
487 | "iconv-lite": "0.4.24",
488 | "unpipe": "1.0.0"
489 | }
490 | },
491 | "regexp-clone": {
492 | "version": "0.0.1",
493 | "resolved": "https://registry.npmjs.org/regexp-clone/-/regexp-clone-0.0.1.tgz",
494 | "integrity": "sha1-p8LgmJH9vzj7sQ03b7cwA+aKxYk="
495 | },
496 | "require_optional": {
497 | "version": "1.0.1",
498 | "resolved": "https://registry.npmjs.org/require_optional/-/require_optional-1.0.1.tgz",
499 | "integrity": "sha512-qhM/y57enGWHAe3v/NcwML6a3/vfESLe/sGM2dII+gEO0BpKRUkWZow/tyloNqJyN6kXSl3RyyM8Ll5D/sJP8g==",
500 | "requires": {
501 | "resolve-from": "^2.0.0",
502 | "semver": "^5.1.0"
503 | }
504 | },
505 | "resolve-from": {
506 | "version": "2.0.0",
507 | "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz",
508 | "integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c="
509 | },
510 | "safe-buffer": {
511 | "version": "5.1.2",
512 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
513 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
514 | },
515 | "safer-buffer": {
516 | "version": "2.1.2",
517 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
518 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
519 | },
520 | "saslprep": {
521 | "version": "1.0.3",
522 | "resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz",
523 | "integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==",
524 | "optional": true,
525 | "requires": {
526 | "sparse-bitfield": "^3.0.3"
527 | }
528 | },
529 | "semver": {
530 | "version": "5.7.0",
531 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz",
532 | "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA=="
533 | },
534 | "send": {
535 | "version": "0.16.2",
536 | "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz",
537 | "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==",
538 | "requires": {
539 | "debug": "2.6.9",
540 | "depd": "~1.1.2",
541 | "destroy": "~1.0.4",
542 | "encodeurl": "~1.0.2",
543 | "escape-html": "~1.0.3",
544 | "etag": "~1.8.1",
545 | "fresh": "0.5.2",
546 | "http-errors": "~1.6.2",
547 | "mime": "1.4.1",
548 | "ms": "2.0.0",
549 | "on-finished": "~2.3.0",
550 | "range-parser": "~1.2.0",
551 | "statuses": "~1.4.0"
552 | },
553 | "dependencies": {
554 | "http-errors": {
555 | "version": "1.6.3",
556 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz",
557 | "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=",
558 | "requires": {
559 | "depd": "~1.1.2",
560 | "inherits": "2.0.3",
561 | "setprototypeof": "1.1.0",
562 | "statuses": ">= 1.4.0 < 2"
563 | }
564 | },
565 | "setprototypeof": {
566 | "version": "1.1.0",
567 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz",
568 | "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ=="
569 | },
570 | "statuses": {
571 | "version": "1.4.0",
572 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz",
573 | "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew=="
574 | }
575 | }
576 | },
577 | "serve-static": {
578 | "version": "1.13.2",
579 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz",
580 | "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==",
581 | "requires": {
582 | "encodeurl": "~1.0.2",
583 | "escape-html": "~1.0.3",
584 | "parseurl": "~1.3.2",
585 | "send": "0.16.2"
586 | }
587 | },
588 | "setprototypeof": {
589 | "version": "1.1.1",
590 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
591 | "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw=="
592 | },
593 | "sift": {
594 | "version": "7.0.1",
595 | "resolved": "https://registry.npmjs.org/sift/-/sift-7.0.1.tgz",
596 | "integrity": "sha512-oqD7PMJ+uO6jV9EQCl0LrRw1OwsiPsiFQR5AR30heR+4Dl7jBBbDLnNvWiak20tzZlSE1H7RB30SX/1j/YYT7g=="
597 | },
598 | "sliced": {
599 | "version": "1.0.1",
600 | "resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz",
601 | "integrity": "sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E="
602 | },
603 | "sparse-bitfield": {
604 | "version": "3.0.3",
605 | "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz",
606 | "integrity": "sha1-/0rm5oZWBWuks+eSqzM004JzyhE=",
607 | "optional": true,
608 | "requires": {
609 | "memory-pager": "^1.0.2"
610 | }
611 | },
612 | "statuses": {
613 | "version": "1.5.0",
614 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
615 | "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
616 | },
617 | "toidentifier": {
618 | "version": "1.0.0",
619 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
620 | "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw=="
621 | },
622 | "type-is": {
623 | "version": "1.6.18",
624 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
625 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
626 | "requires": {
627 | "media-typer": "0.3.0",
628 | "mime-types": "~2.1.24"
629 | }
630 | },
631 | "unpipe": {
632 | "version": "1.0.0",
633 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
634 | "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
635 | },
636 | "utils-merge": {
637 | "version": "1.0.1",
638 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
639 | "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
640 | },
641 | "vary": {
642 | "version": "1.1.2",
643 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
644 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
645 | }
646 | }
647 | }
648 |
--------------------------------------------------------------------------------