├── .gitignore
├── LICENSE
├── README2.md
├── ReadMe.md
├── Readme.md
├── _data
├── bootcamps.json
├── courses.json
├── reviews.json
└── users.json
├── config
├── config.env.env
└── db.js
├── controllers
├── auth.js
├── bootcamps.js
├── courses.js
├── reviews.js
└── users.js
├── middleware
├── advancedResults.js
├── async.js
├── auth.js
├── error.js
└── logger.js
├── models
├── Bootcamp.js
├── Course.js
├── Review.js
└── User.js
├── package-lock.json
├── package.json
├── public
├── fonts
│ ├── glyphicons-halflings-regular.eot
│ ├── glyphicons-halflings-regular.woff
│ └── glyphicons-halflings-regular.woff2
└── index.html
├── routes
├── auth.js
├── bootcamps.js
├── courses.js
├── reviews.js
└── users.js
├── seeder.js
├── server.js
└── utils
├── errorResponse.js
├── geocoder.js
└── sendEmail.js
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules/
2 | .DS_Store
3 | config/config.env
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Packt
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README2.md:
--------------------------------------------------------------------------------
1 | # DevCamper API
2 |
3 | > Backend API for DevCamper application, which is a bootcamp directory website
4 |
5 | ## Usage
6 |
7 | Rename "config/config.env.env" to "config/config.env" and update the values/settings to your own
8 |
9 | ## Install Dependencies
10 |
11 | ```
12 | npm install
13 | ```
14 |
15 | ## Run App
16 |
17 | ```
18 | # Run in dev mode
19 | npm run dev
20 |
21 | # Run in prod mode
22 | npm start
23 | ```
24 |
25 | ## Database Seeder
26 |
27 | To seed the database with users, bootcamps, courses and reviews with data from the "\_data" folder, run
28 |
29 | ```
30 | # Destroy all data
31 | node seeder -d
32 |
33 | # Import all data
34 | node seeder -i
35 | ```
36 |
37 | ## Demo
38 |
39 | The API is live at [devcamper.io](https://devcamper.io)
40 |
41 | Extensive documentation with examples [here](https://documenter.getpostman.com/view/8923145/SVtVVTzd?version=latest)
42 |
43 | - Version: 1.0.0
44 | - License: MIT
45 | - Author: Brad Traversy
46 |
--------------------------------------------------------------------------------
/ReadMe.md:
--------------------------------------------------------------------------------
1 | This is the code repository for [ Node.js API Masterclass with Express and MongoDB [Video]](https://www.packtpub.com/web-development/node-js-api-masterclass-with-express-and-mongodb-video), published by [Packt](https://www.packtpub.com/?utm_source=github). It contains all the supporting project files necessary to work through the video course from start to finish.
2 | ## About the Video Course
3 | This course will help you to create an extensive, in-depth backend API for DevCamper, a Bootcamp directory app. You’ll learn how to deploy a professional API with documentation from the ground up.
4 |
5 | The course starts with an overview of the project and an introduction to the HTTP essentials and Postman client. You’ll study HTTP status codes and how to send data to the server. The next section of the course will take you through the DevCamper project and show you how to create routes and responses in Express along with creating controller methods. As you make progress, you’ll learn how to create, fetch, and update and delete Bootcamps. You’ll also get to grips with the concepts of authentication, users, and permissions.
6 |
7 | By the end of the course, you’ll be able to build a real-world backend RESTful API for a Bootcamp directory app and have learned about advanced Mongoose queries.
8 |
9 |
What You Will Learn
10 |
11 |
12 | - Create a real-world backend RESTful API for a Bootcamp directory app
13 |
- Get to grips with HTTP fundamentals, including Req/Res Cycle and status codes
14 |
- Understand advanced Mongoose queries
15 |
- Explore API security NoSQL injection, XSS protection, and rate-limiting
16 |
- Work on API documentation and deployment
17 |
18 |
19 | ### Course Requirements
20 | For successful completion of this course, students will need knowledge of the following:
21 | • Javascript fundamentals
22 | • Basic programming principles and control structures
23 | • Modern Javascript (ES6) - Arrows, promises, destructuring and more
24 |
25 |
26 |
27 | ### Recommended Hardware Requirements:
28 | For an optimal experience with hands-on labs and other practical activities, we recommend the following configuration:
29 |
30 | • Windows 10
31 | • OS: Microsoft Windows 10/8 (incl.64-bit)
32 | • Processor: Dual core processor
33 | • Memory: 4 GB RAM minimum, 8 GB RAM recommended
34 | • Storage: 1.5 GB hard disk space + at least 1 GB for caches
35 | • Optional: GPU: NVIDIA® GPU card with CUDA® Compute Capability 3.5 or higher.
36 |
37 |
38 |
39 | ## Related Products
40 | * [RESTful API Design with Node, Express, and MongoDB [Video]](https://www.packtpub.com/application-development/restful-api-design-node-express-and-mongodb-video)
41 |
42 | * [The Complete Node.js Developer Course (3rd Edition) [Video]](https://www.packtpub.com/application-development/complete-nodejs-developer-course-3rd-edition-video)
43 |
44 | * [Node.js, Express and MongoDB Dev to Deployment [Video]](https://www.packtpub.com/application-development/nodejs-express-and-mongodb-dev-deployment-video)
45 |
--------------------------------------------------------------------------------
/Readme.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/_data/bootcamps.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "_id": "5d713995b721c3bb38c1f5d0",
4 | "user": "5d7a514b5d2c12c7449be045",
5 | "name": "Devworks Bootcamp",
6 | "description": "Devworks is a full stack JavaScript Bootcamp located in the heart of Boston that focuses on the technologies you need to get a high paying job as a web developer",
7 | "website": "https://devworks.com",
8 | "phone": "(111) 111-1111",
9 | "email": "enroll@devworks.com",
10 | "address": "233 Bay State Rd Boston MA 02215",
11 | "careers": ["Web Development", "UI/UX", "Business"],
12 | "housing": true,
13 | "jobAssistance": true,
14 | "jobGuarantee": false,
15 | "acceptGi": true
16 | },
17 | {
18 | "_id": "5d713a66ec8f2b88b8f830b8",
19 | "user": "5d7a514b5d2c12c7449be046",
20 | "name": "ModernTech Bootcamp",
21 | "description": "ModernTech has one goal, and that is to make you a rockstar developer and/or designer with a six figure salary. We teach both development and UI/UX",
22 | "website": "https://moderntech.com",
23 | "phone": "(222) 222-2222",
24 | "email": "enroll@moderntech.com",
25 | "address": "220 Pawtucket St, Lowell, MA 01854",
26 | "careers": ["Web Development", "UI/UX", "Mobile Development"],
27 | "housing": false,
28 | "jobAssistance": true,
29 | "jobGuarantee": false,
30 | "acceptGi": true
31 | },
32 | {
33 | "_id": "5d725a037b292f5f8ceff787",
34 | "user": "5c8a1d5b0190b214360dc031",
35 | "name": "Codemasters",
36 | "description": "Is coding your passion? Codemasters will give you the skills and the tools to become the best developer possible. We specialize in full stack web development and data science",
37 | "website": "https://codemasters.com",
38 | "phone": "(333) 333-3333",
39 | "email": "enroll@codemasters.com",
40 | "address": "85 South Prospect Street Burlington VT 05405",
41 | "careers": ["Web Development", "Data Science", "Business"],
42 | "housing": false,
43 | "jobAssistance": false,
44 | "jobGuarantee": false,
45 | "acceptGi": false
46 | },
47 | {
48 | "_id": "5d725a1b7b292f5f8ceff788",
49 | "user": "5c8a1d5b0190b214360dc032",
50 | "name": "Devcentral Bootcamp",
51 | "description": "Is coding your passion? Codemasters will give you the skills and the tools to become the best developer possible. We specialize in front end and full stack web development",
52 | "website": "https://devcentral.com",
53 | "phone": "(444) 444-4444",
54 | "email": "enroll@devcentral.com",
55 | "address": "45 Upper College Rd Kingston RI 02881",
56 | "careers": [
57 | "Mobile Development",
58 | "Web Development",
59 | "Data Science",
60 | "Business"
61 | ],
62 | "housing": false,
63 | "jobAssistance": true,
64 | "jobGuarantee": true,
65 | "acceptGi": true
66 | }
67 | ]
68 |
--------------------------------------------------------------------------------
/_data/courses.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "_id": "5d725a4a7b292f5f8ceff789",
4 | "title": "Front End Web Development",
5 | "description": "This course will provide you with all of the essentials to become a successful frontend web developer. You will learn to master HTML, CSS and front end JavaScript, along with tools like Git, VSCode and front end frameworks like Vue",
6 | "weeks": 8,
7 | "tuition": 8000,
8 | "minimumSkill": "beginner",
9 | "scholarshipsAvailable": true,
10 | "bootcamp": "5d713995b721c3bb38c1f5d0",
11 | "user": "5d7a514b5d2c12c7449be045"
12 | },
13 | {
14 | "_id": "5d725c84c4ded7bcb480eaa0",
15 | "title": "Full Stack Web Development",
16 | "description": "In this course you will learn full stack web development, first learning all about the frontend with HTML/CSS/JS/Vue and then the backend with Node.js/Express/MongoDB",
17 | "weeks": 12,
18 | "tuition": 10000,
19 | "minimumSkill": "intermediate",
20 | "scholarshipsAvailable": true,
21 | "bootcamp": "5d713995b721c3bb38c1f5d0",
22 | "user": "5d7a514b5d2c12c7449be045"
23 | },
24 | {
25 | "_id": "5d725cb9c4ded7bcb480eaa1",
26 | "title": "Full Stack Web Dev",
27 | "description": "In this course you will learn all about the front end with HTML, CSS and JavaScript. You will master tools like Git and Webpack and also learn C# and ASP.NET with Postgres",
28 | "weeks": 10,
29 | "tuition": 12000,
30 | "minimumSkill": "intermediate",
31 | "scholarshipsAvailable": true,
32 | "bootcamp": "5d713a66ec8f2b88b8f830b8",
33 | "user": "5d7a514b5d2c12c7449be046"
34 | },
35 | {
36 | "_id": "5d725cd2c4ded7bcb480eaa2",
37 | "title": "UI/UX",
38 | "description": "In this course you will learn to create beautiful interfaces. It is a mix of design and development to create modern user experiences on both web and mobile",
39 | "weeks": 12,
40 | "tuition": 10000,
41 | "minimumSkill": "intermediate",
42 | "scholarshipsAvailable": true,
43 | "bootcamp": "5d713a66ec8f2b88b8f830b8",
44 | "user": "5d7a514b5d2c12c7449be046"
45 | },
46 | {
47 | "_id": "5d725ce8c4ded7bcb480eaa3",
48 | "title": "Web Design & Development",
49 | "description": "Get started building websites and web apps with HTML/CSS/JavaScript/PHP. We teach you",
50 | "weeks": 10,
51 | "tuition": 12000,
52 | "minimumSkill": "beginner",
53 | "scholarshipsAvailable": true,
54 | "bootcamp": "5d725a037b292f5f8ceff787",
55 | "user": "5c8a1d5b0190b214360dc031"
56 | },
57 | {
58 | "_id": "5d725cfec4ded7bcb480eaa4",
59 | "title": "Data Science Program",
60 | "description": "In this course you will learn Python for data science, machine learning and big data tools",
61 | "weeks": 10,
62 | "tuition": 9000,
63 | "minimumSkill": "intermediate",
64 | "scholarshipsAvailable": false,
65 | "bootcamp": "5d725a037b292f5f8ceff787",
66 | "user": "5c8a1d5b0190b214360dc031"
67 | },
68 | {
69 | "_id": "5d725cfec4ded7bcb480eaa5",
70 | "title": "Web Development",
71 | "description": "This course will teach you how to build high quality web applications with technologies like React, Node.js, PHP & Laravel",
72 | "weeks": 8,
73 | "tuition": 8000,
74 | "minimumSkill": "beginner",
75 | "scholarshipsAvailable": false,
76 | "bootcamp": "5d725a1b7b292f5f8ceff788",
77 | "user": "5c8a1d5b0190b214360dc032"
78 | },
79 | {
80 | "_id": "5d725cfec4ded7bcb480eaa6",
81 | "title": "Software QA",
82 | "description": "This course will teach you everything you need to know about quality assurance",
83 | "weeks": 6,
84 | "tuition": 5000,
85 | "minimumSkill": "intermediate",
86 | "scholarshipsAvailable": false,
87 | "bootcamp": "5d725a1b7b292f5f8ceff788",
88 | "user": "5c8a1d5b0190b214360dc032"
89 | },
90 | {
91 | "_id": "5d725cfec4ded7bcb480eaa7",
92 | "title": "IOS Development",
93 | "description": "Get started building mobile applications for IOS using Swift and other tools",
94 | "weeks": 8,
95 | "tuition": 6000,
96 | "minimumSkill": "intermediate",
97 | "scholarshipsAvailable": false,
98 | "bootcamp": "5d725a1b7b292f5f8ceff788",
99 | "user": "5c8a1d5b0190b214360dc032"
100 | }
101 | ]
102 |
--------------------------------------------------------------------------------
/_data/reviews.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "_id": "5d7a514b5d2c12c7449be020",
4 | "title": "Learned a ton!",
5 | "text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec viverra feugiat mauris id viverra. Duis luctus ex sed facilisis ultrices. Curabitur scelerisque bibendum ligula, quis condimentum libero fermentum in. Aenean erat erat, aliquam in purus a, rhoncus hendrerit tellus. Donec accumsan justo in felis consequat sollicitudin. Fusce luctus mattis nunc vitae maximus. Curabitur semper felis eu magna laoreet scelerisque",
6 | "rating": "8",
7 | "bootcamp": "5d713995b721c3bb38c1f5d0",
8 | "user": "5c8a1d5b0190b214360dc033"
9 | },
10 | {
11 | "_id": "5d7a514b5d2c12c7449be021",
12 | "title": "Great bootcamp",
13 | "text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec viverra feugiat mauris id viverra. Duis luctus ex sed facilisis ultrices. Curabitur scelerisque bibendum ligula, quis condimentum libero fermentum in. Aenean erat erat, aliquam in purus a, rhoncus hendrerit tellus. Donec accumsan justo in felis consequat sollicitudin. Fusce luctus mattis nunc vitae maximus. Curabitur semper felis eu magna laoreet scelerisque",
14 | "rating": "10",
15 | "bootcamp": "5d713995b721c3bb38c1f5d0",
16 | "user": "5c8a1d5b0190b214360dc034"
17 | },
18 | {
19 | "_id": "5d7a514b5d2c12c7449be022",
20 | "title": "Got me a developer job",
21 | "text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec viverra feugiat mauris id viverra. Duis luctus ex sed facilisis ultrices. Curabitur scelerisque bibendum ligula, quis condimentum libero fermentum in. Aenean erat erat, aliquam in purus a, rhoncus hendrerit tellus. Donec accumsan justo in felis consequat sollicitudin. Fusce luctus mattis nunc vitae maximus. Curabitur semper felis eu magna laoreet scelerisque",
22 | "rating": "7",
23 | "bootcamp": "5d713a66ec8f2b88b8f830b8",
24 | "user": "5c8a1d5b0190b214360dc035"
25 | },
26 | {
27 | "_id": "5d7a514b5d2c12c7449be023",
28 | "title": "Not that great",
29 | "text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec viverra feugiat mauris id viverra. Duis luctus ex sed facilisis ultrices. Curabitur scelerisque bibendum ligula, quis condimentum libero fermentum in. Aenean erat erat, aliquam in purus a, rhoncus hendrerit tellus. Donec accumsan justo in felis consequat sollicitudin. Fusce luctus mattis nunc vitae maximus. Curabitur semper felis eu magna laoreet scelerisque",
30 | "rating": "4",
31 | "bootcamp": "5d713a66ec8f2b88b8f830b8",
32 | "user": "5c8a1d5b0190b214360dc036"
33 | },
34 | {
35 | "_id": "5d7a514b5d2c12c7449be024",
36 | "title": "Great overall experience",
37 | "text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec viverra feugiat mauris id viverra. Duis luctus ex sed facilisis ultrices. Curabitur scelerisque bibendum ligula, quis condimentum libero fermentum in. Aenean erat erat, aliquam in purus a, rhoncus hendrerit tellus. Donec accumsan justo in felis consequat sollicitudin. Fusce luctus mattis nunc vitae maximus. Curabitur semper felis eu magna laoreet scelerisque",
38 | "rating": "7",
39 | "bootcamp": "5d725a037b292f5f8ceff787",
40 | "user": "5c8a1d5b0190b214360dc037"
41 | },
42 | {
43 | "_id": "5d7a514b5d2c12c7449be025",
44 | "title": "Not worth the money",
45 | "text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec viverra feugiat mauris id viverra. Duis luctus ex sed facilisis ultrices. Curabitur scelerisque bibendum ligula, quis condimentum libero fermentum in. Aenean erat erat, aliquam in purus a, rhoncus hendrerit tellus. Donec accumsan justo in felis consequat sollicitudin. Fusce luctus mattis nunc vitae maximus. Curabitur semper felis eu magna laoreet scelerisque",
46 | "rating": "5",
47 | "bootcamp": "5d725a037b292f5f8ceff787",
48 | "user": "5c8a1d5b0190b214360dc038"
49 | },
50 | {
51 | "_id": "5d7a514b5d2c12c7449be026",
52 | "title": "Best instructors",
53 | "text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec viverra feugiat mauris id viverra. Duis luctus ex sed facilisis ultrices. Curabitur scelerisque bibendum ligula, quis condimentum libero fermentum in. Aenean erat erat, aliquam in purus a, rhoncus hendrerit tellus. Donec accumsan justo in felis consequat sollicitudin. Fusce luctus mattis nunc vitae maximus. Curabitur semper felis eu magna laoreet scelerisque",
54 | "rating": "10",
55 | "bootcamp": "5d725a1b7b292f5f8ceff788",
56 | "user": "5c8a1d5b0190b214360dc039"
57 | },
58 | {
59 | "_id": "5d7a514b5d2c12c7449be027",
60 | "title": "Was worth the investment",
61 | "text": "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec viverra feugiat mauris id viverra. Duis luctus ex sed facilisis ultrices. Curabitur scelerisque bibendum ligula, quis condimentum libero fermentum in. Aenean erat erat, aliquam in purus a, rhoncus hendrerit tellus. Donec accumsan justo in felis consequat sollicitudin. Fusce luctus mattis nunc vitae maximus. Curabitur semper felis eu magna laoreet scelerisque",
62 | "rating": "7",
63 | "bootcamp": "5d725a1b7b292f5f8ceff788",
64 | "user": "5c8a1d5b0190b214360dc040"
65 | }
66 | ]
67 |
--------------------------------------------------------------------------------
/_data/users.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "_id": "5d7a514b5d2c12c7449be042",
4 | "name": "Admin Account",
5 | "email": "admin@gmail.com",
6 | "role": "user",
7 | "password": "123456"
8 | },
9 | {
10 | "_id": "5d7a514b5d2c12c7449be043",
11 | "name": "Publisher Account",
12 | "email": "publisher@gmail.com",
13 | "role": "publisher",
14 | "password": "123456"
15 | },
16 | {
17 | "_id": "5d7a514b5d2c12c7449be044",
18 | "name": "User Account",
19 | "email": "user@gmail.com",
20 | "role": "user",
21 | "password": "123456"
22 | },
23 | {
24 | "_id": "5d7a514b5d2c12c7449be045",
25 | "name": "John Doe",
26 | "email": "john@gmail.com",
27 | "role": "publisher",
28 | "password": "123456"
29 | },
30 | {
31 | "_id": "5d7a514b5d2c12c7449be046",
32 | "name": "Kevin Smith",
33 | "email": "kevin@gmail.com",
34 | "role": "publisher",
35 | "password": "123456"
36 | },
37 | {
38 | "_id": "5c8a1d5b0190b214360dc031",
39 | "name": "Mary Williams",
40 | "email": "mary@gmail.com",
41 | "role": "publisher",
42 | "password": "123456"
43 | },
44 | {
45 | "_id": "5c8a1d5b0190b214360dc032",
46 | "name": "Sasha Ryan",
47 | "email": "sasha@gmail.com",
48 | "role": "publisher",
49 | "password": "123456"
50 | },
51 | {
52 | "_id": "5c8a1d5b0190b214360dc033",
53 | "name": "Greg Harris",
54 | "email": "greg@gmail.com",
55 | "role": "user",
56 | "password": "123456"
57 | },
58 | {
59 | "_id": "5c8a1d5b0190b214360dc034",
60 | "name": "Derek Glover",
61 | "email": "derek@gmail.com",
62 | "role": "user",
63 | "password": "123456"
64 | },
65 | {
66 | "_id": "5c8a1d5b0190b214360dc035",
67 | "name": "Stephanie Hanson",
68 | "email": "steph@gmail.com",
69 | "role": "user",
70 | "password": "123456"
71 | },
72 | {
73 | "_id": "5c8a1d5b0190b214360dc036",
74 | "name": "Jerry Wiliams",
75 | "email": "jerry@gmail.com",
76 | "role": "user",
77 | "password": "123456"
78 | },
79 | {
80 | "_id": "5c8a1d5b0190b214360dc037",
81 | "name": "Maggie Johnson",
82 | "email": "maggie@gmail.com",
83 | "role": "user",
84 | "password": "123456"
85 | },
86 | {
87 | "_id": "5c8a1d5b0190b214360dc038",
88 | "name": "Barry Dickens",
89 | "email": "barry@gmail.com",
90 | "role": "user",
91 | "password": "123456"
92 | },
93 | {
94 | "_id": "5c8a1d5b0190b214360dc039",
95 | "name": "Ryan Bolin",
96 | "email": "ryan@gmail.com",
97 | "role": "user",
98 | "password": "123456"
99 | },
100 | {
101 | "_id": "5c8a1d5b0190b214360dc040",
102 | "name": "Sara Kensing",
103 | "email": "sara@gmail.com",
104 | "role": "user",
105 | "password": "123456"
106 | }
107 | ]
108 |
--------------------------------------------------------------------------------
/config/config.env.env:
--------------------------------------------------------------------------------
1 | NODE_ENV=development
2 | PORT=5000
3 |
4 | MONGO_URI=
5 |
6 | GEOCODER_PROVIDER=mapquest
7 | GEOCODER_API_KEY=
8 |
9 | FILE_UPLOAD_PATH= ./public/uploads
10 | MAX_FILE_UPLOAD=1000000
11 |
12 | JWT_SECRET=
13 | JWT_EXPIRE=30d
14 | JWT_COOKIE_EXPIRE=30
15 |
16 | SMTP_HOST=smtp.mailtrap.io
17 | SMTP_PORT=2525
18 | SMTP_EMAIL=
19 | SMTP_PASSWORD=
20 | FROM_EMAIL=
21 | FROM_NAME=
--------------------------------------------------------------------------------
/config/db.js:
--------------------------------------------------------------------------------
1 | const mongoose = require('mongoose');
2 |
3 | const connectDB = async () => {
4 | const conn = await mongoose.connect(process.env.MONGO_URI, {
5 | useNewUrlParser: true,
6 | useCreateIndex: true,
7 | useFindAndModify: false,
8 | useUnifiedTopology: true
9 | });
10 |
11 | console.log(`MongoDB Connected: ${conn.connection.host}`.cyan.underline.bold);
12 | };
13 |
14 | module.exports = connectDB;
15 |
--------------------------------------------------------------------------------
/controllers/auth.js:
--------------------------------------------------------------------------------
1 | const crypto = require('crypto');
2 | const ErrorResponse = require('../utils/errorResponse');
3 | const asyncHandler = require('../middleware/async');
4 | const sendEmail = require('../utils/sendEmail');
5 | const User = require('../models/User');
6 |
7 | // @desc Register user
8 | // @route POST /api/v1/auth/register
9 | // @access Public
10 | exports.register = asyncHandler(async (req, res, next) => {
11 | const { name, email, password, role } = req.body;
12 |
13 | // Create user
14 | const user = await User.create({
15 | name,
16 | email,
17 | password,
18 | role
19 | });
20 |
21 | sendTokenResponse(user, 200, res);
22 | });
23 |
24 | // @desc Login user
25 | // @route POST /api/v1/auth/login
26 | // @access Public
27 | exports.login = asyncHandler(async (req, res, next) => {
28 | const { email, password } = req.body;
29 |
30 | // Validate emil & password
31 | if (!email || !password) {
32 | return next(new ErrorResponse('Please provide an email and password', 400));
33 | }
34 |
35 | // Check for user
36 | const user = await User.findOne({ email }).select('+password');
37 |
38 | if (!user) {
39 | return next(new ErrorResponse('Invalid credentials', 401));
40 | }
41 |
42 | // Check if password matches
43 | const isMatch = await user.matchPassword(password);
44 |
45 | if (!isMatch) {
46 | return next(new ErrorResponse('Invalid credentials', 401));
47 | }
48 |
49 | sendTokenResponse(user, 200, res);
50 | });
51 |
52 | // @desc Log user out / clear cookie
53 | // @route GET /api/v1/auth/logout
54 | // @access Public
55 | exports.logout = asyncHandler(async (req, res, next) => {
56 | res.cookie('token', 'none', {
57 | expires: new Date(Date.now() + 10 * 1000),
58 | httpOnly: true
59 | });
60 |
61 | res.status(200).json({
62 | success: true,
63 | data: {}
64 | });
65 | });
66 |
67 | // @desc Get current logged in user
68 | // @route GET /api/v1/auth/me
69 | // @access Private
70 | exports.getMe = asyncHandler(async (req, res, next) => {
71 | // user is already available in req due to the protect middleware
72 | const user = req.user;
73 |
74 | res.status(200).json({
75 | success: true,
76 | data: user
77 | });
78 | });
79 |
80 | // @desc Update user details
81 | // @route PUT /api/v1/auth/updatedetails
82 | // @access Private
83 | exports.updateDetails = asyncHandler(async (req, res, next) => {
84 | const fieldsToUpdate = {
85 | name: req.body.name,
86 | email: req.body.email
87 | };
88 |
89 | const user = await User.findByIdAndUpdate(req.user.id, fieldsToUpdate, {
90 | new: true,
91 | runValidators: true
92 | });
93 |
94 | res.status(200).json({
95 | success: true,
96 | data: user
97 | });
98 | });
99 |
100 | // @desc Update password
101 | // @route PUT /api/v1/auth/updatepassword
102 | // @access Private
103 | exports.updatePassword = asyncHandler(async (req, res, next) => {
104 | const user = await User.findById(req.user.id).select('+password');
105 |
106 | // Check current password
107 | if (!(await user.matchPassword(req.body.currentPassword))) {
108 | return next(new ErrorResponse('Password is incorrect', 401));
109 | }
110 |
111 | user.password = req.body.newPassword;
112 | await user.save();
113 |
114 | sendTokenResponse(user, 200, res);
115 | });
116 |
117 | // @desc Forgot password
118 | // @route POST /api/v1/auth/forgotpassword
119 | // @access Public
120 | exports.forgotPassword = asyncHandler(async (req, res, next) => {
121 | const user = await User.findOne({ email: req.body.email });
122 |
123 | if (!user) {
124 | return next(new ErrorResponse('There is no user with that email', 404));
125 | }
126 |
127 | // Get reset token
128 | const resetToken = user.getResetPasswordToken();
129 |
130 | await user.save({ validateBeforeSave: false });
131 |
132 | // Create reset url
133 | const resetUrl = `${req.protocol}://${req.get(
134 | 'host'
135 | )}/api/v1/auth/resetpassword/${resetToken}`;
136 |
137 | const message = `You are receiving this email because you (or someone else) has requested the reset of a password. Please make a PUT request to: \n\n ${resetUrl}`;
138 |
139 | try {
140 | await sendEmail({
141 | email: user.email,
142 | subject: 'Password reset token',
143 | message
144 | });
145 |
146 | res.status(200).json({ success: true, data: 'Email sent' });
147 | } catch (err) {
148 | console.log(err);
149 | user.resetPasswordToken = undefined;
150 | user.resetPasswordExpire = undefined;
151 |
152 | await user.save({ validateBeforeSave: false });
153 |
154 | return next(new ErrorResponse('Email could not be sent', 500));
155 | }
156 | });
157 |
158 | // @desc Reset password
159 | // @route PUT /api/v1/auth/resetpassword/:resettoken
160 | // @access Public
161 | exports.resetPassword = asyncHandler(async (req, res, next) => {
162 | // Get hashed token
163 | const resetPasswordToken = crypto
164 | .createHash('sha256')
165 | .update(req.params.resettoken)
166 | .digest('hex');
167 |
168 | const user = await User.findOne({
169 | resetPasswordToken,
170 | resetPasswordExpire: { $gt: Date.now() }
171 | });
172 |
173 | if (!user) {
174 | return next(new ErrorResponse('Invalid token', 400));
175 | }
176 |
177 | // Set new password
178 | user.password = req.body.password;
179 | user.resetPasswordToken = undefined;
180 | user.resetPasswordExpire = undefined;
181 | await user.save();
182 |
183 | sendTokenResponse(user, 200, res);
184 | });
185 |
186 | // Get token from model, create cookie and send response
187 | const sendTokenResponse = (user, statusCode, res) => {
188 | // Create token
189 | const token = user.getSignedJwtToken();
190 |
191 | const options = {
192 | expires: new Date(
193 | Date.now() + process.env.JWT_COOKIE_EXPIRE * 24 * 60 * 60 * 1000
194 | ),
195 | httpOnly: true
196 | };
197 |
198 | if (process.env.NODE_ENV === 'production') {
199 | options.secure = true;
200 | }
201 |
202 | res
203 | .status(statusCode)
204 | .cookie('token', token, options)
205 | .json({
206 | success: true,
207 | token
208 | });
209 | };
210 |
--------------------------------------------------------------------------------
/controllers/bootcamps.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const ErrorResponse = require('../utils/errorResponse');
3 | const asyncHandler = require('../middleware/async');
4 | const geocoder = require('../utils/geocoder');
5 | const Bootcamp = require('../models/Bootcamp');
6 |
7 | // @desc Get all bootcamps
8 | // @route GET /api/v1/bootcamps
9 | // @access Public
10 | exports.getBootcamps = asyncHandler(async (req, res, next) => {
11 | res.status(200).json(res.advancedResults);
12 | });
13 |
14 | // @desc Get single bootcamp
15 | // @route GET /api/v1/bootcamps/:id
16 | // @access Public
17 | exports.getBootcamp = asyncHandler(async (req, res, next) => {
18 | const bootcamp = await Bootcamp.findById(req.params.id);
19 |
20 | if (!bootcamp) {
21 | return next(
22 | new ErrorResponse(`Bootcamp not found with id of ${req.params.id}`, 404)
23 | );
24 | }
25 |
26 | res.status(200).json({ success: true, data: bootcamp });
27 | });
28 |
29 | // @desc Create new bootcamp
30 | // @route POST /api/v1/bootcamps
31 | // @access Private
32 | exports.createBootcamp = asyncHandler(async (req, res, next) => {
33 | // Add user to req,body
34 | req.body.user = req.user.id;
35 |
36 | // Check for published bootcamp
37 | const publishedBootcamp = await Bootcamp.findOne({ user: req.user.id });
38 |
39 | // If the user is not an admin, they can only add one bootcamp
40 | if (publishedBootcamp && req.user.role !== 'admin') {
41 | return next(
42 | new ErrorResponse(
43 | `The user with ID ${req.user.id} has already published a bootcamp`,
44 | 400
45 | )
46 | );
47 | }
48 |
49 | const bootcamp = await Bootcamp.create(req.body);
50 |
51 | res.status(201).json({
52 | success: true,
53 | data: bootcamp
54 | });
55 | });
56 |
57 | // @desc Update bootcamp
58 | // @route PUT /api/v1/bootcamps/:id
59 | // @access Private
60 | exports.updateBootcamp = asyncHandler(async (req, res, next) => {
61 | let bootcamp = await Bootcamp.findById(req.params.id);
62 |
63 | if (!bootcamp) {
64 | return next(
65 | new ErrorResponse(`Bootcamp not found with id of ${req.params.id}`, 404)
66 | );
67 | }
68 |
69 | // Make sure user is bootcamp owner
70 | if (bootcamp.user.toString() !== req.user.id && req.user.role !== 'admin') {
71 | return next(
72 | new ErrorResponse(
73 | `User ${req.user.id} is not authorized to update this bootcamp`,
74 | 401
75 | )
76 | );
77 | }
78 |
79 | bootcamp = await Bootcamp.findByIdAndUpdate(req.params.id, req.body, {
80 | new: true,
81 | runValidators: true
82 | });
83 |
84 | res.status(200).json({ success: true, data: bootcamp });
85 | });
86 |
87 | // @desc Delete bootcamp
88 | // @route DELETE /api/v1/bootcamps/:id
89 | // @access Private
90 | exports.deleteBootcamp = asyncHandler(async (req, res, next) => {
91 | const bootcamp = await Bootcamp.findById(req.params.id);
92 |
93 | if (!bootcamp) {
94 | return next(
95 | new ErrorResponse(`Bootcamp not found with id of ${req.params.id}`, 404)
96 | );
97 | }
98 |
99 | // Make sure user is bootcamp owner
100 | if (bootcamp.user.toString() !== req.user.id && req.user.role !== 'admin') {
101 | return next(
102 | new ErrorResponse(
103 | `User ${req.user.id} is not authorized to delete this bootcamp`,
104 | 401
105 | )
106 | );
107 | }
108 |
109 | await bootcamp.remove();
110 |
111 | res.status(200).json({ success: true, data: {} });
112 | });
113 |
114 | // @desc Get bootcamps within a radius
115 | // @route GET /api/v1/bootcamps/radius/:zipcode/:distance
116 | // @access Private
117 | exports.getBootcampsInRadius = asyncHandler(async (req, res, next) => {
118 | const { zipcode, distance } = req.params;
119 |
120 | // Get lat/lng from geocoder
121 | const loc = await geocoder.geocode(zipcode);
122 | const lat = loc[0].latitude;
123 | const lng = loc[0].longitude;
124 |
125 | // Calc radius using radians
126 | // Divide dist by radius of Earth
127 | // Earth Radius = 3,963 mi / 6,378 km
128 | const radius = distance / 3963;
129 |
130 | const bootcamps = await Bootcamp.find({
131 | location: { $geoWithin: { $centerSphere: [[lng, lat], radius] } }
132 | });
133 |
134 | res.status(200).json({
135 | success: true,
136 | count: bootcamps.length,
137 | data: bootcamps
138 | });
139 | });
140 |
141 | // @desc Upload photo for bootcamp
142 | // @route PUT /api/v1/bootcamps/:id/photo
143 | // @access Private
144 | exports.bootcampPhotoUpload = asyncHandler(async (req, res, next) => {
145 | const bootcamp = await Bootcamp.findById(req.params.id);
146 |
147 | if (!bootcamp) {
148 | return next(
149 | new ErrorResponse(`Bootcamp not found with id of ${req.params.id}`, 404)
150 | );
151 | }
152 |
153 | // Make sure user is bootcamp owner
154 | if (bootcamp.user.toString() !== req.user.id && req.user.role !== 'admin') {
155 | return next(
156 | new ErrorResponse(
157 | `User ${req.user.id} is not authorized to update this bootcamp`,
158 | 401
159 | )
160 | );
161 | }
162 |
163 | if (!req.files) {
164 | return next(new ErrorResponse(`Please upload a file`, 400));
165 | }
166 |
167 | const file = req.files.file;
168 |
169 | // Make sure the image is a photo
170 | if (!file.mimetype.startsWith('image')) {
171 | return next(new ErrorResponse(`Please upload an image file`, 400));
172 | }
173 |
174 | // Check filesize
175 | if (file.size > process.env.MAX_FILE_UPLOAD) {
176 | return next(
177 | new ErrorResponse(
178 | `Please upload an image less than ${process.env.MAX_FILE_UPLOAD}`,
179 | 400
180 | )
181 | );
182 | }
183 |
184 | // Create custom filename
185 | file.name = `photo_${bootcamp._id}${path.parse(file.name).ext}`;
186 |
187 | file.mv(`${process.env.FILE_UPLOAD_PATH}/${file.name}`, async err => {
188 | if (err) {
189 | console.error(err);
190 | return next(new ErrorResponse(`Problem with file upload`, 500));
191 | }
192 |
193 | await Bootcamp.findByIdAndUpdate(req.params.id, { photo: file.name });
194 |
195 | res.status(200).json({
196 | success: true,
197 | data: file.name
198 | });
199 | });
200 | });
201 |
--------------------------------------------------------------------------------
/controllers/courses.js:
--------------------------------------------------------------------------------
1 | const ErrorResponse = require('../utils/errorResponse');
2 | const asyncHandler = require('../middleware/async');
3 | const Course = require('../models/Course');
4 | const Bootcamp = require('../models/Bootcamp');
5 |
6 | // @desc Get courses
7 | // @route GET /api/v1/courses
8 | // @route GET /api/v1/bootcamps/:bootcampId/courses
9 | // @access Public
10 | exports.getCourses = asyncHandler(async (req, res, next) => {
11 | if (req.params.bootcampId) {
12 | const courses = await Course.find({ bootcamp: req.params.bootcampId });
13 |
14 | return res.status(200).json({
15 | success: true,
16 | count: courses.length,
17 | data: courses
18 | });
19 | } else {
20 | res.status(200).json(res.advancedResults);
21 | }
22 | });
23 |
24 | // @desc Get single course
25 | // @route GET /api/v1/courses/:id
26 | // @access Public
27 | exports.getCourse = asyncHandler(async (req, res, next) => {
28 | const course = await Course.findById(req.params.id).populate({
29 | path: 'bootcamp',
30 | select: 'name description'
31 | });
32 |
33 | if (!course) {
34 | return next(
35 | new ErrorResponse(`No course with the id of ${req.params.id}`, 404)
36 | );
37 | }
38 |
39 | res.status(200).json({
40 | success: true,
41 | data: course
42 | });
43 | });
44 |
45 | // @desc Add course
46 | // @route POST /api/v1/bootcamps/:bootcampId/courses
47 | // @access Private
48 | exports.addCourse = asyncHandler(async (req, res, next) => {
49 | req.body.bootcamp = req.params.bootcampId;
50 | req.body.user = req.user.id;
51 |
52 | const bootcamp = await Bootcamp.findById(req.params.bootcampId);
53 |
54 | if (!bootcamp) {
55 | return next(
56 | new ErrorResponse(
57 | `No bootcamp with the id of ${req.params.bootcampId}`,
58 | 404
59 | )
60 | );
61 | }
62 |
63 | // Make sure user is bootcamp owner
64 | if (bootcamp.user.toString() !== req.user.id && req.user.role !== 'admin') {
65 | return next(
66 | new ErrorResponse(
67 | `User ${req.user.id} is not authorized to add a course to bootcamp ${bootcamp._id}`,
68 | 401
69 | )
70 | );
71 | }
72 |
73 | const course = await Course.create(req.body);
74 |
75 | res.status(200).json({
76 | success: true,
77 | data: course
78 | });
79 | });
80 |
81 | // @desc Update course
82 | // @route PUT /api/v1/courses/:id
83 | // @access Private
84 | exports.updateCourse = asyncHandler(async (req, res, next) => {
85 | let course = await Course.findById(req.params.id);
86 |
87 | if (!course) {
88 | return next(
89 | new ErrorResponse(`No course with the id of ${req.params.id}`, 404)
90 | );
91 | }
92 |
93 | // Make sure user is course owner
94 | if (course.user.toString() !== req.user.id && req.user.role !== 'admin') {
95 | return next(
96 | new ErrorResponse(
97 | `User ${req.user.id} is not authorized to update course ${course._id}`,
98 | 401
99 | )
100 | );
101 | }
102 |
103 | course = await Course.findByIdAndUpdate(req.params.id, req.body, {
104 | new: true,
105 | runValidators: true
106 | });
107 |
108 | course.save();
109 |
110 | res.status(200).json({
111 | success: true,
112 | data: course
113 | });
114 | });
115 |
116 | // @desc Delete course
117 | // @route DELETE /api/v1/courses/:id
118 | // @access Private
119 | exports.deleteCourse = asyncHandler(async (req, res, next) => {
120 | const course = await Course.findById(req.params.id);
121 |
122 | if (!course) {
123 | return next(
124 | new ErrorResponse(`No course with the id of ${req.params.id}`, 404)
125 | );
126 | }
127 |
128 | // Make sure user is course owner
129 | if (course.user.toString() !== req.user.id && req.user.role !== 'admin') {
130 | return next(
131 | new ErrorResponse(
132 | `User ${req.user.id} is not authorized to delete course ${course._id}`,
133 | 401
134 | )
135 | );
136 | }
137 |
138 | await course.remove();
139 |
140 | res.status(200).json({
141 | success: true,
142 | data: {}
143 | });
144 | });
145 |
--------------------------------------------------------------------------------
/controllers/reviews.js:
--------------------------------------------------------------------------------
1 | const ErrorResponse = require('../utils/errorResponse');
2 | const asyncHandler = require('../middleware/async');
3 | const Review = require('../models/Review');
4 | const Bootcamp = require('../models/Bootcamp');
5 |
6 | // @desc Get reviews
7 | // @route GET /api/v1/reviews
8 | // @route GET /api/v1/bootcamps/:bootcampId/reviews
9 | // @access Public
10 | exports.getReviews = asyncHandler(async (req, res, next) => {
11 | if (req.params.bootcampId) {
12 | const reviews = await Review.find({ bootcamp: req.params.bootcampId });
13 |
14 | return res.status(200).json({
15 | success: true,
16 | count: reviews.length,
17 | data: reviews
18 | });
19 | } else {
20 | res.status(200).json(res.advancedResults);
21 | }
22 | });
23 |
24 | // @desc Get single review
25 | // @route GET /api/v1/reviews/:id
26 | // @access Public
27 | exports.getReview = asyncHandler(async (req, res, next) => {
28 | const review = await Review.findById(req.params.id).populate({
29 | path: 'bootcamp',
30 | select: 'name description'
31 | });
32 |
33 | if (!review) {
34 | return next(
35 | new ErrorResponse(`No review found with the id of ${req.params.id}`, 404)
36 | );
37 | }
38 |
39 | res.status(200).json({
40 | success: true,
41 | data: review
42 | });
43 | });
44 |
45 | // @desc Add review
46 | // @route POST /api/v1/bootcamps/:bootcampId/reviews
47 | // @access Private
48 | exports.addReview = asyncHandler(async (req, res, next) => {
49 | req.body.bootcamp = req.params.bootcampId;
50 | req.body.user = req.user.id;
51 |
52 | const bootcamp = await Bootcamp.findById(req.params.bootcampId);
53 |
54 | if (!bootcamp) {
55 | return next(
56 | new ErrorResponse(
57 | `No bootcamp with the id of ${req.params.bootcampId}`,
58 | 404
59 | )
60 | );
61 | }
62 |
63 | const review = await Review.create(req.body);
64 |
65 | res.status(201).json({
66 | success: true,
67 | data: review
68 | });
69 | });
70 |
71 | // @desc Update review
72 | // @route PUT /api/v1/reviews/:id
73 | // @access Private
74 | exports.updateReview = asyncHandler(async (req, res, next) => {
75 | let review = await Review.findById(req.params.id);
76 |
77 | if (!review) {
78 | return next(
79 | new ErrorResponse(`No review with the id of ${req.params.id}`, 404)
80 | );
81 | }
82 |
83 | // Make sure review belongs to user or user is admin
84 | if (review.user.toString() !== req.user.id && req.user.role !== 'admin') {
85 | return next(new ErrorResponse(`Not authorized to update review`, 401));
86 | }
87 |
88 | review = await Review.findByIdAndUpdate(req.params.id, req.body, {
89 | new: true,
90 | runValidators: true
91 | });
92 |
93 | review.save();
94 |
95 | res.status(200).json({
96 | success: true,
97 | data: review
98 | });
99 | });
100 |
101 | // @desc Delete review
102 | // @route DELETE /api/v1/reviews/:id
103 | // @access Private
104 | exports.deleteReview = asyncHandler(async (req, res, next) => {
105 | const review = await Review.findById(req.params.id);
106 |
107 | if (!review) {
108 | return next(
109 | new ErrorResponse(`No review with the id of ${req.params.id}`, 404)
110 | );
111 | }
112 |
113 | // Make sure review belongs to user or user is admin
114 | if (review.user.toString() !== req.user.id && req.user.role !== 'admin') {
115 | return next(new ErrorResponse(`Not authorized to update review`, 401));
116 | }
117 |
118 | await review.remove();
119 |
120 | res.status(200).json({
121 | success: true,
122 | data: {}
123 | });
124 | });
125 |
--------------------------------------------------------------------------------
/controllers/users.js:
--------------------------------------------------------------------------------
1 | const ErrorResponse = require('../utils/errorResponse');
2 | const asyncHandler = require('../middleware/async');
3 | const User = require('../models/User');
4 |
5 | // @desc Get all users
6 | // @route GET /api/v1/users
7 | // @access Private/Admin
8 | exports.getUsers = asyncHandler(async (req, res, next) => {
9 | res.status(200).json(res.advancedResults);
10 | });
11 |
12 | // @desc Get single user
13 | // @route GET /api/v1/users/:id
14 | // @access Private/Admin
15 | exports.getUser = asyncHandler(async (req, res, next) => {
16 | const user = await User.findById(req.params.id);
17 |
18 | res.status(200).json({
19 | success: true,
20 | data: user
21 | });
22 | });
23 |
24 | // @desc Create user
25 | // @route POST /api/v1/users
26 | // @access Private/Admin
27 | exports.createUser = asyncHandler(async (req, res, next) => {
28 | const user = await User.create(req.body);
29 |
30 | res.status(201).json({
31 | success: true,
32 | data: user
33 | });
34 | });
35 |
36 | // @desc Update user
37 | // @route PUT /api/v1/users/:id
38 | // @access Private/Admin
39 | exports.updateUser = asyncHandler(async (req, res, next) => {
40 | const user = await User.findByIdAndUpdate(req.params.id, req.body, {
41 | new: true,
42 | runValidators: true
43 | });
44 |
45 | res.status(200).json({
46 | success: true,
47 | data: user
48 | });
49 | });
50 |
51 | // @desc Delete user
52 | // @route DELETE /api/v1/users/:id
53 | // @access Private/Admin
54 | exports.deleteUser = asyncHandler(async (req, res, next) => {
55 | await User.findByIdAndDelete(req.params.id);
56 |
57 | res.status(200).json({
58 | success: true,
59 | data: {}
60 | });
61 | });
62 |
--------------------------------------------------------------------------------
/middleware/advancedResults.js:
--------------------------------------------------------------------------------
1 | const advancedResults = (model, populate) => async (req, res, next) => {
2 | let query;
3 |
4 | // Copy req.query
5 | const reqQuery = { ...req.query };
6 |
7 | // Fields to exclude
8 | const removeFields = ['select', 'sort', 'page', 'limit'];
9 |
10 | // Loop over removeFields and delete them from reqQuery
11 | removeFields.forEach(param => delete reqQuery[param]);
12 |
13 | // Create query string
14 | let queryStr = JSON.stringify(reqQuery);
15 |
16 | // Create operators ($gt, $gte, etc)
17 | queryStr = queryStr.replace(/\b(gt|gte|lt|lte|in)\b/g, match => `$${match}`);
18 |
19 | // Finding resource
20 | query = model.find(JSON.parse(queryStr));
21 |
22 | // Select Fields
23 | if (req.query.select) {
24 | const fields = req.query.select.split(',').join(' ');
25 | query = query.select(fields);
26 | }
27 |
28 | // Sort
29 | if (req.query.sort) {
30 | const sortBy = req.query.sort.split(',').join(' ');
31 | query = query.sort(sortBy);
32 | } else {
33 | query = query.sort('-createdAt');
34 | }
35 |
36 | // Pagination
37 | const page = parseInt(req.query.page, 10) || 1;
38 | const limit = parseInt(req.query.limit, 10) || 25;
39 | const startIndex = (page - 1) * limit;
40 | const endIndex = page * limit;
41 | const total = await model.countDocuments(JSON.parse(queryStr));
42 |
43 | query = query.skip(startIndex).limit(limit);
44 |
45 | if (populate) {
46 | query = query.populate(populate);
47 | }
48 |
49 | // Executing query
50 | const results = await query;
51 |
52 | // Pagination result
53 | const pagination = {};
54 |
55 | if (endIndex < total) {
56 | pagination.next = {
57 | page: page + 1,
58 | limit
59 | };
60 | }
61 |
62 | if (startIndex > 0) {
63 | pagination.prev = {
64 | page: page - 1,
65 | limit
66 | };
67 | }
68 |
69 | res.advancedResults = {
70 | success: true,
71 | count: results.length,
72 | pagination,
73 | data: results
74 | };
75 |
76 | next();
77 | };
78 |
79 | module.exports = advancedResults;
80 |
--------------------------------------------------------------------------------
/middleware/async.js:
--------------------------------------------------------------------------------
1 | const asyncHandler = fn => (req, res, next) =>
2 | Promise.resolve(fn(req, res, next)).catch(next);
3 |
4 | module.exports = asyncHandler;
5 |
--------------------------------------------------------------------------------
/middleware/auth.js:
--------------------------------------------------------------------------------
1 | const jwt = require('jsonwebtoken');
2 | const asyncHandler = require('./async');
3 | const ErrorResponse = require('../utils/errorResponse');
4 | const User = require('../models/User');
5 |
6 | // Protect routes
7 | exports.protect = asyncHandler(async (req, res, next) => {
8 | let token;
9 |
10 | if (
11 | req.headers.authorization &&
12 | req.headers.authorization.startsWith('Bearer')
13 | ) {
14 | // Set token from Bearer token in header
15 | token = req.headers.authorization.split(' ')[1];
16 | // Set token from cookie
17 | }
18 | // else if (req.cookies.token) {
19 | // token = req.cookies.token;
20 | // }
21 |
22 | // Make sure token exists
23 | if (!token) {
24 | return next(new ErrorResponse('Not authorized to access this route', 401));
25 | }
26 |
27 | try {
28 | // Verify token
29 | const decoded = jwt.verify(token, process.env.JWT_SECRET);
30 |
31 | req.user = await User.findById(decoded.id);
32 |
33 | next();
34 | } catch (err) {
35 | return next(new ErrorResponse('Not authorized to access this route', 401));
36 | }
37 | });
38 |
39 | // Grant access to specific roles
40 | exports.authorize = (...roles) => {
41 | return (req, res, next) => {
42 | if (!roles.includes(req.user.role)) {
43 | return next(
44 | new ErrorResponse(
45 | `User role ${req.user.role} is not authorized to access this route`,
46 | 403
47 | )
48 | );
49 | }
50 | next();
51 | };
52 | };
53 |
--------------------------------------------------------------------------------
/middleware/error.js:
--------------------------------------------------------------------------------
1 | const ErrorResponse = require('../utils/errorResponse');
2 |
3 | const errorHandler = (err, req, res, next) => {
4 | let error = { ...err };
5 |
6 | error.message = err.message;
7 |
8 | // Log to console for dev
9 | console.log(err);
10 |
11 | // Mongoose bad ObjectId
12 | if (err.name === 'CastError') {
13 | const message = `Resource not found`;
14 | error = new ErrorResponse(message, 404);
15 | }
16 |
17 | // Mongoose duplicate key
18 | if (err.code === 11000) {
19 | const message = 'Duplicate field value entered';
20 | error = new ErrorResponse(message, 400);
21 | }
22 |
23 | // Mongoose validation error
24 | if (err.name === 'ValidationError') {
25 | const message = Object.values(err.errors).map(val => val.message);
26 | error = new ErrorResponse(message, 400);
27 | }
28 |
29 | res.status(error.statusCode || 500).json({
30 | success: false,
31 | error: error.message || 'Server Error'
32 | });
33 | };
34 |
35 | module.exports = errorHandler;
36 |
--------------------------------------------------------------------------------
/middleware/logger.js:
--------------------------------------------------------------------------------
1 | // @desc Logs request to console
2 | const logger = (req, res, next) => {
3 | console.log(
4 | `${req.method} ${req.protocol}://${req.get('host')}${req.originalUrl}`
5 | );
6 | next();
7 | };
8 |
9 | module.exports = logger;
10 |
--------------------------------------------------------------------------------
/models/Bootcamp.js:
--------------------------------------------------------------------------------
1 | const mongoose = require('mongoose');
2 | const slugify = require('slugify');
3 | const geocoder = require('../utils/geocoder');
4 |
5 | const BootcampSchema = new mongoose.Schema(
6 | {
7 | name: {
8 | type: String,
9 | required: [true, 'Please add a name'],
10 | unique: true,
11 | trim: true,
12 | maxlength: [50, 'Name can not be more than 50 characters']
13 | },
14 | slug: String,
15 | description: {
16 | type: String,
17 | required: [true, 'Please add a description'],
18 | maxlength: [500, 'Description can not be more than 500 characters']
19 | },
20 | website: {
21 | type: String,
22 | match: [
23 | /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/,
24 | 'Please use a valid URL with HTTP or HTTPS'
25 | ]
26 | },
27 | phone: {
28 | type: String,
29 | maxlength: [20, 'Phone number can not be longer than 20 characters']
30 | },
31 | email: {
32 | type: String,
33 | match: [
34 | /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/,
35 | 'Please add a valid email'
36 | ]
37 | },
38 | address: {
39 | type: String,
40 | required: [true, 'Please add an address']
41 | },
42 | location: {
43 | // GeoJSON Point
44 | type: {
45 | type: String,
46 | enum: ['Point']
47 | },
48 | coordinates: {
49 | type: [Number],
50 | index: '2dsphere'
51 | },
52 | formattedAddress: String,
53 | street: String,
54 | city: String,
55 | state: String,
56 | zipcode: String,
57 | country: String
58 | },
59 | careers: {
60 | // Array of strings
61 | type: [String],
62 | required: true,
63 | enum: [
64 | 'Web Development',
65 | 'Mobile Development',
66 | 'UI/UX',
67 | 'Data Science',
68 | 'Business',
69 | 'Other'
70 | ]
71 | },
72 | averageRating: {
73 | type: Number,
74 | min: [1, 'Rating must be at least 1'],
75 | max: [10, 'Rating must can not be more than 10']
76 | },
77 | averageCost: Number,
78 | photo: {
79 | type: String,
80 | default: 'no-photo.jpg'
81 | },
82 | housing: {
83 | type: Boolean,
84 | default: false
85 | },
86 | jobAssistance: {
87 | type: Boolean,
88 | default: false
89 | },
90 | jobGuarantee: {
91 | type: Boolean,
92 | default: false
93 | },
94 | acceptGi: {
95 | type: Boolean,
96 | default: false
97 | },
98 | createdAt: {
99 | type: Date,
100 | default: Date.now
101 | },
102 | user: {
103 | type: mongoose.Schema.ObjectId,
104 | ref: 'User',
105 | required: true
106 | }
107 | },
108 | {
109 | toJSON: { virtuals: true },
110 | toObject: { virtuals: true }
111 | }
112 | );
113 |
114 | // Create bootcamp slug from the name
115 | BootcampSchema.pre('save', function(next) {
116 | this.slug = slugify(this.name, { lower: true });
117 | next();
118 | });
119 |
120 | // Geocode & create location field
121 | BootcampSchema.pre('save', async function(next) {
122 | const loc = await geocoder.geocode(this.address);
123 | this.location = {
124 | type: 'Point',
125 | coordinates: [loc[0].longitude, loc[0].latitude],
126 | formattedAddress: loc[0].formattedAddress,
127 | street: loc[0].streetName,
128 | city: loc[0].city,
129 | state: loc[0].stateCode,
130 | zipcode: loc[0].zipcode,
131 | country: loc[0].countryCode
132 | };
133 |
134 | // Do not save address in DB
135 | this.address = undefined;
136 | next();
137 | });
138 |
139 | // Cascade delete courses when a bootcamp is deleted
140 | BootcampSchema.pre('remove', async function(next) {
141 | console.log(`Courses being removed from bootcamp ${this._id}`);
142 | await this.model('Course').deleteMany({ bootcamp: this._id });
143 | next();
144 | });
145 |
146 | // Reverse populate with virtuals
147 | BootcampSchema.virtual('courses', {
148 | ref: 'Course',
149 | localField: '_id',
150 | foreignField: 'bootcamp',
151 | justOne: false
152 | });
153 |
154 | module.exports = mongoose.model('Bootcamp', BootcampSchema);
155 |
--------------------------------------------------------------------------------
/models/Course.js:
--------------------------------------------------------------------------------
1 | const mongoose = require('mongoose');
2 |
3 | const CourseSchema = new mongoose.Schema({
4 | title: {
5 | type: String,
6 | trim: true,
7 | required: [true, 'Please add a course title']
8 | },
9 | description: {
10 | type: String,
11 | required: [true, 'Please add a description']
12 | },
13 | weeks: {
14 | type: String,
15 | required: [true, 'Please add number of weeks']
16 | },
17 | tuition: {
18 | type: Number,
19 | required: [true, 'Please add a tuition cost']
20 | },
21 | minimumSkill: {
22 | type: String,
23 | required: [true, 'Please add a minimum skill'],
24 | enum: ['beginner', 'intermediate', 'advanced']
25 | },
26 | scholarshipAvailable: {
27 | type: Boolean,
28 | default: false
29 | },
30 | createdAt: {
31 | type: Date,
32 | default: Date.now
33 | },
34 | bootcamp: {
35 | type: mongoose.Schema.ObjectId,
36 | ref: 'Bootcamp',
37 | required: true
38 | },
39 | user: {
40 | type: mongoose.Schema.ObjectId,
41 | ref: 'User',
42 | required: true
43 | }
44 | });
45 |
46 | // Static method to get avg of course tuitions
47 | CourseSchema.statics.getAverageCost = async function(bootcampId) {
48 | const obj = await this.aggregate([
49 | {
50 | $match: { bootcamp: bootcampId }
51 | },
52 | {
53 | $group: {
54 | _id: '$bootcamp',
55 | averageCost: { $avg: '$tuition' }
56 | }
57 | }
58 | ]);
59 |
60 | try {
61 | await this.model('Bootcamp').findByIdAndUpdate(bootcampId, {
62 | averageCost: Math.ceil(obj[0].averageCost / 10) * 10
63 | });
64 | } catch (err) {
65 | console.error(err);
66 | }
67 | };
68 |
69 | // Call getAverageCost after save
70 | CourseSchema.post('save', async function() {
71 | await this.constructor.getAverageCost(this.bootcamp);
72 | });
73 |
74 | // Call getAverageCost after remove
75 | CourseSchema.post('remove', async function () {
76 | await this.constructor.getAverageCost(this.bootcamp);
77 | });
78 |
79 |
80 | module.exports = mongoose.model('Course', CourseSchema);
81 |
--------------------------------------------------------------------------------
/models/Review.js:
--------------------------------------------------------------------------------
1 | const mongoose = require('mongoose');
2 |
3 | const ReviewSchema = new mongoose.Schema({
4 | title: {
5 | type: String,
6 | trim: true,
7 | required: [true, 'Please add a title for the review'],
8 | maxlength: 100
9 | },
10 | text: {
11 | type: String,
12 | required: [true, 'Please add some text']
13 | },
14 | rating: {
15 | type: Number,
16 | min: 1,
17 | max: 10,
18 | required: [true, 'Please add a rating between 1 and 10']
19 | },
20 | createdAt: {
21 | type: Date,
22 | default: Date.now
23 | },
24 | bootcamp: {
25 | type: mongoose.Schema.ObjectId,
26 | ref: 'Bootcamp',
27 | required: true
28 | },
29 | user: {
30 | type: mongoose.Schema.ObjectId,
31 | ref: 'User',
32 | required: true
33 | }
34 | });
35 |
36 | // Prevent user from submitting more than one review per bootcamp
37 | ReviewSchema.index({ bootcamp: 1, user: 1 }, { unique: true });
38 |
39 | // Static method to get avg rating and save
40 | ReviewSchema.statics.getAverageRating = async function(bootcampId) {
41 | const obj = await this.aggregate([
42 | {
43 | $match: { bootcamp: bootcampId }
44 | },
45 | {
46 | $group: {
47 | _id: '$bootcamp',
48 | averageRating: { $avg: '$rating' }
49 | }
50 | }
51 | ]);
52 |
53 | try {
54 | await this.model('Bootcamp').findByIdAndUpdate(bootcampId, {
55 | averageRating: obj[0].averageRating
56 | });
57 | } catch (err) {
58 | console.error(err);
59 | }
60 | };
61 |
62 | // Call getAverageCost after save
63 | ReviewSchema.post('save', async function() {
64 | await this.constructor.getAverageRating(this.bootcamp);
65 | });
66 |
67 | // Call getAverageCost before remove
68 | ReviewSchema.pre('remove', async function() {
69 | await this.constructor.getAverageRating(this.bootcamp);
70 | });
71 |
72 | module.exports = mongoose.model('Review', ReviewSchema);
73 |
--------------------------------------------------------------------------------
/models/User.js:
--------------------------------------------------------------------------------
1 | const crypto = require('crypto');
2 | const mongoose = require('mongoose');
3 | const bcrypt = require('bcryptjs');
4 | const jwt = require('jsonwebtoken');
5 |
6 | const UserSchema = new mongoose.Schema({
7 | name: {
8 | type: String,
9 | required: [true, 'Please add a name']
10 | },
11 | email: {
12 | type: String,
13 | required: [true, 'Please add an email'],
14 | unique: true,
15 | match: [
16 | /^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/,
17 | 'Please add a valid email'
18 | ]
19 | },
20 | role: {
21 | type: String,
22 | enum: ['user', 'publisher'],
23 | default: 'user'
24 | },
25 | password: {
26 | type: String,
27 | required: [true, 'Please add a password'],
28 | minlength: 6,
29 | select: false
30 | },
31 | resetPasswordToken: String,
32 | resetPasswordExpire: Date,
33 | createdAt: {
34 | type: Date,
35 | default: Date.now
36 | }
37 | });
38 |
39 | // Encrypt password using bcrypt
40 | UserSchema.pre('save', async function(next) {
41 | if (!this.isModified('password')) {
42 | next();
43 | }
44 |
45 | const salt = await bcrypt.genSalt(10);
46 | this.password = await bcrypt.hash(this.password, salt);
47 | });
48 |
49 | // Sign JWT and return
50 | UserSchema.methods.getSignedJwtToken = function() {
51 | return jwt.sign({ id: this._id }, process.env.JWT_SECRET, {
52 | expiresIn: process.env.JWT_EXPIRE
53 | });
54 | };
55 |
56 | // Match user entered password to hashed password in database
57 | UserSchema.methods.matchPassword = async function(enteredPassword) {
58 | return await bcrypt.compare(enteredPassword, this.password);
59 | };
60 |
61 | // Generate and hash password token
62 | UserSchema.methods.getResetPasswordToken = function() {
63 | // Generate token
64 | const resetToken = crypto.randomBytes(20).toString('hex');
65 |
66 | // Hash token and set to resetPasswordToken field
67 | this.resetPasswordToken = crypto
68 | .createHash('sha256')
69 | .update(resetToken)
70 | .digest('hex');
71 |
72 | // Set expire
73 | this.resetPasswordExpire = Date.now() + 10 * 60 * 1000;
74 |
75 | return resetToken;
76 | };
77 |
78 | module.exports = mongoose.model('User', UserSchema);
79 |
--------------------------------------------------------------------------------
/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "devcamper_api",
3 | "version": "1.0.0",
4 | "lockfileVersion": 1,
5 | "requires": true,
6 | "dependencies": {
7 | "abbrev": {
8 | "version": "1.1.1",
9 | "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
10 | "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
11 | "dev": true
12 | },
13 | "accepts": {
14 | "version": "1.3.7",
15 | "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
16 | "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
17 | "requires": {
18 | "mime-types": "~2.1.24",
19 | "negotiator": "0.6.2"
20 | }
21 | },
22 | "ajv": {
23 | "version": "6.10.2",
24 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz",
25 | "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==",
26 | "requires": {
27 | "fast-deep-equal": "^2.0.1",
28 | "fast-json-stable-stringify": "^2.0.0",
29 | "json-schema-traverse": "^0.4.1",
30 | "uri-js": "^4.2.2"
31 | }
32 | },
33 | "ansi-align": {
34 | "version": "2.0.0",
35 | "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-2.0.0.tgz",
36 | "integrity": "sha1-w2rsy6VjuJzrVW82kPCx2eNUf38=",
37 | "dev": true,
38 | "requires": {
39 | "string-width": "^2.0.0"
40 | }
41 | },
42 | "ansi-regex": {
43 | "version": "3.0.0",
44 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
45 | "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
46 | "dev": true
47 | },
48 | "ansi-styles": {
49 | "version": "3.2.1",
50 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
51 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
52 | "dev": true,
53 | "requires": {
54 | "color-convert": "^1.9.0"
55 | }
56 | },
57 | "anymatch": {
58 | "version": "2.0.0",
59 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz",
60 | "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==",
61 | "dev": true,
62 | "requires": {
63 | "micromatch": "^3.1.4",
64 | "normalize-path": "^2.1.1"
65 | },
66 | "dependencies": {
67 | "normalize-path": {
68 | "version": "2.1.1",
69 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
70 | "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
71 | "dev": true,
72 | "requires": {
73 | "remove-trailing-separator": "^1.0.1"
74 | }
75 | }
76 | }
77 | },
78 | "arr-diff": {
79 | "version": "4.0.0",
80 | "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
81 | "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=",
82 | "dev": true
83 | },
84 | "arr-flatten": {
85 | "version": "1.1.0",
86 | "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
87 | "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==",
88 | "dev": true
89 | },
90 | "arr-union": {
91 | "version": "3.1.0",
92 | "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz",
93 | "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=",
94 | "dev": true
95 | },
96 | "array-flatten": {
97 | "version": "1.1.1",
98 | "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
99 | "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
100 | },
101 | "array-unique": {
102 | "version": "0.3.2",
103 | "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
104 | "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=",
105 | "dev": true
106 | },
107 | "asn1": {
108 | "version": "0.2.4",
109 | "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
110 | "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==",
111 | "requires": {
112 | "safer-buffer": "~2.1.0"
113 | }
114 | },
115 | "assert-plus": {
116 | "version": "1.0.0",
117 | "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
118 | "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
119 | },
120 | "assign-symbols": {
121 | "version": "1.0.0",
122 | "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz",
123 | "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=",
124 | "dev": true
125 | },
126 | "async-each": {
127 | "version": "1.0.3",
128 | "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz",
129 | "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==",
130 | "dev": true
131 | },
132 | "asynckit": {
133 | "version": "0.4.0",
134 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
135 | "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
136 | },
137 | "atob": {
138 | "version": "2.1.2",
139 | "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
140 | "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
141 | "dev": true
142 | },
143 | "aws-sign2": {
144 | "version": "0.7.0",
145 | "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
146 | "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg="
147 | },
148 | "aws4": {
149 | "version": "1.8.0",
150 | "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz",
151 | "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ=="
152 | },
153 | "balanced-match": {
154 | "version": "1.0.0",
155 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
156 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
157 | "dev": true
158 | },
159 | "base": {
160 | "version": "0.11.2",
161 | "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz",
162 | "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==",
163 | "dev": true,
164 | "requires": {
165 | "cache-base": "^1.0.1",
166 | "class-utils": "^0.3.5",
167 | "component-emitter": "^1.2.1",
168 | "define-property": "^1.0.0",
169 | "isobject": "^3.0.1",
170 | "mixin-deep": "^1.2.0",
171 | "pascalcase": "^0.1.1"
172 | },
173 | "dependencies": {
174 | "define-property": {
175 | "version": "1.0.0",
176 | "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
177 | "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
178 | "dev": true,
179 | "requires": {
180 | "is-descriptor": "^1.0.0"
181 | }
182 | },
183 | "is-accessor-descriptor": {
184 | "version": "1.0.0",
185 | "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
186 | "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
187 | "dev": true,
188 | "requires": {
189 | "kind-of": "^6.0.0"
190 | }
191 | },
192 | "is-data-descriptor": {
193 | "version": "1.0.0",
194 | "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
195 | "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
196 | "dev": true,
197 | "requires": {
198 | "kind-of": "^6.0.0"
199 | }
200 | },
201 | "is-descriptor": {
202 | "version": "1.0.2",
203 | "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
204 | "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
205 | "dev": true,
206 | "requires": {
207 | "is-accessor-descriptor": "^1.0.0",
208 | "is-data-descriptor": "^1.0.0",
209 | "kind-of": "^6.0.2"
210 | }
211 | }
212 | }
213 | },
214 | "basic-auth": {
215 | "version": "2.0.1",
216 | "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz",
217 | "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==",
218 | "requires": {
219 | "safe-buffer": "5.1.2"
220 | }
221 | },
222 | "bcrypt-pbkdf": {
223 | "version": "1.0.2",
224 | "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
225 | "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
226 | "requires": {
227 | "tweetnacl": "^0.14.3"
228 | }
229 | },
230 | "bcryptjs": {
231 | "version": "2.4.3",
232 | "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz",
233 | "integrity": "sha1-mrVie5PmBiH/fNrF2pczAn3x0Ms="
234 | },
235 | "binary-extensions": {
236 | "version": "1.13.1",
237 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz",
238 | "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==",
239 | "dev": true
240 | },
241 | "bluebird": {
242 | "version": "3.5.1",
243 | "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz",
244 | "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA=="
245 | },
246 | "body-parser": {
247 | "version": "1.19.0",
248 | "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
249 | "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==",
250 | "requires": {
251 | "bytes": "3.1.0",
252 | "content-type": "~1.0.4",
253 | "debug": "2.6.9",
254 | "depd": "~1.1.2",
255 | "http-errors": "1.7.2",
256 | "iconv-lite": "0.4.24",
257 | "on-finished": "~2.3.0",
258 | "qs": "6.7.0",
259 | "raw-body": "2.4.0",
260 | "type-is": "~1.6.17"
261 | }
262 | },
263 | "bowser": {
264 | "version": "2.7.0",
265 | "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.7.0.tgz",
266 | "integrity": "sha512-aIlMvstvu8x+34KEiOHD3AsBgdrzg6sxALYiukOWhFvGMbQI6TRP/iY0LMhUrHs56aD6P1G0Z7h45PUJaa5m9w=="
267 | },
268 | "boxen": {
269 | "version": "1.3.0",
270 | "resolved": "https://registry.npmjs.org/boxen/-/boxen-1.3.0.tgz",
271 | "integrity": "sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw==",
272 | "dev": true,
273 | "requires": {
274 | "ansi-align": "^2.0.0",
275 | "camelcase": "^4.0.0",
276 | "chalk": "^2.0.1",
277 | "cli-boxes": "^1.0.0",
278 | "string-width": "^2.0.0",
279 | "term-size": "^1.2.0",
280 | "widest-line": "^2.0.0"
281 | }
282 | },
283 | "brace-expansion": {
284 | "version": "1.1.11",
285 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
286 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
287 | "dev": true,
288 | "requires": {
289 | "balanced-match": "^1.0.0",
290 | "concat-map": "0.0.1"
291 | }
292 | },
293 | "braces": {
294 | "version": "2.3.2",
295 | "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
296 | "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
297 | "dev": true,
298 | "requires": {
299 | "arr-flatten": "^1.1.0",
300 | "array-unique": "^0.3.2",
301 | "extend-shallow": "^2.0.1",
302 | "fill-range": "^4.0.0",
303 | "isobject": "^3.0.1",
304 | "repeat-element": "^1.1.2",
305 | "snapdragon": "^0.8.1",
306 | "snapdragon-node": "^2.0.1",
307 | "split-string": "^3.0.2",
308 | "to-regex": "^3.0.1"
309 | },
310 | "dependencies": {
311 | "extend-shallow": {
312 | "version": "2.0.1",
313 | "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
314 | "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
315 | "dev": true,
316 | "requires": {
317 | "is-extendable": "^0.1.0"
318 | }
319 | }
320 | }
321 | },
322 | "bson": {
323 | "version": "1.1.1",
324 | "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.1.tgz",
325 | "integrity": "sha512-jCGVYLoYMHDkOsbwJZBCqwMHyH4c+wzgI9hG7Z6SZJRXWr+x58pdIbm2i9a/jFGCkRJqRUr8eoI7lDWa0hTkxg=="
326 | },
327 | "buffer-equal-constant-time": {
328 | "version": "1.0.1",
329 | "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
330 | "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk="
331 | },
332 | "busboy": {
333 | "version": "0.2.14",
334 | "resolved": "https://registry.npmjs.org/busboy/-/busboy-0.2.14.tgz",
335 | "integrity": "sha1-bCpiLvz0fFe7vh4qnDetNseSVFM=",
336 | "requires": {
337 | "dicer": "0.2.5",
338 | "readable-stream": "1.1.x"
339 | },
340 | "dependencies": {
341 | "isarray": {
342 | "version": "0.0.1",
343 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
344 | "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
345 | },
346 | "readable-stream": {
347 | "version": "1.1.14",
348 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
349 | "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
350 | "requires": {
351 | "core-util-is": "~1.0.0",
352 | "inherits": "~2.0.1",
353 | "isarray": "0.0.1",
354 | "string_decoder": "~0.10.x"
355 | }
356 | },
357 | "string_decoder": {
358 | "version": "0.10.31",
359 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
360 | "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
361 | }
362 | }
363 | },
364 | "bytes": {
365 | "version": "3.1.0",
366 | "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
367 | "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg=="
368 | },
369 | "cache-base": {
370 | "version": "1.0.1",
371 | "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz",
372 | "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==",
373 | "dev": true,
374 | "requires": {
375 | "collection-visit": "^1.0.0",
376 | "component-emitter": "^1.2.1",
377 | "get-value": "^2.0.6",
378 | "has-value": "^1.0.0",
379 | "isobject": "^3.0.1",
380 | "set-value": "^2.0.0",
381 | "to-object-path": "^0.3.0",
382 | "union-value": "^1.0.0",
383 | "unset-value": "^1.0.0"
384 | }
385 | },
386 | "camelcase": {
387 | "version": "4.1.0",
388 | "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz",
389 | "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=",
390 | "dev": true
391 | },
392 | "camelize": {
393 | "version": "1.0.0",
394 | "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.0.tgz",
395 | "integrity": "sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs="
396 | },
397 | "capture-stack-trace": {
398 | "version": "1.0.1",
399 | "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.1.tgz",
400 | "integrity": "sha512-mYQLZnx5Qt1JgB1WEiMCf2647plpGeQ2NMR/5L0HNZzGQo4fuSPnK+wjfPnKZV0aiJDgzmWqqkV/g7JD+DW0qw==",
401 | "dev": true
402 | },
403 | "caseless": {
404 | "version": "0.12.0",
405 | "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
406 | "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
407 | },
408 | "chalk": {
409 | "version": "2.4.2",
410 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
411 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
412 | "dev": true,
413 | "requires": {
414 | "ansi-styles": "^3.2.1",
415 | "escape-string-regexp": "^1.0.5",
416 | "supports-color": "^5.3.0"
417 | }
418 | },
419 | "chokidar": {
420 | "version": "2.1.8",
421 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz",
422 | "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==",
423 | "dev": true,
424 | "requires": {
425 | "anymatch": "^2.0.0",
426 | "async-each": "^1.0.1",
427 | "braces": "^2.3.2",
428 | "fsevents": "^1.2.7",
429 | "glob-parent": "^3.1.0",
430 | "inherits": "^2.0.3",
431 | "is-binary-path": "^1.0.0",
432 | "is-glob": "^4.0.0",
433 | "normalize-path": "^3.0.0",
434 | "path-is-absolute": "^1.0.0",
435 | "readdirp": "^2.2.1",
436 | "upath": "^1.1.1"
437 | }
438 | },
439 | "ci-info": {
440 | "version": "1.6.0",
441 | "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.6.0.tgz",
442 | "integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==",
443 | "dev": true
444 | },
445 | "class-utils": {
446 | "version": "0.3.6",
447 | "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz",
448 | "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==",
449 | "dev": true,
450 | "requires": {
451 | "arr-union": "^3.1.0",
452 | "define-property": "^0.2.5",
453 | "isobject": "^3.0.0",
454 | "static-extend": "^0.1.1"
455 | },
456 | "dependencies": {
457 | "define-property": {
458 | "version": "0.2.5",
459 | "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
460 | "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
461 | "dev": true,
462 | "requires": {
463 | "is-descriptor": "^0.1.0"
464 | }
465 | }
466 | }
467 | },
468 | "cli-boxes": {
469 | "version": "1.0.0",
470 | "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-1.0.0.tgz",
471 | "integrity": "sha1-T6kXw+WclKAEzWH47lCdplFocUM=",
472 | "dev": true
473 | },
474 | "collection-visit": {
475 | "version": "1.0.0",
476 | "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
477 | "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=",
478 | "dev": true,
479 | "requires": {
480 | "map-visit": "^1.0.0",
481 | "object-visit": "^1.0.0"
482 | }
483 | },
484 | "color-convert": {
485 | "version": "1.9.3",
486 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
487 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
488 | "dev": true,
489 | "requires": {
490 | "color-name": "1.1.3"
491 | }
492 | },
493 | "color-name": {
494 | "version": "1.1.3",
495 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
496 | "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
497 | "dev": true
498 | },
499 | "colors": {
500 | "version": "1.4.0",
501 | "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz",
502 | "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA=="
503 | },
504 | "combined-stream": {
505 | "version": "1.0.8",
506 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
507 | "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
508 | "requires": {
509 | "delayed-stream": "~1.0.0"
510 | }
511 | },
512 | "component-emitter": {
513 | "version": "1.3.0",
514 | "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
515 | "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==",
516 | "dev": true
517 | },
518 | "concat-map": {
519 | "version": "0.0.1",
520 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
521 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
522 | "dev": true
523 | },
524 | "configstore": {
525 | "version": "3.1.2",
526 | "resolved": "https://registry.npmjs.org/configstore/-/configstore-3.1.2.tgz",
527 | "integrity": "sha512-vtv5HtGjcYUgFrXc6Kx747B83MRRVS5R1VTEQoXvuP+kMI+if6uywV0nDGoiydJRy4yk7h9od5Og0kxx4zUXmw==",
528 | "dev": true,
529 | "requires": {
530 | "dot-prop": "^4.1.0",
531 | "graceful-fs": "^4.1.2",
532 | "make-dir": "^1.0.0",
533 | "unique-string": "^1.0.0",
534 | "write-file-atomic": "^2.0.0",
535 | "xdg-basedir": "^3.0.0"
536 | }
537 | },
538 | "content-disposition": {
539 | "version": "0.5.3",
540 | "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz",
541 | "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==",
542 | "requires": {
543 | "safe-buffer": "5.1.2"
544 | }
545 | },
546 | "content-security-policy-builder": {
547 | "version": "2.1.0",
548 | "resolved": "https://registry.npmjs.org/content-security-policy-builder/-/content-security-policy-builder-2.1.0.tgz",
549 | "integrity": "sha512-/MtLWhJVvJNkA9dVLAp6fg9LxD2gfI6R2Fi1hPmfjYXSahJJzcfvoeDOxSyp4NvxMuwWv3WMssE9o31DoULHrQ=="
550 | },
551 | "content-type": {
552 | "version": "1.0.4",
553 | "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
554 | "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
555 | },
556 | "cookie": {
557 | "version": "0.4.0",
558 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz",
559 | "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg=="
560 | },
561 | "cookie-parser": {
562 | "version": "1.4.4",
563 | "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.4.tgz",
564 | "integrity": "sha512-lo13tqF3JEtFO7FyA49CqbhaFkskRJ0u/UAiINgrIXeRCY41c88/zxtrECl8AKH3B0hj9q10+h3Kt8I7KlW4tw==",
565 | "requires": {
566 | "cookie": "0.3.1",
567 | "cookie-signature": "1.0.6"
568 | },
569 | "dependencies": {
570 | "cookie": {
571 | "version": "0.3.1",
572 | "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz",
573 | "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s="
574 | }
575 | }
576 | },
577 | "cookie-signature": {
578 | "version": "1.0.6",
579 | "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
580 | "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
581 | },
582 | "copy-descriptor": {
583 | "version": "0.1.1",
584 | "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz",
585 | "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=",
586 | "dev": true
587 | },
588 | "core-util-is": {
589 | "version": "1.0.2",
590 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
591 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
592 | },
593 | "cors": {
594 | "version": "2.8.5",
595 | "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
596 | "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
597 | "requires": {
598 | "object-assign": "^4",
599 | "vary": "^1"
600 | }
601 | },
602 | "create-error-class": {
603 | "version": "3.0.2",
604 | "resolved": "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz",
605 | "integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=",
606 | "dev": true,
607 | "requires": {
608 | "capture-stack-trace": "^1.0.0"
609 | }
610 | },
611 | "cross-spawn": {
612 | "version": "5.1.0",
613 | "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",
614 | "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=",
615 | "dev": true,
616 | "requires": {
617 | "lru-cache": "^4.0.1",
618 | "shebang-command": "^1.2.0",
619 | "which": "^1.2.9"
620 | }
621 | },
622 | "crypto-random-string": {
623 | "version": "1.0.0",
624 | "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz",
625 | "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=",
626 | "dev": true
627 | },
628 | "dashdash": {
629 | "version": "1.14.1",
630 | "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
631 | "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
632 | "requires": {
633 | "assert-plus": "^1.0.0"
634 | }
635 | },
636 | "dasherize": {
637 | "version": "2.0.0",
638 | "resolved": "https://registry.npmjs.org/dasherize/-/dasherize-2.0.0.tgz",
639 | "integrity": "sha1-bYCcnNDPe7iVLYD8hPoT1H3bEwg="
640 | },
641 | "debug": {
642 | "version": "2.6.9",
643 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
644 | "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
645 | "requires": {
646 | "ms": "2.0.0"
647 | }
648 | },
649 | "decode-uri-component": {
650 | "version": "0.2.0",
651 | "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
652 | "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=",
653 | "dev": true
654 | },
655 | "deep-extend": {
656 | "version": "0.6.0",
657 | "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
658 | "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
659 | "dev": true
660 | },
661 | "define-property": {
662 | "version": "2.0.2",
663 | "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz",
664 | "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==",
665 | "dev": true,
666 | "requires": {
667 | "is-descriptor": "^1.0.2",
668 | "isobject": "^3.0.1"
669 | },
670 | "dependencies": {
671 | "is-accessor-descriptor": {
672 | "version": "1.0.0",
673 | "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
674 | "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
675 | "dev": true,
676 | "requires": {
677 | "kind-of": "^6.0.0"
678 | }
679 | },
680 | "is-data-descriptor": {
681 | "version": "1.0.0",
682 | "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
683 | "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
684 | "dev": true,
685 | "requires": {
686 | "kind-of": "^6.0.0"
687 | }
688 | },
689 | "is-descriptor": {
690 | "version": "1.0.2",
691 | "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
692 | "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
693 | "dev": true,
694 | "requires": {
695 | "is-accessor-descriptor": "^1.0.0",
696 | "is-data-descriptor": "^1.0.0",
697 | "kind-of": "^6.0.2"
698 | }
699 | }
700 | }
701 | },
702 | "delayed-stream": {
703 | "version": "1.0.0",
704 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
705 | "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
706 | },
707 | "depd": {
708 | "version": "1.1.2",
709 | "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
710 | "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
711 | },
712 | "destroy": {
713 | "version": "1.0.4",
714 | "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
715 | "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
716 | },
717 | "dicer": {
718 | "version": "0.2.5",
719 | "resolved": "https://registry.npmjs.org/dicer/-/dicer-0.2.5.tgz",
720 | "integrity": "sha1-WZbAhrszIYyBLAkL3cCc0S+stw8=",
721 | "requires": {
722 | "readable-stream": "1.1.x",
723 | "streamsearch": "0.1.2"
724 | },
725 | "dependencies": {
726 | "isarray": {
727 | "version": "0.0.1",
728 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
729 | "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
730 | },
731 | "readable-stream": {
732 | "version": "1.1.14",
733 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
734 | "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
735 | "requires": {
736 | "core-util-is": "~1.0.0",
737 | "inherits": "~2.0.1",
738 | "isarray": "0.0.1",
739 | "string_decoder": "~0.10.x"
740 | }
741 | },
742 | "string_decoder": {
743 | "version": "0.10.31",
744 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
745 | "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
746 | }
747 | }
748 | },
749 | "dns-prefetch-control": {
750 | "version": "0.2.0",
751 | "resolved": "https://registry.npmjs.org/dns-prefetch-control/-/dns-prefetch-control-0.2.0.tgz",
752 | "integrity": "sha512-hvSnros73+qyZXhHFjx2CMLwoj3Fe7eR9EJsFsqmcI1bB2OBWL/+0YzaEaKssCHnj/6crawNnUyw74Gm2EKe+Q=="
753 | },
754 | "dont-sniff-mimetype": {
755 | "version": "1.1.0",
756 | "resolved": "https://registry.npmjs.org/dont-sniff-mimetype/-/dont-sniff-mimetype-1.1.0.tgz",
757 | "integrity": "sha512-ZjI4zqTaxveH2/tTlzS1wFp+7ncxNZaIEWYg3lzZRHkKf5zPT/MnEG6WL0BhHMJUabkh8GeU5NL5j+rEUCb7Ug=="
758 | },
759 | "dot-prop": {
760 | "version": "4.2.0",
761 | "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz",
762 | "integrity": "sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==",
763 | "dev": true,
764 | "requires": {
765 | "is-obj": "^1.0.0"
766 | }
767 | },
768 | "dotenv": {
769 | "version": "8.1.0",
770 | "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.1.0.tgz",
771 | "integrity": "sha512-GUE3gqcDCaMltj2++g6bRQ5rBJWtkWTmqmD0fo1RnnMuUqHNCt2oTPeDnS9n6fKYvlhn7AeBkb38lymBtWBQdA=="
772 | },
773 | "duplexer3": {
774 | "version": "0.1.4",
775 | "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz",
776 | "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=",
777 | "dev": true
778 | },
779 | "ecc-jsbn": {
780 | "version": "0.1.2",
781 | "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
782 | "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
783 | "requires": {
784 | "jsbn": "~0.1.0",
785 | "safer-buffer": "^2.1.0"
786 | }
787 | },
788 | "ecdsa-sig-formatter": {
789 | "version": "1.0.11",
790 | "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
791 | "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
792 | "requires": {
793 | "safe-buffer": "^5.0.1"
794 | }
795 | },
796 | "ee-first": {
797 | "version": "1.1.1",
798 | "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
799 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
800 | },
801 | "encodeurl": {
802 | "version": "1.0.2",
803 | "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
804 | "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
805 | },
806 | "escape-html": {
807 | "version": "1.0.3",
808 | "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
809 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
810 | },
811 | "escape-string-regexp": {
812 | "version": "1.0.5",
813 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
814 | "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
815 | "dev": true
816 | },
817 | "etag": {
818 | "version": "1.8.1",
819 | "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
820 | "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
821 | },
822 | "execa": {
823 | "version": "0.7.0",
824 | "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz",
825 | "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=",
826 | "dev": true,
827 | "requires": {
828 | "cross-spawn": "^5.0.1",
829 | "get-stream": "^3.0.0",
830 | "is-stream": "^1.1.0",
831 | "npm-run-path": "^2.0.0",
832 | "p-finally": "^1.0.0",
833 | "signal-exit": "^3.0.0",
834 | "strip-eof": "^1.0.0"
835 | }
836 | },
837 | "expand-brackets": {
838 | "version": "2.1.4",
839 | "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",
840 | "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=",
841 | "dev": true,
842 | "requires": {
843 | "debug": "^2.3.3",
844 | "define-property": "^0.2.5",
845 | "extend-shallow": "^2.0.1",
846 | "posix-character-classes": "^0.1.0",
847 | "regex-not": "^1.0.0",
848 | "snapdragon": "^0.8.1",
849 | "to-regex": "^3.0.1"
850 | },
851 | "dependencies": {
852 | "define-property": {
853 | "version": "0.2.5",
854 | "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
855 | "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
856 | "dev": true,
857 | "requires": {
858 | "is-descriptor": "^0.1.0"
859 | }
860 | },
861 | "extend-shallow": {
862 | "version": "2.0.1",
863 | "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
864 | "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
865 | "dev": true,
866 | "requires": {
867 | "is-extendable": "^0.1.0"
868 | }
869 | }
870 | }
871 | },
872 | "expect-ct": {
873 | "version": "0.2.0",
874 | "resolved": "https://registry.npmjs.org/expect-ct/-/expect-ct-0.2.0.tgz",
875 | "integrity": "sha512-6SK3MG/Bbhm8MsgyJAylg+ucIOU71/FzyFalcfu5nY19dH8y/z0tBJU0wrNBXD4B27EoQtqPF/9wqH0iYAd04g=="
876 | },
877 | "express": {
878 | "version": "4.17.1",
879 | "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz",
880 | "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==",
881 | "requires": {
882 | "accepts": "~1.3.7",
883 | "array-flatten": "1.1.1",
884 | "body-parser": "1.19.0",
885 | "content-disposition": "0.5.3",
886 | "content-type": "~1.0.4",
887 | "cookie": "0.4.0",
888 | "cookie-signature": "1.0.6",
889 | "debug": "2.6.9",
890 | "depd": "~1.1.2",
891 | "encodeurl": "~1.0.2",
892 | "escape-html": "~1.0.3",
893 | "etag": "~1.8.1",
894 | "finalhandler": "~1.1.2",
895 | "fresh": "0.5.2",
896 | "merge-descriptors": "1.0.1",
897 | "methods": "~1.1.2",
898 | "on-finished": "~2.3.0",
899 | "parseurl": "~1.3.3",
900 | "path-to-regexp": "0.1.7",
901 | "proxy-addr": "~2.0.5",
902 | "qs": "6.7.0",
903 | "range-parser": "~1.2.1",
904 | "safe-buffer": "5.1.2",
905 | "send": "0.17.1",
906 | "serve-static": "1.14.1",
907 | "setprototypeof": "1.1.1",
908 | "statuses": "~1.5.0",
909 | "type-is": "~1.6.18",
910 | "utils-merge": "1.0.1",
911 | "vary": "~1.1.2"
912 | }
913 | },
914 | "express-fileupload": {
915 | "version": "1.1.6-alpha.5",
916 | "resolved": "https://registry.npmjs.org/express-fileupload/-/express-fileupload-1.1.6-alpha.5.tgz",
917 | "integrity": "sha512-M/PLB3moD1stnfYUHGtAVqfdjOz0VSY00NWnA9CpSEyPxhs/lEeperWOffaBzom+DO8Sq1z1okJOy2N4MDRYtA==",
918 | "requires": {
919 | "busboy": "^0.2.14"
920 | }
921 | },
922 | "express-mongo-sanitize": {
923 | "version": "1.3.2",
924 | "resolved": "https://registry.npmjs.org/express-mongo-sanitize/-/express-mongo-sanitize-1.3.2.tgz",
925 | "integrity": "sha1-+6QE9sBBV3y+7sTdkFfO+7Q53lo="
926 | },
927 | "express-rate-limit": {
928 | "version": "5.0.0",
929 | "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-5.0.0.tgz",
930 | "integrity": "sha512-dhT57wqxfqmkOi4HM7NuT4Gd7gbUgSK2ocG27Y6lwm8lbOAw9XQfeANawGq8wLDtlGPO1ZgDj0HmKsykTxfFAg=="
931 | },
932 | "extend": {
933 | "version": "3.0.2",
934 | "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
935 | "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
936 | },
937 | "extend-shallow": {
938 | "version": "3.0.2",
939 | "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
940 | "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=",
941 | "dev": true,
942 | "requires": {
943 | "assign-symbols": "^1.0.0",
944 | "is-extendable": "^1.0.1"
945 | },
946 | "dependencies": {
947 | "is-extendable": {
948 | "version": "1.0.1",
949 | "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
950 | "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
951 | "dev": true,
952 | "requires": {
953 | "is-plain-object": "^2.0.4"
954 | }
955 | }
956 | }
957 | },
958 | "extglob": {
959 | "version": "2.0.4",
960 | "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz",
961 | "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==",
962 | "dev": true,
963 | "requires": {
964 | "array-unique": "^0.3.2",
965 | "define-property": "^1.0.0",
966 | "expand-brackets": "^2.1.4",
967 | "extend-shallow": "^2.0.1",
968 | "fragment-cache": "^0.2.1",
969 | "regex-not": "^1.0.0",
970 | "snapdragon": "^0.8.1",
971 | "to-regex": "^3.0.1"
972 | },
973 | "dependencies": {
974 | "define-property": {
975 | "version": "1.0.0",
976 | "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
977 | "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
978 | "dev": true,
979 | "requires": {
980 | "is-descriptor": "^1.0.0"
981 | }
982 | },
983 | "extend-shallow": {
984 | "version": "2.0.1",
985 | "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
986 | "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
987 | "dev": true,
988 | "requires": {
989 | "is-extendable": "^0.1.0"
990 | }
991 | },
992 | "is-accessor-descriptor": {
993 | "version": "1.0.0",
994 | "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
995 | "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
996 | "dev": true,
997 | "requires": {
998 | "kind-of": "^6.0.0"
999 | }
1000 | },
1001 | "is-data-descriptor": {
1002 | "version": "1.0.0",
1003 | "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
1004 | "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
1005 | "dev": true,
1006 | "requires": {
1007 | "kind-of": "^6.0.0"
1008 | }
1009 | },
1010 | "is-descriptor": {
1011 | "version": "1.0.2",
1012 | "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
1013 | "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
1014 | "dev": true,
1015 | "requires": {
1016 | "is-accessor-descriptor": "^1.0.0",
1017 | "is-data-descriptor": "^1.0.0",
1018 | "kind-of": "^6.0.2"
1019 | }
1020 | }
1021 | }
1022 | },
1023 | "extsprintf": {
1024 | "version": "1.3.0",
1025 | "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
1026 | "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU="
1027 | },
1028 | "fast-deep-equal": {
1029 | "version": "2.0.1",
1030 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
1031 | "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk="
1032 | },
1033 | "fast-json-stable-stringify": {
1034 | "version": "2.0.0",
1035 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz",
1036 | "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I="
1037 | },
1038 | "feature-policy": {
1039 | "version": "0.3.0",
1040 | "resolved": "https://registry.npmjs.org/feature-policy/-/feature-policy-0.3.0.tgz",
1041 | "integrity": "sha512-ZtijOTFN7TzCujt1fnNhfWPFPSHeZkesff9AXZj+UEjYBynWNUIYpC87Ve4wHzyexQsImicLu7WsC2LHq7/xrQ=="
1042 | },
1043 | "fill-range": {
1044 | "version": "4.0.0",
1045 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
1046 | "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
1047 | "dev": true,
1048 | "requires": {
1049 | "extend-shallow": "^2.0.1",
1050 | "is-number": "^3.0.0",
1051 | "repeat-string": "^1.6.1",
1052 | "to-regex-range": "^2.1.0"
1053 | },
1054 | "dependencies": {
1055 | "extend-shallow": {
1056 | "version": "2.0.1",
1057 | "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
1058 | "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
1059 | "dev": true,
1060 | "requires": {
1061 | "is-extendable": "^0.1.0"
1062 | }
1063 | }
1064 | }
1065 | },
1066 | "finalhandler": {
1067 | "version": "1.1.2",
1068 | "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
1069 | "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
1070 | "requires": {
1071 | "debug": "2.6.9",
1072 | "encodeurl": "~1.0.2",
1073 | "escape-html": "~1.0.3",
1074 | "on-finished": "~2.3.0",
1075 | "parseurl": "~1.3.3",
1076 | "statuses": "~1.5.0",
1077 | "unpipe": "~1.0.0"
1078 | }
1079 | },
1080 | "for-in": {
1081 | "version": "1.0.2",
1082 | "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
1083 | "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=",
1084 | "dev": true
1085 | },
1086 | "forever-agent": {
1087 | "version": "0.6.1",
1088 | "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
1089 | "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE="
1090 | },
1091 | "form-data": {
1092 | "version": "2.3.3",
1093 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
1094 | "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
1095 | "requires": {
1096 | "asynckit": "^0.4.0",
1097 | "combined-stream": "^1.0.6",
1098 | "mime-types": "^2.1.12"
1099 | }
1100 | },
1101 | "forwarded": {
1102 | "version": "0.1.2",
1103 | "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
1104 | "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ="
1105 | },
1106 | "fragment-cache": {
1107 | "version": "0.2.1",
1108 | "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
1109 | "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=",
1110 | "dev": true,
1111 | "requires": {
1112 | "map-cache": "^0.2.2"
1113 | }
1114 | },
1115 | "frameguard": {
1116 | "version": "3.1.0",
1117 | "resolved": "https://registry.npmjs.org/frameguard/-/frameguard-3.1.0.tgz",
1118 | "integrity": "sha512-TxgSKM+7LTA6sidjOiSZK9wxY0ffMPY3Wta//MqwmX0nZuEHc8QrkV8Fh3ZhMJeiH+Uyh/tcaarImRy8u77O7g=="
1119 | },
1120 | "fresh": {
1121 | "version": "0.5.2",
1122 | "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
1123 | "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
1124 | },
1125 | "fsevents": {
1126 | "version": "1.2.9",
1127 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz",
1128 | "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==",
1129 | "dev": true,
1130 | "optional": true,
1131 | "requires": {
1132 | "nan": "^2.12.1",
1133 | "node-pre-gyp": "^0.12.0"
1134 | },
1135 | "dependencies": {
1136 | "abbrev": {
1137 | "version": "1.1.1",
1138 | "bundled": true,
1139 | "dev": true,
1140 | "optional": true
1141 | },
1142 | "ansi-regex": {
1143 | "version": "2.1.1",
1144 | "bundled": true,
1145 | "dev": true,
1146 | "optional": true
1147 | },
1148 | "aproba": {
1149 | "version": "1.2.0",
1150 | "bundled": true,
1151 | "dev": true,
1152 | "optional": true
1153 | },
1154 | "are-we-there-yet": {
1155 | "version": "1.1.5",
1156 | "bundled": true,
1157 | "dev": true,
1158 | "optional": true,
1159 | "requires": {
1160 | "delegates": "^1.0.0",
1161 | "readable-stream": "^2.0.6"
1162 | }
1163 | },
1164 | "balanced-match": {
1165 | "version": "1.0.0",
1166 | "bundled": true,
1167 | "dev": true,
1168 | "optional": true
1169 | },
1170 | "brace-expansion": {
1171 | "version": "1.1.11",
1172 | "bundled": true,
1173 | "dev": true,
1174 | "optional": true,
1175 | "requires": {
1176 | "balanced-match": "^1.0.0",
1177 | "concat-map": "0.0.1"
1178 | }
1179 | },
1180 | "chownr": {
1181 | "version": "1.1.1",
1182 | "bundled": true,
1183 | "dev": true,
1184 | "optional": true
1185 | },
1186 | "code-point-at": {
1187 | "version": "1.1.0",
1188 | "bundled": true,
1189 | "dev": true,
1190 | "optional": true
1191 | },
1192 | "concat-map": {
1193 | "version": "0.0.1",
1194 | "bundled": true,
1195 | "dev": true,
1196 | "optional": true
1197 | },
1198 | "console-control-strings": {
1199 | "version": "1.1.0",
1200 | "bundled": true,
1201 | "dev": true,
1202 | "optional": true
1203 | },
1204 | "core-util-is": {
1205 | "version": "1.0.2",
1206 | "bundled": true,
1207 | "dev": true,
1208 | "optional": true
1209 | },
1210 | "debug": {
1211 | "version": "4.1.1",
1212 | "bundled": true,
1213 | "dev": true,
1214 | "optional": true,
1215 | "requires": {
1216 | "ms": "^2.1.1"
1217 | }
1218 | },
1219 | "deep-extend": {
1220 | "version": "0.6.0",
1221 | "bundled": true,
1222 | "dev": true,
1223 | "optional": true
1224 | },
1225 | "delegates": {
1226 | "version": "1.0.0",
1227 | "bundled": true,
1228 | "dev": true,
1229 | "optional": true
1230 | },
1231 | "detect-libc": {
1232 | "version": "1.0.3",
1233 | "bundled": true,
1234 | "dev": true,
1235 | "optional": true
1236 | },
1237 | "fs-minipass": {
1238 | "version": "1.2.5",
1239 | "bundled": true,
1240 | "dev": true,
1241 | "optional": true,
1242 | "requires": {
1243 | "minipass": "^2.2.1"
1244 | }
1245 | },
1246 | "fs.realpath": {
1247 | "version": "1.0.0",
1248 | "bundled": true,
1249 | "dev": true,
1250 | "optional": true
1251 | },
1252 | "gauge": {
1253 | "version": "2.7.4",
1254 | "bundled": true,
1255 | "dev": true,
1256 | "optional": true,
1257 | "requires": {
1258 | "aproba": "^1.0.3",
1259 | "console-control-strings": "^1.0.0",
1260 | "has-unicode": "^2.0.0",
1261 | "object-assign": "^4.1.0",
1262 | "signal-exit": "^3.0.0",
1263 | "string-width": "^1.0.1",
1264 | "strip-ansi": "^3.0.1",
1265 | "wide-align": "^1.1.0"
1266 | }
1267 | },
1268 | "glob": {
1269 | "version": "7.1.3",
1270 | "bundled": true,
1271 | "dev": true,
1272 | "optional": true,
1273 | "requires": {
1274 | "fs.realpath": "^1.0.0",
1275 | "inflight": "^1.0.4",
1276 | "inherits": "2",
1277 | "minimatch": "^3.0.4",
1278 | "once": "^1.3.0",
1279 | "path-is-absolute": "^1.0.0"
1280 | }
1281 | },
1282 | "has-unicode": {
1283 | "version": "2.0.1",
1284 | "bundled": true,
1285 | "dev": true,
1286 | "optional": true
1287 | },
1288 | "iconv-lite": {
1289 | "version": "0.4.24",
1290 | "bundled": true,
1291 | "dev": true,
1292 | "optional": true,
1293 | "requires": {
1294 | "safer-buffer": ">= 2.1.2 < 3"
1295 | }
1296 | },
1297 | "ignore-walk": {
1298 | "version": "3.0.1",
1299 | "bundled": true,
1300 | "dev": true,
1301 | "optional": true,
1302 | "requires": {
1303 | "minimatch": "^3.0.4"
1304 | }
1305 | },
1306 | "inflight": {
1307 | "version": "1.0.6",
1308 | "bundled": true,
1309 | "dev": true,
1310 | "optional": true,
1311 | "requires": {
1312 | "once": "^1.3.0",
1313 | "wrappy": "1"
1314 | }
1315 | },
1316 | "inherits": {
1317 | "version": "2.0.3",
1318 | "bundled": true,
1319 | "dev": true,
1320 | "optional": true
1321 | },
1322 | "ini": {
1323 | "version": "1.3.5",
1324 | "bundled": true,
1325 | "dev": true,
1326 | "optional": true
1327 | },
1328 | "is-fullwidth-code-point": {
1329 | "version": "1.0.0",
1330 | "bundled": true,
1331 | "dev": true,
1332 | "optional": true,
1333 | "requires": {
1334 | "number-is-nan": "^1.0.0"
1335 | }
1336 | },
1337 | "isarray": {
1338 | "version": "1.0.0",
1339 | "bundled": true,
1340 | "dev": true,
1341 | "optional": true
1342 | },
1343 | "minimatch": {
1344 | "version": "3.0.4",
1345 | "bundled": true,
1346 | "dev": true,
1347 | "optional": true,
1348 | "requires": {
1349 | "brace-expansion": "^1.1.7"
1350 | }
1351 | },
1352 | "minimist": {
1353 | "version": "0.0.8",
1354 | "bundled": true,
1355 | "dev": true,
1356 | "optional": true
1357 | },
1358 | "minipass": {
1359 | "version": "2.3.5",
1360 | "bundled": true,
1361 | "dev": true,
1362 | "optional": true,
1363 | "requires": {
1364 | "safe-buffer": "^5.1.2",
1365 | "yallist": "^3.0.0"
1366 | }
1367 | },
1368 | "minizlib": {
1369 | "version": "1.2.1",
1370 | "bundled": true,
1371 | "dev": true,
1372 | "optional": true,
1373 | "requires": {
1374 | "minipass": "^2.2.1"
1375 | }
1376 | },
1377 | "mkdirp": {
1378 | "version": "0.5.1",
1379 | "bundled": true,
1380 | "dev": true,
1381 | "optional": true,
1382 | "requires": {
1383 | "minimist": "0.0.8"
1384 | }
1385 | },
1386 | "ms": {
1387 | "version": "2.1.1",
1388 | "bundled": true,
1389 | "dev": true,
1390 | "optional": true
1391 | },
1392 | "needle": {
1393 | "version": "2.3.0",
1394 | "bundled": true,
1395 | "dev": true,
1396 | "optional": true,
1397 | "requires": {
1398 | "debug": "^4.1.0",
1399 | "iconv-lite": "^0.4.4",
1400 | "sax": "^1.2.4"
1401 | }
1402 | },
1403 | "node-pre-gyp": {
1404 | "version": "0.12.0",
1405 | "bundled": true,
1406 | "dev": true,
1407 | "optional": true,
1408 | "requires": {
1409 | "detect-libc": "^1.0.2",
1410 | "mkdirp": "^0.5.1",
1411 | "needle": "^2.2.1",
1412 | "nopt": "^4.0.1",
1413 | "npm-packlist": "^1.1.6",
1414 | "npmlog": "^4.0.2",
1415 | "rc": "^1.2.7",
1416 | "rimraf": "^2.6.1",
1417 | "semver": "^5.3.0",
1418 | "tar": "^4"
1419 | }
1420 | },
1421 | "nopt": {
1422 | "version": "4.0.1",
1423 | "bundled": true,
1424 | "dev": true,
1425 | "optional": true,
1426 | "requires": {
1427 | "abbrev": "1",
1428 | "osenv": "^0.1.4"
1429 | }
1430 | },
1431 | "npm-bundled": {
1432 | "version": "1.0.6",
1433 | "bundled": true,
1434 | "dev": true,
1435 | "optional": true
1436 | },
1437 | "npm-packlist": {
1438 | "version": "1.4.1",
1439 | "bundled": true,
1440 | "dev": true,
1441 | "optional": true,
1442 | "requires": {
1443 | "ignore-walk": "^3.0.1",
1444 | "npm-bundled": "^1.0.1"
1445 | }
1446 | },
1447 | "npmlog": {
1448 | "version": "4.1.2",
1449 | "bundled": true,
1450 | "dev": true,
1451 | "optional": true,
1452 | "requires": {
1453 | "are-we-there-yet": "~1.1.2",
1454 | "console-control-strings": "~1.1.0",
1455 | "gauge": "~2.7.3",
1456 | "set-blocking": "~2.0.0"
1457 | }
1458 | },
1459 | "number-is-nan": {
1460 | "version": "1.0.1",
1461 | "bundled": true,
1462 | "dev": true,
1463 | "optional": true
1464 | },
1465 | "object-assign": {
1466 | "version": "4.1.1",
1467 | "bundled": true,
1468 | "dev": true,
1469 | "optional": true
1470 | },
1471 | "once": {
1472 | "version": "1.4.0",
1473 | "bundled": true,
1474 | "dev": true,
1475 | "optional": true,
1476 | "requires": {
1477 | "wrappy": "1"
1478 | }
1479 | },
1480 | "os-homedir": {
1481 | "version": "1.0.2",
1482 | "bundled": true,
1483 | "dev": true,
1484 | "optional": true
1485 | },
1486 | "os-tmpdir": {
1487 | "version": "1.0.2",
1488 | "bundled": true,
1489 | "dev": true,
1490 | "optional": true
1491 | },
1492 | "osenv": {
1493 | "version": "0.1.5",
1494 | "bundled": true,
1495 | "dev": true,
1496 | "optional": true,
1497 | "requires": {
1498 | "os-homedir": "^1.0.0",
1499 | "os-tmpdir": "^1.0.0"
1500 | }
1501 | },
1502 | "path-is-absolute": {
1503 | "version": "1.0.1",
1504 | "bundled": true,
1505 | "dev": true,
1506 | "optional": true
1507 | },
1508 | "process-nextick-args": {
1509 | "version": "2.0.0",
1510 | "bundled": true,
1511 | "dev": true,
1512 | "optional": true
1513 | },
1514 | "rc": {
1515 | "version": "1.2.8",
1516 | "bundled": true,
1517 | "dev": true,
1518 | "optional": true,
1519 | "requires": {
1520 | "deep-extend": "^0.6.0",
1521 | "ini": "~1.3.0",
1522 | "minimist": "^1.2.0",
1523 | "strip-json-comments": "~2.0.1"
1524 | },
1525 | "dependencies": {
1526 | "minimist": {
1527 | "version": "1.2.0",
1528 | "bundled": true,
1529 | "dev": true,
1530 | "optional": true
1531 | }
1532 | }
1533 | },
1534 | "readable-stream": {
1535 | "version": "2.3.6",
1536 | "bundled": true,
1537 | "dev": true,
1538 | "optional": true,
1539 | "requires": {
1540 | "core-util-is": "~1.0.0",
1541 | "inherits": "~2.0.3",
1542 | "isarray": "~1.0.0",
1543 | "process-nextick-args": "~2.0.0",
1544 | "safe-buffer": "~5.1.1",
1545 | "string_decoder": "~1.1.1",
1546 | "util-deprecate": "~1.0.1"
1547 | }
1548 | },
1549 | "rimraf": {
1550 | "version": "2.6.3",
1551 | "bundled": true,
1552 | "dev": true,
1553 | "optional": true,
1554 | "requires": {
1555 | "glob": "^7.1.3"
1556 | }
1557 | },
1558 | "safe-buffer": {
1559 | "version": "5.1.2",
1560 | "bundled": true,
1561 | "dev": true,
1562 | "optional": true
1563 | },
1564 | "safer-buffer": {
1565 | "version": "2.1.2",
1566 | "bundled": true,
1567 | "dev": true,
1568 | "optional": true
1569 | },
1570 | "sax": {
1571 | "version": "1.2.4",
1572 | "bundled": true,
1573 | "dev": true,
1574 | "optional": true
1575 | },
1576 | "semver": {
1577 | "version": "5.7.0",
1578 | "bundled": true,
1579 | "dev": true,
1580 | "optional": true
1581 | },
1582 | "set-blocking": {
1583 | "version": "2.0.0",
1584 | "bundled": true,
1585 | "dev": true,
1586 | "optional": true
1587 | },
1588 | "signal-exit": {
1589 | "version": "3.0.2",
1590 | "bundled": true,
1591 | "dev": true,
1592 | "optional": true
1593 | },
1594 | "string-width": {
1595 | "version": "1.0.2",
1596 | "bundled": true,
1597 | "dev": true,
1598 | "optional": true,
1599 | "requires": {
1600 | "code-point-at": "^1.0.0",
1601 | "is-fullwidth-code-point": "^1.0.0",
1602 | "strip-ansi": "^3.0.0"
1603 | }
1604 | },
1605 | "string_decoder": {
1606 | "version": "1.1.1",
1607 | "bundled": true,
1608 | "dev": true,
1609 | "optional": true,
1610 | "requires": {
1611 | "safe-buffer": "~5.1.0"
1612 | }
1613 | },
1614 | "strip-ansi": {
1615 | "version": "3.0.1",
1616 | "bundled": true,
1617 | "dev": true,
1618 | "optional": true,
1619 | "requires": {
1620 | "ansi-regex": "^2.0.0"
1621 | }
1622 | },
1623 | "strip-json-comments": {
1624 | "version": "2.0.1",
1625 | "bundled": true,
1626 | "dev": true,
1627 | "optional": true
1628 | },
1629 | "tar": {
1630 | "version": "4.4.8",
1631 | "bundled": true,
1632 | "dev": true,
1633 | "optional": true,
1634 | "requires": {
1635 | "chownr": "^1.1.1",
1636 | "fs-minipass": "^1.2.5",
1637 | "minipass": "^2.3.4",
1638 | "minizlib": "^1.1.1",
1639 | "mkdirp": "^0.5.0",
1640 | "safe-buffer": "^5.1.2",
1641 | "yallist": "^3.0.2"
1642 | }
1643 | },
1644 | "util-deprecate": {
1645 | "version": "1.0.2",
1646 | "bundled": true,
1647 | "dev": true,
1648 | "optional": true
1649 | },
1650 | "wide-align": {
1651 | "version": "1.1.3",
1652 | "bundled": true,
1653 | "dev": true,
1654 | "optional": true,
1655 | "requires": {
1656 | "string-width": "^1.0.2 || 2"
1657 | }
1658 | },
1659 | "wrappy": {
1660 | "version": "1.0.2",
1661 | "bundled": true,
1662 | "dev": true,
1663 | "optional": true
1664 | },
1665 | "yallist": {
1666 | "version": "3.0.3",
1667 | "bundled": true,
1668 | "dev": true,
1669 | "optional": true
1670 | }
1671 | }
1672 | },
1673 | "get-stream": {
1674 | "version": "3.0.0",
1675 | "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
1676 | "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=",
1677 | "dev": true
1678 | },
1679 | "get-value": {
1680 | "version": "2.0.6",
1681 | "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz",
1682 | "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=",
1683 | "dev": true
1684 | },
1685 | "getpass": {
1686 | "version": "0.1.7",
1687 | "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
1688 | "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
1689 | "requires": {
1690 | "assert-plus": "^1.0.0"
1691 | }
1692 | },
1693 | "glob-parent": {
1694 | "version": "3.1.0",
1695 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz",
1696 | "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=",
1697 | "dev": true,
1698 | "requires": {
1699 | "is-glob": "^3.1.0",
1700 | "path-dirname": "^1.0.0"
1701 | },
1702 | "dependencies": {
1703 | "is-glob": {
1704 | "version": "3.1.0",
1705 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
1706 | "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
1707 | "dev": true,
1708 | "requires": {
1709 | "is-extglob": "^2.1.0"
1710 | }
1711 | }
1712 | }
1713 | },
1714 | "global-dirs": {
1715 | "version": "0.1.1",
1716 | "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz",
1717 | "integrity": "sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=",
1718 | "dev": true,
1719 | "requires": {
1720 | "ini": "^1.3.4"
1721 | }
1722 | },
1723 | "got": {
1724 | "version": "6.7.1",
1725 | "resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz",
1726 | "integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=",
1727 | "dev": true,
1728 | "requires": {
1729 | "create-error-class": "^3.0.0",
1730 | "duplexer3": "^0.1.4",
1731 | "get-stream": "^3.0.0",
1732 | "is-redirect": "^1.0.0",
1733 | "is-retry-allowed": "^1.0.0",
1734 | "is-stream": "^1.0.0",
1735 | "lowercase-keys": "^1.0.0",
1736 | "safe-buffer": "^5.0.1",
1737 | "timed-out": "^4.0.0",
1738 | "unzip-response": "^2.0.1",
1739 | "url-parse-lax": "^1.0.0"
1740 | }
1741 | },
1742 | "graceful-fs": {
1743 | "version": "4.2.2",
1744 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.2.tgz",
1745 | "integrity": "sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q==",
1746 | "dev": true
1747 | },
1748 | "har-schema": {
1749 | "version": "2.0.0",
1750 | "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
1751 | "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI="
1752 | },
1753 | "har-validator": {
1754 | "version": "5.1.3",
1755 | "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz",
1756 | "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==",
1757 | "requires": {
1758 | "ajv": "^6.5.5",
1759 | "har-schema": "^2.0.0"
1760 | }
1761 | },
1762 | "has-flag": {
1763 | "version": "3.0.0",
1764 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
1765 | "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
1766 | "dev": true
1767 | },
1768 | "has-value": {
1769 | "version": "1.0.0",
1770 | "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz",
1771 | "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=",
1772 | "dev": true,
1773 | "requires": {
1774 | "get-value": "^2.0.6",
1775 | "has-values": "^1.0.0",
1776 | "isobject": "^3.0.0"
1777 | }
1778 | },
1779 | "has-values": {
1780 | "version": "1.0.0",
1781 | "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz",
1782 | "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=",
1783 | "dev": true,
1784 | "requires": {
1785 | "is-number": "^3.0.0",
1786 | "kind-of": "^4.0.0"
1787 | },
1788 | "dependencies": {
1789 | "kind-of": {
1790 | "version": "4.0.0",
1791 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz",
1792 | "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=",
1793 | "dev": true,
1794 | "requires": {
1795 | "is-buffer": "^1.1.5"
1796 | }
1797 | }
1798 | }
1799 | },
1800 | "helmet": {
1801 | "version": "3.21.1",
1802 | "resolved": "https://registry.npmjs.org/helmet/-/helmet-3.21.1.tgz",
1803 | "integrity": "sha512-IC/54Lxvvad2YiUdgLmPlNFKLhNuG++waTF5KPYq/Feo3NNhqMFbcLAlbVkai+9q0+4uxjxGPJ9bNykG+3zZNg==",
1804 | "requires": {
1805 | "depd": "2.0.0",
1806 | "dns-prefetch-control": "0.2.0",
1807 | "dont-sniff-mimetype": "1.1.0",
1808 | "expect-ct": "0.2.0",
1809 | "feature-policy": "0.3.0",
1810 | "frameguard": "3.1.0",
1811 | "helmet-crossdomain": "0.4.0",
1812 | "helmet-csp": "2.9.2",
1813 | "hide-powered-by": "1.1.0",
1814 | "hpkp": "2.0.0",
1815 | "hsts": "2.2.0",
1816 | "ienoopen": "1.1.0",
1817 | "nocache": "2.1.0",
1818 | "referrer-policy": "1.2.0",
1819 | "x-xss-protection": "1.3.0"
1820 | },
1821 | "dependencies": {
1822 | "depd": {
1823 | "version": "2.0.0",
1824 | "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
1825 | "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="
1826 | }
1827 | }
1828 | },
1829 | "helmet-crossdomain": {
1830 | "version": "0.4.0",
1831 | "resolved": "https://registry.npmjs.org/helmet-crossdomain/-/helmet-crossdomain-0.4.0.tgz",
1832 | "integrity": "sha512-AB4DTykRw3HCOxovD1nPR16hllrVImeFp5VBV9/twj66lJ2nU75DP8FPL0/Jp4jj79JhTfG+pFI2MD02kWJ+fA=="
1833 | },
1834 | "helmet-csp": {
1835 | "version": "2.9.2",
1836 | "resolved": "https://registry.npmjs.org/helmet-csp/-/helmet-csp-2.9.2.tgz",
1837 | "integrity": "sha512-Lt5WqNfbNjEJ6ysD4UNpVktSyjEKfU9LVJ1LaFmPfYseg/xPealPfgHhtqdAdjPDopp5zbg/VWCyp4cluMIckw==",
1838 | "requires": {
1839 | "bowser": "^2.6.1",
1840 | "camelize": "1.0.0",
1841 | "content-security-policy-builder": "2.1.0",
1842 | "dasherize": "2.0.0"
1843 | }
1844 | },
1845 | "hide-powered-by": {
1846 | "version": "1.1.0",
1847 | "resolved": "https://registry.npmjs.org/hide-powered-by/-/hide-powered-by-1.1.0.tgz",
1848 | "integrity": "sha512-Io1zA2yOA1YJslkr+AJlWSf2yWFkKjvkcL9Ni1XSUqnGLr/qRQe2UI3Cn/J9MsJht7yEVCe0SscY1HgVMujbgg=="
1849 | },
1850 | "hpkp": {
1851 | "version": "2.0.0",
1852 | "resolved": "https://registry.npmjs.org/hpkp/-/hpkp-2.0.0.tgz",
1853 | "integrity": "sha1-EOFCJk52IVpdMMROxD3mTe5tFnI="
1854 | },
1855 | "hpp": {
1856 | "version": "0.2.2",
1857 | "resolved": "https://registry.npmjs.org/hpp/-/hpp-0.2.2.tgz",
1858 | "integrity": "sha1-DsX3dHIEmnQ2HYW6K4jiRwpDVvg=",
1859 | "requires": {
1860 | "lodash": "^4.7.0",
1861 | "type-is": "^1.6.12"
1862 | }
1863 | },
1864 | "hsts": {
1865 | "version": "2.2.0",
1866 | "resolved": "https://registry.npmjs.org/hsts/-/hsts-2.2.0.tgz",
1867 | "integrity": "sha512-ToaTnQ2TbJkochoVcdXYm4HOCliNozlviNsg+X2XQLQvZNI/kCHR9rZxVYpJB3UPcHz80PgxRyWQ7PdU1r+VBQ==",
1868 | "requires": {
1869 | "depd": "2.0.0"
1870 | },
1871 | "dependencies": {
1872 | "depd": {
1873 | "version": "2.0.0",
1874 | "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
1875 | "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="
1876 | }
1877 | }
1878 | },
1879 | "http-errors": {
1880 | "version": "1.7.2",
1881 | "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz",
1882 | "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==",
1883 | "requires": {
1884 | "depd": "~1.1.2",
1885 | "inherits": "2.0.3",
1886 | "setprototypeof": "1.1.1",
1887 | "statuses": ">= 1.5.0 < 2",
1888 | "toidentifier": "1.0.0"
1889 | }
1890 | },
1891 | "http-signature": {
1892 | "version": "1.2.0",
1893 | "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
1894 | "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
1895 | "requires": {
1896 | "assert-plus": "^1.0.0",
1897 | "jsprim": "^1.2.2",
1898 | "sshpk": "^1.7.0"
1899 | }
1900 | },
1901 | "iconv-lite": {
1902 | "version": "0.4.24",
1903 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
1904 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
1905 | "requires": {
1906 | "safer-buffer": ">= 2.1.2 < 3"
1907 | }
1908 | },
1909 | "ienoopen": {
1910 | "version": "1.1.0",
1911 | "resolved": "https://registry.npmjs.org/ienoopen/-/ienoopen-1.1.0.tgz",
1912 | "integrity": "sha512-MFs36e/ca6ohEKtinTJ5VvAJ6oDRAYFdYXweUnGY9L9vcoqFOU4n2ZhmJ0C4z/cwGZ3YIQRSB3XZ1+ghZkY5NQ=="
1913 | },
1914 | "ignore-by-default": {
1915 | "version": "1.0.1",
1916 | "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz",
1917 | "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=",
1918 | "dev": true
1919 | },
1920 | "import-lazy": {
1921 | "version": "2.1.0",
1922 | "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz",
1923 | "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=",
1924 | "dev": true
1925 | },
1926 | "imurmurhash": {
1927 | "version": "0.1.4",
1928 | "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
1929 | "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=",
1930 | "dev": true
1931 | },
1932 | "inherits": {
1933 | "version": "2.0.3",
1934 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
1935 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
1936 | },
1937 | "ini": {
1938 | "version": "1.3.5",
1939 | "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
1940 | "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
1941 | "dev": true
1942 | },
1943 | "ipaddr.js": {
1944 | "version": "1.9.0",
1945 | "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz",
1946 | "integrity": "sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA=="
1947 | },
1948 | "is-accessor-descriptor": {
1949 | "version": "0.1.6",
1950 | "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
1951 | "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=",
1952 | "dev": true,
1953 | "requires": {
1954 | "kind-of": "^3.0.2"
1955 | },
1956 | "dependencies": {
1957 | "kind-of": {
1958 | "version": "3.2.2",
1959 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
1960 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
1961 | "dev": true,
1962 | "requires": {
1963 | "is-buffer": "^1.1.5"
1964 | }
1965 | }
1966 | }
1967 | },
1968 | "is-binary-path": {
1969 | "version": "1.0.1",
1970 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz",
1971 | "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=",
1972 | "dev": true,
1973 | "requires": {
1974 | "binary-extensions": "^1.0.0"
1975 | }
1976 | },
1977 | "is-buffer": {
1978 | "version": "1.1.6",
1979 | "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
1980 | "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
1981 | "dev": true
1982 | },
1983 | "is-ci": {
1984 | "version": "1.2.1",
1985 | "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.2.1.tgz",
1986 | "integrity": "sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==",
1987 | "dev": true,
1988 | "requires": {
1989 | "ci-info": "^1.5.0"
1990 | }
1991 | },
1992 | "is-data-descriptor": {
1993 | "version": "0.1.4",
1994 | "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
1995 | "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=",
1996 | "dev": true,
1997 | "requires": {
1998 | "kind-of": "^3.0.2"
1999 | },
2000 | "dependencies": {
2001 | "kind-of": {
2002 | "version": "3.2.2",
2003 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
2004 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
2005 | "dev": true,
2006 | "requires": {
2007 | "is-buffer": "^1.1.5"
2008 | }
2009 | }
2010 | }
2011 | },
2012 | "is-descriptor": {
2013 | "version": "0.1.6",
2014 | "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
2015 | "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
2016 | "dev": true,
2017 | "requires": {
2018 | "is-accessor-descriptor": "^0.1.6",
2019 | "is-data-descriptor": "^0.1.4",
2020 | "kind-of": "^5.0.0"
2021 | },
2022 | "dependencies": {
2023 | "kind-of": {
2024 | "version": "5.1.0",
2025 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
2026 | "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
2027 | "dev": true
2028 | }
2029 | }
2030 | },
2031 | "is-extendable": {
2032 | "version": "0.1.1",
2033 | "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
2034 | "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=",
2035 | "dev": true
2036 | },
2037 | "is-extglob": {
2038 | "version": "2.1.1",
2039 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
2040 | "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
2041 | "dev": true
2042 | },
2043 | "is-fullwidth-code-point": {
2044 | "version": "2.0.0",
2045 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
2046 | "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
2047 | "dev": true
2048 | },
2049 | "is-glob": {
2050 | "version": "4.0.1",
2051 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz",
2052 | "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
2053 | "dev": true,
2054 | "requires": {
2055 | "is-extglob": "^2.1.1"
2056 | }
2057 | },
2058 | "is-installed-globally": {
2059 | "version": "0.1.0",
2060 | "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.1.0.tgz",
2061 | "integrity": "sha1-Df2Y9akRFxbdU13aZJL2e/PSWoA=",
2062 | "dev": true,
2063 | "requires": {
2064 | "global-dirs": "^0.1.0",
2065 | "is-path-inside": "^1.0.0"
2066 | }
2067 | },
2068 | "is-npm": {
2069 | "version": "1.0.0",
2070 | "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-1.0.0.tgz",
2071 | "integrity": "sha1-8vtjpl5JBbQGyGBydloaTceTufQ=",
2072 | "dev": true
2073 | },
2074 | "is-number": {
2075 | "version": "3.0.0",
2076 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
2077 | "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
2078 | "dev": true,
2079 | "requires": {
2080 | "kind-of": "^3.0.2"
2081 | },
2082 | "dependencies": {
2083 | "kind-of": {
2084 | "version": "3.2.2",
2085 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
2086 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
2087 | "dev": true,
2088 | "requires": {
2089 | "is-buffer": "^1.1.5"
2090 | }
2091 | }
2092 | }
2093 | },
2094 | "is-obj": {
2095 | "version": "1.0.1",
2096 | "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz",
2097 | "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=",
2098 | "dev": true
2099 | },
2100 | "is-path-inside": {
2101 | "version": "1.0.1",
2102 | "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz",
2103 | "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=",
2104 | "dev": true,
2105 | "requires": {
2106 | "path-is-inside": "^1.0.1"
2107 | }
2108 | },
2109 | "is-plain-object": {
2110 | "version": "2.0.4",
2111 | "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
2112 | "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
2113 | "dev": true,
2114 | "requires": {
2115 | "isobject": "^3.0.1"
2116 | }
2117 | },
2118 | "is-redirect": {
2119 | "version": "1.0.0",
2120 | "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz",
2121 | "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=",
2122 | "dev": true
2123 | },
2124 | "is-retry-allowed": {
2125 | "version": "1.2.0",
2126 | "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz",
2127 | "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==",
2128 | "dev": true
2129 | },
2130 | "is-stream": {
2131 | "version": "1.1.0",
2132 | "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
2133 | "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=",
2134 | "dev": true
2135 | },
2136 | "is-typedarray": {
2137 | "version": "1.0.0",
2138 | "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
2139 | "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
2140 | },
2141 | "is-windows": {
2142 | "version": "1.0.2",
2143 | "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
2144 | "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==",
2145 | "dev": true
2146 | },
2147 | "isarray": {
2148 | "version": "1.0.0",
2149 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
2150 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
2151 | "dev": true
2152 | },
2153 | "isexe": {
2154 | "version": "2.0.0",
2155 | "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
2156 | "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
2157 | "dev": true
2158 | },
2159 | "isobject": {
2160 | "version": "3.0.1",
2161 | "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
2162 | "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
2163 | "dev": true
2164 | },
2165 | "isstream": {
2166 | "version": "0.1.2",
2167 | "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
2168 | "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
2169 | },
2170 | "jsbn": {
2171 | "version": "0.1.1",
2172 | "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
2173 | "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM="
2174 | },
2175 | "json-schema": {
2176 | "version": "0.2.3",
2177 | "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
2178 | "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM="
2179 | },
2180 | "json-schema-traverse": {
2181 | "version": "0.4.1",
2182 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
2183 | "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
2184 | },
2185 | "json-stringify-safe": {
2186 | "version": "5.0.1",
2187 | "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
2188 | "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
2189 | },
2190 | "jsonwebtoken": {
2191 | "version": "8.5.1",
2192 | "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz",
2193 | "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==",
2194 | "requires": {
2195 | "jws": "^3.2.2",
2196 | "lodash.includes": "^4.3.0",
2197 | "lodash.isboolean": "^3.0.3",
2198 | "lodash.isinteger": "^4.0.4",
2199 | "lodash.isnumber": "^3.0.3",
2200 | "lodash.isplainobject": "^4.0.6",
2201 | "lodash.isstring": "^4.0.1",
2202 | "lodash.once": "^4.0.0",
2203 | "ms": "^2.1.1",
2204 | "semver": "^5.6.0"
2205 | },
2206 | "dependencies": {
2207 | "ms": {
2208 | "version": "2.1.2",
2209 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
2210 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
2211 | }
2212 | }
2213 | },
2214 | "jsprim": {
2215 | "version": "1.4.1",
2216 | "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
2217 | "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
2218 | "requires": {
2219 | "assert-plus": "1.0.0",
2220 | "extsprintf": "1.3.0",
2221 | "json-schema": "0.2.3",
2222 | "verror": "1.10.0"
2223 | }
2224 | },
2225 | "jwa": {
2226 | "version": "1.4.1",
2227 | "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz",
2228 | "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==",
2229 | "requires": {
2230 | "buffer-equal-constant-time": "1.0.1",
2231 | "ecdsa-sig-formatter": "1.0.11",
2232 | "safe-buffer": "^5.0.1"
2233 | }
2234 | },
2235 | "jws": {
2236 | "version": "3.2.2",
2237 | "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
2238 | "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
2239 | "requires": {
2240 | "jwa": "^1.4.1",
2241 | "safe-buffer": "^5.0.1"
2242 | }
2243 | },
2244 | "kareem": {
2245 | "version": "2.3.1",
2246 | "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.3.1.tgz",
2247 | "integrity": "sha512-l3hLhffs9zqoDe8zjmb/mAN4B8VT3L56EUvKNqLFVs9YlFA+zx7ke1DO8STAdDyYNkeSo1nKmjuvQeI12So8Xw=="
2248 | },
2249 | "kind-of": {
2250 | "version": "6.0.2",
2251 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
2252 | "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
2253 | "dev": true
2254 | },
2255 | "latest-version": {
2256 | "version": "3.1.0",
2257 | "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-3.1.0.tgz",
2258 | "integrity": "sha1-ogU4P+oyKzO1rjsYq+4NwvNW7hU=",
2259 | "dev": true,
2260 | "requires": {
2261 | "package-json": "^4.0.0"
2262 | }
2263 | },
2264 | "lodash": {
2265 | "version": "4.17.15",
2266 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
2267 | "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A=="
2268 | },
2269 | "lodash.includes": {
2270 | "version": "4.3.0",
2271 | "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
2272 | "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8="
2273 | },
2274 | "lodash.isboolean": {
2275 | "version": "3.0.3",
2276 | "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
2277 | "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY="
2278 | },
2279 | "lodash.isinteger": {
2280 | "version": "4.0.4",
2281 | "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
2282 | "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M="
2283 | },
2284 | "lodash.isnumber": {
2285 | "version": "3.0.3",
2286 | "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
2287 | "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w="
2288 | },
2289 | "lodash.isplainobject": {
2290 | "version": "4.0.6",
2291 | "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
2292 | "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs="
2293 | },
2294 | "lodash.isstring": {
2295 | "version": "4.0.1",
2296 | "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
2297 | "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE="
2298 | },
2299 | "lodash.once": {
2300 | "version": "4.1.1",
2301 | "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
2302 | "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w="
2303 | },
2304 | "lowercase-keys": {
2305 | "version": "1.0.1",
2306 | "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz",
2307 | "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==",
2308 | "dev": true
2309 | },
2310 | "lru-cache": {
2311 | "version": "4.1.5",
2312 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz",
2313 | "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==",
2314 | "dev": true,
2315 | "requires": {
2316 | "pseudomap": "^1.0.2",
2317 | "yallist": "^2.1.2"
2318 | }
2319 | },
2320 | "make-dir": {
2321 | "version": "1.3.0",
2322 | "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz",
2323 | "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==",
2324 | "dev": true,
2325 | "requires": {
2326 | "pify": "^3.0.0"
2327 | }
2328 | },
2329 | "map-cache": {
2330 | "version": "0.2.2",
2331 | "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
2332 | "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=",
2333 | "dev": true
2334 | },
2335 | "map-visit": {
2336 | "version": "1.0.0",
2337 | "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz",
2338 | "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=",
2339 | "dev": true,
2340 | "requires": {
2341 | "object-visit": "^1.0.0"
2342 | }
2343 | },
2344 | "media-typer": {
2345 | "version": "0.3.0",
2346 | "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
2347 | "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
2348 | },
2349 | "merge-descriptors": {
2350 | "version": "1.0.1",
2351 | "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
2352 | "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
2353 | },
2354 | "methods": {
2355 | "version": "1.1.2",
2356 | "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
2357 | "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
2358 | },
2359 | "micromatch": {
2360 | "version": "3.1.10",
2361 | "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
2362 | "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
2363 | "dev": true,
2364 | "requires": {
2365 | "arr-diff": "^4.0.0",
2366 | "array-unique": "^0.3.2",
2367 | "braces": "^2.3.1",
2368 | "define-property": "^2.0.2",
2369 | "extend-shallow": "^3.0.2",
2370 | "extglob": "^2.0.4",
2371 | "fragment-cache": "^0.2.1",
2372 | "kind-of": "^6.0.2",
2373 | "nanomatch": "^1.2.9",
2374 | "object.pick": "^1.3.0",
2375 | "regex-not": "^1.0.0",
2376 | "snapdragon": "^0.8.1",
2377 | "to-regex": "^3.0.2"
2378 | }
2379 | },
2380 | "mime": {
2381 | "version": "1.6.0",
2382 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
2383 | "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
2384 | },
2385 | "mime-db": {
2386 | "version": "1.40.0",
2387 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz",
2388 | "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA=="
2389 | },
2390 | "mime-types": {
2391 | "version": "2.1.24",
2392 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz",
2393 | "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==",
2394 | "requires": {
2395 | "mime-db": "1.40.0"
2396 | }
2397 | },
2398 | "minimatch": {
2399 | "version": "3.0.4",
2400 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
2401 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
2402 | "dev": true,
2403 | "requires": {
2404 | "brace-expansion": "^1.1.7"
2405 | }
2406 | },
2407 | "minimist": {
2408 | "version": "1.2.0",
2409 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
2410 | "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
2411 | "dev": true
2412 | },
2413 | "mixin-deep": {
2414 | "version": "1.3.2",
2415 | "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz",
2416 | "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==",
2417 | "dev": true,
2418 | "requires": {
2419 | "for-in": "^1.0.2",
2420 | "is-extendable": "^1.0.1"
2421 | },
2422 | "dependencies": {
2423 | "is-extendable": {
2424 | "version": "1.0.1",
2425 | "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
2426 | "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
2427 | "dev": true,
2428 | "requires": {
2429 | "is-plain-object": "^2.0.4"
2430 | }
2431 | }
2432 | }
2433 | },
2434 | "mongodb": {
2435 | "version": "3.3.2",
2436 | "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.3.2.tgz",
2437 | "integrity": "sha512-fqJt3iywelk4yKu/lfwQg163Bjpo5zDKhXiohycvon4iQHbrfflSAz9AIlRE6496Pm/dQKQK5bMigdVo2s6gBg==",
2438 | "requires": {
2439 | "bson": "^1.1.1",
2440 | "require_optional": "^1.0.1",
2441 | "safe-buffer": "^5.1.2"
2442 | }
2443 | },
2444 | "mongoose": {
2445 | "version": "5.7.5",
2446 | "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.7.5.tgz",
2447 | "integrity": "sha512-BZ4FxtnbTurc/wcm/hLltLdI4IDxo4nsE0D9q58YymTdZwreNzwO62CcjVtaHhmr8HmJtOInp2W/T12FZaMf8g==",
2448 | "requires": {
2449 | "bson": "~1.1.1",
2450 | "kareem": "2.3.1",
2451 | "mongodb": "3.3.2",
2452 | "mongoose-legacy-pluralize": "1.0.2",
2453 | "mpath": "0.6.0",
2454 | "mquery": "3.2.2",
2455 | "ms": "2.1.2",
2456 | "regexp-clone": "1.0.0",
2457 | "safe-buffer": "5.1.2",
2458 | "sift": "7.0.1",
2459 | "sliced": "1.0.1"
2460 | },
2461 | "dependencies": {
2462 | "ms": {
2463 | "version": "2.1.2",
2464 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
2465 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
2466 | }
2467 | }
2468 | },
2469 | "mongoose-legacy-pluralize": {
2470 | "version": "1.0.2",
2471 | "resolved": "https://registry.npmjs.org/mongoose-legacy-pluralize/-/mongoose-legacy-pluralize-1.0.2.tgz",
2472 | "integrity": "sha512-Yo/7qQU4/EyIS8YDFSeenIvXxZN+ld7YdV9LqFVQJzTLye8unujAWPZ4NWKfFA+RNjh+wvTWKY9Z3E5XM6ZZiQ=="
2473 | },
2474 | "morgan": {
2475 | "version": "1.9.1",
2476 | "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.9.1.tgz",
2477 | "integrity": "sha512-HQStPIV4y3afTiCYVxirakhlCfGkI161c76kKFca7Fk1JusM//Qeo1ej2XaMniiNeaZklMVrh3vTtIzpzwbpmA==",
2478 | "requires": {
2479 | "basic-auth": "~2.0.0",
2480 | "debug": "2.6.9",
2481 | "depd": "~1.1.2",
2482 | "on-finished": "~2.3.0",
2483 | "on-headers": "~1.0.1"
2484 | }
2485 | },
2486 | "mpath": {
2487 | "version": "0.6.0",
2488 | "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.6.0.tgz",
2489 | "integrity": "sha512-i75qh79MJ5Xo/sbhxrDrPSEG0H/mr1kcZXJ8dH6URU5jD/knFxCVqVC/gVSW7GIXL/9hHWlT9haLbCXWOll3qw=="
2490 | },
2491 | "mquery": {
2492 | "version": "3.2.2",
2493 | "resolved": "https://registry.npmjs.org/mquery/-/mquery-3.2.2.tgz",
2494 | "integrity": "sha512-XB52992COp0KP230I3qloVUbkLUxJIu328HBP2t2EsxSFtf4W1HPSOBWOXf1bqxK4Xbb66lfMJ+Bpfd9/yZE1Q==",
2495 | "requires": {
2496 | "bluebird": "3.5.1",
2497 | "debug": "3.1.0",
2498 | "regexp-clone": "^1.0.0",
2499 | "safe-buffer": "5.1.2",
2500 | "sliced": "1.0.1"
2501 | },
2502 | "dependencies": {
2503 | "debug": {
2504 | "version": "3.1.0",
2505 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
2506 | "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
2507 | "requires": {
2508 | "ms": "2.0.0"
2509 | }
2510 | }
2511 | }
2512 | },
2513 | "ms": {
2514 | "version": "2.0.0",
2515 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
2516 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
2517 | },
2518 | "nan": {
2519 | "version": "2.14.0",
2520 | "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz",
2521 | "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==",
2522 | "dev": true,
2523 | "optional": true
2524 | },
2525 | "nanomatch": {
2526 | "version": "1.2.13",
2527 | "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
2528 | "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==",
2529 | "dev": true,
2530 | "requires": {
2531 | "arr-diff": "^4.0.0",
2532 | "array-unique": "^0.3.2",
2533 | "define-property": "^2.0.2",
2534 | "extend-shallow": "^3.0.2",
2535 | "fragment-cache": "^0.2.1",
2536 | "is-windows": "^1.0.2",
2537 | "kind-of": "^6.0.2",
2538 | "object.pick": "^1.3.0",
2539 | "regex-not": "^1.0.0",
2540 | "snapdragon": "^0.8.1",
2541 | "to-regex": "^3.0.1"
2542 | }
2543 | },
2544 | "negotiator": {
2545 | "version": "0.6.2",
2546 | "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
2547 | "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw=="
2548 | },
2549 | "nocache": {
2550 | "version": "2.1.0",
2551 | "resolved": "https://registry.npmjs.org/nocache/-/nocache-2.1.0.tgz",
2552 | "integrity": "sha512-0L9FvHG3nfnnmaEQPjT9xhfN4ISk0A8/2j4M37Np4mcDesJjHgEUfgPhdCyZuFI954tjokaIj/A3NdpFNdEh4Q=="
2553 | },
2554 | "node-geocoder": {
2555 | "version": "3.24.0",
2556 | "resolved": "https://registry.npmjs.org/node-geocoder/-/node-geocoder-3.24.0.tgz",
2557 | "integrity": "sha512-2k+NfKCcF+HhElT2TtfTGwCsBaxTWy3dYhLDFB4dpPIa20kMPGZQkJR6Qrow4zTKP5DQMIY4UwRsDWo4mkAumQ==",
2558 | "requires": {
2559 | "bluebird": "^3.5.2",
2560 | "request": "^2.88.0",
2561 | "request-promise": "^4.2.2"
2562 | },
2563 | "dependencies": {
2564 | "bluebird": {
2565 | "version": "3.5.5",
2566 | "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.5.tgz",
2567 | "integrity": "sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w=="
2568 | }
2569 | }
2570 | },
2571 | "nodemailer": {
2572 | "version": "6.3.0",
2573 | "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-6.3.0.tgz",
2574 | "integrity": "sha512-TEHBNBPHv7Ie/0o3HXnb7xrPSSQmH1dXwQKRaMKDBGt/ZN54lvDVujP6hKkO/vjkIYL9rK8kHSG11+G42Nhxuw=="
2575 | },
2576 | "nodemon": {
2577 | "version": "1.19.2",
2578 | "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-1.19.2.tgz",
2579 | "integrity": "sha512-hRLYaw5Ihyw9zK7NF+9EUzVyS6Cvgc14yh8CAYr38tPxJa6UrOxwAQ351GwrgoanHCF0FalQFn6w5eoX/LGdJw==",
2580 | "dev": true,
2581 | "requires": {
2582 | "chokidar": "^2.1.5",
2583 | "debug": "^3.1.0",
2584 | "ignore-by-default": "^1.0.1",
2585 | "minimatch": "^3.0.4",
2586 | "pstree.remy": "^1.1.6",
2587 | "semver": "^5.5.0",
2588 | "supports-color": "^5.2.0",
2589 | "touch": "^3.1.0",
2590 | "undefsafe": "^2.0.2",
2591 | "update-notifier": "^2.5.0"
2592 | },
2593 | "dependencies": {
2594 | "debug": {
2595 | "version": "3.2.6",
2596 | "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
2597 | "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
2598 | "dev": true,
2599 | "requires": {
2600 | "ms": "^2.1.1"
2601 | }
2602 | },
2603 | "ms": {
2604 | "version": "2.1.2",
2605 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
2606 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
2607 | "dev": true
2608 | }
2609 | }
2610 | },
2611 | "nopt": {
2612 | "version": "1.0.10",
2613 | "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz",
2614 | "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=",
2615 | "dev": true,
2616 | "requires": {
2617 | "abbrev": "1"
2618 | }
2619 | },
2620 | "normalize-path": {
2621 | "version": "3.0.0",
2622 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
2623 | "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
2624 | "dev": true
2625 | },
2626 | "npm-run-path": {
2627 | "version": "2.0.2",
2628 | "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
2629 | "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=",
2630 | "dev": true,
2631 | "requires": {
2632 | "path-key": "^2.0.0"
2633 | }
2634 | },
2635 | "oauth-sign": {
2636 | "version": "0.9.0",
2637 | "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
2638 | "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ=="
2639 | },
2640 | "object-assign": {
2641 | "version": "4.1.1",
2642 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
2643 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
2644 | },
2645 | "object-copy": {
2646 | "version": "0.1.0",
2647 | "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz",
2648 | "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=",
2649 | "dev": true,
2650 | "requires": {
2651 | "copy-descriptor": "^0.1.0",
2652 | "define-property": "^0.2.5",
2653 | "kind-of": "^3.0.3"
2654 | },
2655 | "dependencies": {
2656 | "define-property": {
2657 | "version": "0.2.5",
2658 | "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
2659 | "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
2660 | "dev": true,
2661 | "requires": {
2662 | "is-descriptor": "^0.1.0"
2663 | }
2664 | },
2665 | "kind-of": {
2666 | "version": "3.2.2",
2667 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
2668 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
2669 | "dev": true,
2670 | "requires": {
2671 | "is-buffer": "^1.1.5"
2672 | }
2673 | }
2674 | }
2675 | },
2676 | "object-visit": {
2677 | "version": "1.0.1",
2678 | "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz",
2679 | "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=",
2680 | "dev": true,
2681 | "requires": {
2682 | "isobject": "^3.0.0"
2683 | }
2684 | },
2685 | "object.pick": {
2686 | "version": "1.3.0",
2687 | "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz",
2688 | "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=",
2689 | "dev": true,
2690 | "requires": {
2691 | "isobject": "^3.0.1"
2692 | }
2693 | },
2694 | "on-finished": {
2695 | "version": "2.3.0",
2696 | "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
2697 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
2698 | "requires": {
2699 | "ee-first": "1.1.1"
2700 | }
2701 | },
2702 | "on-headers": {
2703 | "version": "1.0.2",
2704 | "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz",
2705 | "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA=="
2706 | },
2707 | "p-finally": {
2708 | "version": "1.0.0",
2709 | "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
2710 | "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=",
2711 | "dev": true
2712 | },
2713 | "package-json": {
2714 | "version": "4.0.1",
2715 | "resolved": "https://registry.npmjs.org/package-json/-/package-json-4.0.1.tgz",
2716 | "integrity": "sha1-iGmgQBJTZhxMTKPabCEh7VVfXu0=",
2717 | "dev": true,
2718 | "requires": {
2719 | "got": "^6.7.1",
2720 | "registry-auth-token": "^3.0.1",
2721 | "registry-url": "^3.0.3",
2722 | "semver": "^5.1.0"
2723 | }
2724 | },
2725 | "parseurl": {
2726 | "version": "1.3.3",
2727 | "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
2728 | "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="
2729 | },
2730 | "pascalcase": {
2731 | "version": "0.1.1",
2732 | "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz",
2733 | "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=",
2734 | "dev": true
2735 | },
2736 | "path-dirname": {
2737 | "version": "1.0.2",
2738 | "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz",
2739 | "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=",
2740 | "dev": true
2741 | },
2742 | "path-is-absolute": {
2743 | "version": "1.0.1",
2744 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
2745 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
2746 | "dev": true
2747 | },
2748 | "path-is-inside": {
2749 | "version": "1.0.2",
2750 | "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz",
2751 | "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=",
2752 | "dev": true
2753 | },
2754 | "path-key": {
2755 | "version": "2.0.1",
2756 | "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
2757 | "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=",
2758 | "dev": true
2759 | },
2760 | "path-to-regexp": {
2761 | "version": "0.1.7",
2762 | "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
2763 | "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
2764 | },
2765 | "performance-now": {
2766 | "version": "2.1.0",
2767 | "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
2768 | "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
2769 | },
2770 | "pify": {
2771 | "version": "3.0.0",
2772 | "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz",
2773 | "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=",
2774 | "dev": true
2775 | },
2776 | "posix-character-classes": {
2777 | "version": "0.1.1",
2778 | "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz",
2779 | "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=",
2780 | "dev": true
2781 | },
2782 | "prepend-http": {
2783 | "version": "1.0.4",
2784 | "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz",
2785 | "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=",
2786 | "dev": true
2787 | },
2788 | "process-nextick-args": {
2789 | "version": "2.0.1",
2790 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
2791 | "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
2792 | "dev": true
2793 | },
2794 | "proxy-addr": {
2795 | "version": "2.0.5",
2796 | "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.5.tgz",
2797 | "integrity": "sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ==",
2798 | "requires": {
2799 | "forwarded": "~0.1.2",
2800 | "ipaddr.js": "1.9.0"
2801 | }
2802 | },
2803 | "pseudomap": {
2804 | "version": "1.0.2",
2805 | "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
2806 | "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=",
2807 | "dev": true
2808 | },
2809 | "psl": {
2810 | "version": "1.4.0",
2811 | "resolved": "https://registry.npmjs.org/psl/-/psl-1.4.0.tgz",
2812 | "integrity": "sha512-HZzqCGPecFLyoRj5HLfuDSKYTJkAfB5thKBIkRHtGjWwY7p1dAyveIbXIq4tO0KYfDF2tHqPUgY9SDnGm00uFw=="
2813 | },
2814 | "pstree.remy": {
2815 | "version": "1.1.7",
2816 | "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.7.tgz",
2817 | "integrity": "sha512-xsMgrUwRpuGskEzBFkH8NmTimbZ5PcPup0LA8JJkHIm2IMUbQcpo3yeLNWVrufEYjh8YwtSVh0xz6UeWc5Oh5A==",
2818 | "dev": true
2819 | },
2820 | "punycode": {
2821 | "version": "2.1.1",
2822 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
2823 | "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
2824 | },
2825 | "qs": {
2826 | "version": "6.7.0",
2827 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
2828 | "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ=="
2829 | },
2830 | "range-parser": {
2831 | "version": "1.2.1",
2832 | "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
2833 | "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="
2834 | },
2835 | "raw-body": {
2836 | "version": "2.4.0",
2837 | "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz",
2838 | "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==",
2839 | "requires": {
2840 | "bytes": "3.1.0",
2841 | "http-errors": "1.7.2",
2842 | "iconv-lite": "0.4.24",
2843 | "unpipe": "1.0.0"
2844 | }
2845 | },
2846 | "rc": {
2847 | "version": "1.2.8",
2848 | "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
2849 | "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
2850 | "dev": true,
2851 | "requires": {
2852 | "deep-extend": "^0.6.0",
2853 | "ini": "~1.3.0",
2854 | "minimist": "^1.2.0",
2855 | "strip-json-comments": "~2.0.1"
2856 | }
2857 | },
2858 | "readable-stream": {
2859 | "version": "2.3.6",
2860 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
2861 | "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
2862 | "dev": true,
2863 | "requires": {
2864 | "core-util-is": "~1.0.0",
2865 | "inherits": "~2.0.3",
2866 | "isarray": "~1.0.0",
2867 | "process-nextick-args": "~2.0.0",
2868 | "safe-buffer": "~5.1.1",
2869 | "string_decoder": "~1.1.1",
2870 | "util-deprecate": "~1.0.1"
2871 | }
2872 | },
2873 | "readdirp": {
2874 | "version": "2.2.1",
2875 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz",
2876 | "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==",
2877 | "dev": true,
2878 | "requires": {
2879 | "graceful-fs": "^4.1.11",
2880 | "micromatch": "^3.1.10",
2881 | "readable-stream": "^2.0.2"
2882 | }
2883 | },
2884 | "referrer-policy": {
2885 | "version": "1.2.0",
2886 | "resolved": "https://registry.npmjs.org/referrer-policy/-/referrer-policy-1.2.0.tgz",
2887 | "integrity": "sha512-LgQJIuS6nAy1Jd88DCQRemyE3mS+ispwlqMk3b0yjZ257fI1v9c+/p6SD5gP5FGyXUIgrNOAfmyioHwZtYv2VA=="
2888 | },
2889 | "regex-not": {
2890 | "version": "1.0.2",
2891 | "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz",
2892 | "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==",
2893 | "dev": true,
2894 | "requires": {
2895 | "extend-shallow": "^3.0.2",
2896 | "safe-regex": "^1.1.0"
2897 | }
2898 | },
2899 | "regexp-clone": {
2900 | "version": "1.0.0",
2901 | "resolved": "https://registry.npmjs.org/regexp-clone/-/regexp-clone-1.0.0.tgz",
2902 | "integrity": "sha512-TuAasHQNamyyJ2hb97IuBEif4qBHGjPHBS64sZwytpLEqtBQ1gPJTnOaQ6qmpET16cK14kkjbazl6+p0RRv0yw=="
2903 | },
2904 | "registry-auth-token": {
2905 | "version": "3.4.0",
2906 | "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.4.0.tgz",
2907 | "integrity": "sha512-4LM6Fw8eBQdwMYcES4yTnn2TqIasbXuwDx3um+QRs7S55aMKCBKBxvPXl2RiUjHwuJLTyYfxSpmfSAjQpcuP+A==",
2908 | "dev": true,
2909 | "requires": {
2910 | "rc": "^1.1.6",
2911 | "safe-buffer": "^5.0.1"
2912 | }
2913 | },
2914 | "registry-url": {
2915 | "version": "3.1.0",
2916 | "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz",
2917 | "integrity": "sha1-PU74cPc93h138M+aOBQyRE4XSUI=",
2918 | "dev": true,
2919 | "requires": {
2920 | "rc": "^1.0.1"
2921 | }
2922 | },
2923 | "remove-trailing-separator": {
2924 | "version": "1.1.0",
2925 | "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
2926 | "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=",
2927 | "dev": true
2928 | },
2929 | "repeat-element": {
2930 | "version": "1.1.3",
2931 | "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz",
2932 | "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==",
2933 | "dev": true
2934 | },
2935 | "repeat-string": {
2936 | "version": "1.6.1",
2937 | "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
2938 | "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=",
2939 | "dev": true
2940 | },
2941 | "request": {
2942 | "version": "2.88.0",
2943 | "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz",
2944 | "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==",
2945 | "requires": {
2946 | "aws-sign2": "~0.7.0",
2947 | "aws4": "^1.8.0",
2948 | "caseless": "~0.12.0",
2949 | "combined-stream": "~1.0.6",
2950 | "extend": "~3.0.2",
2951 | "forever-agent": "~0.6.1",
2952 | "form-data": "~2.3.2",
2953 | "har-validator": "~5.1.0",
2954 | "http-signature": "~1.2.0",
2955 | "is-typedarray": "~1.0.0",
2956 | "isstream": "~0.1.2",
2957 | "json-stringify-safe": "~5.0.1",
2958 | "mime-types": "~2.1.19",
2959 | "oauth-sign": "~0.9.0",
2960 | "performance-now": "^2.1.0",
2961 | "qs": "~6.5.2",
2962 | "safe-buffer": "^5.1.2",
2963 | "tough-cookie": "~2.4.3",
2964 | "tunnel-agent": "^0.6.0",
2965 | "uuid": "^3.3.2"
2966 | },
2967 | "dependencies": {
2968 | "qs": {
2969 | "version": "6.5.2",
2970 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
2971 | "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA=="
2972 | }
2973 | }
2974 | },
2975 | "request-promise": {
2976 | "version": "4.2.4",
2977 | "resolved": "https://registry.npmjs.org/request-promise/-/request-promise-4.2.4.tgz",
2978 | "integrity": "sha512-8wgMrvE546PzbR5WbYxUQogUnUDfM0S7QIFZMID+J73vdFARkFy+HElj4T+MWYhpXwlLp0EQ8Zoj8xUA0he4Vg==",
2979 | "requires": {
2980 | "bluebird": "^3.5.0",
2981 | "request-promise-core": "1.1.2",
2982 | "stealthy-require": "^1.1.1",
2983 | "tough-cookie": "^2.3.3"
2984 | }
2985 | },
2986 | "request-promise-core": {
2987 | "version": "1.1.2",
2988 | "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.2.tgz",
2989 | "integrity": "sha512-UHYyq1MO8GsefGEt7EprS8UrXsm1TxEvFUX1IMTuSLU2Rh7fTIdFtl8xD7JiEYiWU2dl+NYAjCTksTehQUxPag==",
2990 | "requires": {
2991 | "lodash": "^4.17.11"
2992 | }
2993 | },
2994 | "require_optional": {
2995 | "version": "1.0.1",
2996 | "resolved": "https://registry.npmjs.org/require_optional/-/require_optional-1.0.1.tgz",
2997 | "integrity": "sha512-qhM/y57enGWHAe3v/NcwML6a3/vfESLe/sGM2dII+gEO0BpKRUkWZow/tyloNqJyN6kXSl3RyyM8Ll5D/sJP8g==",
2998 | "requires": {
2999 | "resolve-from": "^2.0.0",
3000 | "semver": "^5.1.0"
3001 | }
3002 | },
3003 | "resolve-from": {
3004 | "version": "2.0.0",
3005 | "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz",
3006 | "integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c="
3007 | },
3008 | "resolve-url": {
3009 | "version": "0.2.1",
3010 | "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
3011 | "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=",
3012 | "dev": true
3013 | },
3014 | "ret": {
3015 | "version": "0.1.15",
3016 | "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz",
3017 | "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==",
3018 | "dev": true
3019 | },
3020 | "safe-buffer": {
3021 | "version": "5.1.2",
3022 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
3023 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
3024 | },
3025 | "safe-regex": {
3026 | "version": "1.1.0",
3027 | "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz",
3028 | "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=",
3029 | "dev": true,
3030 | "requires": {
3031 | "ret": "~0.1.10"
3032 | }
3033 | },
3034 | "safer-buffer": {
3035 | "version": "2.1.2",
3036 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
3037 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
3038 | },
3039 | "semver": {
3040 | "version": "5.7.1",
3041 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
3042 | "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
3043 | },
3044 | "semver-diff": {
3045 | "version": "2.1.0",
3046 | "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-2.1.0.tgz",
3047 | "integrity": "sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY=",
3048 | "dev": true,
3049 | "requires": {
3050 | "semver": "^5.0.3"
3051 | }
3052 | },
3053 | "send": {
3054 | "version": "0.17.1",
3055 | "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz",
3056 | "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==",
3057 | "requires": {
3058 | "debug": "2.6.9",
3059 | "depd": "~1.1.2",
3060 | "destroy": "~1.0.4",
3061 | "encodeurl": "~1.0.2",
3062 | "escape-html": "~1.0.3",
3063 | "etag": "~1.8.1",
3064 | "fresh": "0.5.2",
3065 | "http-errors": "~1.7.2",
3066 | "mime": "1.6.0",
3067 | "ms": "2.1.1",
3068 | "on-finished": "~2.3.0",
3069 | "range-parser": "~1.2.1",
3070 | "statuses": "~1.5.0"
3071 | },
3072 | "dependencies": {
3073 | "ms": {
3074 | "version": "2.1.1",
3075 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
3076 | "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
3077 | }
3078 | }
3079 | },
3080 | "serve-static": {
3081 | "version": "1.14.1",
3082 | "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz",
3083 | "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==",
3084 | "requires": {
3085 | "encodeurl": "~1.0.2",
3086 | "escape-html": "~1.0.3",
3087 | "parseurl": "~1.3.3",
3088 | "send": "0.17.1"
3089 | }
3090 | },
3091 | "set-value": {
3092 | "version": "2.0.1",
3093 | "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz",
3094 | "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==",
3095 | "dev": true,
3096 | "requires": {
3097 | "extend-shallow": "^2.0.1",
3098 | "is-extendable": "^0.1.1",
3099 | "is-plain-object": "^2.0.3",
3100 | "split-string": "^3.0.1"
3101 | },
3102 | "dependencies": {
3103 | "extend-shallow": {
3104 | "version": "2.0.1",
3105 | "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
3106 | "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
3107 | "dev": true,
3108 | "requires": {
3109 | "is-extendable": "^0.1.0"
3110 | }
3111 | }
3112 | }
3113 | },
3114 | "setprototypeof": {
3115 | "version": "1.1.1",
3116 | "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
3117 | "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw=="
3118 | },
3119 | "shebang-command": {
3120 | "version": "1.2.0",
3121 | "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
3122 | "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
3123 | "dev": true,
3124 | "requires": {
3125 | "shebang-regex": "^1.0.0"
3126 | }
3127 | },
3128 | "shebang-regex": {
3129 | "version": "1.0.0",
3130 | "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
3131 | "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=",
3132 | "dev": true
3133 | },
3134 | "sift": {
3135 | "version": "7.0.1",
3136 | "resolved": "https://registry.npmjs.org/sift/-/sift-7.0.1.tgz",
3137 | "integrity": "sha512-oqD7PMJ+uO6jV9EQCl0LrRw1OwsiPsiFQR5AR30heR+4Dl7jBBbDLnNvWiak20tzZlSE1H7RB30SX/1j/YYT7g=="
3138 | },
3139 | "signal-exit": {
3140 | "version": "3.0.2",
3141 | "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
3142 | "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
3143 | "dev": true
3144 | },
3145 | "sliced": {
3146 | "version": "1.0.1",
3147 | "resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz",
3148 | "integrity": "sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E="
3149 | },
3150 | "slugify": {
3151 | "version": "1.3.5",
3152 | "resolved": "https://registry.npmjs.org/slugify/-/slugify-1.3.5.tgz",
3153 | "integrity": "sha512-5VCnH7aS13b0UqWOs7Ef3E5rkhFe8Od+cp7wybFv5mv/sYSRkucZlJX0bamAJky7b2TTtGvrJBWVdpdEicsSrA=="
3154 | },
3155 | "snapdragon": {
3156 | "version": "0.8.2",
3157 | "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
3158 | "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==",
3159 | "dev": true,
3160 | "requires": {
3161 | "base": "^0.11.1",
3162 | "debug": "^2.2.0",
3163 | "define-property": "^0.2.5",
3164 | "extend-shallow": "^2.0.1",
3165 | "map-cache": "^0.2.2",
3166 | "source-map": "^0.5.6",
3167 | "source-map-resolve": "^0.5.0",
3168 | "use": "^3.1.0"
3169 | },
3170 | "dependencies": {
3171 | "define-property": {
3172 | "version": "0.2.5",
3173 | "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
3174 | "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
3175 | "dev": true,
3176 | "requires": {
3177 | "is-descriptor": "^0.1.0"
3178 | }
3179 | },
3180 | "extend-shallow": {
3181 | "version": "2.0.1",
3182 | "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
3183 | "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
3184 | "dev": true,
3185 | "requires": {
3186 | "is-extendable": "^0.1.0"
3187 | }
3188 | }
3189 | }
3190 | },
3191 | "snapdragon-node": {
3192 | "version": "2.1.1",
3193 | "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz",
3194 | "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==",
3195 | "dev": true,
3196 | "requires": {
3197 | "define-property": "^1.0.0",
3198 | "isobject": "^3.0.0",
3199 | "snapdragon-util": "^3.0.1"
3200 | },
3201 | "dependencies": {
3202 | "define-property": {
3203 | "version": "1.0.0",
3204 | "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
3205 | "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
3206 | "dev": true,
3207 | "requires": {
3208 | "is-descriptor": "^1.0.0"
3209 | }
3210 | },
3211 | "is-accessor-descriptor": {
3212 | "version": "1.0.0",
3213 | "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
3214 | "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
3215 | "dev": true,
3216 | "requires": {
3217 | "kind-of": "^6.0.0"
3218 | }
3219 | },
3220 | "is-data-descriptor": {
3221 | "version": "1.0.0",
3222 | "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
3223 | "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
3224 | "dev": true,
3225 | "requires": {
3226 | "kind-of": "^6.0.0"
3227 | }
3228 | },
3229 | "is-descriptor": {
3230 | "version": "1.0.2",
3231 | "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
3232 | "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
3233 | "dev": true,
3234 | "requires": {
3235 | "is-accessor-descriptor": "^1.0.0",
3236 | "is-data-descriptor": "^1.0.0",
3237 | "kind-of": "^6.0.2"
3238 | }
3239 | }
3240 | }
3241 | },
3242 | "snapdragon-util": {
3243 | "version": "3.0.1",
3244 | "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz",
3245 | "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==",
3246 | "dev": true,
3247 | "requires": {
3248 | "kind-of": "^3.2.0"
3249 | },
3250 | "dependencies": {
3251 | "kind-of": {
3252 | "version": "3.2.2",
3253 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
3254 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
3255 | "dev": true,
3256 | "requires": {
3257 | "is-buffer": "^1.1.5"
3258 | }
3259 | }
3260 | }
3261 | },
3262 | "source-map": {
3263 | "version": "0.5.7",
3264 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
3265 | "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
3266 | "dev": true
3267 | },
3268 | "source-map-resolve": {
3269 | "version": "0.5.2",
3270 | "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz",
3271 | "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==",
3272 | "dev": true,
3273 | "requires": {
3274 | "atob": "^2.1.1",
3275 | "decode-uri-component": "^0.2.0",
3276 | "resolve-url": "^0.2.1",
3277 | "source-map-url": "^0.4.0",
3278 | "urix": "^0.1.0"
3279 | }
3280 | },
3281 | "source-map-url": {
3282 | "version": "0.4.0",
3283 | "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz",
3284 | "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=",
3285 | "dev": true
3286 | },
3287 | "split-string": {
3288 | "version": "3.1.0",
3289 | "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz",
3290 | "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==",
3291 | "dev": true,
3292 | "requires": {
3293 | "extend-shallow": "^3.0.0"
3294 | }
3295 | },
3296 | "sshpk": {
3297 | "version": "1.16.1",
3298 | "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz",
3299 | "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==",
3300 | "requires": {
3301 | "asn1": "~0.2.3",
3302 | "assert-plus": "^1.0.0",
3303 | "bcrypt-pbkdf": "^1.0.0",
3304 | "dashdash": "^1.12.0",
3305 | "ecc-jsbn": "~0.1.1",
3306 | "getpass": "^0.1.1",
3307 | "jsbn": "~0.1.0",
3308 | "safer-buffer": "^2.0.2",
3309 | "tweetnacl": "~0.14.0"
3310 | }
3311 | },
3312 | "static-extend": {
3313 | "version": "0.1.2",
3314 | "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz",
3315 | "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=",
3316 | "dev": true,
3317 | "requires": {
3318 | "define-property": "^0.2.5",
3319 | "object-copy": "^0.1.0"
3320 | },
3321 | "dependencies": {
3322 | "define-property": {
3323 | "version": "0.2.5",
3324 | "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
3325 | "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
3326 | "dev": true,
3327 | "requires": {
3328 | "is-descriptor": "^0.1.0"
3329 | }
3330 | }
3331 | }
3332 | },
3333 | "statuses": {
3334 | "version": "1.5.0",
3335 | "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
3336 | "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
3337 | },
3338 | "stealthy-require": {
3339 | "version": "1.1.1",
3340 | "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz",
3341 | "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks="
3342 | },
3343 | "streamsearch": {
3344 | "version": "0.1.2",
3345 | "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz",
3346 | "integrity": "sha1-gIudDlb8Jz2Am6VzOOkpkZoanxo="
3347 | },
3348 | "string-width": {
3349 | "version": "2.1.1",
3350 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
3351 | "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
3352 | "dev": true,
3353 | "requires": {
3354 | "is-fullwidth-code-point": "^2.0.0",
3355 | "strip-ansi": "^4.0.0"
3356 | }
3357 | },
3358 | "string_decoder": {
3359 | "version": "1.1.1",
3360 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
3361 | "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
3362 | "dev": true,
3363 | "requires": {
3364 | "safe-buffer": "~5.1.0"
3365 | }
3366 | },
3367 | "strip-ansi": {
3368 | "version": "4.0.0",
3369 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
3370 | "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
3371 | "dev": true,
3372 | "requires": {
3373 | "ansi-regex": "^3.0.0"
3374 | }
3375 | },
3376 | "strip-eof": {
3377 | "version": "1.0.0",
3378 | "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
3379 | "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=",
3380 | "dev": true
3381 | },
3382 | "strip-json-comments": {
3383 | "version": "2.0.1",
3384 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
3385 | "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
3386 | "dev": true
3387 | },
3388 | "supports-color": {
3389 | "version": "5.5.0",
3390 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
3391 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
3392 | "dev": true,
3393 | "requires": {
3394 | "has-flag": "^3.0.0"
3395 | }
3396 | },
3397 | "term-size": {
3398 | "version": "1.2.0",
3399 | "resolved": "https://registry.npmjs.org/term-size/-/term-size-1.2.0.tgz",
3400 | "integrity": "sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk=",
3401 | "dev": true,
3402 | "requires": {
3403 | "execa": "^0.7.0"
3404 | }
3405 | },
3406 | "timed-out": {
3407 | "version": "4.0.1",
3408 | "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz",
3409 | "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=",
3410 | "dev": true
3411 | },
3412 | "to-object-path": {
3413 | "version": "0.3.0",
3414 | "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz",
3415 | "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=",
3416 | "dev": true,
3417 | "requires": {
3418 | "kind-of": "^3.0.2"
3419 | },
3420 | "dependencies": {
3421 | "kind-of": {
3422 | "version": "3.2.2",
3423 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
3424 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
3425 | "dev": true,
3426 | "requires": {
3427 | "is-buffer": "^1.1.5"
3428 | }
3429 | }
3430 | }
3431 | },
3432 | "to-regex": {
3433 | "version": "3.0.2",
3434 | "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz",
3435 | "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==",
3436 | "dev": true,
3437 | "requires": {
3438 | "define-property": "^2.0.2",
3439 | "extend-shallow": "^3.0.2",
3440 | "regex-not": "^1.0.2",
3441 | "safe-regex": "^1.1.0"
3442 | }
3443 | },
3444 | "to-regex-range": {
3445 | "version": "2.1.1",
3446 | "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
3447 | "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=",
3448 | "dev": true,
3449 | "requires": {
3450 | "is-number": "^3.0.0",
3451 | "repeat-string": "^1.6.1"
3452 | }
3453 | },
3454 | "toidentifier": {
3455 | "version": "1.0.0",
3456 | "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
3457 | "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw=="
3458 | },
3459 | "touch": {
3460 | "version": "3.1.0",
3461 | "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz",
3462 | "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==",
3463 | "dev": true,
3464 | "requires": {
3465 | "nopt": "~1.0.10"
3466 | }
3467 | },
3468 | "tough-cookie": {
3469 | "version": "2.4.3",
3470 | "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz",
3471 | "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==",
3472 | "requires": {
3473 | "psl": "^1.1.24",
3474 | "punycode": "^1.4.1"
3475 | },
3476 | "dependencies": {
3477 | "punycode": {
3478 | "version": "1.4.1",
3479 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
3480 | "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4="
3481 | }
3482 | }
3483 | },
3484 | "tunnel-agent": {
3485 | "version": "0.6.0",
3486 | "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
3487 | "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
3488 | "requires": {
3489 | "safe-buffer": "^5.0.1"
3490 | }
3491 | },
3492 | "tweetnacl": {
3493 | "version": "0.14.5",
3494 | "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
3495 | "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q="
3496 | },
3497 | "type-is": {
3498 | "version": "1.6.18",
3499 | "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
3500 | "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
3501 | "requires": {
3502 | "media-typer": "0.3.0",
3503 | "mime-types": "~2.1.24"
3504 | }
3505 | },
3506 | "undefsafe": {
3507 | "version": "2.0.2",
3508 | "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.2.tgz",
3509 | "integrity": "sha1-Il9rngM3Zj4Njnz9aG/Cg2zKznY=",
3510 | "dev": true,
3511 | "requires": {
3512 | "debug": "^2.2.0"
3513 | }
3514 | },
3515 | "union-value": {
3516 | "version": "1.0.1",
3517 | "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz",
3518 | "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==",
3519 | "dev": true,
3520 | "requires": {
3521 | "arr-union": "^3.1.0",
3522 | "get-value": "^2.0.6",
3523 | "is-extendable": "^0.1.1",
3524 | "set-value": "^2.0.1"
3525 | }
3526 | },
3527 | "unique-string": {
3528 | "version": "1.0.0",
3529 | "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz",
3530 | "integrity": "sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo=",
3531 | "dev": true,
3532 | "requires": {
3533 | "crypto-random-string": "^1.0.0"
3534 | }
3535 | },
3536 | "unpipe": {
3537 | "version": "1.0.0",
3538 | "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
3539 | "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
3540 | },
3541 | "unset-value": {
3542 | "version": "1.0.0",
3543 | "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz",
3544 | "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=",
3545 | "dev": true,
3546 | "requires": {
3547 | "has-value": "^0.3.1",
3548 | "isobject": "^3.0.0"
3549 | },
3550 | "dependencies": {
3551 | "has-value": {
3552 | "version": "0.3.1",
3553 | "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz",
3554 | "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=",
3555 | "dev": true,
3556 | "requires": {
3557 | "get-value": "^2.0.3",
3558 | "has-values": "^0.1.4",
3559 | "isobject": "^2.0.0"
3560 | },
3561 | "dependencies": {
3562 | "isobject": {
3563 | "version": "2.1.0",
3564 | "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
3565 | "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=",
3566 | "dev": true,
3567 | "requires": {
3568 | "isarray": "1.0.0"
3569 | }
3570 | }
3571 | }
3572 | },
3573 | "has-values": {
3574 | "version": "0.1.4",
3575 | "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz",
3576 | "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=",
3577 | "dev": true
3578 | }
3579 | }
3580 | },
3581 | "unzip-response": {
3582 | "version": "2.0.1",
3583 | "resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-2.0.1.tgz",
3584 | "integrity": "sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c=",
3585 | "dev": true
3586 | },
3587 | "upath": {
3588 | "version": "1.2.0",
3589 | "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz",
3590 | "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==",
3591 | "dev": true
3592 | },
3593 | "update-notifier": {
3594 | "version": "2.5.0",
3595 | "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-2.5.0.tgz",
3596 | "integrity": "sha512-gwMdhgJHGuj/+wHJJs9e6PcCszpxR1b236igrOkUofGhqJuG+amlIKwApH1IW1WWl7ovZxsX49lMBWLxSdm5Dw==",
3597 | "dev": true,
3598 | "requires": {
3599 | "boxen": "^1.2.1",
3600 | "chalk": "^2.0.1",
3601 | "configstore": "^3.0.0",
3602 | "import-lazy": "^2.1.0",
3603 | "is-ci": "^1.0.10",
3604 | "is-installed-globally": "^0.1.0",
3605 | "is-npm": "^1.0.0",
3606 | "latest-version": "^3.0.0",
3607 | "semver-diff": "^2.0.0",
3608 | "xdg-basedir": "^3.0.0"
3609 | }
3610 | },
3611 | "uri-js": {
3612 | "version": "4.2.2",
3613 | "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
3614 | "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==",
3615 | "requires": {
3616 | "punycode": "^2.1.0"
3617 | }
3618 | },
3619 | "urix": {
3620 | "version": "0.1.0",
3621 | "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz",
3622 | "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=",
3623 | "dev": true
3624 | },
3625 | "url-parse-lax": {
3626 | "version": "1.0.0",
3627 | "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz",
3628 | "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=",
3629 | "dev": true,
3630 | "requires": {
3631 | "prepend-http": "^1.0.1"
3632 | }
3633 | },
3634 | "use": {
3635 | "version": "3.1.1",
3636 | "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
3637 | "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==",
3638 | "dev": true
3639 | },
3640 | "util-deprecate": {
3641 | "version": "1.0.2",
3642 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
3643 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
3644 | "dev": true
3645 | },
3646 | "utils-merge": {
3647 | "version": "1.0.1",
3648 | "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
3649 | "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
3650 | },
3651 | "uuid": {
3652 | "version": "3.3.3",
3653 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz",
3654 | "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ=="
3655 | },
3656 | "vary": {
3657 | "version": "1.1.2",
3658 | "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
3659 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
3660 | },
3661 | "verror": {
3662 | "version": "1.10.0",
3663 | "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
3664 | "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
3665 | "requires": {
3666 | "assert-plus": "^1.0.0",
3667 | "core-util-is": "1.0.2",
3668 | "extsprintf": "^1.2.0"
3669 | }
3670 | },
3671 | "which": {
3672 | "version": "1.3.1",
3673 | "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
3674 | "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
3675 | "dev": true,
3676 | "requires": {
3677 | "isexe": "^2.0.0"
3678 | }
3679 | },
3680 | "widest-line": {
3681 | "version": "2.0.1",
3682 | "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-2.0.1.tgz",
3683 | "integrity": "sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA==",
3684 | "dev": true,
3685 | "requires": {
3686 | "string-width": "^2.1.1"
3687 | }
3688 | },
3689 | "write-file-atomic": {
3690 | "version": "2.4.3",
3691 | "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz",
3692 | "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==",
3693 | "dev": true,
3694 | "requires": {
3695 | "graceful-fs": "^4.1.11",
3696 | "imurmurhash": "^0.1.4",
3697 | "signal-exit": "^3.0.2"
3698 | }
3699 | },
3700 | "x-xss-protection": {
3701 | "version": "1.3.0",
3702 | "resolved": "https://registry.npmjs.org/x-xss-protection/-/x-xss-protection-1.3.0.tgz",
3703 | "integrity": "sha512-kpyBI9TlVipZO4diReZMAHWtS0MMa/7Kgx8hwG/EuZLiA6sg4Ah/4TRdASHhRRN3boobzcYgFRUFSgHRge6Qhg=="
3704 | },
3705 | "xdg-basedir": {
3706 | "version": "3.0.0",
3707 | "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz",
3708 | "integrity": "sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=",
3709 | "dev": true
3710 | },
3711 | "xss-clean": {
3712 | "version": "0.1.1",
3713 | "resolved": "https://registry.npmjs.org/xss-clean/-/xss-clean-0.1.1.tgz",
3714 | "integrity": "sha1-07poTYXM1SBUlj0BrWqzbWYtsaU=",
3715 | "requires": {
3716 | "xss-filters": "1.2.6"
3717 | }
3718 | },
3719 | "xss-filters": {
3720 | "version": "1.2.6",
3721 | "resolved": "https://registry.npmjs.org/xss-filters/-/xss-filters-1.2.6.tgz",
3722 | "integrity": "sha1-aLOQicsd/4udvIiUhIObL1B/XFU="
3723 | },
3724 | "yallist": {
3725 | "version": "2.1.2",
3726 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
3727 | "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=",
3728 | "dev": true
3729 | }
3730 | }
3731 | }
3732 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "devcamper_api",
3 | "version": "1.0.0",
4 | "description": "Devcamper backend API",
5 | "main": "server.js",
6 | "scripts": {
7 | "start": "NODE_ENV=production node server",
8 | "dev": "nodemon server"
9 | },
10 | "author": "Brad Traversy",
11 | "license": "MIT",
12 | "dependencies": {
13 | "bcryptjs": "^2.4.3",
14 | "colors": "^1.4.0",
15 | "cookie-parser": "^1.4.4",
16 | "cors": "^2.8.5",
17 | "dotenv": "^8.1.0",
18 | "express": "^4.17.1",
19 | "express-fileupload": "^1.1.6-alpha.5",
20 | "express-mongo-sanitize": "^1.3.2",
21 | "express-rate-limit": "^5.0.0",
22 | "helmet": "^3.21.1",
23 | "hpp": "^0.2.2",
24 | "jsonwebtoken": "^8.5.1",
25 | "mongoose": "^5.7.5",
26 | "morgan": "^1.9.1",
27 | "node-geocoder": "^3.24.0",
28 | "nodemailer": "^6.3.0",
29 | "slugify": "^1.3.5",
30 | "xss-clean": "^0.1.1"
31 | },
32 | "devDependencies": {
33 | "nodemon": "^1.19.2"
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/public/fonts/glyphicons-halflings-regular.eot:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Node.js-API-Masterclass-with-Express-and-MongoDB/c2b83902107508247c145202033f23e0280d8f48/public/fonts/glyphicons-halflings-regular.eot
--------------------------------------------------------------------------------
/public/fonts/glyphicons-halflings-regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Node.js-API-Masterclass-with-Express-and-MongoDB/c2b83902107508247c145202033f23e0280d8f48/public/fonts/glyphicons-halflings-regular.woff
--------------------------------------------------------------------------------
/public/fonts/glyphicons-halflings-regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/PacktPublishing/Node.js-API-Masterclass-with-Express-and-MongoDB/c2b83902107508247c145202033f23e0280d8f48/public/fonts/glyphicons-halflings-regular.woff2
--------------------------------------------------------------------------------
/routes/auth.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const {
3 | register,
4 | login,
5 | logout,
6 | getMe,
7 | forgotPassword,
8 | resetPassword,
9 | updateDetails,
10 | updatePassword
11 | } = require('../controllers/auth');
12 |
13 | const router = express.Router();
14 |
15 | const { protect } = require('../middleware/auth');
16 |
17 | router.post('/register', register);
18 | router.post('/login', login);
19 | router.get('/logout', logout);
20 | router.get('/me', protect, getMe);
21 | router.put('/updatedetails', protect, updateDetails);
22 | router.put('/updatepassword', protect, updatePassword);
23 | router.post('/forgotpassword', forgotPassword);
24 | router.put('/resetpassword/:resettoken', resetPassword);
25 |
26 | module.exports = router;
27 |
--------------------------------------------------------------------------------
/routes/bootcamps.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const {
3 | getBootcamps,
4 | getBootcamp,
5 | createBootcamp,
6 | updateBootcamp,
7 | deleteBootcamp,
8 | getBootcampsInRadius,
9 | bootcampPhotoUpload
10 | } = require('../controllers/bootcamps');
11 |
12 | const Bootcamp = require('../models/Bootcamp');
13 |
14 | // Include other resource routers
15 | const courseRouter = require('./courses');
16 | const reviewRouter = require('./reviews');
17 |
18 | const router = express.Router();
19 |
20 | const advancedResults = require('../middleware/advancedResults');
21 | const { protect, authorize } = require('../middleware/auth');
22 |
23 | // Re-route into other resource routers
24 | router.use('/:bootcampId/courses', courseRouter);
25 | router.use('/:bootcampId/reviews', reviewRouter);
26 |
27 | router.route('/radius/:zipcode/:distance').get(getBootcampsInRadius);
28 |
29 | router
30 | .route('/:id/photo')
31 | .put(protect, authorize('publisher', 'admin'), bootcampPhotoUpload);
32 |
33 | router
34 | .route('/')
35 | .get(advancedResults(Bootcamp, 'courses'), getBootcamps)
36 | .post(protect, authorize('publisher', 'admin'), createBootcamp);
37 |
38 | router
39 | .route('/:id')
40 | .get(getBootcamp)
41 | .put(protect, authorize('publisher', 'admin'), updateBootcamp)
42 | .delete(protect, authorize('publisher', 'admin'), deleteBootcamp);
43 |
44 | module.exports = router;
45 |
--------------------------------------------------------------------------------
/routes/courses.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const {
3 | getCourses,
4 | getCourse,
5 | addCourse,
6 | updateCourse,
7 | deleteCourse
8 | } = require('../controllers/courses');
9 |
10 | const Course = require('../models/Course');
11 |
12 | const router = express.Router({ mergeParams: true });
13 |
14 | const advancedResults = require('../middleware/advancedResults');
15 | const { protect, authorize } = require('../middleware/auth');
16 |
17 | router
18 | .route('/')
19 | .get(
20 | advancedResults(Course, {
21 | path: 'bootcamp',
22 | select: 'name description'
23 | }),
24 | getCourses
25 | )
26 | .post(protect, authorize('publisher', 'admin'), addCourse);
27 |
28 | router
29 | .route('/:id')
30 | .get(getCourse)
31 | .put(protect, authorize('publisher', 'admin'), updateCourse)
32 | .delete(protect, authorize('publisher', 'admin'), deleteCourse);
33 |
34 | module.exports = router;
35 |
--------------------------------------------------------------------------------
/routes/reviews.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const {
3 | getReviews,
4 | getReview,
5 | addReview,
6 | updateReview,
7 | deleteReview
8 | } = require('../controllers/reviews');
9 |
10 | const Review = require('../models/Review');
11 |
12 | const router = express.Router({ mergeParams: true });
13 |
14 | const advancedResults = require('../middleware/advancedResults');
15 | const { protect, authorize } = require('../middleware/auth');
16 |
17 | router
18 | .route('/')
19 | .get(
20 | advancedResults(Review, {
21 | path: 'bootcamp',
22 | select: 'name description'
23 | }),
24 | getReviews
25 | )
26 | .post(protect, authorize('user', 'admin'), addReview);
27 |
28 | router
29 | .route('/:id')
30 | .get(getReview)
31 | .put(protect, authorize('user', 'admin'), updateReview)
32 | .delete(protect, authorize('user', 'admin'), deleteReview);
33 |
34 | module.exports = router;
35 |
--------------------------------------------------------------------------------
/routes/users.js:
--------------------------------------------------------------------------------
1 | const express = require('express');
2 | const {
3 | getUsers,
4 | getUser,
5 | createUser,
6 | updateUser,
7 | deleteUser
8 | } = require('../controllers/users');
9 |
10 | const User = require('../models/User');
11 |
12 | const router = express.Router({ mergeParams: true });
13 |
14 | const advancedResults = require('../middleware/advancedResults');
15 | const { protect, authorize } = require('../middleware/auth');
16 |
17 | router.use(protect);
18 | router.use(authorize('admin'));
19 |
20 | router
21 | .route('/')
22 | .get(advancedResults(User), getUsers)
23 | .post(createUser);
24 |
25 | router
26 | .route('/:id')
27 | .get(getUser)
28 | .put(updateUser)
29 | .delete(deleteUser);
30 |
31 | module.exports = router;
32 |
--------------------------------------------------------------------------------
/seeder.js:
--------------------------------------------------------------------------------
1 | const fs = require('fs');
2 | const mongoose = require('mongoose');
3 | const colors = require('colors');
4 | const dotenv = require('dotenv');
5 |
6 | // Load env vars
7 | dotenv.config({ path: './config/config.env' });
8 |
9 | // Load models
10 | const Bootcamp = require('./models/Bootcamp');
11 | const Course = require('./models/Course');
12 | const User = require('./models/User');
13 | const Review = require('./models/Review');
14 |
15 | // Connect to DB
16 | mongoose.connect(process.env.MONGO_URI, {
17 | useNewUrlParser: true,
18 | useCreateIndex: true,
19 | useFindAndModify: false,
20 | useUnifiedTopology: true
21 | });
22 |
23 | // Read JSON files
24 | const bootcamps = JSON.parse(
25 | fs.readFileSync(`${__dirname}/_data/bootcamps.json`, 'utf-8')
26 | );
27 |
28 | const courses = JSON.parse(
29 | fs.readFileSync(`${__dirname}/_data/courses.json`, 'utf-8')
30 | );
31 |
32 | const users = JSON.parse(
33 | fs.readFileSync(`${__dirname}/_data/users.json`, 'utf-8')
34 | );
35 |
36 | const reviews = JSON.parse(
37 | fs.readFileSync(`${__dirname}/_data/reviews.json`, 'utf-8')
38 | );
39 |
40 | // Import into DB
41 | const importData = async () => {
42 | try {
43 | await Bootcamp.create(bootcamps);
44 | await Course.create(courses);
45 | await User.create(users);
46 | await Review.create(reviews);
47 | console.log('Data Imported...'.green.inverse);
48 | process.exit();
49 | } catch (err) {
50 | console.error(err);
51 | }
52 | };
53 |
54 | // Delete data
55 | const deleteData = async () => {
56 | try {
57 | await Bootcamp.deleteMany();
58 | await Course.deleteMany();
59 | await User.deleteMany();
60 | await Review.deleteMany();
61 | console.log('Data Destroyed...'.red.inverse);
62 | process.exit();
63 | } catch (err) {
64 | console.error(err);
65 | }
66 | };
67 |
68 | if (process.argv[2] === '-i') {
69 | importData();
70 | } else if (process.argv[2] === '-d') {
71 | deleteData();
72 | }
73 |
--------------------------------------------------------------------------------
/server.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const express = require('express');
3 | const dotenv = require('dotenv');
4 | const morgan = require('morgan');
5 | const colors = require('colors');
6 | const fileupload = require('express-fileupload');
7 | const cookieParser = require('cookie-parser');
8 | const mongoSanitize = require('express-mongo-sanitize');
9 | const helmet = require('helmet');
10 | const xss = require('xss-clean');
11 | const rateLimit = require('express-rate-limit');
12 | const hpp = require('hpp');
13 | const cors = require('cors');
14 | const errorHandler = require('./middleware/error');
15 | const connectDB = require('./config/db');
16 |
17 | // Load env vars
18 | dotenv.config({ path: './config/config.env' });
19 |
20 | // Connect to database
21 | connectDB();
22 |
23 | // Route files
24 | const bootcamps = require('./routes/bootcamps');
25 | const courses = require('./routes/courses');
26 | const auth = require('./routes/auth');
27 | const users = require('./routes/users');
28 | const reviews = require('./routes/reviews');
29 |
30 | const app = express();
31 |
32 | // Body parser
33 | app.use(express.json());
34 |
35 | // Cookie parser
36 | app.use(cookieParser());
37 |
38 | // Dev logging middleware
39 | if (process.env.NODE_ENV === 'development') {
40 | app.use(morgan('dev'));
41 | }
42 |
43 | // File uploading
44 | app.use(fileupload());
45 |
46 | // Sanitize data
47 | app.use(mongoSanitize());
48 |
49 | // Set security headers
50 | app.use(helmet());
51 |
52 | // Prevent XSS attacks
53 | app.use(xss());
54 |
55 | // Rate limiting
56 | const limiter = rateLimit({
57 | windowMs: 10 * 60 * 1000, // 10 mins
58 | max: 100
59 | });
60 | app.use(limiter);
61 |
62 | // Prevent http param pollution
63 | app.use(hpp());
64 |
65 | // Enable CORS
66 | app.use(cors());
67 |
68 | // Set static folder
69 | app.use(express.static(path.join(__dirname, 'public')));
70 |
71 | // Mount routers
72 | app.use('/api/v1/bootcamps', bootcamps);
73 | app.use('/api/v1/courses', courses);
74 | app.use('/api/v1/auth', auth);
75 | app.use('/api/v1/users', users);
76 | app.use('/api/v1/reviews', reviews);
77 |
78 | app.use(errorHandler);
79 |
80 | const PORT = process.env.PORT || 5000;
81 |
82 | const server = app.listen(
83 | PORT,
84 | console.log(
85 | `Server running in ${process.env.NODE_ENV} mode on port ${PORT}`.yellow.bold
86 | )
87 | );
88 |
89 | // Handle unhandled promise rejections
90 | process.on('unhandledRejection', (err, promise) => {
91 | console.log(`Error: ${err.message}`.red);
92 | // Close server & exit process
93 | // server.close(() => process.exit(1));
94 | });
95 |
--------------------------------------------------------------------------------
/utils/errorResponse.js:
--------------------------------------------------------------------------------
1 | class ErrorResponse extends Error {
2 | constructor(message, statusCode) {
3 | super(message);
4 | this.statusCode = statusCode;
5 |
6 | Error.captureStackTrace(this, this.constructor);
7 | }
8 | }
9 |
10 | module.exports = ErrorResponse;
11 |
--------------------------------------------------------------------------------
/utils/geocoder.js:
--------------------------------------------------------------------------------
1 | const NodeGeocoder = require('node-geocoder');
2 |
3 | const options = {
4 | provider: process.env.GEOCODER_PROVIDER,
5 | httpAdapter: 'https',
6 | apiKey: process.env.GEOCODER_API_KEY,
7 | formatter: null
8 | };
9 |
10 | const geocoder = NodeGeocoder(options);
11 |
12 | module.exports = geocoder;
13 |
--------------------------------------------------------------------------------
/utils/sendEmail.js:
--------------------------------------------------------------------------------
1 | const nodemailer = require('nodemailer');
2 |
3 | const sendEmail = async options => {
4 | const transporter = nodemailer.createTransport({
5 | host: process.env.SMTP_HOST,
6 | port: process.env.SMTP_PORT,
7 | auth: {
8 | user: process.env.SMTP_EMAIL,
9 | pass: process.env.SMTP_PASSWORD
10 | }
11 | });
12 |
13 | const message = {
14 | from: `${process.env.FROM_NAME} <${process.env.FROM_EMAIL}>`,
15 | to: options.email,
16 | subject: options.subject,
17 | text: options.message
18 | };
19 |
20 | const info = await transporter.sendMail(message);
21 |
22 | console.log('Message sent: %s', info.messageId);
23 | };
24 |
25 | module.exports = sendEmail;
26 |
--------------------------------------------------------------------------------