├── chat-app ├── .gitignore ├── public │ ├── img │ │ └── favicon.png │ ├── index.html │ ├── css │ │ ├── styles.min.css │ │ └── styles.css │ ├── chat.html │ └── js │ │ └── chat.js ├── src │ ├── utils │ │ ├── messages.js │ │ └── users.js │ └── index.js └── package.json ├── notes-app ├── .gitignore ├── notes.json ├── package.json ├── app.js ├── notes.js └── package-lock.json ├── web-server ├── .gitignore ├── templates │ ├── partials │ │ ├── footer.hbs │ │ └── header.hbs │ └── views │ │ ├── help.hbs │ │ ├── 404.hbs │ │ ├── about.hbs │ │ └── index.hbs ├── public │ ├── img │ │ ├── me.png │ │ └── weather.png │ ├── js │ │ └── app.js │ └── css │ │ └── styles.css ├── package.json ├── src │ ├── utils │ │ ├── forecast.js │ │ └── geocode.js │ └── app.js └── package-lock.json ├── task-manager ├── .gitignore ├── tests │ ├── __mocks__ │ │ └── @sendgrid │ │ │ └── mail.js │ ├── fixtures │ │ ├── profile-pic.jpg │ │ └── db.js │ ├── task.test.js │ └── user.test.js ├── src │ ├── index.js │ ├── db │ │ └── mongoose.js │ ├── app.js │ ├── models │ │ ├── task.js │ │ └── user.js │ ├── middleware │ │ └── auth.js │ ├── emails │ │ └── account.js │ └── routers │ │ ├── task.js │ │ └── user.js └── package.json ├── playground ├── 1-json.json ├── 7-default-params.js ├── 1-json.js ├── 4-callbacks.js ├── 6-raw-http.js ├── 2-arrow-function.js ├── 9-async-await.js ├── 8-promises.js ├── 3-arrow-challenge.js └── 5-es6-objects.js └── weather-app ├── package.json ├── app.js ├── utils ├── forecast.js └── geocode.js └── package-lock.json /chat-app/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /notes-app/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ -------------------------------------------------------------------------------- /web-server/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ -------------------------------------------------------------------------------- /task-manager/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | config -------------------------------------------------------------------------------- /playground/1-json.json: -------------------------------------------------------------------------------- 1 | {"name":"Gunther","planet":"Earth","age":54} -------------------------------------------------------------------------------- /notes-app/notes.json: -------------------------------------------------------------------------------- 1 | [{"title":"t","body":"b"},{"title":"Course ideas","body":""}] -------------------------------------------------------------------------------- /web-server/templates/partials/footer.hbs: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /web-server/public/img/me.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewjmead/node-course-v3-code/HEAD/web-server/public/img/me.png -------------------------------------------------------------------------------- /chat-app/public/img/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewjmead/node-course-v3-code/HEAD/chat-app/public/img/favicon.png -------------------------------------------------------------------------------- /web-server/public/img/weather.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewjmead/node-course-v3-code/HEAD/web-server/public/img/weather.png -------------------------------------------------------------------------------- /task-manager/tests/__mocks__/@sendgrid/mail.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | setApiKey() { 3 | 4 | }, 5 | send() { 6 | 7 | } 8 | } -------------------------------------------------------------------------------- /task-manager/tests/fixtures/profile-pic.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/andrewjmead/node-course-v3-code/HEAD/task-manager/tests/fixtures/profile-pic.jpg -------------------------------------------------------------------------------- /playground/7-default-params.js: -------------------------------------------------------------------------------- 1 | const greeter = (name = 'user', age) => { 2 | console.log('Hello ' + name) 3 | } 4 | 5 | greeter('Andrew') 6 | 7 | greeter() -------------------------------------------------------------------------------- /task-manager/src/index.js: -------------------------------------------------------------------------------- 1 | const app = require('./app') 2 | const port = process.env.PORT 3 | 4 | app.listen(port, () => { 5 | console.log('Server is up on port ' + port) 6 | }) -------------------------------------------------------------------------------- /web-server/templates/partials/header.hbs: -------------------------------------------------------------------------------- 1 |
2 |

{{title}}

3 | 4 | Weather 5 | About 6 | Help 7 |
-------------------------------------------------------------------------------- /task-manager/src/db/mongoose.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose') 2 | 3 | mongoose.connect(process.env.MONGODB_URL, { 4 | useNewUrlParser: true, 5 | useCreateIndex: true, 6 | useFindAndModify: false 7 | }) -------------------------------------------------------------------------------- /playground/1-json.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | 3 | const dataBuffer = fs.readFileSync('1-json.json') 4 | const dataJSON = dataBuffer.toString() 5 | const user = JSON.parse(dataJSON) 6 | 7 | user.name = 'Gunther' 8 | user.age = 54 9 | 10 | const userJSON = JSON.stringify(user) 11 | fs.writeFileSync('1-json.json', userJSON) -------------------------------------------------------------------------------- /task-manager/src/app.js: -------------------------------------------------------------------------------- 1 | const express = require('express') 2 | require('./db/mongoose') 3 | const userRouter = require('./routers/user') 4 | const taskRouter = require('./routers/task') 5 | 6 | const app = express() 7 | 8 | app.use(express.json()) 9 | app.use(userRouter) 10 | app.use(taskRouter) 11 | 12 | module.exports = app -------------------------------------------------------------------------------- /weather-app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "weather-app", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "app.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "request": "^2.88.0" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /playground/4-callbacks.js: -------------------------------------------------------------------------------- 1 | const doWorkCallback = (callback) => { 2 | setTimeout(() => { 3 | // callback('This is my error!', undefined) 4 | callback(undefined, [1, 4, 7]) 5 | }, 2000) 6 | } 7 | 8 | doWorkCallback((error, result) => { 9 | if (error) { 10 | return console.log(error) 11 | } 12 | 13 | console.log(result) 14 | }) -------------------------------------------------------------------------------- /notes-app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "notes-app", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "app.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "chalk": "^2.4.1", 13 | "validator": "^10.8.0", 14 | "yargs": "^12.0.2" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /web-server/templates/views/help.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Help 7 | 8 | 9 | 10 | 11 | 12 |
13 | {{>header}} 14 |

{{helpText}}

15 |
16 | 17 | {{>footer}} 18 | 19 | 20 | -------------------------------------------------------------------------------- /web-server/templates/views/404.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 404 7 | 8 | 9 | 10 | 11 | 12 |
13 | {{>header}} 14 |

{{errorMessage}}

