diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 000000000..461dfc9a1 Binary files /dev/null and b/.DS_Store differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..ed86a42c0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +config.env +node_modules diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 000000000..b58b603fe --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,5 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ diff --git a/.idea/final-project.iml b/.idea/final-project.iml new file mode 100644 index 000000000..24643cc37 --- /dev/null +++ b/.idea/final-project.iml @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 000000000..28a804d89 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 000000000..466f7a68c --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 000000000..94a25f7f4 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/README.md b/README.md index 6faca9f83..7878e8e13 100644 --- a/README.md +++ b/README.md @@ -1,56 +1,33 @@ # cs4241-FinalProject +# Team Members: Jonathan Dang, Ivan Eroshenko, Clay Oshiro-Leavitt, Adrianna Staszewska -For your final project, you'll implement a course project that exhibits your mastery of the course materials. -This project should provide an opportunity to be creative and to pursue individual research and learning. +1. We created an exciting multimedia experience - Pacpeople. This web application is a modern take on the hit classic - Pacman. This time, there are multiple players and takes place on a larger game board. With up to four human players and 5 monsters, the game can become quite intense and challenging. -## General description +Game Link: https://pac-people.herokuapp.com -Your project should consist of a complete Web application, exhibiting facets of the three main sections of the course material: - -- Static Web page content and design. You should have a project that is accessible, easily navigable, and features significant content. -- Dynamic behavior implemented with JavaScript (TypeScript is also allowed if your group wants to explore it). -- Server-side programming *using Node.js*. Typically this will take the form of some sort of persistent data, authentication, and possibly server-side computation. Ideally it will also include support for realtime commmunication as discussed below. -- Groups are *highly encouraged* to consider including some type of realtime communication technology in their projects (chat, networked multiplayer games, collaborative coding/editing, video/audio via WebRTC etc.) We'll be discussing many of these technologies in class next week. -- A video (less than five minutes) where each group member explains some aspect of the project. An easy way to produce this video is for you all the groups members to join a Zoom call that is recorded; each member can share their screen when they discuss the project or one member can "drive" the interface while other members narrate (this second option will probably work better.) The video should be posted on YouTube or some other accessible video hosting service. - -## Project ideation - -Excellent projects serve someone/some group; for this assignment you need to define your users and stakeholders. I encourage you to identify projects that will have impact, either artistically, politically, or in terms of productivity. Consider creating something useful for a cause or hobby you care about. - -## Logistics - -### Team size -Students are will work in teams of 3-5 students for the project; teams of two can be approved with the permission of the instructor. Working in teams will allow you to build a good project in a limited amount of time. - -### Deliverables - -__Proposal:__ -Provide an outline of your project direction and the names of the team members. -The outline should have enough detail so that staff can determine if it meets the minimum expectations, or if it goes too far to be reasonable by the deadline. -This file must be named proposal.md so we can find it. -Submit a PR to turn it in by Monday, 11:59 PM - -There are no other scheduled checkpoints for your project. - -#### Turning in Your Outline / Project - -**NOTE: code is due before the project presentation day due to the end of term / grading schedule constraints** -Submit a second PR on the final project repo to turn in your app and code. - -Deploy your app, in the form of a webpage, to Glitch/Heroku/Digital Ocean or some other service. -Folks on the same team do not need to post the same webpage, but must instead clearly state who is on the team in their proposal. - -The README for your second pull request doesn’t need to be a formal report, but it should contain: - -1. A brief description of what you created, and a link to the project itself. -2. Any additional instructions that might be needed to fully use your project (login information etc.) +2. Additional instructions: you can play as a single person, however it is preferable to play with 1-3 other players. You can open up multiple browser windows to test the multiplayer aspect. If two players run into each other they will die. 3. An outline of the technologies you used and how you used them. -4. What challenges you faced in completing the project. -5. What each group member was responsible for designing / developing. -6. A link to your project video. - -Think of 1,3, and 4 in particular in a similar vein to the design / tech achievements for A1—A4… make a case for why what you did was challenging and why your implementation deserves a grade of 100%. - -## FAQs +4. While working, we quickly discovered the limitations of Ably’s free services. We continually exceeded Ably’s message rates and limits, resulting in several of our accounts being suspended while testing. We also ran into issues with the maximum message size that is allowable over Ably. This required some rework of our message design to fit within the allowable message size. +5. Team Workload: +- Jonathan Dang + - Handled logic of players colliding with one another + - Handled the detection of when game ended + - Helped out with player movement logic +- Clay Oshiro-Leavitt + - Wall detection and move validation logic + - Player spawn location logic + - Player movement logic + - Integration and composition of game music +- Ivan Eroshenko + - Implemented UI + - Helped to give a head start on project implementation + - Implemented the boss with A* + +- Adrianna Staszewska + - Coin collection by players + - Updating user’s scores in the database + - Movement of monsters + +6. Here is the link to our project demonstration video. +https://youtu.be/Lpv8TB81V8g -- **Can I use XYZ framework?** You can use any web-based frameworks or tools available, but for your server programming you need to use node.js. Your client-side language should be either JavaScript or TypeScript. diff --git a/config/db.js b/config/db.js new file mode 100644 index 000000000..3d154b90a --- /dev/null +++ b/config/db.js @@ -0,0 +1,23 @@ +const mongoose = require("mongoose") + +const connectDb = async(mongoUri) => { + try { + const conn = await mongoose.connect(mongoUri, { + useNewUrlParser: true, + useUnifiedTopology: true, + useFindAndModify: false, + }); + + + console.log(`MongoDB Connected: ${conn.connection.host}`) + + + } catch (e) { + console.log(e); + process.exit(1); + } +} + + + +module.exports = connectDb diff --git a/config/passport.js b/config/passport.js new file mode 100644 index 000000000..e69de29bb diff --git a/middleware/auth.js b/middleware/auth.js new file mode 100644 index 000000000..7b01e644f --- /dev/null +++ b/middleware/auth.js @@ -0,0 +1,16 @@ +module.exports = { + ensureAuth: function (req, res, next) { + if (!req.user) { + res.redirect("/login"); + } else { + next(); + } + }, + ensureGuest: function (req, res, next) { + if (req.user) { + res.redirect("/"); + } else { + return next(); + } + } +} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 000000000..62c58a97a --- /dev/null +++ b/package-lock.json @@ -0,0 +1,2054 @@ +{ + "name": "final-project", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@ably/msgpack-js": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@ably/msgpack-js/-/msgpack-js-0.3.3.tgz", + "integrity": "sha512-H7oWg97VyA1JhWUP7YN7zwp9W1ozCqMSsqCcXNz4XLmZNdJKT2ntF/6DPgbviFgUpShjQlbPC/iamisTjwLHdQ==", + "requires": { + "bops": "~0.0.6" + } + }, + "@sindresorhus/is": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", + "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", + "dev": true + }, + "@szmarczak/http-timer": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", + "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", + "dev": true, + "requires": { + "defer-to-connect": "^1.0.1" + } + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "ably": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/ably/-/ably-1.2.3.tgz", + "integrity": "sha512-JEZwAvqk1IKCUtETA9MlDeLmnvY2sqMpemjYNl+/K9aogLB+WGJLF1KE/dp6MYL4BeybtFiFg/1KYmQ+KpleVA==", + "requires": { + "@ably/msgpack-js": "^0.3.3", + "request": "^2.87.0", + "ws": "^5.1" + } + }, + "accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "requires": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + } + }, + "ajv": { + "version": "6.12.5", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.5.tgz", + "integrity": "sha512-lRF8RORchjpKG50/WFf8xmg7sgCLFiYNNnqdKflk63whMQcWR5ngGjiSXkL9bjxy6B2npOK2HSMN49jEBMSkag==", + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-align": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.0.tgz", + "integrity": "sha512-ZpClVKqXN3RGBmKibdfWzqCY4lnjEuoNzU5T0oEFpfd/z5qJHVarukridD4juLO2FXMiwUQxr9WqQtaYa8XRYw==", + "dev": true, + "requires": { + "string-width": "^3.0.0" + }, + "dependencies": { + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + } + } + }, + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "anymatch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" + }, + "async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==" + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" + }, + "aws4": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.10.1.tgz", + "integrity": "sha512-zg7Hz2k5lI8kb7U32998pRRFin7zJlkfezGJjUc2heaD4Pw2wObakCDVzkKztTm/Ln7eiVvYsjqak0Ed4LkMDA==" + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "base64-js": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-0.0.2.tgz", + "integrity": "sha1-Ak8Pcq+iW3X5wO5zzU9V7Bvtl4Q=" + }, + "basic-auth": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.1.tgz", + "integrity": "sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==", + "requires": { + "safe-buffer": "5.1.2" + } + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "binary-extensions": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", + "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==", + "dev": true + }, + "bl": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/bl/-/bl-2.2.1.tgz", + "integrity": "sha512-6Pesp1w0DEX1N550i/uGV/TqucVL4AM/pgThFSN/Qq9si1/DF9aIHs1BxD8V/QU0HoeHO6cQRTAuYnLPKq1e4g==", + "requires": { + "readable-stream": "^2.3.5", + "safe-buffer": "^5.1.1" + } + }, + "bluebird": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", + "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==" + }, + "body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "requires": { + "bytes": "3.1.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + } + }, + "bops": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/bops/-/bops-0.0.7.tgz", + "integrity": "sha1-tKClqDmkBkVK8P4FqLkaenZqVOI=", + "requires": { + "base64-js": "0.0.2", + "to-utf8": "0.0.1" + } + }, + "boxen": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-4.2.0.tgz", + "integrity": "sha512-eB4uT9RGzg2odpER62bBwSLvUeGC+WbRjjyyFhGsKnc8wp/m0+hQsMUvUe3H2V0D5vw0nBdO1hCJoZo5mKeuIQ==", + "dev": true, + "requires": { + "ansi-align": "^3.0.0", + "camelcase": "^5.3.1", + "chalk": "^3.0.0", + "cli-boxes": "^2.2.0", + "string-width": "^4.1.0", + "term-size": "^2.1.0", + "type-fest": "^0.8.1", + "widest-line": "^3.1.0" + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "bson": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.5.tgz", + "integrity": "sha512-kDuEzldR21lHciPQAIulLs1LZlCXdLziXI6Mb/TDkwXhb//UORJNPXgcRs2CuO4H0DcMkpfT3/ySsP3unoZjBg==" + }, + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" + }, + "cacheable-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", + "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", + "dev": true, + "requires": { + "clone-response": "^1.0.2", + "get-stream": "^5.1.0", + "http-cache-semantics": "^4.0.0", + "keyv": "^3.0.0", + "lowercase-keys": "^2.0.0", + "normalize-url": "^4.1.0", + "responselike": "^1.0.2" + }, + "dependencies": { + "get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "lowercase-keys": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-2.0.0.tgz", + "integrity": "sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==", + "dev": true + } + } + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" + }, + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "chokidar": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.4.2.tgz", + "integrity": "sha512-IZHaDeBeI+sZJRX7lGcXsdzgvZqKv6sECqsbErJA4mHWfpRrD8B97kSFN4cQz6nGBGiuFia1MKR4d6c1o8Cv7A==", + "dev": true, + "requires": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "fsevents": "~2.1.2", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.4.0" + } + }, + "ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true + }, + "cli-boxes": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", + "integrity": "sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw==", + "dev": true + }, + "clone-response": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/clone-response/-/clone-response-1.0.2.tgz", + "integrity": "sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=", + "dev": true, + "requires": { + "mimic-response": "^1.0.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "configstore": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-5.0.1.tgz", + "integrity": "sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==", + "dev": true, + "requires": { + "dot-prop": "^5.2.0", + "graceful-fs": "^4.1.2", + "make-dir": "^3.0.0", + "unique-string": "^2.0.0", + "write-file-atomic": "^3.0.0", + "xdg-basedir": "^4.0.0" + } + }, + "connect-mongo": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/connect-mongo/-/connect-mongo-3.2.0.tgz", + "integrity": "sha512-0Mx88079Z20CG909wCFlR3UxhMYGg6Ibn1hkIje1hwsqOLWtL9HJV+XD0DAjUvQScK6WqY/FA8tSVQM9rR64Rw==", + "requires": { + "mongodb": "^3.1.0" + } + }, + "content-disposition": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "requires": { + "safe-buffer": "5.1.2" + } + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" + }, + "cookie-parser": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.5.tgz", + "integrity": "sha512-f13bPUj/gG/5mDr+xLmSxxDsB9DQiTIfhJS/sqjrmfAWiAN+x2O4i/XguTL9yDZ+/IFDanJ+5x7hC4CXT9Tdzw==", + "requires": { + "cookie": "0.4.0", + "cookie-signature": "1.0.6" + } + }, + "cookie-session": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/cookie-session/-/cookie-session-1.4.0.tgz", + "integrity": "sha512-0hhwD+BUIwMXQraiZP/J7VP2YFzqo6g4WqZlWHtEHQ22t0MeZZrNBSCxC1zcaLAs8ApT3BzAKizx9gW/AP9vNA==", + "requires": { + "cookies": "0.8.0", + "debug": "2.6.9", + "on-headers": "~1.0.2" + } + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" + }, + "cookies": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/cookies/-/cookies-0.8.0.tgz", + "integrity": "sha512-8aPsApQfebXnuI+537McwYsDtjVxGm8gTIzQI3FDW6t5t/DAhERxtnbEPN/8RX+uZthoz4eCOgloXaE5cYyNow==", + "requires": { + "depd": "~2.0.0", + "keygrip": "~1.1.0" + }, + "dependencies": { + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" + } + } + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "crypto-random-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz", + "integrity": "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==", + "dev": true + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "requires": { + "assert-plus": "^1.0.0" + } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "decompress-response": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", + "integrity": "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=", + "dev": true, + "requires": { + "mimic-response": "^1.0.0" + } + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true + }, + "defer-to-connect": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", + "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==", + "dev": true + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" + }, + "denque": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/denque/-/denque-1.4.1.tgz", + "integrity": "sha512-OfzPuSZKGcgr96rf1oODnfjqBFmr1DVoc/TrItj3Ohe0Ah1C5WX5Baquw/9U9KovnQ88EqmJbD66rKYUQYN1tQ==" + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "dot-prop": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", + "integrity": "sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==", + "dev": true, + "requires": { + "is-obj": "^2.0.0" + } + }, + "dotenv": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-8.2.0.tgz", + "integrity": "sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==" + }, + "duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", + "dev": true + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "escape-goat": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/escape-goat/-/escape-goat-2.1.1.tgz", + "integrity": "sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==", + "dev": true + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + }, + "express": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz", + "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==", + "requires": { + "accepts": "~1.3.7", + "array-flatten": "1.1.1", + "body-parser": "1.19.0", + "content-disposition": "0.5.3", + "content-type": "~1.0.4", + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~1.1.2", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "~1.1.2", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.5", + "qs": "6.7.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.1.2", + "send": "0.17.1", + "serve-static": "1.14.1", + "setprototypeof": "1.1.1", + "statuses": "~1.5.0", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + } + }, + "express-session": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.17.1.tgz", + "integrity": "sha512-UbHwgqjxQZJiWRTMyhvWGvjBQduGCSBDhhZXYenziMFjxst5rMV+aJZ6hKPHZnPyHGsrqRICxtX8jtEbm/z36Q==", + "requires": { + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~2.0.0", + "on-headers": "~1.0.2", + "parseurl": "~1.3.3", + "safe-buffer": "5.2.0", + "uid-safe": "~2.1.5" + }, + "dependencies": { + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" + }, + "safe-buffer": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", + "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==" + } + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + } + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" + }, + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "forwarded": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz", + "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, + "fsevents": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", + "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", + "dev": true, + "optional": true + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "requires": { + "assert-plus": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "global-dirs": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-2.0.1.tgz", + "integrity": "sha512-5HqUqdhkEovj2Of/ms3IeS/EekcO54ytHRLV4PEY2rhRwrHXLQjeVEES0Lhka0xwNDtGYn58wyC4s5+MHsOO6A==", + "dev": true, + "requires": { + "ini": "^1.3.5" + } + }, + "got": { + "version": "9.6.0", + "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", + "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", + "dev": true, + "requires": { + "@sindresorhus/is": "^0.14.0", + "@szmarczak/http-timer": "^1.1.2", + "cacheable-request": "^6.0.0", + "decompress-response": "^3.3.0", + "duplexer3": "^0.1.4", + "get-stream": "^4.1.0", + "lowercase-keys": "^1.0.1", + "mimic-response": "^1.0.1", + "p-cancelable": "^1.0.0", + "to-readable-stream": "^1.0.0", + "url-parse-lax": "^3.0.0" + } + }, + "graceful-fs": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz", + "integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw==", + "dev": true + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" + }, + "har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "requires": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "has-yarn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/has-yarn/-/has-yarn-2.1.0.tgz", + "integrity": "sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==", + "dev": true + }, + "http-cache-semantics": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", + "dev": true + }, + "http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha1-SMptcvbGo68Aqa1K5odr44ieKwk=", + "dev": true + }, + "import-lazy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", + "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=", + "dev": true + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "ini": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", + "dev": true + }, + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "dev": true, + "requires": { + "ci-info": "^2.0.0" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-installed-globally": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.3.2.tgz", + "integrity": "sha512-wZ8x1js7Ia0kecP/CHM/3ABkAmujX7WPvQk6uu3Fly/Mk44pySulQpnHG46OMjHGXApINnV4QhY3SWnECO2z5g==", + "dev": true, + "requires": { + "global-dirs": "^2.0.1", + "is-path-inside": "^3.0.1" + } + }, + "is-npm": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-4.0.0.tgz", + "integrity": "sha512-96ECIfh9xtDDlPylNPXhzjsykHsMJZ18ASpaWzQyBr4YRTcVjUvzaHayDAES2oU/3KpljhHUjtSRNiDwi0F0ig==", + "dev": true + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-obj": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-2.0.0.tgz", + "integrity": "sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==", + "dev": true + }, + "is-path-inside": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.2.tgz", + "integrity": "sha512-/2UGPSgmtqwo1ktx8NDHjuPwZWmHhO+gj0f93EkhLB5RgW9RZevWYYlIkS6zePc6U2WpOdQYIwHe9YC4DWEBVg==", + "dev": true + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" + }, + "is-yarn-global": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/is-yarn-global/-/is-yarn-global-0.3.0.tgz", + "integrity": "sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" + }, + "json-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", + "integrity": "sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=", + "dev": true + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "kareem": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.3.1.tgz", + "integrity": "sha512-l3hLhffs9zqoDe8zjmb/mAN4B8VT3L56EUvKNqLFVs9YlFA+zx7ke1DO8STAdDyYNkeSo1nKmjuvQeI12So8Xw==" + }, + "keygrip": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/keygrip/-/keygrip-1.1.0.tgz", + "integrity": "sha512-iYSchDJ+liQ8iwbSI2QqsQOvqv58eJCEanyJPJi+Khyu8smkcKSFUCbPwzFcL7YVtZ6eONjqRX/38caJ7QjRAQ==", + "requires": { + "tsscmp": "1.0.6" + } + }, + "keyv": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", + "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", + "dev": true, + "requires": { + "json-buffer": "3.0.0" + } + }, + "latest-version": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-5.1.0.tgz", + "integrity": "sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==", + "dev": true, + "requires": { + "package-json": "^6.3.0" + } + }, + "lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "dev": true + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "memory-pager": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", + "optional": true + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, + "mime-db": { + "version": "1.44.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz", + "integrity": "sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg==" + }, + "mime-types": { + "version": "2.1.27", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz", + "integrity": "sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w==", + "requires": { + "mime-db": "1.44.0" + } + }, + "mimic-response": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz", + "integrity": "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "mongodb": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.6.2.tgz", + "integrity": "sha512-sSZOb04w3HcnrrXC82NEh/YGCmBuRgR+C1hZgmmv4L6dBz4BkRse6Y8/q/neXer9i95fKUBbFi4KgeceXmbsOA==", + "requires": { + "bl": "^2.2.1", + "bson": "^1.1.4", + "denque": "^1.4.1", + "require_optional": "^1.0.1", + "safe-buffer": "^5.1.2", + "saslprep": "^1.0.0" + } + }, + "mongoose": { + "version": "5.10.8", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-5.10.8.tgz", + "integrity": "sha512-hbpFhOU6rWkWPkekUeSJxqWwzsjVQZ9xPg4WmWA1HJ8YDvjyNye1xbp82fw67BpnyvcjHxyU3/YhujsOCx55yw==", + "requires": { + "bson": "^1.1.4", + "kareem": "2.3.1", + "mongodb": "3.6.2", + "mongoose-legacy-pluralize": "1.0.2", + "mpath": "0.7.0", + "mquery": "3.2.2", + "ms": "2.1.2", + "regexp-clone": "1.0.0", + "safe-buffer": "5.2.1", + "sift": "7.0.1", + "sliced": "1.0.1" + }, + "dependencies": { + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + } + } + }, + "mongoose-legacy-pluralize": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/mongoose-legacy-pluralize/-/mongoose-legacy-pluralize-1.0.2.tgz", + "integrity": "sha512-Yo/7qQU4/EyIS8YDFSeenIvXxZN+ld7YdV9LqFVQJzTLye8unujAWPZ4NWKfFA+RNjh+wvTWKY9Z3E5XM6ZZiQ==" + }, + "morgan": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", + "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==", + "requires": { + "basic-auth": "~2.0.1", + "debug": "2.6.9", + "depd": "~2.0.0", + "on-finished": "~2.3.0", + "on-headers": "~1.0.2" + }, + "dependencies": { + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" + } + } + }, + "mpath": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.7.0.tgz", + "integrity": "sha512-Aiq04hILxhz1L+f7sjGyn7IxYzWm1zLNNXcfhDtx04kZ2Gk7uvFdgZ8ts1cWa/6d0TQmag2yR8zSGZUmp0tFNg==" + }, + "mquery": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/mquery/-/mquery-3.2.2.tgz", + "integrity": "sha512-XB52992COp0KP230I3qloVUbkLUxJIu328HBP2t2EsxSFtf4W1HPSOBWOXf1bqxK4Xbb66lfMJ+Bpfd9/yZE1Q==", + "requires": { + "bluebird": "3.5.1", + "debug": "3.1.0", + "regexp-clone": "^1.0.0", + "safe-buffer": "5.1.2", + "sliced": "1.0.1" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + } + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" + }, + "nodemon": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.4.tgz", + "integrity": "sha512-Ltced+hIfTmaS28Zjv1BM552oQ3dbwPqI4+zI0SLgq+wpJhSyqgYude/aZa/3i31VCQWMfXJVxvu86abcam3uQ==", + "dev": true, + "requires": { + "chokidar": "^3.2.2", + "debug": "^3.2.6", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.0.4", + "pstree.remy": "^1.1.7", + "semver": "^5.7.1", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.2", + "update-notifier": "^4.0.0" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", + "dev": true, + "requires": { + "abbrev": "1" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "normalize-url": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.0.tgz", + "integrity": "sha512-2s47yzUxdexf1OhyRi4Em83iQk0aPvwTddtFz4hnSSw9dCEsLEGf6SwIO8ss/19S9iBb5sJaOuTvTGDeZI00BQ==", + "dev": true + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, + "on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==" + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "p-cancelable": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", + "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", + "dev": true + }, + "package-json": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-6.5.0.tgz", + "integrity": "sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==", + "dev": true, + "requires": { + "got": "^9.6.0", + "registry-auth-token": "^4.0.0", + "registry-url": "^5.0.0", + "semver": "^6.2.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, + "passport": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/passport/-/passport-0.4.1.tgz", + "integrity": "sha512-IxXgZZs8d7uFSt3eqNjM9NQ3g3uQCW5avD8mRNoXV99Yig50vjuaez6dQK2qC0kVWPRTujxY0dWgGfT09adjYg==", + "requires": { + "passport-strategy": "1.x.x", + "pause": "0.0.1" + } + }, + "passport-local": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/passport-local/-/passport-local-1.0.0.tgz", + "integrity": "sha1-H+YyaMkudWBmJkN+O5BmYsFbpu4=", + "requires": { + "passport-strategy": "1.x.x" + } + }, + "passport-strategy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", + "integrity": "sha1-tVOaqPwiWj0a0XlHbd8ja0QPUuQ=" + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" + }, + "pause": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", + "integrity": "sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10=" + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" + }, + "picomatch": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "dev": true + }, + "prepend-http": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", + "integrity": "sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=", + "dev": true + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "proxy-addr": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.6.tgz", + "integrity": "sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==", + "requires": { + "forwarded": "~0.1.2", + "ipaddr.js": "1.9.1" + } + }, + "psl": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz", + "integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==" + }, + "pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "dev": true + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" + }, + "pupa": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pupa/-/pupa-2.0.1.tgz", + "integrity": "sha512-hEJH0s8PXLY/cdXh66tNEQGndDrIKNqNC5xmrysZy3i5C3oEoLna7YAOad+7u125+zH1HNXUmGEkrhb3c2VriA==", + "dev": true, + "requires": { + "escape-goat": "^2.0.0" + } + }, + "qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" + }, + "random-bytes": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", + "integrity": "sha1-T2ih3Arli9P7lYSMMDJNt11kNgs=" + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + }, + "raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "requires": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + } + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "readdirp": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.4.0.tgz", + "integrity": "sha512-0xe001vZBnJEK+uKcj8qOhyAKPzIT+gStxWr3LCB0DwcXR5NZJ3IaC+yGnHCYzB/S7ov3m3EEbZI2zeNvX+hGQ==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "regexp-clone": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/regexp-clone/-/regexp-clone-1.0.0.tgz", + "integrity": "sha512-TuAasHQNamyyJ2hb97IuBEif4qBHGjPHBS64sZwytpLEqtBQ1gPJTnOaQ6qmpET16cK14kkjbazl6+p0RRv0yw==" + }, + "registry-auth-token": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-4.2.0.tgz", + "integrity": "sha512-P+lWzPrsgfN+UEpDS3U8AQKg/UjZX6mQSJueZj3EK+vNESoqBSpBUD3gmu4sF9lOsjXWjF11dQKUqemf3veq1w==", + "dev": true, + "requires": { + "rc": "^1.2.8" + } + }, + "registry-url": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-5.1.0.tgz", + "integrity": "sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==", + "dev": true, + "requires": { + "rc": "^1.2.8" + } + }, + "request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "dependencies": { + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" + } + } + }, + "require_optional": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require_optional/-/require_optional-1.0.1.tgz", + "integrity": "sha512-qhM/y57enGWHAe3v/NcwML6a3/vfESLe/sGM2dII+gEO0BpKRUkWZow/tyloNqJyN6kXSl3RyyM8Ll5D/sJP8g==", + "requires": { + "resolve-from": "^2.0.0", + "semver": "^5.1.0" + } + }, + "resolve-from": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz", + "integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c=" + }, + "responselike": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", + "integrity": "sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=", + "dev": true, + "requires": { + "lowercase-keys": "^1.0.0" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "saslprep": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/saslprep/-/saslprep-1.0.3.tgz", + "integrity": "sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==", + "optional": true, + "requires": { + "sparse-bitfield": "^3.0.3" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + }, + "semver-diff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-3.1.1.tgz", + "integrity": "sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==", + "dev": true, + "requires": { + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "send": { + "version": "0.17.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz", + "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==", + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.7.2", + "mime": "1.6.0", + "ms": "2.1.1", + "on-finished": "~2.3.0", + "range-parser": "~1.2.1", + "statuses": "~1.5.0" + }, + "dependencies": { + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==" + } + } + }, + "serve-static": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz", + "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.17.1" + } + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, + "sift": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/sift/-/sift-7.0.1.tgz", + "integrity": "sha512-oqD7PMJ+uO6jV9EQCl0LrRw1OwsiPsiFQR5AR30heR+4Dl7jBBbDLnNvWiak20tzZlSE1H7RB30SX/1j/YYT7g==" + }, + "signal-exit": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", + "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", + "dev": true + }, + "sliced": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz", + "integrity": "sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E=" + }, + "sparse-bitfield": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", + "integrity": "sha1-/0rm5oZWBWuks+eSqzM004JzyhE=", + "optional": true, + "requires": { + "memory-pager": "^1.0.2" + } + }, + "sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + }, + "string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + } + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "term-size": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/term-size/-/term-size-2.2.0.tgz", + "integrity": "sha512-a6sumDlzyHVJWb8+YofY4TW112G6p2FCPEAFk+59gIYHv3XHRhm9ltVQ9kli4hNWeQBwSpe8cRN25x0ROunMOw==", + "dev": true + }, + "to-readable-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", + "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", + "dev": true + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "to-utf8": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/to-utf8/-/to-utf8-0.0.1.tgz", + "integrity": "sha1-0Xrqcv8vujm55DYBvns/9y4ImFI=" + }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" + }, + "touch": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.0.tgz", + "integrity": "sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==", + "dev": true, + "requires": { + "nopt": "~1.0.10" + } + }, + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + }, + "tsscmp": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.6.tgz", + "integrity": "sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==" + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "typedarray-to-buffer": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", + "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", + "dev": true, + "requires": { + "is-typedarray": "^1.0.0" + } + }, + "uid-safe": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz", + "integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==", + "requires": { + "random-bytes": "~1.0.0" + } + }, + "undefsafe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.3.tgz", + "integrity": "sha512-nrXZwwXrD/T/JXeygJqdCO6NZZ1L66HrxM/Z7mIq2oPanoN0F1nLx3lwJMu6AwJY69hdixaFQOuoYsMjE5/C2A==", + "dev": true, + "requires": { + "debug": "^2.2.0" + } + }, + "unique-string": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz", + "integrity": "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==", + "dev": true, + "requires": { + "crypto-random-string": "^2.0.0" + } + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "update-notifier": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-4.1.3.tgz", + "integrity": "sha512-Yld6Z0RyCYGB6ckIjffGOSOmHXj1gMeE7aROz4MG+XMkmixBX4jUngrGXNYz7wPKBmtoD4MnBa2Anu7RSKht/A==", + "dev": true, + "requires": { + "boxen": "^4.2.0", + "chalk": "^3.0.0", + "configstore": "^5.0.1", + "has-yarn": "^2.1.0", + "import-lazy": "^2.1.0", + "is-ci": "^2.0.0", + "is-installed-globally": "^0.3.1", + "is-npm": "^4.0.0", + "is-yarn-global": "^0.3.0", + "latest-version": "^5.0.0", + "pupa": "^2.0.1", + "semver-diff": "^3.1.1", + "xdg-basedir": "^4.0.0" + } + }, + "uri-js": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz", + "integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==", + "requires": { + "punycode": "^2.1.0" + } + }, + "url-parse-lax": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", + "integrity": "sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=", + "dev": true, + "requires": { + "prepend-http": "^2.0.0" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "widest-line": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz", + "integrity": "sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg==", + "dev": true, + "requires": { + "string-width": "^4.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "write-file-atomic": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", + "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4", + "is-typedarray": "^1.0.0", + "signal-exit": "^3.0.2", + "typedarray-to-buffer": "^3.1.5" + } + }, + "ws": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz", + "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==", + "requires": { + "async-limiter": "~1.0.0" + } + }, + "xdg-basedir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-4.0.0.tgz", + "integrity": "sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==", + "dev": true + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 000000000..e0217c028 --- /dev/null +++ b/package.json @@ -0,0 +1,39 @@ +{ + "name": "final-project", + "version": "1.0.0", + "description": "For your final project, you'll implement a course project that exhibits your mastery of the course materials. This project should provide an opportunity to be creative and to pursue individual research and learning.", + "main": "server.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "start": "node server.js", + "dev": "nodemon server.js" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/WebwareClassProject/final-project.git" + }, + "author": "", + "license": "ISC", + "bugs": { + "url": "https://github.com/WebwareClassProject/final-project/issues" + }, + "homepage": "https://github.com/WebwareClassProject/final-project#readme", + "dependencies": { + "ably": "^1.2.3", + "body-parser": "^1.19.0", + "connect-mongo": "^3.2.0", + "cookie-parser": "^1.4.5", + "cookie-session": "^1.4.0", + "dotenv": "^8.2.0", + "express": "^4.17.1", + "express-session": "^1.17.1", + "mongodb": "^3.6.2", + "mongoose": "^5.10.8", + "morgan": "^1.10.0", + "passport": "^0.4.1", + "passport-local": "^1.0.0" + }, + "devDependencies": { + "nodemon": "^2.0.4" + } +} diff --git a/public/.DS_Store b/public/.DS_Store new file mode 100644 index 000000000..0511ed0f2 Binary files /dev/null and b/public/.DS_Store differ diff --git a/public/assets/.DS_Store b/public/assets/.DS_Store new file mode 100644 index 000000000..b514ab1e3 Binary files /dev/null and b/public/assets/.DS_Store differ diff --git a/public/assets/avatarA.png b/public/assets/avatarA.png new file mode 100644 index 000000000..a44d2d01d Binary files /dev/null and b/public/assets/avatarA.png differ diff --git a/public/assets/avatarAcyan.png b/public/assets/avatarAcyan.png new file mode 100644 index 000000000..ba668b95f Binary files /dev/null and b/public/assets/avatarAcyan.png differ diff --git a/public/assets/avatarAgreen.png b/public/assets/avatarAgreen.png new file mode 100644 index 000000000..edf04d4f2 Binary files /dev/null and b/public/assets/avatarAgreen.png differ diff --git a/public/assets/avatarAyellow.png b/public/assets/avatarAyellow.png new file mode 100644 index 000000000..8c99640c4 Binary files /dev/null and b/public/assets/avatarAyellow.png differ diff --git a/public/assets/avatarB.png b/public/assets/avatarB.png new file mode 100644 index 000000000..2526e54ba Binary files /dev/null and b/public/assets/avatarB.png differ diff --git a/public/assets/avatarBcyan.png b/public/assets/avatarBcyan.png new file mode 100644 index 000000000..da013511b Binary files /dev/null and b/public/assets/avatarBcyan.png differ diff --git a/public/assets/avatarBgreen.png b/public/assets/avatarBgreen.png new file mode 100644 index 000000000..467624b2d Binary files /dev/null and b/public/assets/avatarBgreen.png differ diff --git a/public/assets/avatarByellow.png b/public/assets/avatarByellow.png new file mode 100644 index 000000000..82fe30c73 Binary files /dev/null and b/public/assets/avatarByellow.png differ diff --git a/public/assets/avatarC.png b/public/assets/avatarC.png new file mode 100644 index 000000000..555c55803 Binary files /dev/null and b/public/assets/avatarC.png differ diff --git a/public/assets/avatarCcyan.png b/public/assets/avatarCcyan.png new file mode 100644 index 000000000..ddeb6c6a7 Binary files /dev/null and b/public/assets/avatarCcyan.png differ diff --git a/public/assets/avatarCgreen.png b/public/assets/avatarCgreen.png new file mode 100644 index 000000000..d7bd3c8e8 Binary files /dev/null and b/public/assets/avatarCgreen.png differ diff --git a/public/assets/avatarCyellow.png b/public/assets/avatarCyellow.png new file mode 100644 index 000000000..cdcace1d7 Binary files /dev/null and b/public/assets/avatarCyellow.png differ diff --git a/public/assets/boss.png b/public/assets/boss.png new file mode 100644 index 000000000..647781b7a Binary files /dev/null and b/public/assets/boss.png differ diff --git a/public/assets/coin_actual.png b/public/assets/coin_actual.png new file mode 100644 index 000000000..7a9bb8034 Binary files /dev/null and b/public/assets/coin_actual.png differ diff --git a/public/assets/monsterOne.png b/public/assets/monsterOne.png new file mode 100644 index 000000000..ab6e1d096 Binary files /dev/null and b/public/assets/monsterOne.png differ diff --git a/public/assets/pac_people.png b/public/assets/pac_people.png new file mode 100644 index 000000000..9b569eb1c Binary files /dev/null and b/public/assets/pac_people.png differ diff --git a/public/assets/wall_actual.png b/public/assets/wall_actual.png new file mode 100644 index 000000000..16d510678 Binary files /dev/null and b/public/assets/wall_actual.png differ diff --git a/public/home.js b/public/home.js new file mode 100644 index 000000000..1724b2385 --- /dev/null +++ b/public/home.js @@ -0,0 +1,24 @@ +function joinGame() { + window.location.replace('/game'); +} + +window.onload = () => { + // init elements + let leaderBoardlist = document.getElementById("leaders-container") + + // get leaders + fetch("/topScores", { + method: 'GET', + headers: {'Content-Type': 'application/json'}, + }) + .then((res) => res.json()).then(leaders => { + leaders.forEach((user) => { + if (user.username && user.score) { + let listItem = document.createElement("li"); + listItem.textContent = `${user.username} - ${user.score}`; + + leaderBoardlist.appendChild(listItem); + } + }) + }) +} diff --git a/public/leaderboard.js b/public/leaderboard.js new file mode 100644 index 000000000..9b360da9e --- /dev/null +++ b/public/leaderboard.js @@ -0,0 +1,7 @@ +window.onload = () => { + fetch("/topScores", { + method: 'GET', + headers: {'Content-Type': 'application/json'}, + }) + .then((res) => res.json()).then(json => console.log(json)) +} diff --git a/public/login.js b/public/login.js new file mode 100644 index 000000000..2cb7345ef --- /dev/null +++ b/public/login.js @@ -0,0 +1,68 @@ +let userNameInput; +let passwordInput; +let logInButton; +let signUpButton; +let form; +let errorMessage; + +function getLoginPasswordData() { + let username = userNameInput.value; + let password = passwordInput.value; + + return {username: username, password: password} +} + +function setErrorMessage(message) { + errorMessage.innerText = message; +} + +function handleSignUpOrLogin() { + // clear error message + setErrorMessage(""); + + let data = getLoginPasswordData(); + + let route = "/auth/signin"; + + if (data.username.length && data.password.length) { + // make the api request to create new user + fetch(route, { + method: 'POST', + headers: {'Content-Type': 'application/json'}, + body: JSON.stringify(data) + }) + .then((res) => { + console.log(res); + if (res.status === 401) { + try { + res.json().then((jsonRes) => { + setErrorMessage(jsonRes.message); + }) + } catch (e) { + setErrorMessage("Something went wrong"); + } + } else { + localStorage.setItem("nickname", data.username); + console.log('Did not get 401'); + window.location.replace("/"); + } + }) + } else { + // user didn't enter password / username + setErrorMessage("Do not forget to specify username / password!"); + } +} + +window.onload = () => { + userNameInput = document.getElementById("username"); + passwordInput = document.getElementById("password"); + logInButton = document.getElementById("log-in"); + signUpButton = document.getElementById("sign-up"); + errorMessage = document.getElementById("error-message"); + + // prevent default form submit + form = document.getElementById("the-form"); + form.addEventListener('submit', (e) => { + e.preventDefault(); + }) +} diff --git a/public/music/Pacpeople.mp3 b/public/music/Pacpeople.mp3 new file mode 100644 index 000000000..0acba9747 Binary files /dev/null and b/public/music/Pacpeople.mp3 differ diff --git a/public/script.js b/public/script.js new file mode 100644 index 000000000..08888b6c3 --- /dev/null +++ b/public/script.js @@ -0,0 +1,429 @@ +let gameRoom; +let myClientId; +let myChannel; +let gameOn = false; +let players = {}; +let totalPlayers = 0; +let amIalive = false; +let game; +let monsters = {} +let backendCoins = null; +let clientCoins = {}; +let prevKey = ""; +let board = []; // init +let boss = {}; + +const RATIO = 25; + +const BASE_SERVER_URL = "https://pac-people.herokuapp.com"; +let myNickname = ""; + +const realtime = Ably.Realtime({ + authUrl: "/auth/game", +}); + +realtime.connection.once("connected", () => { + myClientId = realtime.auth.clientId; + myNickname = realtime.auth.clientId; + gameRoom = realtime.channels.get("game-room"); + myChannel = realtime.channels.get("clientChannel-" + myClientId); + gameRoom.presence.enter(myNickname); + game = new Phaser.Game(config); +}); +var myMusic= document.getElementById("music"); +function playMusic() { +myMusic.play(); +} + +function pauseMusic() { +myMusic.pause(); +} + +class Explosion extends Phaser.GameObjects.Sprite { + constructor(scene, x, y) { + super(scene, x, y, "explosion"); + scene.add.existing(this); + this.play("explode"); + } +} + + +class GameScene extends Phaser.Scene { + constructor() { + super("gameScene"); + } + + //load assets + preload() { + this.load.spritesheet( + "avatarA", + "/assets/avatarA.png", + { + frameWidth: 25, + frameHeight: 25 + } + ); + this.load.spritesheet( + "avatarB", + "/assets/avatarB.png", + { + frameWidth: 25, + frameHeight: 25 + } + ); + this.load.spritesheet( + "avatarC", + "/assets/avatarC.png", + { + frameWidth: 25, + frameHeight: 25 + } + ); + this.load.spritesheet( + "avatarAgreen", + "/assets/avatarAgreen.png", + { + frameWidth: 25, + frameHeight: 25 + } + ); + this.load.spritesheet( + "avatarAcyan", + "/assets/avatarAcyan.png", + { + frameWidth: 25, + frameHeight: 25 + } + ); + this.load.spritesheet( + "avatarAyellow", + "/assets/avatarAyellow.png", + { + frameWidth: 25, + frameHeight: 25 + } + ); + this.load.spritesheet( + "avatarBgreen", + "/assets/avatarBgreen.png", + { + frameWidth: 25, + frameHeight: 25 + } + ); + this.load.spritesheet( + "avatarBcyan", + "/assets/avatarBcyan.png", + { + frameWidth: 25, + frameHeight: 25 + } + ); + this.load.spritesheet( + "avatarByellow", + "/assets/avatarByellow.png", + { + frameWidth: 25, + frameHeight: 25 + } + ); + this.load.spritesheet( + "avatarCgreen", + "/assets/avatarCgreen.png", + { + frameWidth: 25, + frameHeight: 25 + } + ); + this.load.spritesheet( + "avatarCcyan", + "/assets/avatarCcyan.png", + { + frameWidth: 25, + frameHeight: 25 + } + ); + this.load.spritesheet( + "avatarCyellow", + "/assets/avatarCyellow.png", + { + frameWidth: 25, + frameHeight: 25 + } + ); + this.load.spritesheet( + "explosion", + "https://cdn.glitch.com/f66772e3-bbf6-4f6d-b5d5-94559e3c1c6f%2Fexplosion57%20(2).png?v=1589491279459", + { + frameWidth: 48, + frameHeight: 48 + } + ); + this.load.image("wall", "/assets/wall_actual.png"); + + this.load.spritesheet( + "coin", + "/assets/coin_actual.png", { + frameWidth: 25, + frameHeight: 25 + } + ) + + this.load.spritesheet( + "Ada", + "/assets/monsterOne.png", { + frameWidth: 25, + frameHeight: 25 + } + ) + + this.load.spritesheet( + "boss", + "/assets/boss.png", { + frameWidth: 25, + frameHeight: 25 + } + ) + + //load board + fetch("/getBoard", {headers: {'Content-Type': 'application/json'}}) + .then((response) => response.json()) + .then((walls) => board = walls); + } + + //init variables, define animations & sounds, and display assets + create() { + this.bossAvatar = {} + this.monsterAvatars = {}; + this.avatars = {}; + this.cursorKeys = this.input.keyboard.createCursorKeys(); + + this.anims.create({ + key: "explode", + frames: this.anims.generateFrameNumbers("explosion"), + frameRate: 20, + repeat: 0, + hideOnComplete: true + }); + + this.renderBoardAndCoins(); + + gameRoom.subscribe("game-state", (msg) => { + if (msg.data.gameOn) { + gameOn = true; + } + players = msg.data.players; + totalPlayers = msg.data.playerCount; + backendCoins = msg.data.coins; + monsters = msg.data.monsters; + boss = msg.data.boss; + }); + + gameRoom.subscribe("game-over", (msg) => { + gameOn = false; + gameRoom.unsubscribe(); + myChannel.unsubscribe(); + window.location.replace(BASE_SERVER_URL + "/"); + }); + } + + //update the attributes of various game objects per game logic + update() { + let scores = []; + + for (let item in this.avatars) { + if (!players[item]) { + this.avatars[item].destroy(); + delete this.avatars[item]; + } + } + + for (let item in players) { + + let avatarId = players[item].id; + if (this.avatars[avatarId] && players[item].isAlive) { + // render position of the avatar to match player's + + this.avatars[avatarId].x = players[item].x; + this.avatars[avatarId].y = players[item].y; + + scores.push({id: players[item].id, score: players[item].score}) + } else if (!this.avatars[avatarId] && players[item].isAlive) { + + // initialize the avatar on client side + if (players[item].id !== myClientId) { + + // if this is another user's avatar, get its color + let avatarName = + "avatar" + + players[item].invaderAvatarType + + players[item].invaderAvatarColor; + this.avatars[avatarId] = this.physics.add + .sprite(players[item].x, players[item].y, avatarName) + .setOrigin(0.5, 0.5); + this.avatars[avatarId].setCollideWorldBounds(true); + } else if (players[item].id === myClientId) { + + // if it's our avatar, color it with default (white) + let avatarName = "avatar" + players[item].invaderAvatarType; + this.avatars[avatarId] = this.physics.add + .sprite(players[item].x, players[item].y, avatarName) + .setOrigin(0.5, 0.5); + this.avatars[avatarId].setCollideWorldBounds(true); + amIalive = true; + } + } else if (this.avatars[avatarId] && !players[item].isAlive) { + // player died + + console.log("death"); + + this.explodeAndKill(avatarId); + + if (players[item].id === myClientId) { + amIalive = false; + } + } + } + + for (let monsterId in monsters) { + + if (this.monsterAvatars[monsterId]) { + // update monsters positions + this.monsterAvatars[monsterId].x = monsters[monsterId].x; + this.monsterAvatars[monsterId].y = monsters[monsterId].y; + } else if (!this.monsterAvatars[monsterId]) { + // init monster + this.monsterAvatars[monsterId] = this.physics.add + .sprite(monsters[monsterId].x, monsters[monsterId].y, "Ada") + .setOrigin(0.5, 0.5); + + this.monsterAvatars[monsterId].setCollideWorldBounds(true); + } + } + + // was initialized + if (Object.keys(boss).length !== 0) { + if (Object.keys(this.bossAvatar).length !== 0) { + this.bossAvatar.x = boss.x; + this.bossAvatar.y = boss.y; + } else { + this.bossAvatar = this.physics.add + .sprite(boss.x, boss.y, "boss") + .setOrigin(0.5, 0.5); + + this.bossAvatar.setCollideWorldBounds(true); + } + } + + + this.updateCoinsOnClient() + this.updateScores(scores); + this.publishMyInput(); + } + + updateCoinsOnClient() { + // scale user's x and y + if (backendCoins != null) { + for (let item in clientCoins) { + if (!backendCoins[item]) { + // coin has been picked + clientCoins[item].disableBody(true, true); + delete clientCoins[item]; + } + } + } + } + + explodeAndKill(deadPlayerId) { + this.avatars[deadPlayerId].disableBody(true, true); + let explosion = new Explosion( + this, + this.avatars[deadPlayerId].x, + this.avatars[deadPlayerId].y + ); + delete this.avatars[deadPlayerId]; + } + + publishMyInput() { + if (Phaser.Input.Keyboard.JustDown(this.cursorKeys.left) && amIalive && prevKey !== "left") { + myChannel.publish("pos", { + keyPressed: "left", + }); + prevKey = "left"; + } else if ( + Phaser.Input.Keyboard.JustDown(this.cursorKeys.right) && + amIalive && prevKey !== "right" + ) { + myChannel.publish("pos", { + keyPressed: "right", + }); + prevKey = "right"; + } else if (Phaser.Input.Keyboard.JustDown(this.cursorKeys.down) && + amIalive && prevKey !== "down") { + myChannel.publish("pos", { + keyPressed: "down", + }); + prevKey = "down"; + } else if (Phaser.Input.Keyboard.JustDown(this.cursorKeys.up) && + amIalive && prevKey !== "up") { + myChannel.publish("pos", { + keyPressed: "up", + }); + prevKey = "up"; + } + + } + + updateScores(scores) { + scores.sort((a, b) => a.score < b.score); + let displayStr = ""; + + scores.forEach((item) => { + displayStr += "'" + item.id + " : " + item.score + "' "; + }) + + document.getElementById("score").innerText = displayStr; + } + + renderBoardAndCoins() { + for (let i = 0; i < board[0].length; i++) { + for (let j = 0; j < board.length; j++) { + // console.log(`${i} : ${j}`); + if (board[j][i] === 1) { + this.physics.add.image(((i + 1) * RATIO) - Math.floor(RATIO / 2), ((j + 1) * RATIO) - Math.floor(RATIO / 2), "wall", null, { + restitution: 0.4, + isStatic: true + }); + } else if (board[j][i] === 0) { + let x = i + let y = j + if (x < 10) { + x = `0${x}` + } + + if (y < 10) { + y = `0${y}` + } + + let id = `${x}|${y}` + + clientCoins[id] = this.physics.add + .sprite(((i + 1) * RATIO) - Math.floor(RATIO / 2), ((j + 1) * RATIO) - Math.floor(RATIO / 2), "coin") + .setOrigin(0.5, 0.5); + } + } + } + } +} + + +const config = { + width: 1400, + height: 750, + backgroundColor: "#FFFFF", + parent: "gameContainer", + scene: [GameScene], + physics: { + default: "arcade" + } +}; diff --git a/public/style.css b/public/style.css new file mode 100644 index 000000000..54e89712f --- /dev/null +++ b/public/style.css @@ -0,0 +1,100 @@ +body { + background-color: black; + color: white; + font-family: "Press Start 2P"; + width: 100%; + height: 100%; +} + +.content-container { + background-color: black; + width: 100%; + height: 100vh; + display: flex; + flex-direction: column; + color: white; + align-items: center; +} + +/** LOGIN **/ + +.form-container { + display: flex; + flex-direction: column; + width: 400px; + margin: 120px auto; + align-items: center; + justify-content: center; +} + +#username, #password { + width: 100%; +} + +#log-in, #sign-up { + width: 100%; + margin-top: 10px; + background-color: #4a4a4a; + color: white; +} + +#error-message { + color: deeppink; +} + +#error-message { + height: 50px; +} + +/** HOME **/ + +.leaders-title { + font-size: 30px; + color: yellow; +} + +.leaderboard { + margin: auto; +} + +#leaders-container { + overflow-y: scroll; + height:300px; + font-size: 20px; + color: yellow; + margin-left: 15px; +} + +.play-container { + margin: auto; +} + +#play-button { + width: 250px; + height: 50px; + background-color: white; +} + +.look-settings { + margin: auto; + display: flex; + flex-direction: row; + justify-content: space-around; +} + +.avatar-settings { + display: flex; + flex-direction: column; + width: 45%; +} + +.color-settings { + display: flex; + flex-direction: column; + width: 45%; +} + +/** GAME **/ +.game-div { + margin: auto; +} diff --git a/server.js b/server.js new file mode 100644 index 000000000..b636a62f4 --- /dev/null +++ b/server.js @@ -0,0 +1,1021 @@ +const express = require("express"); +const bodyParser = require('body-parser'); +const dotenv = require("dotenv").config({path: './config.env'}); +const connectDb = require("./config/db"); +const morgan = require("morgan"); +const mongodb = require('mongodb'); +const ObjectID = require('mongodb').ObjectID; +const passport = require('passport'); +const LocalStrategy = require('passport-local').Strategy; +const cookieSession = require('cookie-session'); +const app = express(); +const Ably = require("ably"); +const session = require("express-session"); +const MongoStore = require("connect-mongo")(session); +const cookieParser = require("cookie-parser"); // parse cookie header +const mongoose = require("mongoose"); +const {ensureAuth, ensureGuest} = require("./middleware/auth"); + + +// morgan logging +app.use(morgan("dev")); + +app.use(express.static("public")); +app.use(bodyParser.json()); + +app.use(cookieSession({ + name: "session", + keys: ["thisappisawesome"], + maxAge: 24 * 60 * 60 * 100 +})); + +// parse cookies +app.use(cookieParser()); + +// Sessions +app.use( + session({ + secret: 'keyboard cat', + resave: false, + saveUninitialized: false, + store: new MongoStore({mongooseConnection: mongoose.connection}) + }) +) + + +//////////////////////// MONGO STUFF //////////////////////// +const client = new mongodb.MongoClient(process.env.MONGO_URI, { + useNewUrlParser: true, + useUnifiedTopology: true +}); + +let collection = null; + +client.connect() + .then(() => { + return client.db('final-project').collection('users'); + }) + .then(__collection => { + collection = __collection; + + return collection.find({}).toArray(); + }) + .then(console.log("MongoDB Connected Successfully!")); + + +//////////////////////// PASSPORT JS STUFF //////////////////////// +app.use(passport.initialize()); +app.use(passport.session()); + + +passport.use(new LocalStrategy( + function (userName, passWord, done) { + collection.find({ + username: userName, + }).toArray() + .then(function (result) { + // successful login + if (result.length >= 1) { + console.log("Successful Login!") + console.log(result); + + // verify password + if (result[0].password === passWord) { + return done(null, userName, { + message: "Login Successful!" + }); + } else { + return done(null, null, { + message: "Incorrect username / password" + }); + } + } else { + // create new user + collection.insertOne({username: userName, password: passWord, score: 0}) + .then(() => { + return done(null, userName); + }); + } + }); + } +)); + +passport.serializeUser(function (user, done) { + done(null, user); +}); + +passport.deserializeUser(function (user, done) { + done(null, user); +}); + +//////////////////////// GAME VARS //////////////////////// + +const PLAYER_MOVEMENT_INCREMENT = 25; +const CANVAS_HEIGHT = 750; +const CANVAS_WIDTH = 1400; +const CANVAS_TO_ARRAY_HEIGHT_MODIFIER = (CANVAS_HEIGHT / PLAYER_MOVEMENT_INCREMENT) / CANVAS_HEIGHT +const CANVAS_TO_ARRAY_WIDTH_MODIFIER = (CANVAS_WIDTH / PLAYER_MOVEMENT_INCREMENT) / CANVAS_WIDTH +const PLAYER_VERTICAL_MOVEMENT_UPDATE_INTERVAL = 1000; +const PLAYER_SCORE_INCREMENT = 5; +const P2_WORLD_TIME_STEP = 1 / 16; +const OTHER_AXIS_RANGE = 20; +const SAME_AXIS_RANGE = 12; +const MIN_PLAYERS_TO_START_GAME = 4; +const PLAYER_MOVEMENT_OFFSET = PLAYER_MOVEMENT_INCREMENT / 2; + +const GAME_TICKER_MS = 500; + +let peopleAccessingTheWebsite = 0; +let players = {}; +let monsters = { + "Ada": {x: 687.5, y: 362.5, direction: 1}, + "Johny": {x: 687.5, y: 362.5, direction: 1}, + "Clay": {x: 687.5, y: 362.5, direction: 1}, + "Ivan": {x: 687.5, y: 362.5, direction: 1}, + "Bob": {x: 687.5, y: 362.5, direction: 1} +}; +let deadPlayersLeft = []; +let deadPlayers = new Array(); +let rankings = new Array(); +let coins = {}; // idea was to store this as an object so we can check if the size of the coins is 0 - at that point, the game is over +let walls = [ // 2d array of the whole board (walls) ( 1 is a wall, 0 is empty space that a player can occupy ) this will be 56x30 (each position is 25px). + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], + [1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1], + [1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1], + [1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1], + [1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1], + [1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1], + [1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1], + [1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1], + [1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1], + [1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], + [1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1], + [1, 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1], + [1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], + [1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1], + [1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1], + [1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1], + [1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1], + [1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1], + [1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 1], + [1, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 1], + [1, 0, 0, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1], + [1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1], + [1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1], + [1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1], + [1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1], + [1, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1], + [1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1], + [1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1], + [1, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1], + [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] +]; +let playerChannels = {}; +let gameOn = false; +let alivePlayers = 0; +let totalPlayers = 0; +let gameRoom; +let gameTickerOn = false; + +// spawn locations - these are currently hardcoded for a 1400x750px board +let spawnLocations = [{x: 1362.5, y: 712.5, occupied: false}, {x: 37.5, y: 712.5, occupied: false}, { + x: 1362.5, + y: 37.5, + occupied: false +}, {x: 37.5, y: 37.5, occupied: false}] +let boss = {x: 687.5, y: 362.5} + +let avatarColors = ["green", "cyan", "yellow"]; +let avatarTypes = ["A", "B", "C"]; + + +// setup ably +const realtime = new Ably.Realtime({ + key: process.env.ABLY_API_KEY, + echoMessages: false, +}); + + +///////////////////// GAME LOGIC //////////////////////// +function subscribeToPlayerInput(channelInstance, playerId) { + channelInstance.subscribe("pos", (msg) => { + if (msg.data.keyPressed === "left") { // direction is West + players[playerId].direction = 4; + } else if (msg.data.keyPressed === "right") { // direction is East + players[playerId].direction = 2; + } else if (msg.data.keyPressed === "up") { // direction is North + players[playerId].direction = 1; + } else if (msg.data.keyPressed === "down") { // direction is South + players[playerId].direction = 3; + } + // console.log( "Canvas W: " + CANVAS_WIDTH + // + ", Canvas H: "+ CANVAS_HEIGHT + // + ", Player X: " + players[playerId].x + // + ", Player Y: " + players[playerId].y ) + }); + +} + +// move all present players based on their keyboard input +function moveEveryPlayer() { + + Object.values(players).forEach(function (player) { + + + let tryDirection = player.direction; + let previousX = player.x; + let previousY = player.y; + + let movementDirection = (tryDirection === 1 || tryDirection === 3) ? 0 : 1; + + if (player.isAlive === false) { + //console.log("FOUND DEAD PLAYER: " + player.id); + } + + // can move in the current direction + if (player.isAlive && canMove(tryDirection, player)) { + // console.log( "We can move in this direction: " + tryDirection ) + if (tryDirection === 1) { // direction is North + player.y -= PLAYER_MOVEMENT_INCREMENT + checkIfDead(player.id, player.y, previousY, previousX, movementDirection) + + } else if (tryDirection === 2) { // direction is West + player.x += PLAYER_MOVEMENT_INCREMENT + checkIfDead(player.id, previousX, player.x, previousY, movementDirection) + + } else if (tryDirection === 3) { // direction is South + player.y += PLAYER_MOVEMENT_INCREMENT + checkIfDead(player.id, previousY, player.y, previousX, movementDirection) + + } else if (tryDirection === 4) { // direction is East + player.x -= PLAYER_MOVEMENT_INCREMENT + checkIfDead(player.id, player.x, previousX, previousY, movementDirection) + } + } + + if (player.isAlive) { + // check if any monster killed it + + let playerPosGrid = {x: Math.floor(player.x / 25), y: (Math.floor(player.y / 25))} + Object.values(monsters).forEach((monster) => { + let monsterPosGrid = {x: Math.floor(monster.x / 25), y: (Math.floor(monster.y / 25))} + + if (monsterPosGrid.x === playerPosGrid.x && monsterPosGrid.y === playerPosGrid.y) { + // player died + player.isAlive = false; + deadPlayers.push(player); + savePlayerScore(player.id); + } + }); + } + + //console.log( "My player " + player.id + " updated position: x = " + player.x + ", y = " + player.y ) + + //console.log("My player's updated position: x = " + player.x + ", y = " + player.y) + + player.score += collectCoin(Math.floor(player.x / 25), (Math.floor(player.y / 25))) + }) +} + +function getCoinId(x, y) { + if (x < 10) { + x = `0${x}` + } + + if (y < 10) { + y = `0${y}` + } + + return `${x}|${y}`; +} + +function collectCoin(x, y) { + let coordinates = getCoinId(x, y) + if (coordinates in coins) { + let score = coins[coordinates] + delete coins[coordinates] + return score + } + return 0 +} + + +function checkRange(positionVal, minimalRange, maxRange, constant) { + if ((positionVal >= (minimalRange - constant)) && + (positionVal <= (maxRange + constant))) { + return true; + + } + + return false; +} + + +function checkIfDead(id, minRange, maxRange, otherAxisVal, direction) { + let inRange = false; + + Object.values(players).forEach(function (player) { + + // checking players + if (player.id !== id && player.isAlive) { + // direction was vertical (SAME AXIS WOULD BE Y-AXIS) + if (direction === 0) { + + if (checkRange(player.y, minRange, maxRange, SAME_AXIS_RANGE) && + checkRange(player.x, otherAxisVal, otherAxisVal, OTHER_AXIS_RANGE)) { + inRange = true; + } + + } else { // direction was horizontal (SAME AXIS WOULD BE X-AXIS) + + if (checkRange(player.x, minRange, maxRange, SAME_AXIS_RANGE) && + checkRange(player.y, otherAxisVal, otherAxisVal, OTHER_AXIS_RANGE)) { + inRange = true; + } + } + + if (inRange) { + players[id].isAlive = false; + player.isAlive = false; + deadPlayers.push(player); + deadPlayers.push(players[id]); + savePlayerScore(id); + } + } + + inRange = false + }) +} + +function savePlayerScore(id) { + collection.findOne({username: id}).then((user) => { + if (user.score < players[id].score) { + collection + .updateOne( + {username: players[id].id}, + { + $set: {"score": players[id].score} + } + ) + } + }) +} + + +function withinBoundary(x, y) { + if (x >= 0 && x <= CANVAS_WIDTH) { + if (y >= 0 && y <= CANVAS_HEIGHT) { + return true; + } + } + + return false; +} + +function gameHasEnded() { + let numOfDeadPlayers = deadPlayers.length + + let count = Object.keys(coins).length + + // do no know if this works + if (count === 0) { + return true; + } + + //console.log(numOfDeadPlayers) + //console.log(totalPlayers) + + if (totalPlayers > 1) { + if (numOfDeadPlayers === totalPlayers || numOfDeadPlayers === (totalPlayers - 1)) { + return true; + } + + } else if (totalPlayers === 1) { + if (numOfDeadPlayers === totalPlayers) { + return true; + } + } + + + return false; +} + + +function finishGame() { + + console.log("Dead Players = " + deadPlayers.length) + console.log("Alive Players = " + alivePlayers) + + let winnerName = "Nobody"; + + Object.values(players).forEach(function (player) { + rankings.push({ + name: player.id, + score: player.score, + }); + collection + .updateOne( + {username: player.id}, + { + $set: {"score": player.score} + } + ) + }); + + rankings.sort((a, b) => { + return b.score - a.score; + }); + + if (totalPlayers === 1) { + winnerName = rankings[0].name; + + } else if (rankings[0].score !== rankings[1].score) { + winnerName = rankings[0].name; + } + + + gameRoom.publish("game-over", { + winner: winnerName, + totalPlayers: totalPlayers, + }); + + console.log("GAME OVER"); + resetServerState(); +} + + +// check if a player's move would be valid +// check against game boundaries +// check against wall locations +function canMove(direction, player) { + + if (players[player.id] === null) { + return false; + } + + let positionX = player.x; + let positionY = player.y; + + // console.log( "My current location: Pixels - " + positionX + ", " + positionY ". Array - " ) + + var positionXArray = 1 + var positionYArray = 1 + //console.log("My direction: " + direction) + if (direction === 1) { // direction is North + positionY -= PLAYER_MOVEMENT_INCREMENT; + positionXArray = (positionX - PLAYER_MOVEMENT_OFFSET) * CANVAS_TO_ARRAY_WIDTH_MODIFIER + positionYArray = (positionY - PLAYER_MOVEMENT_OFFSET) * CANVAS_TO_ARRAY_HEIGHT_MODIFIER + + + } else if (direction === 2) { // direction is East + positionX += PLAYER_MOVEMENT_INCREMENT; + positionXArray = (positionX - PLAYER_MOVEMENT_OFFSET) * CANVAS_TO_ARRAY_WIDTH_MODIFIER + positionYArray = (positionY - PLAYER_MOVEMENT_OFFSET) * CANVAS_TO_ARRAY_HEIGHT_MODIFIER + + } else if (direction === 3) { // direction is South + positionY += PLAYER_MOVEMENT_INCREMENT; + positionXArray = (positionX - PLAYER_MOVEMENT_OFFSET) * CANVAS_TO_ARRAY_WIDTH_MODIFIER + positionYArray = (positionY + PLAYER_MOVEMENT_OFFSET) * CANVAS_TO_ARRAY_HEIGHT_MODIFIER - 1 + + } else if (direction === 4) { // direction is West + positionX -= PLAYER_MOVEMENT_INCREMENT; + positionXArray = (positionX + PLAYER_MOVEMENT_OFFSET) * CANVAS_TO_ARRAY_WIDTH_MODIFIER - 1 + positionYArray = (positionY - PLAYER_MOVEMENT_OFFSET) * CANVAS_TO_ARRAY_HEIGHT_MODIFIER + } + + if (!withinBoundary(positionXArray, positionYArray)) { + console.log("Error! That would be outside of the boundary. X: " + positionX + ", Y: " + positionY) + return false; + } + + //checking if wall is present + + //console.log( "destination coordinates: Pixels - " + positionX + ", " + positionY + ". Array - " + positionYArray + ", " + positionXArray ) + // console.log( "That space contains: " + walls[positionYArray][positionXArray] ) + if (walls[positionYArray][positionXArray] === 1) { + //console.log("There is a wall here") + return false; + } else { + return true + } + +} + +function moveAllMonsters() { + Object.values(monsters).forEach(function (monster) { + let backwards = 1 + switch (monster.direction) { + case 1: + backwards = 3 + break + case 2: + backwards = 4 + break + case 3: + backwards = 1 + break + case 4: + backwards = 2 + break + } + let newDirection = getRandomAvailableDir(monster, backwards) + monster.direction = newDirection + + if (newDirection === 1) { // direction is North + monster.y -= PLAYER_MOVEMENT_INCREMENT + + } else if (newDirection === 2) { // direction is West + monster.x += PLAYER_MOVEMENT_INCREMENT + + } else if (newDirection === 3) { // direction is South + monster.y += PLAYER_MOVEMENT_INCREMENT + + } else if (newDirection === 4) { // direction is East + monster.x -= PLAYER_MOVEMENT_INCREMENT + } + // console.log("Monster's new position: " + monster.x + ", " + monster.y) + + let monsterPosGrid = {x: Math.floor(monster.x / 25), y: (Math.floor(monster.y / 25))} + + // check if monster kills any player at this position + Object.values(players).forEach(function (player) { + if (player.isAlive) { + // check if any monster killed it + let playerPosGrid = {x: Math.floor(player.x / 25), y: (Math.floor(player.y / 25))} + if (monsterPosGrid.x === playerPosGrid.x && monsterPosGrid.y === playerPosGrid.y) { + // player died + player.isAlive = false; + deadPlayers.push(player); + savePlayerScore(player.id); + } + } + }) + } + ) +} + +function moveBoss() { + // get the closes player target + let agroRange = 1300; //TODO: maybe change later + let closestPlayerSoFar = null; + let closestDistanceSoFar = 1000000; + for (let playerId in players) { + if (players[playerId].isAlive) { + let distance = Math.sqrt(Math.pow(boss.x - players[playerId].x, 2) + Math.pow(boss.y - players[playerId].y, 2)); + + if (distance < closestDistanceSoFar && distance <= agroRange) { + closestPlayerSoFar = players[playerId] + closestDistanceSoFar = distance + } + } + } + + if (closestPlayerSoFar != null) { + // we have a target + + let targetGridNode = {x: Math.floor(closestPlayerSoFar.x / 25), y: (Math.floor(closestPlayerSoFar.y / 25))}; + let currentGridNode = {x: Math.floor(boss.x / 25), y: (Math.floor(boss.y / 25))}; + + let pathToTheUser = findPathAStar(currentGridNode, targetGridNode); + + if (pathToTheUser.length > 1) { + boss.x = ((pathToTheUser[1].x + 1) * 25) - Math.floor(25 / 2) + boss.y = ((pathToTheUser[1].y + 1) * 25) - Math.floor(25 / 2) + + // check if boss kills the player + if (pathToTheUser[1].x === targetGridNode.x && pathToTheUser[1].y === targetGridNode.y) { + // death + players[closestPlayerSoFar.id].isAlive = false; + deadPlayers.push(closestPlayerSoFar); + savePlayerScore(closestPlayerSoFar.id); + } + } + } +} + +function getRandomAvailableDir(monster, backwards) { + let available = [] + for (let i = 1; i < 5; i++) { + if (i !== backwards && canMove(i, monster)) { + available.push(i) + } + } + //console.log(available, backwards) + if (available.length === 0) return backwards + return available[Math.floor(Math.random() * available.length)] +} + + +const startGameDataTicker = function () { + + for (let i = 0; i < walls[0].length; i++) { + for (let j = 0; j < walls.length; j++) { + if (walls[j][i] === 0) { + let id = getCoinId(i, j) + let coin = 5 + coins[id] = coin + } + } + } + + let tickInterval = setInterval(() => { + if (!gameTickerOn) { + clearInterval(tickInterval); + } else { + // move every player + moveEveryPlayer(); + moveAllMonsters(); + moveBoss(); + gameRoom.publish("game-state", { + players: players, + playerCount: totalPlayers, + gameOn: gameOn, + monsters: monsters, + boss: boss, + coins + }); + + // right here check for end game + if (gameHasEnded()) { + finishGame(); + } + } + }, GAME_TICKER_MS); +} + + +const handlePlayerEntered = function (player) { + + let playedBefore = false; + + console.log(player.clientId); + + deadPlayersLeft.forEach((player) => { + if (player.id === player.clientId) + playedBefore = true; + }) + + if (!playedBefore) { + + let newPlayerId; + alivePlayers++; + totalPlayers++; + + let xPos; + let yPos; + if (totalPlayers === 1) { + gameTickerOn = true; + startGameDataTicker(); + } + + newPlayerId = player.clientId; + playerChannels[newPlayerId] = realtime.channels.get( + "clientChannel-" + player.clientId + ); + + + // check through the spawn locations to find a location that has not been used yet + + + for (location of spawnLocations) { + if (location.occupied === false) { + xPos = location.x + yPos = location.y + location.occupied = true + break; + } + } + + //TODO figure out how to spawn them in a smarter way + + let newPlayerObject = { + id: newPlayerId, + x: xPos, + y: yPos, + invaderAvatarType: avatarTypes[randomAvatarSelector()], // get from db + invaderAvatarColor: avatarColors[randomAvatarSelector()], + direction: 0, + score: 0, + isAlive: true + }; + + players[newPlayerId] = newPlayerObject; + subscribeToPlayerInput(playerChannels[newPlayerId], newPlayerId); + } +} + +const handlePlayerLeft = function (player) { + let leavingPlayer = player.clientId; + alivePlayers--; + totalPlayers--; + + deadPlayersLeft = deadPlayers; + + console.log("before: ", deadPlayers.length); + + deadPlayers = deadPlayers.filter((deadPlayer) => deadPlayer.id === player.id); + + console.log("after: ", deadPlayers.length); + + delete players[leavingPlayer]; + if (totalPlayers <= 0) { + resetServerState(); + } + + // unsubscribe from players channel + playerChannels[leavingPlayer].unsubscribe(); +} + +function resetServerState() { + peopleAccessingTheWebsite = 0; + gameOn = false; + gameTickerOn = false; + totalPlayers = 0; + alivePlayers = 0; + deadPlayers = []; + spawnLocations = [{x: 1362.5, y: 712.5, occupied: false}, {x: 37.5, y: 712.5, occupied: false}, { + x: 1362.5, + y: 37.5, + occupied: false + }, {x: 37.5, y: 37.5, occupied: false}] + + deadPlayersLeft = [] + + monsters = { + "Ada": {x: 687.5, y: 362.5, direction: 1}, + "Johny": {x: 687.5, y: 362.5, direction: 1}, + "Clay": {x: 687.5, y: 362.5, direction: 1}, + "Ivan": {x: 687.5, y: 362.5, direction: 1}, + "Bob": {x: 687.5, y: 362.5, direction: 1} + }; + + boss = {x: 687.5, y: 362.5}; + + for (let item in playerChannels) { + playerChannels[item].unsubscribe(); + } +} + +function randomAvatarSelector() { + return Math.floor(Math.random() * 3); +} + + +///////////////////// END GAME LOGIC //////////////////////// + +// initialize channels and channel-listeners +realtime.connection.once("connected", () => { + gameRoom = realtime.channels.get("game-room"); + gameRoom.presence.subscribe("enter", (player) => handlePlayerEntered(player)); + gameRoom.presence.subscribe("leave", (player) => handlePlayerLeft(player)); +}); + + +// routes +app.get("/auth/game", (request, response) => { + const tokenParams = {clientId: request.user}; + realtime.auth.createTokenRequest(tokenParams, function (err, tokenRequest) { + if (err) { + response + .status(500) + .send("Error requesting token: " + JSON.stringify(err)); + } else { + response.setHeader("Content-Type", "application/json"); + response.send(JSON.stringify(tokenRequest)); + } + }); +}); + +app.get("/getBoard", bodyParser.json(), (req, res) => res.json(walls)) + +app.get("/topScores", bodyParser.json(), (req, res) => { + collection.find().project({ + username: 1, + score: 1 + }).sort({score: -1}).limit(10).toArray().then(result => res.json(result)) +}) + +app.get('/', ensureAuth, (req, res) => { + res.sendFile(__dirname + "/views/home.html"); +}); + +app.get('/login', ensureGuest, (req, res) => { + res.sendFile(__dirname + "/views/login.html"); +}); + +app.get('/game', ensureAuth, (req, res) => { + peopleAccessingTheWebsite++; + + let personPlayedBefore = false; + + deadPlayersLeft.forEach((player) => { + if (player.id === req.user) { + console.log("dead player: ", player.id); + console.log("user entering ", req.user); + personPlayedBefore = true; + } + }) + + + if (peopleAccessingTheWebsite > MIN_PLAYERS_TO_START_GAME || personPlayedBefore) { + res.sendFile(__dirname + "/views/gameRoomFull.html") + } else { + res.sendFile(__dirname + "/views/game.html"); + } +}); + +app.get('/auth/logout', (req, res) => { + req.logout(); + res.redirect('/login') +}); + +app.post("/auth/signin", passport.authenticate('local', {failureRedirect: '/login'}), (req, res) => { + res.redirect('/'); +}); + +app.listen(process.env.PORT, () => { + console.log("Server is listening on port: ", process.env.PORT); +}); + + +////////////////// A* stuff ////////////////// + +function findPathAStar(startGridNode, targetGridNode) { + let frontier = new PriorityQueue(); + let cameFrom = {}; + let costSoFar = {}; + frontier.enqueue(startGridNode, 0); + cameFrom[`${startGridNode.x}|${startGridNode.y}`] = ""; + costSoFar[`${startGridNode.x}|${startGridNode.y}`] = 0; + + while (!frontier.isEmpty()) { + let currentGridNode = frontier.dequeue().element; + let currentNodeId = `${currentGridNode.x}|${currentGridNode.y}`; + + // if the target nod was found, break + if (currentGridNode.x === targetGridNode.x && currentGridNode.y === targetGridNode.y) { + break; + } + + // for every legal node current node has edge to: + let legalNodes = getLegalGridConnections(currentGridNode); + legalNodes.forEach(nextNode => { + let nextNodeId = `${nextNode.x}|${nextNode.y}`; + + // calculate the cost of next node + let newCost = costSoFar[currentNodeId] + cost(nextNode, currentGridNode); + + if (!costSoFar[nextNodeId] || newCost < costSoFar[nextNodeId]) { + // update the cost of next node + costSoFar[nextNodeId] = newCost; + + // calculate and update the priority of nextNode + let priority = newCost + heuristic(nextNode, targetGridNode); + frontier.enqueue(nextNode, priority); + + // keep track of where nodes come from + // to generate the path to goal node + cameFrom[nextNodeId] = currentNodeId; + } + }) + } + + return generatePath(startGridNode, targetGridNode, cameFrom); +} + +function generatePath(startGridNode, targetGridNode, cameFrom) { + let path = []; + let currentId = `${targetGridNode.x}|${targetGridNode.y}`; + + path.unshift(targetGridNode) + + while (currentId !== `${startGridNode.x}|${startGridNode.y}`) { + currentId = cameFrom[currentId]; + + let coordArray = currentId.split("|"); + let node = {x: parseInt(coordArray[0]), y: parseInt(coordArray[1])} + + path.unshift(node) + } + + return path; +} + +function getLegalGridConnections(gridNode) { + let legalNodes = []; + + if (walls[gridNode.y + 1][gridNode.x] !== 1) { + legalNodes.push({x: gridNode.x, y: gridNode.y + 1}) + } + if (walls[gridNode.y - 1][gridNode.x] !== 1) { + legalNodes.push({x: gridNode.x, y: gridNode.y - 1}) + } + if (walls[gridNode.y][gridNode.x + 1] !== 1) { + legalNodes.push({x: gridNode.x + 1, y: gridNode.y}) + } + if (walls[gridNode.y][gridNode.x - 1] !== 1) { + legalNodes.push({x: gridNode.x - 1, y: gridNode.y}) + } + + return legalNodes; +} + + +function cost(currentLocation, nextLocation) { + return Math.sqrt(Math.pow(currentLocation.x - nextLocation.x, 2) + Math.pow(currentLocation.y - nextLocation.y, 2)); +} + +function heuristic(currentLocation, goalLocation) { + return Math.abs(goalLocation.x - currentLocation.x) + Math.abs(goalLocation.y - currentLocation.y); +} + +// User defined class +// to store element and its priority +class QElement { + constructor(element, priority) { + this.element = element; + this.priority = priority; + } +} + +// PriorityQueue class +class PriorityQueue { + + // An array is used to implement priority + constructor() { + this.items = []; + } + + // enqueue function to add element + // to the queue as per priority + enqueue(element, priority) { + // creating object from queue element + let qElement = new QElement(element, priority); + let contain = false; + + // iterating through the entire + // item array to add element at the + // correct location of the Queue + for (let i = 0; i < this.items.length; i++) { + if (this.items[i].priority > qElement.priority) { + // Once the correct location is found it is + // enqueued + this.items.splice(i, 0, qElement); + contain = true; + break; + } + } + + // if the element have the highest priority + // it is added at the end of the queue + if (!contain) { + this.items.push(qElement); + } + } + + // dequeue method to remove + // element from the queue + dequeue() { + // return the dequeued element + // and remove it. + // if the queue is empty + // returns null + if (this.isEmpty()) + return null; + return this.items.shift(); + } + + // front function + front() { + // returns the highest priority element + // in the Priority queue without removing it. + if (this.isEmpty()) + return null; + let item = this.items[0]; + return item; + } + + // rear function + rear() { + // returns the lowest priorty + // element of the queue + if (this.isEmpty()) + return null; + return this.items[this.items.length - 1]; + } + + // isEmpty function + isEmpty() { + // return true if the queue is empty. + return this.items.length === 0; + } + + // printQueue function + // prints all the element of the queue + printPQueue() { + let str = ""; + for (let i = 0; i < this.items.length; i++) + str += this.items[i].element + " "; + return str; + } +} diff --git a/test b/test new file mode 100644 index 000000000..1c77e3627 --- /dev/null +++ b/test @@ -0,0 +1,856 @@ +{ + '3|2': 5, + '3|3': 5, + '1|1': 5, + '1|3': 5, + '1|4': 5, + '1|5': 5, + '1|7': 5, + '1|8': 5, + '1|9': 5, + '1|11': 5, + '1|13': 5, + '1|15': 5, + '1|17': 5, + '1|19': 5, + '1|20': 5, + '1|22': 5, + '1|23': 5, + '1|24': 5, + '1|26': 5, + '1|27': 5, + '1|28': 5, + '2|1': 5, + '2|3': 5, + '2|5': 5, + '2|9': 5, + '2|11': 5, + '2|13': 5, + '2|15': 5, + '2|17': 5, + '2|19': 5, + '2|20': 5, + '2|21': 5, + '2|22': 5, + '2|26': 5, + '3|1': 5, + '3|5': 5, + '3|7': 5, + '3|8': 5, + '3|9': 5, + '3|11': 5, + '3|12': 5, + '3|13': 5, + '3|14': 5, + '3|15': 5, + '3|16': 5, + '3|17': 5, + '3|18': 5, + '3|19': 5, + '3|22': 5, + '3|23': 5, + '3|24': 5, + '3|25': 5, + '3|26': 5, + '3|27': 5, + '3|28': 5, + '4|3': 5, + '4|4': 5, + '4|5': 5, + '4|7': 5, + '4|11': 5, + '4|23': 5, + '4|28': 5, + '5|1': 5, + '5|5': 5, + '5|6': 5, + '5|7': 5, + '5|8': 5, + '5|9': 5, + '5|10': 5, + '5|11': 5, + '5|12': 5, + '5|13': 5, + '5|14': 5, + '5|15': 5, + '5|16': 5, + '5|17': 5, + '5|18': 5, + '5|20': 5, + '5|22': 5, + '5|23': 5, + '5|24': 5, + '5|26': 5, + '5|27': 5, + '5|28': 5, + '6|1': 5, + '6|3': 5, + '6|4': 5, + '6|5': 5, + '6|7': 5, + '6|12': 5, + '6|16': 5, + '6|20': 5, + '6|22': 5, + '6|24': 5, + '6|25': 5, + '6|26': 5, + '7|1': 5, + '7|2': 5, + '7|3': 5, + '7|4': 5, + '7|7': 5, + '7|8': 5, + '7|10': 5, + '7|11': 5, + '7|12': 5, + '7|14': 5, + '7|15': 5, + '7|16': 5, + '7|18': 5, + '7|19': 5, + '7|20': 5, + '7|21': 5, + '7|22': 5, + '7|25': 5, + '7|28': 5, + '8|2': 5, + '8|12': 5, + '8|13': 5, + '8|14': 5, + '8|16': 5, + '8|18': 5, + '8|22': 5, + '8|23': 5, + '8|25': 5, + '8|26': 5, + '8|28': 5, + '9|1': 5, + '9|2': 5, + '9|4': 5, + '9|5': 5, + '9|6': 5, + '9|7': 5, + '9|8': 5, + '9|9': 5, + '9|10': 5, + '9|16': 5, + '9|17': 5, + '9|18': 5, + '9|20': 5, + '9|26': 5, + '9|27': 5, + '9|28': 5, + '10|1': 5, + '10|4': 5, + '10|6': 5, + '10|7': 5, + '10|10': 5, + '10|12': 5, + '10|13': 5, + '10|15': 5, + '10|16': 5, + '10|20': 5, + '10|21': 5, + '10|22': 5, + '10|23': 5, + '10|24': 5, + '10|26': 5, + '11|1': 5, + '11|2': 5, + '11|4': 5, + '11|7': 5, + '11|8': 5, + '11|9': 5, + '11|10': 5, + '11|13': 5, + '11|14': 5, + '11|15': 5, + '11|18': 5, + '11|19': 5, + '11|20': 5, + '11|24': 5, + '11|26': 5, + '11|27': 5, + '11|28': 5, + '12|2': 5, + '12|4': 5, + '12|6': 5, + '12|7': 5, + '12|10': 5, + '12|11': 5, + '12|12': 5, + '12|13': 5, + '12|15': 5, + '12|18': 5, + '12|22': 5, + '12|24': 5, + '12|28': 5, + '13|1': 5, + '13|2': 5, + '13|4': 5, + '13|5': 5, + '13|6': 5, + '13|7': 5, + '13|9': 5, + '13|10': 5, + '13|11': 5, + '13|15': 5, + '13|16': 5, + '13|17': 5, + '13|18': 5, + '13|19': 5, + '13|20': 5, + '13|21': 5, + '13|22': 5, + '13|23': 5, + '13|24': 5, + '13|26': 5, + '13|27': 5, + '13|28': 5, + '14|2': 5, + '14|4': 5, + '14|7': 5, + '14|11': 5, + '14|12': 5, + '14|13': 5, + '14|17': 5, + '14|19': 5, + '14|22': 5, + '14|24': 5, + '14|26': 5, + '15|1': 5, + '15|2': 5, + '15|3': 5, + '15|4': 5, + '15|6': 5, + '15|7': 5, + '15|8': 5, + '15|10': 5, + '15|11': 5, + '15|13': 5, + '15|15': 5, + '15|16': 5, + '15|17': 5, + '15|19': 5, + '15|21': 5, + '15|22': 5, + '15|24': 5, + '15|26': 5, + '15|27': 5, + '15|28': 5, + '16|4': 5, + '16|8': 5, + '16|11': 5, + '16|13': 5, + '16|16': 5, + '16|19': 5, + '16|21': 5, + '16|24': 5, + '16|26': 5, + '16|27': 5, + '16|28': 5, + '17|1': 5, + '17|4': 5, + '17|5': 5, + '17|6': 5, + '17|7': 5, + '17|8': 5, + '17|10': 5, + '17|11': 5, + '17|13': 5, + '17|14': 5, + '17|15': 5, + '17|16': 5, + '17|17': 5, + '17|19': 5, + '17|21': 5, + '17|22': 5, + '17|24': 5, + '17|25': 5, + '17|26': 5, + '17|27': 5, + '17|28': 5, + '18|1': 5, + '18|2': 5, + '18|3': 5, + '18|4': 5, + '18|8': 5, + '18|13': 5, + '18|15': 5, + '19|3': 5, + '19|6': 5, + '19|7': 5, + '19|8': 5, + '19|9': 5, + '19|11': 5, + '19|12': 5, + '19|13': 5, + '19|15': 5, + '19|16': 5, + '19|17': 5, + '19|18': 5, + '19|19': 5, + '19|20': 5, + '19|21': 5, + '19|22': 5, + '19|23': 5, + '19|24': 5, + '19|25': 5, + '19|26': 5, + '19|27': 5, + '19|28': 5, + '20|1': 5, + '20|2': 5, + '20|3': 5, + '20|5': 5, + '20|6': 5, + '20|8': 5, + '20|9': 5, + '20|11': 5, + '20|17': 5, + '20|22': 5, + '20|26': 5, + '20|28': 5, + '21|2': 5, + '21|5': 5, + '21|9': 5, + '21|10': 5, + '21|11': 5, + '21|12': 5, + '21|13': 5, + '21|15': 5, + '21|16': 5, + '21|17': 5, + '21|18': 5, + '21|19': 5, + '21|21': 5, + '21|22': 5, + '21|24': 5, + '21|25': 5, + '21|26': 5, + '21|28': 5, + '22|1': 5, + '22|2': 5, + '22|7': 5, + '22|8': 5, + '22|9': 5, + '22|13': 5, + '22|14': 5, + '22|15': 5, + '22|17': 5, + '22|19': 5, + '22|20': 5, + '22|21': 5, + '22|22': 5, + '22|23': 5, + '22|24': 5, + '22|28': 5, + '23|2': 5, + '23|4': 5, + '23|5': 5, + '23|8': 5, + '23|9': 5, + '23|10': 5, + '23|11': 5, + '23|13': 5, + '23|17': 5, + '23|23': 5, + '23|24': 5, + '23|25': 5, + '23|27': 5, + '23|28': 5, + '24|1': 5, + '24|2': 5, + '24|5': 5, + '24|7': 5, + '24|8': 5, + '24|10': 5, + '24|11': 5, + '24|13': 5, + '24|14': 5, + '24|15': 5, + '24|16': 5, + '24|17': 5, + '24|18': 5, + '24|19': 5, + '24|20': 5, + '24|21': 5, + '24|25': 5, + '24|28': 5, + '25|1': 5, + '25|4': 5, + '25|5': 5, + '25|6': 5, + '25|7': 5, + '25|8': 5, + '25|14': 5, + '25|17': 5, + '25|20': 5, + '25|21': 5, + '25|22': 5, + '25|23': 5, + '25|24': 5, + '25|25': 5, + '25|26': 5, + '25|28': 5, + '26|1': 5, + '26|2': 5, + '26|3': 5, + '26|4': 5, + '26|8': 5, + '26|9': 5, + '26|10': 5, + '26|11': 5, + '26|13': 5, + '26|14': 5, + '26|15': 5, + '26|17': 5, + '26|19': 5, + '26|20': 5, + '26|24': 5, + '26|28': 5, + '27|6': 5, + '27|8': 5, + '27|11': 5, + '27|12': 5, + '27|13': 5, + '27|14': 5, + '27|15': 5, + '27|16': 5, + '27|17': 5, + '27|22': 5, + '27|23': 5, + '27|24': 5, + '27|25': 5, + '27|26': 5, + '27|27': 5, + '27|28': 5, + '28|1': 5, + '28|2': 5, + '28|3': 5, + '28|4': 5, + '28|5': 5, + '28|6': 5, + '28|8': 5, + '28|9': 5, + '28|11': 5, + '28|13': 5, + '28|14': 5, + '28|15': 5, + '28|17': 5, + '28|18': 5, + '28|19': 5, + '28|21': 5, + '28|22': 5, + '28|26': 5, + '29|1': 5, + '29|3': 5, + '29|6': 5, + '29|8': 5, + '29|11': 5, + '29|14': 5, + '29|19': 5, + '29|22': 5, + '29|24': 5, + '29|26': 5, + '29|27': 5, + '29|28': 5, + '30|1': 5, + '30|3': 5, + '30|4': 5, + '30|5': 5, + '30|6': 5, + '30|7': 5, + '30|8': 5, + '30|9': 5, + '30|10': 5, + '30|11': 5, + '30|13': 5, + '30|14': 5, + '30|15': 5, + '30|16': 5, + '30|17': 5, + '30|18': 5, + '30|19': 5, + '30|21': 5, + '30|22': 5, + '30|23': 5, + '30|24': 5, + '30|28': 5, + '31|1': 5, + '31|2': 5, + '31|3': 5, + '31|8': 5, + '31|10': 5, + '31|11': 5, + '31|13': 5, + '31|17': 5, + '31|19': 5, + '31|21': 5, + '31|24': 5, + '31|25': 5, + '31|26': 5, + '31|27': 5, + '31|28': 5, + '32|2': 5, + '32|5': 5, + '32|7': 5, + '32|8': 5, + '32|10': 5, + '32|13': 5, + '32|14': 5, + '32|15': 5, + '32|17': 5, + '32|21': 5, + '32|22': 5, + '32|24': 5, + '32|26': 5, + '33|1': 5, + '33|2': 5, + '33|3': 5, + '33|4': 5, + '33|5': 5, + '33|9': 5, + '33|10': 5, + '33|11': 5, + '33|12': 5, + '33|13': 5, + '33|15': 5, + '33|16': 5, + '33|17': 5, + '33|18': 5, + '33|19': 5, + '33|20': 5, + '33|21': 5, + '33|22': 5, + '33|24': 5, + '33|26': 5, + '33|27': 5, + '33|28': 5, + '34|1': 5, + '34|3': 5, + '34|5': 5, + '34|6': 5, + '34|7': 5, + '34|8': 5, + '34|9': 5, + '34|10': 5, + '34|12': 5, + '34|15': 5, + '34|20': 5, + '34|22': 5, + '34|23': 5, + '34|24': 5, + '34|25': 5, + '34|26': 5, + '34|28': 5, + '35|1': 5, + '35|5': 5, + '35|7': 5, + '35|10': 5, + '35|12': 5, + '35|13': 5, + '35|14': 5, + '35|15': 5, + '35|17': 5, + '35|19': 5, + '35|20': 5, + '35|23': 5, + '35|28': 5, + '36|1': 5, + '36|2': 5, + '36|3': 5, + '36|7': 5, + '36|8': 5, + '36|9': 5, + '36|10': 5, + '36|11': 5, + '36|12': 5, + '36|14': 5, + '36|15': 5, + '36|16': 5, + '36|17': 5, + '36|18': 5, + '36|19': 5, + '36|22': 5, + '36|23': 5, + '36|25': 5, + '36|26': 5, + '37|1': 5, + '37|3': 5, + '37|4': 5, + '37|5': 5, + '37|8': 5, + '37|11': 5, + '37|12': 5, + '37|14': 5, + '37|16': 5, + '37|17': 5, + '37|19': 5, + '37|20': 5, + '37|21': 5, + '37|22': 5, + '37|26': 5, + '37|27': 5, + '37|28': 5, + '38|5': 5, + '38|7': 5, + '38|8': 5, + '38|9': 5, + '38|17': 5, + '38|20': 5, + '38|22': 5, + '38|23': 5, + '38|24': 5, + '38|25': 5, + '38|26': 5, + '39|1': 5, + '39|2': 5, + '39|3': 5, + '39|4': 5, + '39|5': 5, + '39|6': 5, + '39|7': 5, + '39|9': 5, + '39|11': 5, + '39|12': 5, + '39|14': 5, + '39|15': 5, + '39|16': 5, + '39|17': 5, + '39|19': 5, + '39|20': 5, + '39|26': 5, + '39|27': 5, + '39|28': 5, + '40|1': 5, + '40|3': 5, + '40|6': 5, + '40|7': 5, + '40|8': 5, + '40|9': 5, + '40|12': 5, + '40|14': 5, + '40|16': 5, + '40|17': 5, + '40|20': 5, + '40|22': 5, + '40|24': 5, + '40|28': 5, + '41|1': 5, + '41|3': 5, + '41|4': 5, + '41|8': 5, + '41|12': 5, + '41|13': 5, + '41|14': 5, + '41|17': 5, + '41|19': 5, + '41|20': 5, + '41|21': 5, + '41|22': 5, + '41|23': 5, + '41|24': 5, + '41|25': 5, + '41|26': 5, + '41|28': 5, + '42|6': 5, + '42|7': 5, + '42|8': 5, + '42|9': 5, + '42|10': 5, + '42|14': 5, + '42|16': 5, + '42|17': 5, + '42|20': 5, + '42|21': 5, + '42|24': 5, + '42|28': 5, + '43|1': 5, + '43|2': 5, + '43|3': 5, + '43|4': 5, + '43|5': 5, + '43|6': 5, + '43|9': 5, + '43|10': 5, + '43|12': 5, + '43|14': 5, + '43|17': 5, + '43|18': 5, + '43|21': 5, + '43|22': 5, + '43|26': 5, + '43|27': 5, + '43|28': 5, + '44|1': 5, + '44|2': 5, + '44|4': 5, + '44|6': 5, + '44|7': 5, + '44|10': 5, + '44|11': 5, + '44|12': 5, + '44|13': 5, + '44|14': 5, + '44|15': 5, + '44|18': 5, + '44|22': 5, + '44|23': 5, + '44|24': 5, + '44|26': 5, + '45|1': 5, + '45|4': 5, + '45|7': 5, + '45|8': 5, + '45|12': 5, + '45|14': 5, + '45|17': 5, + '45|18': 5, + '45|19': 5, + '45|20': 5, + '45|26': 5, + '45|27': 5, + '45|28': 5, + '46|1': 5, + '46|2': 5, + '46|4': 5, + '46|5': 5, + '46|8': 5, + '46|9': 5, + '46|12': 5, + '46|14': 5, + '46|15': 5, + '46|17': 5, + '46|18': 5, + '46|20': 5, + '46|22': 5, + '46|23': 5, + '46|24': 5, + '46|28': 5, + '47|2': 5, + '47|5': 5, + '47|9': 5, + '47|12': 5, + '47|15': 5, + '47|20': 5, + '47|22': 5, + '47|24': 5, + '47|25': 5, + '47|26': 5, + '47|28': 5, + '48|1': 5, + '48|2': 5, + '48|4': 5, + '48|5': 5, + '48|6': 5, + '48|7': 5, + '48|9': 5, + '48|10': 5, + '48|11': 5, + '48|12': 5, + '48|13': 5, + '48|14': 5, + '48|15': 5, + '48|16': 5, + '48|17': 5, + '48|18': 5, + '48|20': 5, + '48|21': 5, + '48|22': 5, + '48|24': 5, + '48|26': 5, + '48|27': 5, + '48|28': 5, + '49|01': 5, + '49|07': 5, + '49|09': 5, + '49|12': 5, + '49|15': 5, + '49|17': 5, + '49|24': 5, + '49|28': 5, + '50|01': 5, + '50|03': 5, + '50|04': 5, + '50|06': 5, + '50|07': 5, + '50|09': 5, + '50|11': 5, + '50|12': 5, + '50|14': 5, + '50|15': 5, + '50|17': 5, + '50|18': 5, + '50|19': 5, + '50|20': 5, + '50|21': 5, + '50|22': 5, + '50|23': 5, + '50|24': 5, + '50|25': 5, + '50|26': 5, + '50|28': 5, + '51|01': 5, + '51|04': 5, + '51|06': 5, + '51|09': 5, + '51|10': 5, + '51|12': 5, + '51|18': 5, + '51|22': 5, + '51|24': 5, + '51|26': 5, + '52|01': 5, + '52|02': 5, + '52|03': 5, + '52|04': 5, + '52|05': 5, + '52|06': 5, + '52|07': 5, + '52|09': 5, + '52|12': 5, + '52|14': 5, + '52|15': 5, + '52|16': 5, + '52|17': 5, + '52|18': 5, + '52|19': 5, + '52|22': 5, + '52|24': 5, + '52|26': 5, + '52|27': 5, + '52|28': 5, + '53|03': 5, + '53|07': 5, + '53|09': 5, + '53|10': 5, + '53|11': 5, + '53|12': 5, + '53|14': 5, + '53|19': 5, + '53|20': 5, + '53|26': 5, + '53|28': 5, + '54|01': 5, + '54|02': 5, + '54|03': 5, + '54|05': 5, + '54|06': 5, + '54|07': 5, + '54|09': 5, + '54|12': 5, + '54|14': 5, + '54|15': 5, + '54|16': 5, + '54|17': 5, + '54|20': 5, + '54|21': 5, + '54|22': 5, + '54|23': 5, + '54|24': 5, + '54|25': 5, + '54|26': 5, + '54|28': 5 +} diff --git a/views/game.html b/views/game.html new file mode 100644 index 000000000..73d6eb07a --- /dev/null +++ b/views/game.html @@ -0,0 +1,36 @@ + + + + + Game + + + + + + + + +
+
+ + +
+ +
+ + +
+
+ + + + + + diff --git a/views/gameRoomFull.html b/views/gameRoomFull.html new file mode 100644 index 000000000..d23bf89d8 --- /dev/null +++ b/views/gameRoomFull.html @@ -0,0 +1,37 @@ + + + + + Game Full + + + + + + +
+ Space invaders + +
+

+ SORRY, YOU ARE LATE, THIS GAME ROOM IS ALREADY FULL!

+

+
+ + Invader avatars + +
+ + + diff --git a/views/home.html b/views/home.html new file mode 100644 index 000000000..bac4faaca --- /dev/null +++ b/views/home.html @@ -0,0 +1,49 @@ + + + + + Home + + + + + + +
+ + Space invaders + +
+ +
+ +
+
TOP 10 RECENT PLAYERS
+
    + + + + + + + + + + + + + + + + +
    + + + + diff --git a/views/login.html b/views/login.html new file mode 100644 index 000000000..176855133 --- /dev/null +++ b/views/login.html @@ -0,0 +1,43 @@ + + + + + Login + + + + + + + +
    + Space invaders +
    +
    +
    + +
    If you do not have an account already, it will be created once you hit that Log in / Sign up button
    + +
    + + + +