15 |
16 | 17 | {{>footer}} 18 | 19 | 20 | -------------------------------------------------------------------------------- /chat-app/src/utils/messages.js: -------------------------------------------------------------------------------- 1 | const generateMessage = (username, text) => { 2 | return { 3 | username, 4 | text, 5 | createdAt: new Date().getTime() 6 | } 7 | } 8 | 9 | const generateLocationMessage = (username, url) => { 10 | return { 11 | username, 12 | url, 13 | createdAt: new Date().getTime() 14 | } 15 | } 16 | 17 | module.exports = { 18 | generateMessage, 19 | generateLocationMessage 20 | } -------------------------------------------------------------------------------- /chat-app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "chat-app", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "node src/index.js", 8 | "dev": "nodemon src/index.js" 9 | }, 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "bad-words": "^3.0.0", 14 | "express": "^4.16.4", 15 | "socket.io": "^2.2.0" 16 | }, 17 | "devDependencies": { 18 | "nodemon": "^1.18.7" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /web-server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "web-server", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "node src/app.js", 8 | "dev": "nodemon src/app.js -e js,hbs" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "license": "ISC", 13 | "dependencies": { 14 | "express": "^4.16.4", 15 | "hbs": "^4.0.1", 16 | "request": "^2.88.0" 17 | }, 18 | "devDependencies": { 19 | "nodemon": "^1.2.0" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /web-server/templates/views/about.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | About 7 | 8 | 9 | 10 | 11 | 12 |
13 | {{>header}} 14 |

This site was created by Andrew Mead. It uses data from mapbox.com and darksky.net!

15 | 16 |
17 | 18 | {{>footer}} 19 | 20 | 21 | -------------------------------------------------------------------------------- /playground/6-raw-http.js: -------------------------------------------------------------------------------- 1 | const https = require('https') 2 | const url = 'https://api.darksky.net/forecast/9d1465c6f3bb7a6c71944bdd8548d026/40,-75' 3 | 4 | const request = https.request(url, (response) => { 5 | let data = '' 6 | 7 | response.on('data', (chunk) => { 8 | data = data + chunk.toString() 9 | }) 10 | 11 | response.on('end', () => { 12 | const body = JSON.parse(data) 13 | console.log(body) 14 | }) 15 | 16 | }) 17 | 18 | request.on('error', (error) => { 19 | console.log('An error', error) 20 | }) 21 | 22 | request.end() -------------------------------------------------------------------------------- /task-manager/src/models/task.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose') 2 | 3 | const taskSchema = new mongoose.Schema({ 4 | description: { 5 | type: String, 6 | required: true, 7 | trim: true 8 | }, 9 | completed: { 10 | type: Boolean, 11 | default: false 12 | }, 13 | owner: { 14 | type: mongoose.Schema.Types.ObjectId, 15 | required: true, 16 | ref: 'User' 17 | } 18 | }, { 19 | timestamps: true 20 | }) 21 | 22 | const Task = mongoose.model('Task', taskSchema) 23 | 24 | module.exports = Task -------------------------------------------------------------------------------- /playground/2-arrow-function.js: -------------------------------------------------------------------------------- 1 | // const square = function (x) { 2 | // return x * x 3 | // } 4 | 5 | // const square = (x) => { 6 | // return x * x 7 | // } 8 | 9 | // const square = (x) => x * x 10 | 11 | // console.log(square(2)) 12 | 13 | const event = { 14 | name: 'Birthday Party', 15 | guestList: ['Andrew', 'Jen', 'Mike'], 16 | printGuestList() { 17 | console.log('Guest list for ' + this.name) 18 | 19 | this.guestList.forEach((guest) => { 20 | console.log(guest + ' is attending ' + this.name) 21 | }) 22 | } 23 | } 24 | 25 | event.printGuestList() -------------------------------------------------------------------------------- /playground/9-async-await.js: -------------------------------------------------------------------------------- 1 | const add = (a, b) => { 2 | return new Promise((resolve, reject) => { 3 | setTimeout(() => { 4 | if (a < 0 || b < 0) { 5 | return reject('Numbers must be non-negative') 6 | } 7 | 8 | resolve(a + b) 9 | }, 2000) 10 | }) 11 | } 12 | 13 | const doWork = async () => { 14 | const sum = await add(1, -99) 15 | const sum2 = await add(sum, 50) 16 | const sum3 = await add(sum2, -3) 17 | return sum3 18 | } 19 | 20 | doWork().then((result) => { 21 | console.log('result', result) 22 | }).catch((e) => { 23 | console.log('e', e) 24 | }) -------------------------------------------------------------------------------- /playground/8-promises.js: -------------------------------------------------------------------------------- 1 | const add = (a, b) => { 2 | return new Promise((resolve, reject) => { 3 | setTimeout(() => { 4 | resolve(a + b) 5 | }, 2000) 6 | }) 7 | } 8 | 9 | // add(1, 2).then((sum) => { 10 | // console.log(sum) 11 | 12 | // add(sum, 5).then((sum2) => { 13 | // console.log(sum2) 14 | // }).catch((e) => { 15 | // console.log(e) 16 | // }) 17 | // }).catch((e) => { 18 | // console.log(e) 19 | // }) 20 | 21 | add(1, 1).then((sum) => { 22 | console.log(sum) 23 | return add(sum, 4) 24 | }).then((sum2) => { 25 | console.log(sum2) 26 | }).catch((e) => { 27 | console.log(e) 28 | }) -------------------------------------------------------------------------------- /playground/3-arrow-challenge.js: -------------------------------------------------------------------------------- 1 | // 2 | // Goal: Create method to get incomplete tasks 3 | // 4 | // 1. Define getTasksToDo method 5 | // 2. Use filter to to return just the incompleted tasks (arrow function) 6 | // 3. Test your work by running the script 7 | 8 | const tasks = { 9 | tasks: [{ 10 | text: 'Grocery shopping', 11 | completed: true 12 | }, { 13 | text: 'Clean yard', 14 | completed: false 15 | }, { 16 | text: 'Film course', 17 | completed: false 18 | }], 19 | getTasksToDo() { 20 | return this.tasks.filter((task) => task.completed === false) 21 | } 22 | } 23 | 24 | console.log(tasks.getTasksToDo()) -------------------------------------------------------------------------------- /weather-app/app.js: -------------------------------------------------------------------------------- 1 | const geocode = require('./utils/geocode') 2 | const forecast = require('./utils/forecast') 3 | 4 | const address = process.argv[2] 5 | 6 | if (!address) { 7 | console.log('Please provide an address') 8 | } else { 9 | geocode(address, (error, { latitude, longitude, location }) => { 10 | if (error) { 11 | return console.log(error) 12 | } 13 | 14 | forecast(latitude, longitude, (error, forecastData) => { 15 | if (error) { 16 | return console.log(error) 17 | } 18 | 19 | console.log(location) 20 | console.log(forecastData) 21 | }) 22 | }) 23 | } 24 | -------------------------------------------------------------------------------- /web-server/templates/views/index.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Weather 7 | 8 | 9 | 10 | 11 | 12 |
13 | {{>header}} 14 | 15 |

Use this site to get your weather!

16 | 17 |
18 | 19 | 20 |
21 | 22 |

23 |

24 |
25 | 26 | {{>footer}} 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /task-manager/src/middleware/auth.js: -------------------------------------------------------------------------------- 1 | const jwt = require('jsonwebtoken') 2 | const User = require('../models/user') 3 | 4 | const auth = async (req, res, next) => { 5 | try { 6 | const token = req.header('Authorization').replace('Bearer ', '') 7 | const decoded = jwt.verify(token, process.env.JWT_SECRET) 8 | const user = await User.findOne({ _id: decoded._id, 'tokens.token': token }) 9 | 10 | if (!user) { 11 | throw new Error() 12 | } 13 | 14 | req.token = token 15 | req.user = user 16 | next() 17 | } catch (e) { 18 | res.status(401).send({ error: 'Please authenticate.' }) 19 | } 20 | } 21 | 22 | module.exports = auth -------------------------------------------------------------------------------- /task-manager/src/emails/account.js: -------------------------------------------------------------------------------- 1 | const sgMail = require('@sendgrid/mail') 2 | 3 | sgMail.setApiKey(process.env.SENDGRID_API_KEY) 4 | 5 | const sendWelcomeEmail = (email, name) => { 6 | sgMail.send({ 7 | to: email, 8 | from: 'andrew@mead.io', 9 | subject: 'Thanks for joining in!', 10 | text: `Welcome to the app, ${name}. Let me know how you get along with the app.` 11 | }) 12 | } 13 | 14 | const sendCancelationEmail = (email, name) => { 15 | sgMail.send({ 16 | to: email, 17 | from: 'andrew@mead.io', 18 | subject: 'Sorry to see you go!', 19 | text: `Goodbye, ${name}. I hope to see you back sometime soon.` 20 | }) 21 | } 22 | 23 | module.exports = { 24 | sendWelcomeEmail, 25 | sendCancelationEmail 26 | } -------------------------------------------------------------------------------- /weather-app/utils/forecast.js: -------------------------------------------------------------------------------- 1 | const request = require('request') 2 | 3 | const forecast = (latitude, longitude, callback) => { 4 | const url = 'https://api.darksky.net/forecast/9d1465c6f3bb7a6c71944bdd8548d026/' + latitude + ',' + longitude 5 | 6 | request({ url, json: true }, (error, { body }) => { 7 | if (error) { 8 | callback('Unable to connect to weather service!', undefined) 9 | } else if (body.error) { 10 | callback('Unable to find location', undefined) 11 | } else { 12 | callback(undefined, body.daily.data[0].summary + ' It is currently ' + body.currently.temperature + ' degress out. There is a ' + body.currently.precipProbability + '% chance of rain.') 13 | } 14 | }) 15 | } 16 | 17 | module.exports = forecast -------------------------------------------------------------------------------- /playground/5-es6-objects.js: -------------------------------------------------------------------------------- 1 | // Object property shorthand 2 | 3 | const name = 'Andrew' 4 | const userAge = 27 5 | 6 | const user = { 7 | name, 8 | age: userAge, 9 | location: 'Philadelphia' 10 | } 11 | 12 | console.log(user) 13 | 14 | // Object destructuring 15 | 16 | const product = { 17 | label: 'Red notebook', 18 | price: 3, 19 | stock: 201, 20 | salePrice: undefined, 21 | rating: 4.2 22 | } 23 | 24 | // const label = product.label 25 | // const stock = product.stock 26 | 27 | // const {label:productLabel, stock, rating = 5} = product 28 | // console.log(productLabel) 29 | // console.log(stock) 30 | // console.log(rating) 31 | 32 | const transaction = (type, { label, stock = 0 } = {}) => { 33 | console.log(type, label, stock) 34 | } 35 | 36 | transaction('order', product) -------------------------------------------------------------------------------- /chat-app/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Chat App 5 | 6 | 7 | 8 | 9 |
10 |
11 |

Join

12 |
13 | 14 | 15 | 16 | 17 | 18 |
19 |
20 |
21 | 22 | -------------------------------------------------------------------------------- /web-server/public/js/app.js: -------------------------------------------------------------------------------- 1 | const weatherForm = document.querySelector('form') 2 | const search = document.querySelector('input') 3 | const messageOne = document.querySelector('#message-1') 4 | const messageTwo = document.querySelector('#message-2') 5 | 6 | weatherForm.addEventListener('submit', (e) => { 7 | e.preventDefault() 8 | 9 | const location = search.value 10 | 11 | messageOne.textContent = 'Loading...' 12 | messageTwo.textContent = '' 13 | 14 | fetch('/weather?address=' + location).then((response) => { 15 | response.json().then((data) => { 16 | if (data.error) { 17 | messageOne.textContent = data.error 18 | } else { 19 | messageOne.textContent = data.location 20 | messageTwo.textContent = data.forecast 21 | } 22 | }) 23 | }) 24 | }) -------------------------------------------------------------------------------- /web-server/src/utils/forecast.js: -------------------------------------------------------------------------------- 1 | const request = require('request') 2 | 3 | const forecast = (latitude, longitude, callback) => { 4 | const url = 'https://api.darksky.net/forecast/9d1465c6f3bb7a6c71944bdd8548d026/' + latitude + ',' + longitude 5 | 6 | request({ url, json: true }, (error, { body }) => { 7 | if (error) { 8 | callback('Unable to connect to weather service!', undefined) 9 | } else if (body.error) { 10 | callback('Unable to find location', undefined) 11 | } else { 12 | callback(undefined, body.daily.data[0].summary + ' It is currently ' + body.currently.temperature + ' degress out. This high today is ' + body.daily.data[0].temperatureHigh + ' with a low of ' + body.daily.data[0].temperatureLow + '. There is a ' + body.currently.precipProbability + '% chance of rain.') 13 | } 14 | }) 15 | } 16 | 17 | module.exports = forecast -------------------------------------------------------------------------------- /task-manager/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "task-manager", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "node src/index.js", 8 | "dev": "env-cmd ./config/dev.env nodemon src/index.js", 9 | "test": "env-cmd ./config/test.env jest --watch --runInBand" 10 | }, 11 | "jest": { 12 | "testEnvironment": "node" 13 | }, 14 | "keywords": [], 15 | "author": "", 16 | "license": "ISC", 17 | "dependencies": { 18 | "@sendgrid/mail": "^6.3.1", 19 | "bcryptjs": "^2.4.3", 20 | "express": "^4.16.4", 21 | "jsonwebtoken": "^8.4.0", 22 | "mongodb": "^3.1.10", 23 | "mongoose": "^5.3.16", 24 | "multer": "^1.4.1", 25 | "sharp": "^0.21.1", 26 | "validator": "^10.9.0" 27 | }, 28 | "devDependencies": { 29 | "env-cmd": "^8.0.2", 30 | "jest": "^23.6.0", 31 | "nodemon": "^1.18.9", 32 | "supertest": "^3.4.1" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /weather-app/utils/geocode.js: -------------------------------------------------------------------------------- 1 | const request = require('request') 2 | 3 | const geocode = (address, callback) => { 4 | const url = 'https://api.mapbox.com/geocoding/v5/mapbox.places/' + address + '.json?access_token=pk.eyJ1IjoiYW5kcmV3bWVhZDEiLCJhIjoiY2pvOG8ybW90MDFhazNxcnJ4OTYydzJlOSJ9.njY7HvaalLEVhEOIghPTlw&limit=1' 5 | 6 | request({ url, json: true }, (error, { body }) => { 7 | if (error) { 8 | callback('Unable to connect to location services!', undefined) 9 | } else if (body.features.length === 0) { 10 | callback('Unable to find location. Try another search.', undefined) 11 | } else { 12 | callback(undefined, { 13 | latitude: body.features[0].center[1], 14 | longitude: body.features[0].center[0], 15 | location: body.features[0].place_name 16 | }) 17 | } 18 | }) 19 | } 20 | 21 | module.exports = geocode -------------------------------------------------------------------------------- /web-server/src/utils/geocode.js: -------------------------------------------------------------------------------- 1 | const request = require('request') 2 | 3 | const geocode = (address, callback) => { 4 | const url = 'https://api.mapbox.com/geocoding/v5/mapbox.places/' + address + '.json?access_token=pk.eyJ1IjoiYW5kcmV3bWVhZDEiLCJhIjoiY2pvOG8ybW90MDFhazNxcnJ4OTYydzJlOSJ9.njY7HvaalLEVhEOIghPTlw&limit=1' 5 | 6 | request({ url, json: true }, (error, { body }) => { 7 | if (error) { 8 | callback('Unable to connect to location services!', undefined) 9 | } else if (body.features.length === 0) { 10 | callback('Unable to find location. Try another search.', undefined) 11 | } else { 12 | callback(undefined, { 13 | latitude: body.features[0].center[1], 14 | longitude: body.features[0].center[0], 15 | location: body.features[0].place_name 16 | }) 17 | } 18 | }) 19 | } 20 | 21 | module.exports = geocode -------------------------------------------------------------------------------- /web-server/public/css/styles.css: -------------------------------------------------------------------------------- 1 | body { 2 | color: #333333; 3 | font-family: arial; 4 | max-width: 650px; 5 | margin: 0 auto; 6 | padding: 0 16px; 7 | 8 | display: flex; 9 | flex-direction: column; 10 | min-height: 100vh 11 | } 12 | 13 | .main-content { 14 | flex-grow: 1; 15 | } 16 | 17 | footer { 18 | color: #888888; 19 | border-top: 1px solid #eeeeee; 20 | margin-top: 16px; 21 | padding: 16px 0; 22 | } 23 | 24 | header { 25 | margin-top: 16px; 26 | margin-bottom: 48px; 27 | } 28 | 29 | h1 { 30 | font-size: 64px; 31 | margin-bottom: 16px; 32 | } 33 | 34 | header a { 35 | color: #888888; 36 | margin-right: 16px; 37 | text-decoration: none; 38 | } 39 | 40 | .portrait { 41 | width: 250px; 42 | } 43 | 44 | input { 45 | border: 1px solid #cccccc; 46 | padding: 8px; 47 | } 48 | 49 | button { 50 | cursor: pointer; 51 | border: 1px solid #888888; 52 | background: #888888; 53 | color: white; 54 | padding: 8px; 55 | } -------------------------------------------------------------------------------- /chat-app/src/utils/users.js: -------------------------------------------------------------------------------- 1 | const users = [] 2 | 3 | const addUser = ({ id, username, room }) => { 4 | // Clean the data 5 | username = username.trim().toLowerCase() 6 | room = room.trim().toLowerCase() 7 | 8 | // Validate the data 9 | if (!username || !room) { 10 | return { 11 | error: 'Username and room are required!' 12 | } 13 | } 14 | 15 | // Check for existing user 16 | const existingUser = users.find((user) => { 17 | return user.room === room && user.username === username 18 | }) 19 | 20 | // Validate username 21 | if (existingUser) { 22 | return { 23 | error: 'Username is in use!' 24 | } 25 | } 26 | 27 | // Store user 28 | const user = { id, username, room } 29 | users.push(user) 30 | return { user } 31 | } 32 | 33 | const removeUser = (id) => { 34 | const index = users.findIndex((user) => user.id === id) 35 | 36 | if (index !== -1) { 37 | return users.splice(index, 1)[0] 38 | } 39 | } 40 | 41 | const getUser = (id) => { 42 | return users.find((user) => user.id === id) 43 | } 44 | 45 | const getUsersInRoom = (room) => { 46 | room = room.trim().toLowerCase() 47 | return users.filter((user) => user.room === room) 48 | } 49 | 50 | module.exports = { 51 | addUser, 52 | removeUser, 53 | getUser, 54 | getUsersInRoom 55 | } -------------------------------------------------------------------------------- /task-manager/tests/task.test.js: -------------------------------------------------------------------------------- 1 | const request = require('supertest') 2 | const app = require('../src/app') 3 | const Task = require('../src/models/task') 4 | const { 5 | userOneId, 6 | userOne, 7 | userTwoId, 8 | userTwo, 9 | taskOne, 10 | taskTwo, 11 | taskThree, 12 | setupDatabase 13 | } = require('./fixtures/db') 14 | 15 | beforeEach(setupDatabase) 16 | 17 | test('Should create task for user', async () => { 18 | const response = await request(app) 19 | .post('/tasks') 20 | .set('Authorization', `Bearer ${userOne.tokens[0].token}`) 21 | .send({ 22 | description: 'From my test' 23 | }) 24 | .expect(201) 25 | const task = await Task.findById(response.body._id) 26 | expect(task).not.toBeNull() 27 | expect(task.completed).toEqual(false) 28 | }) 29 | 30 | test('Should fetch user tasks', async () => { 31 | const response = await request(app) 32 | .get('/tasks') 33 | .set('Authorization', `Bearer ${userOne.tokens[0].token}`) 34 | .send() 35 | .expect(200) 36 | expect(response.body.length).toEqual(2) 37 | }) 38 | 39 | test('Should not delete other users tasks', async () => { 40 | const response = await request(app) 41 | .delete(`/tasks/${taskOne._id}`) 42 | .set('Authorization', `Bearer ${userTwo.tokens[0].token}`) 43 | .send() 44 | .expect(404) 45 | const task = await Task.findById(taskOne._id) 46 | expect(task).not.toBeNull() 47 | }) 48 | -------------------------------------------------------------------------------- /chat-app/public/css/styles.min.css: -------------------------------------------------------------------------------- 1 | *{margin:0;padding:0;box-sizing:border-box}html{font-size:16px}input{font-size:14px}body{line-height:1.4;color:#333;font-family:Helvetica,Arial,sans-serif}h1{margin-bottom:16px}label{display:block;font-size:14px;margin-bottom:8px;color:#777}input{border:1px solid #eee;padding:12px;outline:none}button{cursor:pointer;padding:12px;background:#7C5CBF;border:none;color:#fff;font-size:16px;transition:background .3s ease}button:hover{background:#6b47b8}button:disabled{cursor:default;background:#7c5cbf94}.centered-form{background:#333744;width:100vw;height:100vh;display:flex;justify-content:center;align-items:center}.centered-form__box{box-shadow:0 0 17px 1px #1D1F26;background:#F7F7FA;padding:24px;width:250px}.centered-form button{width:100%}.centered-form input{margin-bottom:16px;width:100%}.chat{display:flex}.chat__sidebar{height:100vh;color:#fff;background:#333744;width:225px;overflow-y:scroll}.chat__main{flex-grow:1;display:flex;flex-direction:column;max-height:100vh}.chat__messages{flex-grow:1;padding:24px 24px 0;overflow-y:scroll}.message{margin-bottom:16px}.message__name{font-weight:600;font-size:14px;margin-right:8px}.message__meta{color:#777;font-size:14px}.message a{color:#0070CC}.compose{display:flex;flex-shrink:0;margin-top:16px;padding:24px}.compose form{display:flex;flex-grow:1;margin-right:16px}.compose input{border:1px solid #eee;width:100%;padding:12px;margin:0 16px 0 0;flex-grow:1}.compose button{font-size:14px}.room-title{font-weight:400;font-size:22px;background:#2c2f3a;padding:24px}.list-title{font-weight:500;font-size:18px;margin-bottom:4px;padding:12px 24px 0}.users{list-style-type:none;font-weight:300;padding:12px 24px 0} -------------------------------------------------------------------------------- /notes-app/app.js: -------------------------------------------------------------------------------- 1 | const chalk = require('chalk') 2 | const yargs = require('yargs') 3 | const notes = require('./notes.js') 4 | 5 | // Customize yargs version 6 | yargs.version('1.1.0') 7 | 8 | // Create add command 9 | yargs.command({ 10 | command: 'add', 11 | describe: 'Add a new note', 12 | builder: { 13 | title: { 14 | describe: 'Note title', 15 | demandOption: true, 16 | type: 'string' 17 | }, 18 | body: { 19 | describe: 'Note body', 20 | demandOption: true, 21 | type: 'string' 22 | } 23 | }, 24 | handler(argv) { 25 | notes.addNote(argv.title, argv.body) 26 | } 27 | }) 28 | 29 | // Create remove command 30 | yargs.command({ 31 | command: 'remove', 32 | describe: 'Remove a note', 33 | builder: { 34 | title: { 35 | describe: 'Note title', 36 | demandOption: true, 37 | type: 'string' 38 | } 39 | }, 40 | handler(argv) { 41 | notes.removeNote(argv.title) 42 | } 43 | }) 44 | 45 | // Create list command 46 | yargs.command({ 47 | command: 'list', 48 | describe: 'List your notes', 49 | handler() { 50 | notes.listNotes() 51 | } 52 | }) 53 | 54 | // Create read command 55 | yargs.command({ 56 | command: 'read', 57 | describe: 'Read a note', 58 | builder: { 59 | title: { 60 | describe: 'Note title', 61 | demandOption: true, 62 | type: 'string' 63 | } 64 | }, 65 | handler(argv) { 66 | notes.readNote(argv.title) 67 | } 68 | }) 69 | 70 | yargs.parse() -------------------------------------------------------------------------------- /task-manager/tests/fixtures/db.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose') 2 | const jwt = require('jsonwebtoken') 3 | const User = require('../../src/models/user') 4 | const Task = require('../../src/models/task') 5 | 6 | const userOneId = new mongoose.Types.ObjectId() 7 | const userOne = { 8 | _id: userOneId, 9 | name: 'Mike', 10 | email: 'mike@example.com', 11 | password: '56what!!', 12 | tokens: [{ 13 | token: jwt.sign({ _id: userOneId }, process.env.JWT_SECRET) 14 | }] 15 | } 16 | 17 | const userTwoId = new mongoose.Types.ObjectId() 18 | const userTwo = { 19 | _id: userTwoId, 20 | name: 'Jess', 21 | email: 'jess@example.com', 22 | password: 'myhouse099@@', 23 | tokens: [{ 24 | token: jwt.sign({ _id: userTwoId }, process.env.JWT_SECRET) 25 | }] 26 | } 27 | 28 | const taskOne = { 29 | _id: new mongoose.Types.ObjectId(), 30 | description: 'First task', 31 | completed: false, 32 | owner: userOne._id 33 | } 34 | 35 | const taskTwo = { 36 | _id: new mongoose.Types.ObjectId(), 37 | description: 'Second task', 38 | completed: true, 39 | owner: userOne._id 40 | } 41 | 42 | const taskThree = { 43 | _id: new mongoose.Types.ObjectId(), 44 | description: 'Third task', 45 | completed: true, 46 | owner: userTwo._id 47 | } 48 | 49 | const setupDatabase = async () => { 50 | await User.deleteMany() 51 | await Task.deleteMany() 52 | await new User(userOne).save() 53 | await new User(userTwo).save() 54 | await new Task(taskOne).save() 55 | await new Task(taskTwo).save() 56 | await new Task(taskThree).save() 57 | } 58 | 59 | module.exports = { 60 | userOneId, 61 | userOne, 62 | userTwoId, 63 | userTwo, 64 | taskOne, 65 | taskTwo, 66 | taskThree, 67 | setupDatabase 68 | } -------------------------------------------------------------------------------- /notes-app/notes.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const chalk = require('chalk') 3 | 4 | const addNote = (title, body) => { 5 | const notes = loadNotes() 6 | const duplicateNote = notes.find((note) => note.title === title) 7 | 8 | if (!duplicateNote) { 9 | notes.push({ 10 | title: title, 11 | body: body 12 | }) 13 | saveNotes(notes) 14 | console.log(chalk.green.inverse('New note added!')) 15 | } else { 16 | console.log(chalk.red.inverse('Note title taken!')) 17 | } 18 | } 19 | 20 | const removeNote = (title) => { 21 | const notes = loadNotes() 22 | const notesToKeep = notes.filter((note) => note.title !== title) 23 | 24 | if (notes.length > notesToKeep.length) { 25 | console.log(chalk.green.inverse('Note removed!')) 26 | saveNotes(notesToKeep) 27 | } else { 28 | console.log(chalk.red.inverse('No note found!')) 29 | } 30 | } 31 | 32 | const listNotes = () => { 33 | const notes = loadNotes() 34 | 35 | console.log(chalk.inverse('Your notes')) 36 | 37 | notes.forEach((note) => { 38 | console.log(note.title) 39 | }) 40 | } 41 | 42 | const readNote = (title) => { 43 | const notes = loadNotes() 44 | const note = notes.find((note) => note.title === title) 45 | 46 | if (note) { 47 | console.log(chalk.inverse(note.title)) 48 | console.log(note.body) 49 | } else { 50 | console.log(chalk.red.inverse('Note not found!')) 51 | } 52 | } 53 | 54 | const saveNotes = (notes) => { 55 | const dataJSON = JSON.stringify(notes) 56 | fs.writeFileSync('notes.json', dataJSON) 57 | } 58 | 59 | const loadNotes = () => { 60 | try { 61 | const dataBuffer = fs.readFileSync('notes.json') 62 | const dataJSON = dataBuffer.toString() 63 | return JSON.parse(dataJSON) 64 | } catch (e) { 65 | return [] 66 | } 67 | } 68 | 69 | module.exports = { 70 | addNote: addNote, 71 | removeNote: removeNote, 72 | listNotes: listNotes, 73 | readNote: readNote 74 | } -------------------------------------------------------------------------------- /chat-app/public/chat.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Chat App 6 | 7 | 8 | 9 | 10 | 11 |
12 | 15 |
16 |
17 | 18 |
19 |
20 | 21 | 22 |
23 | 24 |
25 |
26 |
27 | 28 | 37 | 38 | 47 | 48 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | -------------------------------------------------------------------------------- /chat-app/src/index.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const http = require('http') 3 | const express = require('express') 4 | const socketio = require('socket.io') 5 | const Filter = require('bad-words') 6 | const { generateMessage, generateLocationMessage } = require('./utils/messages') 7 | const { addUser, removeUser, getUser, getUsersInRoom } = require('./utils/users') 8 | 9 | const app = express() 10 | const server = http.createServer(app) 11 | const io = socketio(server) 12 | 13 | const port = process.env.PORT || 3000 14 | const publicDirectoryPath = path.join(__dirname, '../public') 15 | 16 | app.use(express.static(publicDirectoryPath)) 17 | 18 | io.on('connection', (socket) => { 19 | console.log('New WebSocket connection') 20 | 21 | socket.on('join', (options, callback) => { 22 | const { error, user } = addUser({ id: socket.id, ...options }) 23 | 24 | if (error) { 25 | return callback(error) 26 | } 27 | 28 | socket.join(user.room) 29 | 30 | socket.emit('message', generateMessage('Admin', 'Welcome!')) 31 | socket.broadcast.to(user.room).emit('message', generateMessage('Admin', `${user.username} has joined!`)) 32 | io.to(user.room).emit('roomData', { 33 | room: user.room, 34 | users: getUsersInRoom(user.room) 35 | }) 36 | 37 | callback() 38 | }) 39 | 40 | socket.on('sendMessage', (message, callback) => { 41 | const user = getUser(socket.id) 42 | const filter = new Filter() 43 | 44 | if (filter.isProfane(message)) { 45 | return callback('Profanity is not allowed!') 46 | } 47 | 48 | io.to(user.room).emit('message', generateMessage(user.username, message)) 49 | callback() 50 | }) 51 | 52 | socket.on('sendLocation', (coords, callback) => { 53 | const user = getUser(socket.id) 54 | io.to(user.room).emit('locationMessage', generateLocationMessage(user.username, `https://google.com/maps?q=${coords.latitude},${coords.longitude}`)) 55 | callback() 56 | }) 57 | 58 | socket.on('disconnect', () => { 59 | const user = removeUser(socket.id) 60 | 61 | if (user) { 62 | io.to(user.room).emit('message', generateMessage('Admin', `${user.username} has left!`)) 63 | io.to(user.room).emit('roomData', { 64 | room: user.room, 65 | users: getUsersInRoom(user.room) 66 | }) 67 | } 68 | }) 69 | }) 70 | 71 | server.listen(port, () => { 72 | console.log(`Server is up on port ${port}!`) 73 | }) -------------------------------------------------------------------------------- /web-server/src/app.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const express = require('express') 3 | const hbs = require('hbs') 4 | const geocode = require('./utils/geocode') 5 | const forecast = require('./utils/forecast') 6 | 7 | const app = express() 8 | const port = process.env.PORT || 3000 9 | 10 | // Define paths for Express config 11 | const publicDirectoryPath = path.join(__dirname, '../public') 12 | const viewsPath = path.join(__dirname, '../templates/views') 13 | const partialsPath = path.join(__dirname, '../templates/partials') 14 | 15 | // Setup handlebars engine and views location 16 | app.set('view engine', 'hbs') 17 | app.set('views', viewsPath) 18 | hbs.registerPartials(partialsPath) 19 | 20 | // Setup static directory to serve 21 | app.use(express.static(publicDirectoryPath)) 22 | 23 | app.get('', (req, res) => { 24 | res.render('index', { 25 | title: 'Weather', 26 | name: 'Andrew Mead' 27 | }) 28 | }) 29 | 30 | app.get('/about', (req, res) => { 31 | res.render('about', { 32 | title: 'About Me', 33 | name: 'Andrew Mead' 34 | }) 35 | }) 36 | 37 | app.get('/help', (req, res) => { 38 | res.render('help', { 39 | helpText: 'This is some helpful text.', 40 | title: 'Help', 41 | name: 'Andrew Mead' 42 | }) 43 | }) 44 | 45 | app.get('/weather', (req, res) => { 46 | if (!req.query.address) { 47 | return res.send({ 48 | error: 'You must provide an address!' 49 | }) 50 | } 51 | 52 | geocode(req.query.address, (error, { latitude, longitude, location } = {}) => { 53 | if (error) { 54 | return res.send({ error }) 55 | } 56 | 57 | forecast(latitude, longitude, (error, forecastData) => { 58 | if (error) { 59 | return res.send({ error }) 60 | } 61 | 62 | res.send({ 63 | forecast: forecastData, 64 | location, 65 | address: req.query.address 66 | }) 67 | }) 68 | }) 69 | }) 70 | 71 | app.get('/products', (req, res) => { 72 | if (!req.query.search) { 73 | return res.send({ 74 | error: 'You must provide a search term' 75 | }) 76 | } 77 | 78 | console.log(req.query.search) 79 | res.send({ 80 | products: [] 81 | }) 82 | }) 83 | 84 | app.get('/help/*', (req, res) => { 85 | res.render('404', { 86 | title: '404', 87 | name: 'Andrew Mead', 88 | errorMessage: 'Help article not found.' 89 | }) 90 | }) 91 | 92 | app.get('*', (req, res) => { 93 | res.render('404', { 94 | title: '404', 95 | name: 'Andrew Mead', 96 | errorMessage: 'Page not found.' 97 | }) 98 | }) 99 | 100 | app.listen(port, () => { 101 | console.log('Server is up on port ' + port) 102 | }) -------------------------------------------------------------------------------- /task-manager/src/routers/task.js: -------------------------------------------------------------------------------- 1 | const express = require('express') 2 | const Task = require('../models/task') 3 | const auth = require('../middleware/auth') 4 | const router = new express.Router() 5 | 6 | router.post('/tasks', auth, async (req, res) => { 7 | const task = new Task({ 8 | ...req.body, 9 | owner: req.user._id 10 | }) 11 | 12 | try { 13 | await task.save() 14 | res.status(201).send(task) 15 | } catch (e) { 16 | res.status(400).send(e) 17 | } 18 | }) 19 | 20 | // GET /tasks?completed=true 21 | // GET /tasks?limit=10&skip=20 22 | // GET /tasks?sortBy=createdAt:desc 23 | router.get('/tasks', auth, async (req, res) => { 24 | const match = {} 25 | const sort = {} 26 | 27 | if (req.query.completed) { 28 | match.completed = req.query.completed === 'true' 29 | } 30 | 31 | if (req.query.sortBy) { 32 | const parts = req.query.sortBy.split(':') 33 | sort[parts[0]] = parts[1] === 'desc' ? -1 : 1 34 | } 35 | 36 | try { 37 | await req.user.populate({ 38 | path: 'tasks', 39 | match, 40 | options: { 41 | limit: parseInt(req.query.limit), 42 | skip: parseInt(req.query.skip), 43 | sort 44 | } 45 | }).execPopulate() 46 | res.send(req.user.tasks) 47 | } catch (e) { 48 | res.status(500).send() 49 | } 50 | }) 51 | 52 | router.get('/tasks/:id', auth, async (req, res) => { 53 | const _id = req.params.id 54 | 55 | try { 56 | const task = await Task.findOne({ _id, owner: req.user._id }) 57 | 58 | if (!task) { 59 | return res.status(404).send() 60 | } 61 | 62 | res.send(task) 63 | } catch (e) { 64 | res.status(500).send() 65 | } 66 | }) 67 | 68 | router.patch('/tasks/:id', auth, async (req, res) => { 69 | const updates = Object.keys(req.body) 70 | const allowedUpdates = ['description', 'completed'] 71 | const isValidOperation = updates.every((update) => allowedUpdates.includes(update)) 72 | 73 | if (!isValidOperation) { 74 | return res.status(400).send({ error: 'Invalid updates!' }) 75 | } 76 | 77 | try { 78 | const task = await Task.findOne({ _id: req.params.id, owner: req.user._id}) 79 | 80 | if (!task) { 81 | return res.status(404).send() 82 | } 83 | 84 | updates.forEach((update) => task[update] = req.body[update]) 85 | await task.save() 86 | res.send(task) 87 | } catch (e) { 88 | res.status(400).send(e) 89 | } 90 | }) 91 | 92 | router.delete('/tasks/:id', auth, async (req, res) => { 93 | try { 94 | const task = await Task.findOneAndDelete({ _id: req.params.id, owner: req.user._id }) 95 | 96 | if (!task) { 97 | res.status(404).send() 98 | } 99 | 100 | res.send(task) 101 | } catch (e) { 102 | res.status(500).send() 103 | } 104 | }) 105 | 106 | module.exports = router -------------------------------------------------------------------------------- /task-manager/src/models/user.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose') 2 | const validator = require('validator') 3 | const bcrypt = require('bcryptjs') 4 | const jwt = require('jsonwebtoken') 5 | const Task = require('./task') 6 | 7 | const userSchema = new mongoose.Schema({ 8 | name: { 9 | type: String, 10 | required: true, 11 | trim: true 12 | }, 13 | email: { 14 | type: String, 15 | unique: true, 16 | required: true, 17 | trim: true, 18 | lowercase: true, 19 | validate(value) { 20 | if (!validator.isEmail(value)) { 21 | throw new Error('Email is invalid') 22 | } 23 | } 24 | }, 25 | password: { 26 | type: String, 27 | required: true, 28 | minlength: 7, 29 | trim: true, 30 | validate(value) { 31 | if (value.toLowerCase().includes('password')) { 32 | throw new Error('Password cannot contain "password"') 33 | } 34 | } 35 | }, 36 | age: { 37 | type: Number, 38 | default: 0, 39 | validate(value) { 40 | if (value < 0) { 41 | throw new Error('Age must be a postive number') 42 | } 43 | } 44 | }, 45 | tokens: [{ 46 | token: { 47 | type: String, 48 | required: true 49 | } 50 | }], 51 | avatar: { 52 | type: Buffer 53 | } 54 | }, { 55 | timestamps: true 56 | }) 57 | 58 | userSchema.virtual('tasks', { 59 | ref: 'Task', 60 | localField: '_id', 61 | foreignField: 'owner' 62 | }) 63 | 64 | userSchema.methods.toJSON = function () { 65 | const user = this 66 | const userObject = user.toObject() 67 | 68 | delete userObject.password 69 | delete userObject.tokens 70 | delete userObject.avatar 71 | 72 | return userObject 73 | } 74 | 75 | userSchema.methods.generateAuthToken = async function () { 76 | const user = this 77 | const token = jwt.sign({ _id: user._id.toString() }, process.env.JWT_SECRET) 78 | 79 | user.tokens = user.tokens.concat({ token }) 80 | await user.save() 81 | 82 | return token 83 | } 84 | 85 | userSchema.statics.findByCredentials = async (email, password) => { 86 | const user = await User.findOne({ email }) 87 | 88 | if (!user) { 89 | throw new Error('Unable to login') 90 | } 91 | 92 | const isMatch = await bcrypt.compare(password, user.password) 93 | 94 | if (!isMatch) { 95 | throw new Error('Unable to login') 96 | } 97 | 98 | return user 99 | } 100 | 101 | // Hash the plain text password before saving 102 | userSchema.pre('save', async function (next) { 103 | const user = this 104 | 105 | if (user.isModified('password')) { 106 | user.password = await bcrypt.hash(user.password, 8) 107 | } 108 | 109 | next() 110 | }) 111 | 112 | // Delete user tasks when user is removed 113 | userSchema.pre('remove', async function (next) { 114 | const user = this 115 | await Task.deleteMany({ owner: user._id }) 116 | next() 117 | }) 118 | 119 | const User = mongoose.model('User', userSchema) 120 | 121 | module.exports = User -------------------------------------------------------------------------------- /chat-app/public/css/styles.css: -------------------------------------------------------------------------------- 1 | /* General Styles */ 2 | 3 | * { 4 | margin: 0; 5 | padding: 0; 6 | box-sizing: border-box; 7 | } 8 | 9 | html { 10 | font-size: 16px; 11 | } 12 | 13 | input { 14 | font-size: 14px; 15 | } 16 | 17 | body { 18 | line-height: 1.4; 19 | color: #333333; 20 | font-family: Helvetica, Arial, sans-serif; 21 | } 22 | 23 | h1 { 24 | margin-bottom: 16px; 25 | } 26 | 27 | label { 28 | display: block; 29 | font-size: 14px; 30 | margin-bottom: 8px; 31 | color: #777; 32 | } 33 | 34 | input { 35 | border: 1px solid #eeeeee; 36 | padding: 12px; 37 | outline: none; 38 | } 39 | 40 | button { 41 | cursor: pointer; 42 | padding: 12px; 43 | background: #7C5CBF; 44 | border: none; 45 | color: white; 46 | font-size: 16px; 47 | transition: background .3s ease; 48 | } 49 | 50 | button:hover { 51 | background: #6b47b8; 52 | } 53 | 54 | button:disabled { 55 | cursor: default; 56 | background: #7c5cbf94; 57 | } 58 | 59 | /* Join Page Styles */ 60 | 61 | .centered-form { 62 | background: #333744; 63 | width: 100vw; 64 | height: 100vh; 65 | display: flex; 66 | justify-content: center; 67 | align-items: center; 68 | } 69 | 70 | .centered-form__box { 71 | box-shadow: 0px 0px 17px 1px #1D1F26; 72 | background: #F7F7FA; 73 | padding: 24px; 74 | width: 250px; 75 | } 76 | 77 | .centered-form button { 78 | width: 100%; 79 | } 80 | 81 | .centered-form input { 82 | margin-bottom: 16px; 83 | width: 100%; 84 | } 85 | 86 | /* Chat Page Layout */ 87 | 88 | .chat { 89 | display: flex; 90 | } 91 | 92 | .chat__sidebar { 93 | height: 100vh; 94 | color: white; 95 | background: #333744; 96 | width: 225px; 97 | overflow-y: scroll 98 | } 99 | 100 | /* Chat styles */ 101 | 102 | .chat__main { 103 | flex-grow: 1; 104 | display: flex; 105 | flex-direction: column; 106 | max-height: 100vh; 107 | } 108 | 109 | .chat__messages { 110 | flex-grow: 1; 111 | padding: 24px 24px 0 24px; 112 | overflow-y: scroll; 113 | } 114 | 115 | /* Message Styles */ 116 | 117 | .message { 118 | margin-bottom: 16px; 119 | } 120 | 121 | .message__name { 122 | font-weight: 600; 123 | font-size: 14px; 124 | margin-right: 8px; 125 | } 126 | 127 | .message__meta { 128 | color: #777; 129 | font-size: 14px; 130 | } 131 | 132 | .message a { 133 | color: #0070CC; 134 | } 135 | 136 | /* Message Composition Styles */ 137 | 138 | .compose { 139 | display: flex; 140 | flex-shrink: 0; 141 | margin-top: 16px; 142 | padding: 24px; 143 | } 144 | 145 | .compose form { 146 | display: flex; 147 | flex-grow: 1; 148 | margin-right: 16px; 149 | } 150 | 151 | .compose input { 152 | border: 1px solid #eeeeee; 153 | width: 100%; 154 | padding: 12px; 155 | margin: 0 16px 0 0; 156 | flex-grow: 1; 157 | } 158 | 159 | .compose button { 160 | font-size: 14px; 161 | } 162 | 163 | /* Chat Sidebar Styles */ 164 | 165 | .room-title { 166 | font-weight: 400; 167 | font-size: 22px; 168 | background: #2c2f3a; 169 | padding: 24px; 170 | } 171 | 172 | .list-title { 173 | font-weight: 500; 174 | font-size: 18px; 175 | margin-bottom: 4px; 176 | padding: 12px 24px 0 24px; 177 | } 178 | 179 | .users { 180 | list-style-type: none; 181 | font-weight: 300; 182 | padding: 12px 24px 0 24px; 183 | } -------------------------------------------------------------------------------- /task-manager/tests/user.test.js: -------------------------------------------------------------------------------- 1 | const request = require('supertest') 2 | const app = require('../src/app') 3 | const User = require('../src/models/user') 4 | const { userOneId, userOne, setupDatabase } = require('./fixtures/db') 5 | 6 | beforeEach(setupDatabase) 7 | 8 | test('Should signup a new user', async () => { 9 | const response = await request(app).post('/users').send({ 10 | name: 'Andrew', 11 | email: 'andrew@example.com', 12 | password: 'MyPass777!' 13 | }).expect(201) 14 | 15 | // Assert that the database was changed correctly 16 | const user = await User.findById(response.body.user._id) 17 | expect(user).not.toBeNull() 18 | 19 | // Assertions about the response 20 | expect(response.body).toMatchObject({ 21 | user: { 22 | name: 'Andrew', 23 | email: 'andrew@example.com' 24 | }, 25 | token: user.tokens[0].token 26 | }) 27 | expect(user.password).not.toBe('MyPass777!') 28 | }) 29 | 30 | test('Should login existing user', async () => { 31 | const response = await request(app).post('/users/login').send({ 32 | email: userOne.email, 33 | password: userOne.password 34 | }).expect(200) 35 | const user = await User.findById(userOneId) 36 | expect(response.body.token).toBe(user.tokens[1].token) 37 | }) 38 | 39 | test('Should not login nonexistent user', async () => { 40 | await request(app).post('/users/login').send({ 41 | email: userOne.email, 42 | password: 'thisisnotmypass' 43 | }).expect(400) 44 | }) 45 | 46 | test('Should get profile for user', async () => { 47 | await request(app) 48 | .get('/users/me') 49 | .set('Authorization', `Bearer ${userOne.tokens[0].token}`) 50 | .send() 51 | .expect(200) 52 | }) 53 | 54 | test('Should not get profile for unauthenticated user', async () => { 55 | await request(app) 56 | .get('/users/me') 57 | .send() 58 | .expect(401) 59 | }) 60 | 61 | test('Should delete account for user', async () => { 62 | await request(app) 63 | .delete('/users/me') 64 | .set('Authorization', `Bearer ${userOne.tokens[0].token}`) 65 | .send() 66 | .expect(200) 67 | const user = await User.findById(userOneId) 68 | expect(user).toBeNull() 69 | }) 70 | 71 | test('Should not delete account for unauthenticate user', async () => { 72 | await request(app) 73 | .delete('/users/me') 74 | .send() 75 | .expect(401) 76 | }) 77 | 78 | test('Should upload avatar image', async () => { 79 | await request(app) 80 | .post('/users/me/avatar') 81 | .set('Authorization', `Bearer ${userOne.tokens[0].token}`) 82 | .attach('avatar', 'tests/fixtures/profile-pic.jpg') 83 | .expect(200) 84 | const user = await User.findById(userOneId) 85 | expect(user.avatar).toEqual(expect.any(Buffer)) 86 | }) 87 | 88 | test('Should update valid user fields', async () => { 89 | await request(app) 90 | .patch('/users/me') 91 | .set('Authorization', `Bearer ${userOne.tokens[0].token}`) 92 | .send({ 93 | name: 'Jess' 94 | }) 95 | .expect(200) 96 | const user = await User.findById(userOneId) 97 | expect(user.name).toEqual('Jess') 98 | }) 99 | 100 | test('Should not update invalid user fields', async () => { 101 | await request(app) 102 | .patch('/users/me') 103 | .set('Authorization', `Bearer ${userOne.tokens[0].token}`) 104 | .send({ 105 | location: 'Philadelphia' 106 | }) 107 | .expect(400) 108 | }) -------------------------------------------------------------------------------- /chat-app/public/js/chat.js: -------------------------------------------------------------------------------- 1 | const socket = io() 2 | 3 | // Elements 4 | const $messageForm = document.querySelector('#message-form') 5 | const $messageFormInput = $messageForm.querySelector('input') 6 | const $messageFormButton = $messageForm.querySelector('button') 7 | const $sendLocationButton = document.querySelector('#send-location') 8 | const $messages = document.querySelector('#messages') 9 | 10 | // Templates 11 | const messageTemplate = document.querySelector('#message-template').innerHTML 12 | const locationMessageTemplate = document.querySelector('#location-message-template').innerHTML 13 | const sidebarTemplate = document.querySelector('#sidebar-template').innerHTML 14 | 15 | // Options 16 | const { username, room } = Qs.parse(location.search, { ignoreQueryPrefix: true }) 17 | 18 | const autoscroll = () => { 19 | // New message element 20 | const $newMessage = $messages.lastElementChild 21 | 22 | // Height of the new message 23 | const newMessageStyles = getComputedStyle($newMessage) 24 | const newMessageMargin = parseInt(newMessageStyles.marginBottom) 25 | const newMessageHeight = $newMessage.offsetHeight + newMessageMargin 26 | 27 | // Visible height 28 | const visibleHeight = $messages.offsetHeight 29 | 30 | // Height of messages container 31 | const containerHeight = $messages.scrollHeight 32 | 33 | // How far have I scrolled? 34 | const scrollOffset = $messages.scrollTop + visibleHeight 35 | 36 | if (containerHeight - newMessageHeight <= scrollOffset) { 37 | $messages.scrollTop = $messages.scrollHeight 38 | } 39 | } 40 | 41 | socket.on('message', (message) => { 42 | console.log(message) 43 | const html = Mustache.render(messageTemplate, { 44 | username: message.username, 45 | message: message.text, 46 | createdAt: moment(message.createdAt).format('h:mm a') 47 | }) 48 | $messages.insertAdjacentHTML('beforeend', html) 49 | autoscroll() 50 | }) 51 | 52 | socket.on('locationMessage', (message) => { 53 | console.log(message) 54 | const html = Mustache.render(locationMessageTemplate, { 55 | username: message.username, 56 | url: message.url, 57 | createdAt: moment(message.createdAt).format('h:mm a') 58 | }) 59 | $messages.insertAdjacentHTML('beforeend', html) 60 | autoscroll() 61 | }) 62 | 63 | socket.on('roomData', ({ room, users }) => { 64 | const html = Mustache.render(sidebarTemplate, { 65 | room, 66 | users 67 | }) 68 | document.querySelector('#sidebar').innerHTML = html 69 | }) 70 | 71 | $messageForm.addEventListener('submit', (e) => { 72 | e.preventDefault() 73 | 74 | $messageFormButton.setAttribute('disabled', 'disabled') 75 | 76 | const message = e.target.elements.message.value 77 | 78 | socket.emit('sendMessage', message, (error) => { 79 | $messageFormButton.removeAttribute('disabled') 80 | $messageFormInput.value = '' 81 | $messageFormInput.focus() 82 | 83 | if (error) { 84 | return console.log(error) 85 | } 86 | 87 | console.log('Message delivered!') 88 | }) 89 | }) 90 | 91 | $sendLocationButton.addEventListener('click', () => { 92 | if (!navigator.geolocation) { 93 | return alert('Geolocation is not supported by your browser.') 94 | } 95 | 96 | $sendLocationButton.setAttribute('disabled', 'disabled') 97 | 98 | navigator.geolocation.getCurrentPosition((position) => { 99 | socket.emit('sendLocation', { 100 | latitude: position.coords.latitude, 101 | longitude: position.coords.longitude 102 | }, () => { 103 | $sendLocationButton.removeAttribute('disabled') 104 | console.log('Location shared!') 105 | }) 106 | }) 107 | }) 108 | 109 | socket.emit('join', { username, room }, (error) => { 110 | if (error) { 111 | alert(error) 112 | location.href = '/' 113 | } 114 | }) -------------------------------------------------------------------------------- /task-manager/src/routers/user.js: -------------------------------------------------------------------------------- 1 | const express = require('express') 2 | const multer = require('multer') 3 | const sharp = require('sharp') 4 | const User = require('../models/user') 5 | const auth = require('../middleware/auth') 6 | const { sendWelcomeEmail, sendCancelationEmail } = require('../emails/account') 7 | const router = new express.Router() 8 | 9 | router.post('/users', async (req, res) => { 10 | const user = new User(req.body) 11 | 12 | try { 13 | await user.save() 14 | sendWelcomeEmail(user.email, user.name) 15 | const token = await user.generateAuthToken() 16 | res.status(201).send({ user, token }) 17 | } catch (e) { 18 | res.status(400).send(e) 19 | } 20 | }) 21 | 22 | router.post('/users/login', async (req, res) => { 23 | try { 24 | const user = await User.findByCredentials(req.body.email, req.body.password) 25 | const token = await user.generateAuthToken() 26 | res.send({ user, token }) 27 | } catch (e) { 28 | res.status(400).send() 29 | } 30 | }) 31 | 32 | router.post('/users/logout', auth, async (req, res) => { 33 | try { 34 | req.user.tokens = req.user.tokens.filter((token) => { 35 | return token.token !== req.token 36 | }) 37 | await req.user.save() 38 | 39 | res.send() 40 | } catch (e) { 41 | res.status(500).send() 42 | } 43 | }) 44 | 45 | router.post('/users/logoutAll', auth, async (req, res) => { 46 | try { 47 | req.user.tokens = [] 48 | await req.user.save() 49 | res.send() 50 | } catch (e) { 51 | res.status(500).send() 52 | } 53 | }) 54 | 55 | router.get('/users/me', auth, async (req, res) => { 56 | res.send(req.user) 57 | }) 58 | 59 | router.patch('/users/me', auth, async (req, res) => { 60 | const updates = Object.keys(req.body) 61 | const allowedUpdates = ['name', 'email', 'password', 'age'] 62 | const isValidOperation = updates.every((update) => allowedUpdates.includes(update)) 63 | 64 | if (!isValidOperation) { 65 | return res.status(400).send({ error: 'Invalid updates!' }) 66 | } 67 | 68 | try { 69 | updates.forEach((update) => req.user[update] = req.body[update]) 70 | await req.user.save() 71 | res.send(req.user) 72 | } catch (e) { 73 | res.status(400).send(e) 74 | } 75 | }) 76 | 77 | router.delete('/users/me', auth, async (req, res) => { 78 | try { 79 | await req.user.remove() 80 | sendCancelationEmail(req.user.email, req.user.name) 81 | res.send(req.user) 82 | } catch (e) { 83 | res.status(500).send() 84 | } 85 | }) 86 | 87 | const upload = multer({ 88 | limits: { 89 | fileSize: 1000000 90 | }, 91 | fileFilter(req, file, cb) { 92 | if (!file.originalname.match(/\.(jpg|jpeg|png)$/)) { 93 | return cb(new Error('Please upload an image')) 94 | } 95 | 96 | cb(undefined, true) 97 | } 98 | }) 99 | 100 | router.post('/users/me/avatar', auth, upload.single('avatar'), async (req, res) => { 101 | const buffer = await sharp(req.file.buffer).resize({ width: 250, height: 250 }).png().toBuffer() 102 | req.user.avatar = buffer 103 | await req.user.save() 104 | res.send() 105 | }, (error, req, res, next) => { 106 | res.status(400).send({ error: error.message }) 107 | }) 108 | 109 | router.delete('/users/me/avatar', auth, async (req, res) => { 110 | req.user.avatar = undefined 111 | await req.user.save() 112 | res.send() 113 | }) 114 | 115 | router.get('/users/:id/avatar', async (req, res) => { 116 | try { 117 | const user = await User.findById(req.params.id) 118 | 119 | if (!user || !user.avatar) { 120 | throw new Error() 121 | } 122 | 123 | res.set('Content-Type', 'image/png') 124 | res.send(user.avatar) 125 | } catch (e) { 126 | res.status(404).send() 127 | } 128 | }) 129 | 130 | module.exports = router -------------------------------------------------------------------------------- /weather-app/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "weather-app", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "ajv": { 8 | "version": "6.5.5", 9 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.5.tgz", 10 | "integrity": "sha512-7q7gtRQDJSyuEHjuVgHoUa2VuemFiCMrfQc9Tc08XTAc4Zj/5U1buQJ0HU6i7fKjXU09SVgSmxa4sLvuvS8Iyg==", 11 | "requires": { 12 | "fast-deep-equal": "^2.0.1", 13 | "fast-json-stable-stringify": "^2.0.0", 14 | "json-schema-traverse": "^0.4.1", 15 | "uri-js": "^4.2.2" 16 | } 17 | }, 18 | "asn1": { 19 | "version": "0.2.4", 20 | "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", 21 | "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", 22 | "requires": { 23 | "safer-buffer": "~2.1.0" 24 | } 25 | }, 26 | "assert-plus": { 27 | "version": "1.0.0", 28 | "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", 29 | "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" 30 | }, 31 | "asynckit": { 32 | "version": "0.4.0", 33 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 34 | "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" 35 | }, 36 | "aws-sign2": { 37 | "version": "0.7.0", 38 | "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", 39 | "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" 40 | }, 41 | "aws4": { 42 | "version": "1.8.0", 43 | "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", 44 | "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" 45 | }, 46 | "bcrypt-pbkdf": { 47 | "version": "1.0.2", 48 | "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", 49 | "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", 50 | "requires": { 51 | "tweetnacl": "^0.14.3" 52 | } 53 | }, 54 | "caseless": { 55 | "version": "0.12.0", 56 | "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", 57 | "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" 58 | }, 59 | "combined-stream": { 60 | "version": "1.0.7", 61 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", 62 | "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==", 63 | "requires": { 64 | "delayed-stream": "~1.0.0" 65 | } 66 | }, 67 | "core-util-is": { 68 | "version": "1.0.2", 69 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 70 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" 71 | }, 72 | "dashdash": { 73 | "version": "1.14.1", 74 | "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", 75 | "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", 76 | "requires": { 77 | "assert-plus": "^1.0.0" 78 | } 79 | }, 80 | "delayed-stream": { 81 | "version": "1.0.0", 82 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", 83 | "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" 84 | }, 85 | "ecc-jsbn": { 86 | "version": "0.1.2", 87 | "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", 88 | "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", 89 | "requires": { 90 | "jsbn": "~0.1.0", 91 | "safer-buffer": "^2.1.0" 92 | } 93 | }, 94 | "extend": { 95 | "version": "3.0.2", 96 | "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", 97 | "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" 98 | }, 99 | "extsprintf": { 100 | "version": "1.3.0", 101 | "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", 102 | "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" 103 | }, 104 | "fast-deep-equal": { 105 | "version": "2.0.1", 106 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", 107 | "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" 108 | }, 109 | "fast-json-stable-stringify": { 110 | "version": "2.0.0", 111 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", 112 | "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" 113 | }, 114 | "forever-agent": { 115 | "version": "0.6.1", 116 | "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", 117 | "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" 118 | }, 119 | "form-data": { 120 | "version": "2.3.3", 121 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", 122 | "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", 123 | "requires": { 124 | "asynckit": "^0.4.0", 125 | "combined-stream": "^1.0.6", 126 | "mime-types": "^2.1.12" 127 | } 128 | }, 129 | "getpass": { 130 | "version": "0.1.7", 131 | "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", 132 | "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", 133 | "requires": { 134 | "assert-plus": "^1.0.0" 135 | } 136 | }, 137 | "har-schema": { 138 | "version": "2.0.0", 139 | "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", 140 | "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" 141 | }, 142 | "har-validator": { 143 | "version": "5.1.2", 144 | "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.2.tgz", 145 | "integrity": "sha512-OFxb5MZXCUMx43X7O8LK4FKggEQx6yC5QPmOcBnYbJ9UjxEcMcrMbaR0af5HZpqeFopw2GwQRQi34ZXI7YLM5w==", 146 | "requires": { 147 | "ajv": "^6.5.5", 148 | "har-schema": "^2.0.0" 149 | } 150 | }, 151 | "http-signature": { 152 | "version": "1.2.0", 153 | "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", 154 | "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", 155 | "requires": { 156 | "assert-plus": "^1.0.0", 157 | "jsprim": "^1.2.2", 158 | "sshpk": "^1.7.0" 159 | } 160 | }, 161 | "is-typedarray": { 162 | "version": "1.0.0", 163 | "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", 164 | "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" 165 | }, 166 | "isstream": { 167 | "version": "0.1.2", 168 | "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", 169 | "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" 170 | }, 171 | "jsbn": { 172 | "version": "0.1.1", 173 | "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", 174 | "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" 175 | }, 176 | "json-schema": { 177 | "version": "0.2.3", 178 | "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", 179 | "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" 180 | }, 181 | "json-schema-traverse": { 182 | "version": "0.4.1", 183 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", 184 | "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" 185 | }, 186 | "json-stringify-safe": { 187 | "version": "5.0.1", 188 | "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", 189 | "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" 190 | }, 191 | "jsprim": { 192 | "version": "1.4.1", 193 | "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", 194 | "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", 195 | "requires": { 196 | "assert-plus": "1.0.0", 197 | "extsprintf": "1.3.0", 198 | "json-schema": "0.2.3", 199 | "verror": "1.10.0" 200 | } 201 | }, 202 | "mime-db": { 203 | "version": "1.37.0", 204 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.37.0.tgz", 205 | "integrity": "sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg==" 206 | }, 207 | "mime-types": { 208 | "version": "2.1.21", 209 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.21.tgz", 210 | "integrity": "sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg==", 211 | "requires": { 212 | "mime-db": "~1.37.0" 213 | } 214 | }, 215 | "oauth-sign": { 216 | "version": "0.9.0", 217 | "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", 218 | "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" 219 | }, 220 | "performance-now": { 221 | "version": "2.1.0", 222 | "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", 223 | "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" 224 | }, 225 | "psl": { 226 | "version": "1.1.29", 227 | "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.29.tgz", 228 | "integrity": "sha512-AeUmQ0oLN02flVHXWh9sSJF7mcdFq0ppid/JkErufc3hGIV/AMa8Fo9VgDo/cT2jFdOWoFvHp90qqBH54W+gjQ==" 229 | }, 230 | "punycode": { 231 | "version": "2.1.1", 232 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", 233 | "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" 234 | }, 235 | "qs": { 236 | "version": "6.5.2", 237 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", 238 | "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" 239 | }, 240 | "request": { 241 | "version": "2.88.0", 242 | "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", 243 | "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", 244 | "requires": { 245 | "aws-sign2": "~0.7.0", 246 | "aws4": "^1.8.0", 247 | "caseless": "~0.12.0", 248 | "combined-stream": "~1.0.6", 249 | "extend": "~3.0.2", 250 | "forever-agent": "~0.6.1", 251 | "form-data": "~2.3.2", 252 | "har-validator": "~5.1.0", 253 | "http-signature": "~1.2.0", 254 | "is-typedarray": "~1.0.0", 255 | "isstream": "~0.1.2", 256 | "json-stringify-safe": "~5.0.1", 257 | "mime-types": "~2.1.19", 258 | "oauth-sign": "~0.9.0", 259 | "performance-now": "^2.1.0", 260 | "qs": "~6.5.2", 261 | "safe-buffer": "^5.1.2", 262 | "tough-cookie": "~2.4.3", 263 | "tunnel-agent": "^0.6.0", 264 | "uuid": "^3.3.2" 265 | } 266 | }, 267 | "safe-buffer": { 268 | "version": "5.1.2", 269 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 270 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" 271 | }, 272 | "safer-buffer": { 273 | "version": "2.1.2", 274 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 275 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 276 | }, 277 | "sshpk": { 278 | "version": "1.15.2", 279 | "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.15.2.tgz", 280 | "integrity": "sha512-Ra/OXQtuh0/enyl4ETZAfTaeksa6BXks5ZcjpSUNrjBr0DvrJKX+1fsKDPpT9TBXgHAFsa4510aNVgI8g/+SzA==", 281 | "requires": { 282 | "asn1": "~0.2.3", 283 | "assert-plus": "^1.0.0", 284 | "bcrypt-pbkdf": "^1.0.0", 285 | "dashdash": "^1.12.0", 286 | "ecc-jsbn": "~0.1.1", 287 | "getpass": "^0.1.1", 288 | "jsbn": "~0.1.0", 289 | "safer-buffer": "^2.0.2", 290 | "tweetnacl": "~0.14.0" 291 | } 292 | }, 293 | "tough-cookie": { 294 | "version": "2.4.3", 295 | "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", 296 | "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", 297 | "requires": { 298 | "psl": "^1.1.24", 299 | "punycode": "^1.4.1" 300 | }, 301 | "dependencies": { 302 | "punycode": { 303 | "version": "1.4.1", 304 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", 305 | "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" 306 | } 307 | } 308 | }, 309 | "tunnel-agent": { 310 | "version": "0.6.0", 311 | "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", 312 | "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", 313 | "requires": { 314 | "safe-buffer": "^5.0.1" 315 | } 316 | }, 317 | "tweetnacl": { 318 | "version": "0.14.5", 319 | "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", 320 | "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" 321 | }, 322 | "uri-js": { 323 | "version": "4.2.2", 324 | "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", 325 | "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", 326 | "requires": { 327 | "punycode": "^2.1.0" 328 | } 329 | }, 330 | "uuid": { 331 | "version": "3.3.2", 332 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", 333 | "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" 334 | }, 335 | "verror": { 336 | "version": "1.10.0", 337 | "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", 338 | "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", 339 | "requires": { 340 | "assert-plus": "^1.0.0", 341 | "core-util-is": "1.0.2", 342 | "extsprintf": "^1.2.0" 343 | } 344 | } 345 | } 346 | } 347 | -------------------------------------------------------------------------------- /notes-app/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "notes-app", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "ansi-regex": { 8 | "version": "3.0.0", 9 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", 10 | "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" 11 | }, 12 | "ansi-styles": { 13 | "version": "3.2.1", 14 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 15 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 16 | "requires": { 17 | "color-convert": "^1.9.0" 18 | } 19 | }, 20 | "camelcase": { 21 | "version": "4.1.0", 22 | "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", 23 | "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=" 24 | }, 25 | "chalk": { 26 | "version": "2.4.1", 27 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz", 28 | "integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==", 29 | "requires": { 30 | "ansi-styles": "^3.2.1", 31 | "escape-string-regexp": "^1.0.5", 32 | "supports-color": "^5.3.0" 33 | } 34 | }, 35 | "cliui": { 36 | "version": "4.1.0", 37 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", 38 | "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", 39 | "requires": { 40 | "string-width": "^2.1.1", 41 | "strip-ansi": "^4.0.0", 42 | "wrap-ansi": "^2.0.0" 43 | } 44 | }, 45 | "code-point-at": { 46 | "version": "1.1.0", 47 | "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", 48 | "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" 49 | }, 50 | "color-convert": { 51 | "version": "1.9.3", 52 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 53 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 54 | "requires": { 55 | "color-name": "1.1.3" 56 | } 57 | }, 58 | "color-name": { 59 | "version": "1.1.3", 60 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 61 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" 62 | }, 63 | "cross-spawn": { 64 | "version": "6.0.5", 65 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", 66 | "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", 67 | "requires": { 68 | "nice-try": "^1.0.4", 69 | "path-key": "^2.0.1", 70 | "semver": "^5.5.0", 71 | "shebang-command": "^1.2.0", 72 | "which": "^1.2.9" 73 | } 74 | }, 75 | "decamelize": { 76 | "version": "2.0.0", 77 | "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-2.0.0.tgz", 78 | "integrity": "sha512-Ikpp5scV3MSYxY39ymh45ZLEecsTdv/Xj2CaQfI8RLMuwi7XvjX9H/fhraiSuU+C5w5NTDu4ZU72xNiZnurBPg==", 79 | "requires": { 80 | "xregexp": "4.0.0" 81 | } 82 | }, 83 | "escape-string-regexp": { 84 | "version": "1.0.5", 85 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 86 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" 87 | }, 88 | "execa": { 89 | "version": "0.10.0", 90 | "resolved": "https://registry.npmjs.org/execa/-/execa-0.10.0.tgz", 91 | "integrity": "sha512-7XOMnz8Ynx1gGo/3hyV9loYNPWM94jG3+3T3Y8tsfSstFmETmENCMU/A/zj8Lyaj1lkgEepKepvd6240tBRvlw==", 92 | "requires": { 93 | "cross-spawn": "^6.0.0", 94 | "get-stream": "^3.0.0", 95 | "is-stream": "^1.1.0", 96 | "npm-run-path": "^2.0.0", 97 | "p-finally": "^1.0.0", 98 | "signal-exit": "^3.0.0", 99 | "strip-eof": "^1.0.0" 100 | } 101 | }, 102 | "find-up": { 103 | "version": "3.0.0", 104 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", 105 | "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", 106 | "requires": { 107 | "locate-path": "^3.0.0" 108 | } 109 | }, 110 | "get-caller-file": { 111 | "version": "1.0.3", 112 | "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", 113 | "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==" 114 | }, 115 | "get-stream": { 116 | "version": "3.0.0", 117 | "resolved": "http://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", 118 | "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=" 119 | }, 120 | "has-flag": { 121 | "version": "3.0.0", 122 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 123 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" 124 | }, 125 | "invert-kv": { 126 | "version": "2.0.0", 127 | "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz", 128 | "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==" 129 | }, 130 | "is-fullwidth-code-point": { 131 | "version": "2.0.0", 132 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", 133 | "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" 134 | }, 135 | "is-stream": { 136 | "version": "1.1.0", 137 | "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", 138 | "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" 139 | }, 140 | "isexe": { 141 | "version": "2.0.0", 142 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", 143 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" 144 | }, 145 | "lcid": { 146 | "version": "2.0.0", 147 | "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz", 148 | "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==", 149 | "requires": { 150 | "invert-kv": "^2.0.0" 151 | } 152 | }, 153 | "locate-path": { 154 | "version": "3.0.0", 155 | "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", 156 | "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", 157 | "requires": { 158 | "p-locate": "^3.0.0", 159 | "path-exists": "^3.0.0" 160 | } 161 | }, 162 | "map-age-cleaner": { 163 | "version": "0.1.2", 164 | "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.2.tgz", 165 | "integrity": "sha512-UN1dNocxQq44IhJyMI4TU8phc2m9BddacHRPRjKGLYaF0jqd3xLz0jS0skpAU9WgYyoR4gHtUpzytNBS385FWQ==", 166 | "requires": { 167 | "p-defer": "^1.0.0" 168 | } 169 | }, 170 | "mem": { 171 | "version": "4.0.0", 172 | "resolved": "https://registry.npmjs.org/mem/-/mem-4.0.0.tgz", 173 | "integrity": "sha512-WQxG/5xYc3tMbYLXoXPm81ET2WDULiU5FxbuIoNbJqLOOI8zehXFdZuiUEgfdrU2mVB1pxBZUGlYORSrpuJreA==", 174 | "requires": { 175 | "map-age-cleaner": "^0.1.1", 176 | "mimic-fn": "^1.0.0", 177 | "p-is-promise": "^1.1.0" 178 | } 179 | }, 180 | "mimic-fn": { 181 | "version": "1.2.0", 182 | "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", 183 | "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==" 184 | }, 185 | "nice-try": { 186 | "version": "1.0.5", 187 | "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", 188 | "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==" 189 | }, 190 | "npm-run-path": { 191 | "version": "2.0.2", 192 | "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", 193 | "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", 194 | "requires": { 195 | "path-key": "^2.0.0" 196 | } 197 | }, 198 | "number-is-nan": { 199 | "version": "1.0.1", 200 | "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", 201 | "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" 202 | }, 203 | "os-locale": { 204 | "version": "3.0.1", 205 | "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.0.1.tgz", 206 | "integrity": "sha512-7g5e7dmXPtzcP4bgsZ8ixDVqA7oWYuEz4lOSujeWyliPai4gfVDiFIcwBg3aGCPnmSGfzOKTK3ccPn0CKv3DBw==", 207 | "requires": { 208 | "execa": "^0.10.0", 209 | "lcid": "^2.0.0", 210 | "mem": "^4.0.0" 211 | } 212 | }, 213 | "p-defer": { 214 | "version": "1.0.0", 215 | "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz", 216 | "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=" 217 | }, 218 | "p-finally": { 219 | "version": "1.0.0", 220 | "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", 221 | "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=" 222 | }, 223 | "p-is-promise": { 224 | "version": "1.1.0", 225 | "resolved": "http://registry.npmjs.org/p-is-promise/-/p-is-promise-1.1.0.tgz", 226 | "integrity": "sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4=" 227 | }, 228 | "p-limit": { 229 | "version": "2.0.0", 230 | "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.0.0.tgz", 231 | "integrity": "sha512-fl5s52lI5ahKCernzzIyAP0QAZbGIovtVHGwpcu1Jr/EpzLVDI2myISHwGqK7m8uQFugVWSrbxH7XnhGtvEc+A==", 232 | "requires": { 233 | "p-try": "^2.0.0" 234 | } 235 | }, 236 | "p-locate": { 237 | "version": "3.0.0", 238 | "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", 239 | "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", 240 | "requires": { 241 | "p-limit": "^2.0.0" 242 | } 243 | }, 244 | "p-try": { 245 | "version": "2.0.0", 246 | "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.0.0.tgz", 247 | "integrity": "sha512-hMp0onDKIajHfIkdRk3P4CdCmErkYAxxDtP3Wx/4nZ3aGlau2VKh3mZpcuFkH27WQkL/3WBCPOktzA9ZOAnMQQ==" 248 | }, 249 | "path-exists": { 250 | "version": "3.0.0", 251 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", 252 | "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" 253 | }, 254 | "path-key": { 255 | "version": "2.0.1", 256 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", 257 | "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" 258 | }, 259 | "require-directory": { 260 | "version": "2.1.1", 261 | "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", 262 | "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" 263 | }, 264 | "require-main-filename": { 265 | "version": "1.0.1", 266 | "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", 267 | "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=" 268 | }, 269 | "semver": { 270 | "version": "5.6.0", 271 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", 272 | "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==" 273 | }, 274 | "set-blocking": { 275 | "version": "2.0.0", 276 | "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", 277 | "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" 278 | }, 279 | "shebang-command": { 280 | "version": "1.2.0", 281 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", 282 | "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", 283 | "requires": { 284 | "shebang-regex": "^1.0.0" 285 | } 286 | }, 287 | "shebang-regex": { 288 | "version": "1.0.0", 289 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", 290 | "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" 291 | }, 292 | "signal-exit": { 293 | "version": "3.0.2", 294 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", 295 | "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" 296 | }, 297 | "string-width": { 298 | "version": "2.1.1", 299 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", 300 | "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", 301 | "requires": { 302 | "is-fullwidth-code-point": "^2.0.0", 303 | "strip-ansi": "^4.0.0" 304 | } 305 | }, 306 | "strip-ansi": { 307 | "version": "4.0.0", 308 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", 309 | "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", 310 | "requires": { 311 | "ansi-regex": "^3.0.0" 312 | } 313 | }, 314 | "strip-eof": { 315 | "version": "1.0.0", 316 | "resolved": "http://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", 317 | "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=" 318 | }, 319 | "supports-color": { 320 | "version": "5.5.0", 321 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 322 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 323 | "requires": { 324 | "has-flag": "^3.0.0" 325 | } 326 | }, 327 | "validator": { 328 | "version": "10.8.0", 329 | "resolved": "https://registry.npmjs.org/validator/-/validator-10.8.0.tgz", 330 | "integrity": "sha512-mXqMxfCh5NLsVgYVKl9WvnHNDPCcbNppHSPPowu0VjtSsGWVY+z8hJF44edLR1nbLNzi3jYoYsIl8KZpioIk6g==" 331 | }, 332 | "which": { 333 | "version": "1.3.1", 334 | "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", 335 | "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", 336 | "requires": { 337 | "isexe": "^2.0.0" 338 | } 339 | }, 340 | "which-module": { 341 | "version": "2.0.0", 342 | "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", 343 | "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" 344 | }, 345 | "wrap-ansi": { 346 | "version": "2.1.0", 347 | "resolved": "http://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", 348 | "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", 349 | "requires": { 350 | "string-width": "^1.0.1", 351 | "strip-ansi": "^3.0.1" 352 | }, 353 | "dependencies": { 354 | "ansi-regex": { 355 | "version": "2.1.1", 356 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", 357 | "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" 358 | }, 359 | "is-fullwidth-code-point": { 360 | "version": "1.0.0", 361 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", 362 | "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", 363 | "requires": { 364 | "number-is-nan": "^1.0.0" 365 | } 366 | }, 367 | "string-width": { 368 | "version": "1.0.2", 369 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", 370 | "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", 371 | "requires": { 372 | "code-point-at": "^1.0.0", 373 | "is-fullwidth-code-point": "^1.0.0", 374 | "strip-ansi": "^3.0.0" 375 | } 376 | }, 377 | "strip-ansi": { 378 | "version": "3.0.1", 379 | "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", 380 | "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", 381 | "requires": { 382 | "ansi-regex": "^2.0.0" 383 | } 384 | } 385 | } 386 | }, 387 | "xregexp": { 388 | "version": "4.0.0", 389 | "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-4.0.0.tgz", 390 | "integrity": "sha512-PHyM+sQouu7xspQQwELlGwwd05mXUFqwFYfqPO0cC7x4fxyHnnuetmQr6CjJiafIDoH4MogHb9dOoJzR/Y4rFg==" 391 | }, 392 | "y18n": { 393 | "version": "4.0.0", 394 | "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", 395 | "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==" 396 | }, 397 | "yargs": { 398 | "version": "12.0.2", 399 | "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.2.tgz", 400 | "integrity": "sha512-e7SkEx6N6SIZ5c5H22RTZae61qtn3PYUE8JYbBFlK9sYmh3DMQ6E5ygtaG/2BW0JZi4WGgTR2IV5ChqlqrDGVQ==", 401 | "requires": { 402 | "cliui": "^4.0.0", 403 | "decamelize": "^2.0.0", 404 | "find-up": "^3.0.0", 405 | "get-caller-file": "^1.0.1", 406 | "os-locale": "^3.0.0", 407 | "require-directory": "^2.1.1", 408 | "require-main-filename": "^1.0.1", 409 | "set-blocking": "^2.0.0", 410 | "string-width": "^2.0.0", 411 | "which-module": "^2.0.0", 412 | "y18n": "^3.2.1 || ^4.0.0", 413 | "yargs-parser": "^10.1.0" 414 | } 415 | }, 416 | "yargs-parser": { 417 | "version": "10.1.0", 418 | "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-10.1.0.tgz", 419 | "integrity": "sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ==", 420 | "requires": { 421 | "camelcase": "^4.1.0" 422 | } 423 | } 424 | } 425 | } 426 | -------------------------------------------------------------------------------- /web-server/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "web-server", 3 | "version": "1.0.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "accepts": { 8 | "version": "1.3.5", 9 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.5.tgz", 10 | "integrity": "sha1-63d99gEXI6OxTopywIBcjoZ0a9I=", 11 | "requires": { 12 | "mime-types": "~2.1.18", 13 | "negotiator": "0.6.1" 14 | } 15 | }, 16 | "ajv": { 17 | "version": "6.5.5", 18 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.5.5.tgz", 19 | "integrity": "sha512-7q7gtRQDJSyuEHjuVgHoUa2VuemFiCMrfQc9Tc08XTAc4Zj/5U1buQJ0HU6i7fKjXU09SVgSmxa4sLvuvS8Iyg==", 20 | "requires": { 21 | "fast-deep-equal": "^2.0.1", 22 | "fast-json-stable-stringify": "^2.0.0", 23 | "json-schema-traverse": "^0.4.1", 24 | "uri-js": "^4.2.2" 25 | } 26 | }, 27 | "align-text": { 28 | "version": "0.1.4", 29 | "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", 30 | "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", 31 | "requires": { 32 | "kind-of": "^3.0.2", 33 | "longest": "^1.0.1", 34 | "repeat-string": "^1.5.2" 35 | } 36 | }, 37 | "amdefine": { 38 | "version": "1.0.1", 39 | "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", 40 | "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=" 41 | }, 42 | "ansi-styles": { 43 | "version": "1.0.0", 44 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.0.0.tgz", 45 | "integrity": "sha1-yxAt8cVvUSPquLZ817mAJ6AnkXg=", 46 | "dev": true 47 | }, 48 | "argparse": { 49 | "version": "1.0.10", 50 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", 51 | "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", 52 | "dev": true, 53 | "requires": { 54 | "sprintf-js": "~1.0.2" 55 | } 56 | }, 57 | "array-flatten": { 58 | "version": "1.1.1", 59 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", 60 | "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" 61 | }, 62 | "asn1": { 63 | "version": "0.2.4", 64 | "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", 65 | "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", 66 | "requires": { 67 | "safer-buffer": "~2.1.0" 68 | } 69 | }, 70 | "assert-plus": { 71 | "version": "1.0.0", 72 | "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", 73 | "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" 74 | }, 75 | "async": { 76 | "version": "1.5.2", 77 | "resolved": "http://registry.npmjs.org/async/-/async-1.5.2.tgz", 78 | "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=" 79 | }, 80 | "asynckit": { 81 | "version": "0.4.0", 82 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 83 | "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" 84 | }, 85 | "aws-sign2": { 86 | "version": "0.7.0", 87 | "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", 88 | "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" 89 | }, 90 | "aws4": { 91 | "version": "1.8.0", 92 | "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", 93 | "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" 94 | }, 95 | "bcrypt-pbkdf": { 96 | "version": "1.0.2", 97 | "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", 98 | "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", 99 | "requires": { 100 | "tweetnacl": "^0.14.3" 101 | } 102 | }, 103 | "body-parser": { 104 | "version": "1.18.3", 105 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.3.tgz", 106 | "integrity": "sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=", 107 | "requires": { 108 | "bytes": "3.0.0", 109 | "content-type": "~1.0.4", 110 | "debug": "2.6.9", 111 | "depd": "~1.1.2", 112 | "http-errors": "~1.6.3", 113 | "iconv-lite": "0.4.23", 114 | "on-finished": "~2.3.0", 115 | "qs": "6.5.2", 116 | "raw-body": "2.3.3", 117 | "type-is": "~1.6.16" 118 | } 119 | }, 120 | "bytes": { 121 | "version": "3.0.0", 122 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", 123 | "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" 124 | }, 125 | "camelcase": { 126 | "version": "1.2.1", 127 | "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", 128 | "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", 129 | "optional": true 130 | }, 131 | "caseless": { 132 | "version": "0.12.0", 133 | "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", 134 | "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" 135 | }, 136 | "center-align": { 137 | "version": "0.1.3", 138 | "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", 139 | "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", 140 | "optional": true, 141 | "requires": { 142 | "align-text": "^0.1.3", 143 | "lazy-cache": "^1.0.3" 144 | } 145 | }, 146 | "chalk": { 147 | "version": "0.4.0", 148 | "resolved": "http://registry.npmjs.org/chalk/-/chalk-0.4.0.tgz", 149 | "integrity": "sha1-UZmj3c0MHv4jvAjBsCewYXbgxk8=", 150 | "dev": true, 151 | "requires": { 152 | "ansi-styles": "~1.0.0", 153 | "has-color": "~0.1.0", 154 | "strip-ansi": "~0.1.0" 155 | } 156 | }, 157 | "cliui": { 158 | "version": "2.1.0", 159 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", 160 | "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", 161 | "optional": true, 162 | "requires": { 163 | "center-align": "^0.1.1", 164 | "right-align": "^0.1.1", 165 | "wordwrap": "0.0.2" 166 | }, 167 | "dependencies": { 168 | "wordwrap": { 169 | "version": "0.0.2", 170 | "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", 171 | "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", 172 | "optional": true 173 | } 174 | } 175 | }, 176 | "combined-stream": { 177 | "version": "1.0.7", 178 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", 179 | "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==", 180 | "requires": { 181 | "delayed-stream": "~1.0.0" 182 | } 183 | }, 184 | "configstore": { 185 | "version": "0.3.2", 186 | "resolved": "https://registry.npmjs.org/configstore/-/configstore-0.3.2.tgz", 187 | "integrity": "sha1-JeTBbDdoq/dcWmW8YXYfSVBVtFk=", 188 | "dev": true, 189 | "requires": { 190 | "graceful-fs": "^3.0.1", 191 | "js-yaml": "^3.1.0", 192 | "mkdirp": "^0.5.0", 193 | "object-assign": "^2.0.0", 194 | "osenv": "^0.1.0", 195 | "user-home": "^1.0.0", 196 | "uuid": "^2.0.1", 197 | "xdg-basedir": "^1.0.0" 198 | }, 199 | "dependencies": { 200 | "uuid": { 201 | "version": "2.0.3", 202 | "resolved": "http://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz", 203 | "integrity": "sha1-Z+LoY3lyFVMN/zGOW/nc6/1Hsho=", 204 | "dev": true 205 | } 206 | } 207 | }, 208 | "content-disposition": { 209 | "version": "0.5.2", 210 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", 211 | "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" 212 | }, 213 | "content-type": { 214 | "version": "1.0.4", 215 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", 216 | "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" 217 | }, 218 | "cookie": { 219 | "version": "0.3.1", 220 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", 221 | "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=" 222 | }, 223 | "cookie-signature": { 224 | "version": "1.0.6", 225 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", 226 | "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" 227 | }, 228 | "core-util-is": { 229 | "version": "1.0.2", 230 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 231 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" 232 | }, 233 | "dashdash": { 234 | "version": "1.14.1", 235 | "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", 236 | "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", 237 | "requires": { 238 | "assert-plus": "^1.0.0" 239 | } 240 | }, 241 | "debug": { 242 | "version": "2.6.9", 243 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", 244 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", 245 | "requires": { 246 | "ms": "2.0.0" 247 | } 248 | }, 249 | "decamelize": { 250 | "version": "1.2.0", 251 | "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", 252 | "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", 253 | "optional": true 254 | }, 255 | "delayed-stream": { 256 | "version": "1.0.0", 257 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", 258 | "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" 259 | }, 260 | "depd": { 261 | "version": "1.1.2", 262 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", 263 | "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" 264 | }, 265 | "destroy": { 266 | "version": "1.0.4", 267 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", 268 | "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" 269 | }, 270 | "ecc-jsbn": { 271 | "version": "0.1.2", 272 | "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", 273 | "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", 274 | "requires": { 275 | "jsbn": "~0.1.0", 276 | "safer-buffer": "^2.1.0" 277 | } 278 | }, 279 | "ee-first": { 280 | "version": "1.1.1", 281 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", 282 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" 283 | }, 284 | "encodeurl": { 285 | "version": "1.0.2", 286 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", 287 | "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" 288 | }, 289 | "escape-html": { 290 | "version": "1.0.3", 291 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", 292 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" 293 | }, 294 | "esprima": { 295 | "version": "4.0.1", 296 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", 297 | "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", 298 | "dev": true 299 | }, 300 | "etag": { 301 | "version": "1.8.1", 302 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", 303 | "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" 304 | }, 305 | "event-stream": { 306 | "version": "0.5.3", 307 | "resolved": "http://registry.npmjs.org/event-stream/-/event-stream-0.5.3.tgz", 308 | "integrity": "sha1-t3uTCfcQet3+q2PwwOr9jbC9jBw=", 309 | "dev": true, 310 | "requires": { 311 | "optimist": "0.2" 312 | }, 313 | "dependencies": { 314 | "optimist": { 315 | "version": "0.2.8", 316 | "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.2.8.tgz", 317 | "integrity": "sha1-6YGrfiaLRXlIWTtVZ0wJmoFcrDE=", 318 | "dev": true, 319 | "requires": { 320 | "wordwrap": ">=0.0.1 <0.1.0" 321 | } 322 | } 323 | } 324 | }, 325 | "express": { 326 | "version": "4.16.4", 327 | "resolved": "https://registry.npmjs.org/express/-/express-4.16.4.tgz", 328 | "integrity": "sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg==", 329 | "requires": { 330 | "accepts": "~1.3.5", 331 | "array-flatten": "1.1.1", 332 | "body-parser": "1.18.3", 333 | "content-disposition": "0.5.2", 334 | "content-type": "~1.0.4", 335 | "cookie": "0.3.1", 336 | "cookie-signature": "1.0.6", 337 | "debug": "2.6.9", 338 | "depd": "~1.1.2", 339 | "encodeurl": "~1.0.2", 340 | "escape-html": "~1.0.3", 341 | "etag": "~1.8.1", 342 | "finalhandler": "1.1.1", 343 | "fresh": "0.5.2", 344 | "merge-descriptors": "1.0.1", 345 | "methods": "~1.1.2", 346 | "on-finished": "~2.3.0", 347 | "parseurl": "~1.3.2", 348 | "path-to-regexp": "0.1.7", 349 | "proxy-addr": "~2.0.4", 350 | "qs": "6.5.2", 351 | "range-parser": "~1.2.0", 352 | "safe-buffer": "5.1.2", 353 | "send": "0.16.2", 354 | "serve-static": "1.13.2", 355 | "setprototypeof": "1.1.0", 356 | "statuses": "~1.4.0", 357 | "type-is": "~1.6.16", 358 | "utils-merge": "1.0.1", 359 | "vary": "~1.1.2" 360 | } 361 | }, 362 | "extend": { 363 | "version": "3.0.2", 364 | "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", 365 | "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" 366 | }, 367 | "extsprintf": { 368 | "version": "1.3.0", 369 | "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", 370 | "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" 371 | }, 372 | "fast-deep-equal": { 373 | "version": "2.0.1", 374 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", 375 | "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=" 376 | }, 377 | "fast-json-stable-stringify": { 378 | "version": "2.0.0", 379 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", 380 | "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" 381 | }, 382 | "finalhandler": { 383 | "version": "1.1.1", 384 | "resolved": "http://registry.npmjs.org/finalhandler/-/finalhandler-1.1.1.tgz", 385 | "integrity": "sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==", 386 | "requires": { 387 | "debug": "2.6.9", 388 | "encodeurl": "~1.0.2", 389 | "escape-html": "~1.0.3", 390 | "on-finished": "~2.3.0", 391 | "parseurl": "~1.3.2", 392 | "statuses": "~1.4.0", 393 | "unpipe": "~1.0.0" 394 | } 395 | }, 396 | "foreachasync": { 397 | "version": "3.0.0", 398 | "resolved": "https://registry.npmjs.org/foreachasync/-/foreachasync-3.0.0.tgz", 399 | "integrity": "sha1-VQKYfchxS+M5IJfzLgBxyd7gfPY=" 400 | }, 401 | "forever-agent": { 402 | "version": "0.6.1", 403 | "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", 404 | "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" 405 | }, 406 | "form-data": { 407 | "version": "2.3.3", 408 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", 409 | "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", 410 | "requires": { 411 | "asynckit": "^0.4.0", 412 | "combined-stream": "^1.0.6", 413 | "mime-types": "^2.1.12" 414 | } 415 | }, 416 | "forwarded": { 417 | "version": "0.1.2", 418 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", 419 | "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" 420 | }, 421 | "fresh": { 422 | "version": "0.5.2", 423 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", 424 | "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" 425 | }, 426 | "getpass": { 427 | "version": "0.1.7", 428 | "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", 429 | "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", 430 | "requires": { 431 | "assert-plus": "^1.0.0" 432 | } 433 | }, 434 | "graceful-fs": { 435 | "version": "3.0.11", 436 | "resolved": "http://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.11.tgz", 437 | "integrity": "sha1-dhPHeKGv6mLyXGMKCG1/Osu92Bg=", 438 | "dev": true, 439 | "requires": { 440 | "natives": "^1.1.0" 441 | } 442 | }, 443 | "handlebars": { 444 | "version": "4.0.5", 445 | "resolved": "http://registry.npmjs.org/handlebars/-/handlebars-4.0.5.tgz", 446 | "integrity": "sha1-ksbta7FkEQxQ1NjQ+93HCAbG+Oc=", 447 | "requires": { 448 | "async": "^1.4.0", 449 | "optimist": "^0.6.1", 450 | "source-map": "^0.4.4", 451 | "uglify-js": "^2.6" 452 | } 453 | }, 454 | "har-schema": { 455 | "version": "2.0.0", 456 | "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", 457 | "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" 458 | }, 459 | "har-validator": { 460 | "version": "5.1.3", 461 | "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", 462 | "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", 463 | "requires": { 464 | "ajv": "^6.5.5", 465 | "har-schema": "^2.0.0" 466 | } 467 | }, 468 | "has-color": { 469 | "version": "0.1.7", 470 | "resolved": "https://registry.npmjs.org/has-color/-/has-color-0.1.7.tgz", 471 | "integrity": "sha1-ZxRKUmDDT8PMpnfQQdr1L+e3iy8=", 472 | "dev": true 473 | }, 474 | "hbs": { 475 | "version": "4.0.1", 476 | "resolved": "https://registry.npmjs.org/hbs/-/hbs-4.0.1.tgz", 477 | "integrity": "sha1-S/2YZQ3IydrESzyprfnAmOi8M7Y=", 478 | "requires": { 479 | "handlebars": "4.0.5", 480 | "walk": "2.3.9" 481 | } 482 | }, 483 | "http-errors": { 484 | "version": "1.6.3", 485 | "resolved": "http://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", 486 | "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", 487 | "requires": { 488 | "depd": "~1.1.2", 489 | "inherits": "2.0.3", 490 | "setprototypeof": "1.1.0", 491 | "statuses": ">= 1.4.0 < 2" 492 | } 493 | }, 494 | "http-signature": { 495 | "version": "1.2.0", 496 | "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", 497 | "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", 498 | "requires": { 499 | "assert-plus": "^1.0.0", 500 | "jsprim": "^1.2.2", 501 | "sshpk": "^1.7.0" 502 | } 503 | }, 504 | "iconv-lite": { 505 | "version": "0.4.23", 506 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.23.tgz", 507 | "integrity": "sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==", 508 | "requires": { 509 | "safer-buffer": ">= 2.1.2 < 3" 510 | } 511 | }, 512 | "inherits": { 513 | "version": "2.0.3", 514 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 515 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 516 | }, 517 | "ipaddr.js": { 518 | "version": "1.8.0", 519 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.8.0.tgz", 520 | "integrity": "sha1-6qM9bd16zo9/b+DJygRA5wZzix4=" 521 | }, 522 | "is-buffer": { 523 | "version": "1.1.6", 524 | "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", 525 | "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" 526 | }, 527 | "is-typedarray": { 528 | "version": "1.0.0", 529 | "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", 530 | "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" 531 | }, 532 | "isstream": { 533 | "version": "0.1.2", 534 | "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", 535 | "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" 536 | }, 537 | "js-yaml": { 538 | "version": "3.12.0", 539 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.0.tgz", 540 | "integrity": "sha512-PIt2cnwmPfL4hKNwqeiuz4bKfnzHTBv6HyVgjahA6mPLwPDzjDWrplJBMjHUFxku/N3FlmrbyPclad+I+4mJ3A==", 541 | "dev": true, 542 | "requires": { 543 | "argparse": "^1.0.7", 544 | "esprima": "^4.0.0" 545 | } 546 | }, 547 | "jsbn": { 548 | "version": "0.1.1", 549 | "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", 550 | "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" 551 | }, 552 | "json-schema": { 553 | "version": "0.2.3", 554 | "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", 555 | "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" 556 | }, 557 | "json-schema-traverse": { 558 | "version": "0.4.1", 559 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", 560 | "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" 561 | }, 562 | "json-stringify-safe": { 563 | "version": "5.0.1", 564 | "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", 565 | "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" 566 | }, 567 | "jsprim": { 568 | "version": "1.4.1", 569 | "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", 570 | "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", 571 | "requires": { 572 | "assert-plus": "1.0.0", 573 | "extsprintf": "1.3.0", 574 | "json-schema": "0.2.3", 575 | "verror": "1.10.0" 576 | } 577 | }, 578 | "kind-of": { 579 | "version": "3.2.2", 580 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", 581 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", 582 | "requires": { 583 | "is-buffer": "^1.1.5" 584 | } 585 | }, 586 | "lazy-cache": { 587 | "version": "1.0.4", 588 | "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", 589 | "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", 590 | "optional": true 591 | }, 592 | "longest": { 593 | "version": "1.0.1", 594 | "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", 595 | "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=" 596 | }, 597 | "lru-cache": { 598 | "version": "2.7.3", 599 | "resolved": "http://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", 600 | "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=", 601 | "dev": true 602 | }, 603 | "media-typer": { 604 | "version": "0.3.0", 605 | "resolved": "http://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", 606 | "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" 607 | }, 608 | "merge-descriptors": { 609 | "version": "1.0.1", 610 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", 611 | "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" 612 | }, 613 | "methods": { 614 | "version": "1.1.2", 615 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", 616 | "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" 617 | }, 618 | "mime": { 619 | "version": "1.4.1", 620 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", 621 | "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==" 622 | }, 623 | "mime-db": { 624 | "version": "1.37.0", 625 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.37.0.tgz", 626 | "integrity": "sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg==" 627 | }, 628 | "mime-types": { 629 | "version": "2.1.21", 630 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.21.tgz", 631 | "integrity": "sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg==", 632 | "requires": { 633 | "mime-db": "~1.37.0" 634 | } 635 | }, 636 | "minimatch": { 637 | "version": "0.3.0", 638 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.3.0.tgz", 639 | "integrity": "sha1-J12O2qxPG7MyZHIInnlJyDlGmd0=", 640 | "dev": true, 641 | "requires": { 642 | "lru-cache": "2", 643 | "sigmund": "~1.0.0" 644 | } 645 | }, 646 | "minimist": { 647 | "version": "0.0.10", 648 | "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz", 649 | "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=" 650 | }, 651 | "mkdirp": { 652 | "version": "0.5.1", 653 | "resolved": "http://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", 654 | "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", 655 | "dev": true, 656 | "requires": { 657 | "minimist": "0.0.8" 658 | }, 659 | "dependencies": { 660 | "minimist": { 661 | "version": "0.0.8", 662 | "resolved": "http://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", 663 | "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", 664 | "dev": true 665 | } 666 | } 667 | }, 668 | "ms": { 669 | "version": "2.0.0", 670 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 671 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 672 | }, 673 | "natives": { 674 | "version": "1.1.6", 675 | "resolved": "https://registry.npmjs.org/natives/-/natives-1.1.6.tgz", 676 | "integrity": "sha512-6+TDFewD4yxY14ptjKaS63GVdtKiES1pTPyxn9Jb0rBqPMZ7VcCiooEhPNsr+mqHtMGxa/5c/HhcC4uPEUw/nA==", 677 | "dev": true 678 | }, 679 | "negotiator": { 680 | "version": "0.6.1", 681 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", 682 | "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" 683 | }, 684 | "nodemon": { 685 | "version": "1.2.0", 686 | "resolved": "http://registry.npmjs.org/nodemon/-/nodemon-1.2.0.tgz", 687 | "integrity": "sha1-/WT7vScwyCj+iXAmraU6ta5Ccnw=", 688 | "dev": true, 689 | "requires": { 690 | "minimatch": "~0.3.0", 691 | "ps-tree": "~0.0.3", 692 | "update-notifier": "~0.1.8" 693 | } 694 | }, 695 | "oauth-sign": { 696 | "version": "0.9.0", 697 | "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", 698 | "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" 699 | }, 700 | "object-assign": { 701 | "version": "2.1.1", 702 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz", 703 | "integrity": "sha1-Q8NuXVaf+OSBbE76i+AtJpZ8GKo=", 704 | "dev": true 705 | }, 706 | "on-finished": { 707 | "version": "2.3.0", 708 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", 709 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", 710 | "requires": { 711 | "ee-first": "1.1.1" 712 | } 713 | }, 714 | "optimist": { 715 | "version": "0.6.1", 716 | "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", 717 | "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", 718 | "requires": { 719 | "minimist": "~0.0.1", 720 | "wordwrap": "~0.0.2" 721 | } 722 | }, 723 | "os-homedir": { 724 | "version": "1.0.2", 725 | "resolved": "http://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", 726 | "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", 727 | "dev": true 728 | }, 729 | "os-tmpdir": { 730 | "version": "1.0.2", 731 | "resolved": "http://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", 732 | "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", 733 | "dev": true 734 | }, 735 | "osenv": { 736 | "version": "0.1.5", 737 | "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", 738 | "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", 739 | "dev": true, 740 | "requires": { 741 | "os-homedir": "^1.0.0", 742 | "os-tmpdir": "^1.0.0" 743 | } 744 | }, 745 | "parseurl": { 746 | "version": "1.3.2", 747 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", 748 | "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=" 749 | }, 750 | "path-to-regexp": { 751 | "version": "0.1.7", 752 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", 753 | "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" 754 | }, 755 | "performance-now": { 756 | "version": "2.1.0", 757 | "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", 758 | "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" 759 | }, 760 | "proxy-addr": { 761 | "version": "2.0.4", 762 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.4.tgz", 763 | "integrity": "sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA==", 764 | "requires": { 765 | "forwarded": "~0.1.2", 766 | "ipaddr.js": "1.8.0" 767 | } 768 | }, 769 | "ps-tree": { 770 | "version": "0.0.3", 771 | "resolved": "http://registry.npmjs.org/ps-tree/-/ps-tree-0.0.3.tgz", 772 | "integrity": "sha1-2/jXUqf+Ivp9WGNWiUmWEOknbdw=", 773 | "dev": true, 774 | "requires": { 775 | "event-stream": "~0.5" 776 | } 777 | }, 778 | "psl": { 779 | "version": "1.1.29", 780 | "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.29.tgz", 781 | "integrity": "sha512-AeUmQ0oLN02flVHXWh9sSJF7mcdFq0ppid/JkErufc3hGIV/AMa8Fo9VgDo/cT2jFdOWoFvHp90qqBH54W+gjQ==" 782 | }, 783 | "punycode": { 784 | "version": "2.1.1", 785 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", 786 | "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" 787 | }, 788 | "qs": { 789 | "version": "6.5.2", 790 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", 791 | "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" 792 | }, 793 | "range-parser": { 794 | "version": "1.2.0", 795 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", 796 | "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" 797 | }, 798 | "raw-body": { 799 | "version": "2.3.3", 800 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.3.tgz", 801 | "integrity": "sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==", 802 | "requires": { 803 | "bytes": "3.0.0", 804 | "http-errors": "1.6.3", 805 | "iconv-lite": "0.4.23", 806 | "unpipe": "1.0.0" 807 | } 808 | }, 809 | "repeat-string": { 810 | "version": "1.6.1", 811 | "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", 812 | "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" 813 | }, 814 | "request": { 815 | "version": "2.88.0", 816 | "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", 817 | "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", 818 | "requires": { 819 | "aws-sign2": "~0.7.0", 820 | "aws4": "^1.8.0", 821 | "caseless": "~0.12.0", 822 | "combined-stream": "~1.0.6", 823 | "extend": "~3.0.2", 824 | "forever-agent": "~0.6.1", 825 | "form-data": "~2.3.2", 826 | "har-validator": "~5.1.0", 827 | "http-signature": "~1.2.0", 828 | "is-typedarray": "~1.0.0", 829 | "isstream": "~0.1.2", 830 | "json-stringify-safe": "~5.0.1", 831 | "mime-types": "~2.1.19", 832 | "oauth-sign": "~0.9.0", 833 | "performance-now": "^2.1.0", 834 | "qs": "~6.5.2", 835 | "safe-buffer": "^5.1.2", 836 | "tough-cookie": "~2.4.3", 837 | "tunnel-agent": "^0.6.0", 838 | "uuid": "^3.3.2" 839 | } 840 | }, 841 | "right-align": { 842 | "version": "0.1.3", 843 | "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", 844 | "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", 845 | "optional": true, 846 | "requires": { 847 | "align-text": "^0.1.1" 848 | } 849 | }, 850 | "safe-buffer": { 851 | "version": "5.1.2", 852 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 853 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" 854 | }, 855 | "safer-buffer": { 856 | "version": "2.1.2", 857 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 858 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 859 | }, 860 | "semver": { 861 | "version": "2.3.2", 862 | "resolved": "http://registry.npmjs.org/semver/-/semver-2.3.2.tgz", 863 | "integrity": "sha1-uYSPJdbPNjMwc+ye+IVtQvEjPlI=", 864 | "dev": true 865 | }, 866 | "send": { 867 | "version": "0.16.2", 868 | "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", 869 | "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", 870 | "requires": { 871 | "debug": "2.6.9", 872 | "depd": "~1.1.2", 873 | "destroy": "~1.0.4", 874 | "encodeurl": "~1.0.2", 875 | "escape-html": "~1.0.3", 876 | "etag": "~1.8.1", 877 | "fresh": "0.5.2", 878 | "http-errors": "~1.6.2", 879 | "mime": "1.4.1", 880 | "ms": "2.0.0", 881 | "on-finished": "~2.3.0", 882 | "range-parser": "~1.2.0", 883 | "statuses": "~1.4.0" 884 | } 885 | }, 886 | "serve-static": { 887 | "version": "1.13.2", 888 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", 889 | "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", 890 | "requires": { 891 | "encodeurl": "~1.0.2", 892 | "escape-html": "~1.0.3", 893 | "parseurl": "~1.3.2", 894 | "send": "0.16.2" 895 | } 896 | }, 897 | "setprototypeof": { 898 | "version": "1.1.0", 899 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", 900 | "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" 901 | }, 902 | "sigmund": { 903 | "version": "1.0.1", 904 | "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", 905 | "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", 906 | "dev": true 907 | }, 908 | "source-map": { 909 | "version": "0.4.4", 910 | "resolved": "http://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", 911 | "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", 912 | "requires": { 913 | "amdefine": ">=0.0.4" 914 | } 915 | }, 916 | "sprintf-js": { 917 | "version": "1.0.3", 918 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", 919 | "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", 920 | "dev": true 921 | }, 922 | "sshpk": { 923 | "version": "1.15.2", 924 | "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.15.2.tgz", 925 | "integrity": "sha512-Ra/OXQtuh0/enyl4ETZAfTaeksa6BXks5ZcjpSUNrjBr0DvrJKX+1fsKDPpT9TBXgHAFsa4510aNVgI8g/+SzA==", 926 | "requires": { 927 | "asn1": "~0.2.3", 928 | "assert-plus": "^1.0.0", 929 | "bcrypt-pbkdf": "^1.0.0", 930 | "dashdash": "^1.12.0", 931 | "ecc-jsbn": "~0.1.1", 932 | "getpass": "^0.1.1", 933 | "jsbn": "~0.1.0", 934 | "safer-buffer": "^2.0.2", 935 | "tweetnacl": "~0.14.0" 936 | } 937 | }, 938 | "statuses": { 939 | "version": "1.4.0", 940 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", 941 | "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==" 942 | }, 943 | "strip-ansi": { 944 | "version": "0.1.1", 945 | "resolved": "http://registry.npmjs.org/strip-ansi/-/strip-ansi-0.1.1.tgz", 946 | "integrity": "sha1-OeipjQRNFQZgq+SmgIrPcLt7yZE=", 947 | "dev": true 948 | }, 949 | "tough-cookie": { 950 | "version": "2.4.3", 951 | "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", 952 | "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", 953 | "requires": { 954 | "psl": "^1.1.24", 955 | "punycode": "^1.4.1" 956 | }, 957 | "dependencies": { 958 | "punycode": { 959 | "version": "1.4.1", 960 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", 961 | "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" 962 | } 963 | } 964 | }, 965 | "tunnel-agent": { 966 | "version": "0.6.0", 967 | "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", 968 | "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", 969 | "requires": { 970 | "safe-buffer": "^5.0.1" 971 | } 972 | }, 973 | "tweetnacl": { 974 | "version": "0.14.5", 975 | "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", 976 | "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" 977 | }, 978 | "type-is": { 979 | "version": "1.6.16", 980 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz", 981 | "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==", 982 | "requires": { 983 | "media-typer": "0.3.0", 984 | "mime-types": "~2.1.18" 985 | } 986 | }, 987 | "uglify-js": { 988 | "version": "2.8.29", 989 | "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", 990 | "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", 991 | "optional": true, 992 | "requires": { 993 | "source-map": "~0.5.1", 994 | "uglify-to-browserify": "~1.0.0", 995 | "yargs": "~3.10.0" 996 | }, 997 | "dependencies": { 998 | "source-map": { 999 | "version": "0.5.7", 1000 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", 1001 | "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", 1002 | "optional": true 1003 | } 1004 | } 1005 | }, 1006 | "uglify-to-browserify": { 1007 | "version": "1.0.2", 1008 | "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", 1009 | "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", 1010 | "optional": true 1011 | }, 1012 | "unpipe": { 1013 | "version": "1.0.0", 1014 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", 1015 | "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" 1016 | }, 1017 | "update-notifier": { 1018 | "version": "0.1.10", 1019 | "resolved": "http://registry.npmjs.org/update-notifier/-/update-notifier-0.1.10.tgz", 1020 | "integrity": "sha1-IVy+EFM2nw1KRPhLUeuny4BIRpU=", 1021 | "dev": true, 1022 | "requires": { 1023 | "chalk": "^0.4.0", 1024 | "configstore": "^0.3.0", 1025 | "request": "^2.36.0", 1026 | "semver": "^2.3.0" 1027 | } 1028 | }, 1029 | "uri-js": { 1030 | "version": "4.2.2", 1031 | "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", 1032 | "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", 1033 | "requires": { 1034 | "punycode": "^2.1.0" 1035 | } 1036 | }, 1037 | "user-home": { 1038 | "version": "1.1.1", 1039 | "resolved": "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz", 1040 | "integrity": "sha1-K1viOjK2Onyd640PKNSFcko98ZA=", 1041 | "dev": true 1042 | }, 1043 | "utils-merge": { 1044 | "version": "1.0.1", 1045 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", 1046 | "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" 1047 | }, 1048 | "uuid": { 1049 | "version": "3.3.2", 1050 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", 1051 | "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" 1052 | }, 1053 | "vary": { 1054 | "version": "1.1.2", 1055 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", 1056 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" 1057 | }, 1058 | "verror": { 1059 | "version": "1.10.0", 1060 | "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", 1061 | "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", 1062 | "requires": { 1063 | "assert-plus": "^1.0.0", 1064 | "core-util-is": "1.0.2", 1065 | "extsprintf": "^1.2.0" 1066 | } 1067 | }, 1068 | "walk": { 1069 | "version": "2.3.9", 1070 | "resolved": "https://registry.npmjs.org/walk/-/walk-2.3.9.tgz", 1071 | "integrity": "sha1-MbTbZnjyrgHDnqn7hyWpAx5Vins=", 1072 | "requires": { 1073 | "foreachasync": "^3.0.0" 1074 | } 1075 | }, 1076 | "window-size": { 1077 | "version": "0.1.0", 1078 | "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", 1079 | "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", 1080 | "optional": true 1081 | }, 1082 | "wordwrap": { 1083 | "version": "0.0.3", 1084 | "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", 1085 | "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=" 1086 | }, 1087 | "xdg-basedir": { 1088 | "version": "1.0.1", 1089 | "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-1.0.1.tgz", 1090 | "integrity": "sha1-FP+PY6T9vLBdW27qIrNvMDO58E4=", 1091 | "dev": true, 1092 | "requires": { 1093 | "user-home": "^1.0.0" 1094 | } 1095 | }, 1096 | "yargs": { 1097 | "version": "3.10.0", 1098 | "resolved": "http://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", 1099 | "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", 1100 | "optional": true, 1101 | "requires": { 1102 | "camelcase": "^1.0.2", 1103 | "cliui": "^2.1.0", 1104 | "decamelize": "^1.0.0", 1105 | "window-size": "0.1.0" 1106 | } 1107 | } 1108 | } 1109 | } 1110 | --------------------------------------------------------------------------------