diff --git a/README.md b/README.md
index 39e2788d..40b8ffd5 100644
--- a/README.md
+++ b/README.md
@@ -1,51 +1,30 @@
-# cs4241-FinalProject
-
-For your final project, you'll implement a course project that exhibits your mastery of the course materials.
-Similar to A4, this project gives you an opportunity to be creative and to pursue individual research and learning.
-
-## General description
-
-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.
-- Server-side programming *using Node.js*. Typically this will take the form of some sort of persistent data, authentication, and possibly server-side computation.
-
-Additionally, you should incorporate features that you independently research, design, and implement for your project.
-
-## 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 encouraged to work in teams of 2-5 students for the project. This will allow you to build a good project without expending an excessive amount of effort. While I would expect a team of four or five students to produce a project with more features, I expect a every team's work to exhibit all of the required facets described above.
-
-### 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, September 30th, before class
-
-There are no other scheduled checkpoints for your project.
-You must be done in time to present before the final project demo day (October 10th).
-
-#### 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.
-(Staff will use the proposal to build the grading sheet.)
-
-## Final Presentation
-
-Presentations will occur during the final day of class.
-
-## FAQs
-
-- **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.
+## Aquatic Dating Software (Teender)
+
+http://fp-percyjiang.glitch.me
+
+**Brief Description**: An online dating software for aquatic creatures.
+
+**Instructions**:
+ - npm i
+ - npm start
+ - register an account and login
+
+**Technologies**:
+ - dat.gui
+ - Web Audio API
+ - Canvas
+ - Express
+ - Passport
+ - Bootstrap
+ - Mongo
+ - Sweet Alert
+ - Font Awesome
+
+**Challenges**:
+ - None of us have experience with dating software so we made up dummy users of cartoons.
+ - We implemented a large amount of user interactions and additional features.
+
+**Roles**:
+ - Zonglin Peng: The dat.gui fizzy text and audio visualization.
+ - Rui Huang: Front end design of the whole project
+ - Haozhe Jiang: The rest of the project
\ No newline at end of file
diff --git a/package-lock.json b/package-lock.json
new file mode 100644
index 00000000..29ac03c2
--- /dev/null
+++ b/package-lock.json
@@ -0,0 +1,586 @@
+{
+ "name": "fp",
+ "requires": true,
+ "lockfileVersion": 1,
+ "dependencies": {
+ "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"
+ }
+ },
+ "array-flatten": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
+ "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
+ },
+ "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"
+ }
+ },
+ "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"
+ }
+ },
+ "bootstrap": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.3.1.tgz",
+ "integrity": "sha512-rXqOmH1VilAt2DyPzluTi2blhk17bO7ef+zLLPlWvG494pDxcM234pJ8wTc/6R40UWizAIIMgxjvxZg5kmsbag=="
+ },
+ "bson": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/bson/-/bson-1.1.1.tgz",
+ "integrity": "sha512-jCGVYLoYMHDkOsbwJZBCqwMHyH4c+wzgI9hG7Z6SZJRXWr+x58pdIbm2i9a/jFGCkRJqRUr8eoI7lDWa0hTkxg=="
+ },
+ "bytes": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
+ "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg=="
+ },
+ "connect-ensure-login": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/connect-ensure-login/-/connect-ensure-login-0.1.1.tgz",
+ "integrity": "sha1-F03MUSQ7nqwj+NmCFa62aU4uihI="
+ },
+ "connect-flash": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/connect-flash/-/connect-flash-0.1.1.tgz",
+ "integrity": "sha1-2GMPJtlaf4UfmVax6MxnMvO2qjA="
+ },
+ "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.3.1",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz",
+ "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s="
+ },
+ "cookie-parser": {
+ "version": "1.4.4",
+ "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.4.tgz",
+ "integrity": "sha512-lo13tqF3JEtFO7FyA49CqbhaFkskRJ0u/UAiINgrIXeRCY41c88/zxtrECl8AKH3B0hj9q10+h3Kt8I7KlW4tw==",
+ "requires": {
+ "cookie": "0.3.1",
+ "cookie-signature": "1.0.6"
+ }
+ },
+ "cookie-signature": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
+ "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
+ },
+ "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"
+ }
+ },
+ "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="
+ },
+ "ee-first": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+ "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
+ },
+ "encodeurl": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+ "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
+ },
+ "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"
+ },
+ "dependencies": {
+ "cookie": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz",
+ "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg=="
+ }
+ }
+ },
+ "express-flash": {
+ "version": "0.0.2",
+ "resolved": "https://registry.npmjs.org/express-flash/-/express-flash-0.0.2.tgz",
+ "integrity": "sha1-I9GovPP5DXB5KOSJ+Whp7K0KzaI=",
+ "requires": {
+ "connect-flash": "0.1.x"
+ }
+ },
+ "express-session": {
+ "version": "1.16.2",
+ "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.16.2.tgz",
+ "integrity": "sha512-oy0sRsdw6n93E9wpCNWKRnSsxYnSDX9Dnr9mhZgqUEEorzcq5nshGYSZ4ZReHFhKQ80WI5iVUUSPW7u3GaKauw==",
+ "requires": {
+ "cookie": "0.3.1",
+ "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.1.2",
+ "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=="
+ }
+ }
+ },
+ "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"
+ }
+ },
+ "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="
+ },
+ "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"
+ }
+ },
+ "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"
+ }
+ },
+ "inherits": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+ "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
+ },
+ "ipaddr.js": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz",
+ "integrity": "sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA=="
+ },
+ "jquery": {
+ "version": "3.4.1",
+ "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.4.1.tgz",
+ "integrity": "sha512-36+AdBzCL+y6qjw5Tx7HgzeGCzC81MDDgaUP8ld2zhx58HdqXGoBd+tHdrBMiyjGQs0Hxs/MLZTu/eHNJJuWPw=="
+ },
+ "media-typer": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+ "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
+ },
+ "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": "2.4.4",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz",
+ "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA=="
+ },
+ "mime-db": {
+ "version": "1.40.0",
+ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz",
+ "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA=="
+ },
+ "mime-types": {
+ "version": "2.1.24",
+ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz",
+ "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==",
+ "requires": {
+ "mime-db": "1.40.0"
+ }
+ },
+ "mongodb": {
+ "version": "3.3.2",
+ "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-3.3.2.tgz",
+ "integrity": "sha512-fqJt3iywelk4yKu/lfwQg163Bjpo5zDKhXiohycvon4iQHbrfflSAz9AIlRE6496Pm/dQKQK5bMigdVo2s6gBg==",
+ "requires": {
+ "bson": "^1.1.1",
+ "require_optional": "^1.0.1",
+ "safe-buffer": "^5.1.2"
+ }
+ },
+ "morgan": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.9.1.tgz",
+ "integrity": "sha512-HQStPIV4y3afTiCYVxirakhlCfGkI161c76kKFca7Fk1JusM//Qeo1ej2XaMniiNeaZklMVrh3vTtIzpzwbpmA==",
+ "requires": {
+ "basic-auth": "~2.0.0",
+ "debug": "2.6.9",
+ "depd": "~1.1.2",
+ "on-finished": "~2.3.0",
+ "on-headers": "~1.0.1"
+ }
+ },
+ "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=="
+ },
+ "node-statsd": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/node-statsd/-/node-statsd-0.1.1.tgz",
+ "integrity": "sha1-J6WTSHY9CvegN6wqAx/vPwUQE9M="
+ },
+ "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=="
+ },
+ "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.0",
+ "resolved": "https://registry.npmjs.org/passport/-/passport-0.4.0.tgz",
+ "integrity": "sha1-xQlWkTR71a07XhgCOMORTRbwWBE=",
+ "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="
+ },
+ "popper.js": {
+ "version": "1.15.0",
+ "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.15.0.tgz",
+ "integrity": "sha512-w010cY1oCUmI+9KwwlWki+r5jxKfTFDVoadl7MSrIujHU5MJ5OR6HTDj6Xo8aoR/QsA56x8jKjA59qGH4ELtrA=="
+ },
+ "proxy-addr": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.5.tgz",
+ "integrity": "sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ==",
+ "requires": {
+ "forwarded": "~0.1.2",
+ "ipaddr.js": "1.9.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"
+ }
+ },
+ "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="
+ },
+ "response-time": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/response-time/-/response-time-2.3.2.tgz",
+ "integrity": "sha1-/6cbq5UtYvfB1Jt0NDVfvGjf/Fo=",
+ "requires": {
+ "depd": "~1.1.0",
+ "on-headers": "~1.0.1"
+ }
+ },
+ "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=="
+ },
+ "semver": {
+ "version": "5.7.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
+ "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
+ },
+ "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": {
+ "mime": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+ "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
+ },
+ "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-favicon": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/serve-favicon/-/serve-favicon-2.5.0.tgz",
+ "integrity": "sha1-k10kDN/g9YBTB/3+ln2IlCosvPA=",
+ "requires": {
+ "etag": "~1.8.1",
+ "fresh": "0.5.2",
+ "ms": "2.1.1",
+ "parseurl": "~1.3.2",
+ "safe-buffer": "5.1.1"
+ },
+ "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=="
+ },
+ "safe-buffer": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
+ "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg=="
+ }
+ }
+ },
+ "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=="
+ },
+ "statuses": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
+ "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
+ },
+ "toidentifier": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
+ "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw=="
+ },
+ "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"
+ }
+ },
+ "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"
+ }
+ },
+ "unpipe": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+ "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
+ },
+ "utils-merge": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
+ "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
+ },
+ "vary": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+ "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
+ }
+ }
+}
diff --git a/package.json b/package.json
new file mode 100644
index 00000000..52caa6f7
--- /dev/null
+++ b/package.json
@@ -0,0 +1,28 @@
+{
+ "name": "fp",
+ "version": "",
+ "description": "",
+ "author": "",
+ "scripts": {
+ "start": "node server.js"
+ },
+ "dependencies": {
+ "body-parser": "latest",
+ "bootstrap": "^4.3.1",
+ "connect-ensure-login": "^0.1.1",
+ "cookie-parser": "^1.4.4",
+ "express": "^4.17.1",
+ "express-flash": "0.0.2",
+ "express-session": "^1.16.2",
+ "jquery": "^3.4.1",
+ "mime": "^2.4.4",
+ "mongodb": "^3.3.2",
+ "morgan": "^1.9.1",
+ "node-statsd": "^0.1.1",
+ "passport": "^0.4.0",
+ "passport-local": "^1.0.0",
+ "popper.js": "^1.15.0",
+ "response-time": "^2.3.2",
+ "serve-favicon": "^2.5.0"
+ }
+}
diff --git a/proposal.md b/proposal.md
new file mode 100644
index 00000000..cb356c1f
--- /dev/null
+++ b/proposal.md
@@ -0,0 +1,34 @@
+# Aquatic Dating Software
+
+## The Team
+ - Haozhe Jiang - @PercyJiang
+ - Zonglin Peng - @zonglinpeng
+ - Rui Huang - @Ryc1x
+
+## Overview
+An online dating software for aquatic creatures with some nice additional features.
+
+## Base Features
+ - Allow users to register and login using authentication.
+ - Allow users to see profiles of other users.
+ - Allow users to “like” other users or “blacklist” other users.
+ - Automatic generated “match score” between current user and other users.
+ - Mobile capabilities.
+
+## Stretch Features
+ - Allow users to upload profile pictures.
+ - Allow users to comment on other users’ profiles.
+ - Dynamic background picture.
+ - Live page titles using dat.GUI.
+ - Page music.
+ - Other more personalized interactions.
+
+## Technologies Used
+ - Express
+ - Local Strategy Passport Authentication
+ - Bootstrap
+ - Sweet Alert
+ - Font Awesome
+ - Three.js
+ - Web Audio API
+ - dat.GUI
diff --git a/public/canvas/index.html b/public/canvas/index.html
new file mode 100644
index 00000000..0ad976a8
--- /dev/null
+++ b/public/canvas/index.html
@@ -0,0 +1,23 @@
+
+
+
+
+ Music Player Demo
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/public/canvas/main.js b/public/canvas/main.js
new file mode 100644
index 00000000..36d4e8d1
--- /dev/null
+++ b/public/canvas/main.js
@@ -0,0 +1,104 @@
+window.onload = function() {
+ let fizzyText = new FizzyText('Teender')
+ this.initPage()
+}
+
+var canvas, ctx, center_x, center_y, radius, bars,
+ x_end, y_end, bar_height, bar_width,
+ frequency_array, context, analyser;
+
+bars = 200;
+bar_width = 2;
+
+function initPage() {
+ let playme = document.getElementById('playme')
+ playme.onclick = function() {
+ if (context !== undefined && context.state === 'running') {
+ context.suspend().then(function() {
+ console.log("music paused.")
+ playme.textContent = 'Resume'
+ })
+ } else if (context !== undefined && context.state === 'suspended') {
+ context.resume().then(function() {
+ console.log("music resumed.")
+ playme.textContent = 'Pause'
+ })
+ } else {
+ context = new AudioContext();
+ analyser = context.createAnalyser();
+ audio = new Audio();
+ audio.src = "../canvas/test.flac"; // <----- the source path
+ source = context.createMediaElementSource(audio);
+ source.connect(analyser);
+ analyser.connect(context.destination);
+ frequency_array = new Uint8Array(analyser.frequencyBinCount);
+
+ audio.play();
+ animationLooper();
+ }
+ }
+ animationLooper();
+}
+
+function animationLooper() {
+
+ // set to the size of device
+ canvas = document.getElementById("renderer");
+ canvas.width = 300;
+ canvas.height = 300;
+ ctx = canvas.getContext("2d");
+
+ // find the center of the window
+ center_x = canvas.width / 2;
+ center_y = canvas.height / 2;
+ radius = 40;
+
+ // style the background
+ var gradient = ctx.createLinearGradient(0, 0, 0, canvas.height);
+ gradient.addColorStop(0, "rgba(35, 7, 77, 1)");
+ gradient.addColorStop(1, "rgba(204, 83, 51, 1)");
+ ctx.fillStyle = gradient;
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
+
+ //draw a circle
+ ctx.beginPath();
+ ctx.arc(center_x, center_y, radius, 0, 2 * Math.PI);
+ ctx.fillStyle = 'white';
+ ctx.fill();
+
+ if (analyser !== undefined) {
+ analyser.getByteFrequencyData(frequency_array);
+
+ for (var i = 0; i < bars; i++) {
+
+ //divide a circle into equal parts
+ rads = Math.PI * 2 / bars;
+
+ bar_height = frequency_array[i] * 0.7;
+
+ // set coordinates
+ x = center_x + Math.cos(rads * i) * (radius);
+ y = center_y + Math.sin(rads * i) * (radius);
+ x_end = center_x + Math.cos(rads * i) * (radius + bar_height);
+ y_end = center_y + Math.sin(rads * i) * (radius + bar_height);
+
+ //draw a bar
+ drawBar(x, y, x_end, y_end, bar_width, frequency_array[i]);
+
+ }
+ }
+ window.requestAnimationFrame(animationLooper);
+}
+
+// for drawing a bar
+function drawBar(x1, y1, x2, y2, width, frequency) {
+
+ var lineColor = "rgb(" + frequency + ", " + frequency + ", " + 205 + ")";
+
+ ctx.strokeStyle = lineColor;
+ ctx.lineWidth = width;
+ ctx.beginPath();
+ ctx.moveTo(x1, y1);
+ ctx.lineTo(x2, y2);
+ ctx.stroke();
+}
\ No newline at end of file
diff --git a/public/canvas/test.flac b/public/canvas/test.flac
new file mode 100644
index 00000000..87f7e315
Binary files /dev/null and b/public/canvas/test.flac differ
diff --git a/public/fizzy/improvedNoise.js b/public/fizzy/improvedNoise.js
new file mode 100644
index 00000000..49472bcb
--- /dev/null
+++ b/public/fizzy/improvedNoise.js
@@ -0,0 +1,181 @@
+// http://mrl.nyu.edu/~perlin/noise/
+
+var ImprovedNoise = function () {
+
+ var p = [151,160,137,91,90,15,131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,
+ 23,190,6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33,88,237,149,56,87,
+ 174,20,125,136,171,168,68,175,74,165,71,134,139,48,27,166,77,146,158,231,83,111,229,122,60,211,
+ 133,230,220,105,92,41,55,46,245,40,244,102,143,54,65,25,63,161,1,216,80,73,209,76,132,187,208,
+ 89,18,169,200,196,135,130,116,188,159,86,164,100,109,198,173,186,3,64,52,217,226,250,124,123,5,
+ 202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42,223,183,170,213,119,
+ 248,152,2,44,154,163,70,221,153,101,155,167,43,172,9,129,22,39,253,19,98,108,110,79,113,224,232,
+ 178,185,112,104,218,246,97,228,251,34,242,193,238,210,144,12,191,179,162,241,81,51,145,235,249,
+ 14,239,107,49,192,214,31,181,199,106,157,184,84,204,176,115,121,50,45,127,4,150,254,138,236,205,
+ 93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180];
+
+ for ( var i = 0; i < 256 ; i++ ) {
+
+ p[ 256 + i ] = p[ i ];
+
+ }
+
+ function fade( t ) {
+
+ return t * t * t * ( t * ( t * 6 - 15 ) + 10 );
+
+ }
+
+ function lerp( t, a, b ) {
+
+ return a + t * ( b - a );
+
+ }
+
+ function grad( hash, x, y, z ) {
+
+ var h = hash & 15;
+ var u = h < 8 ? x : y, v = h < 4 ? y : h == 12 || h == 14 ? x : z;
+ return ( ( h & 1 ) == 0 ? u : -u ) + ( ( h & 2 ) == 0 ? v : -v );
+
+ }
+
+ return {
+
+ noise: function ( x, y, z ) {
+
+ var floorX = Math.floor( x ), floorY = Math.floor( y ), floorZ = Math.floor( z );
+
+ var X = floorX & 255, Y = floorY & 255, Z = floorZ & 255;
+
+ x -= floorX;
+ y -= floorY;
+ z -= floorZ;
+
+ var xMinus1 = x -1, yMinus1 = y - 1, zMinus1 = z - 1;
+
+ var u = fade( x ), v = fade( y ), w = fade( z );
+
+ var A = p[ X ] + Y, AA = p[ A ] + Z, AB = p[ A + 1 ] + Z, B = p[ X + 1 ] + Y, BA = p[ B ] + Z, BB = p[ B + 1 ] + Z;
+
+ return lerp( w, lerp( v, lerp( u, grad( p[ AA ], x, y, z ),
+ grad( p[ BA ], xMinus1, y, z ) ),
+ lerp( u, grad( p[ AB ], x, yMinus1, z ),
+ grad( p[ BB ], xMinus1, yMinus1, z ) ) ),
+ lerp( v, lerp( u, grad( p[ AA + 1 ], x, y, zMinus1 ),
+ grad( p[ BA + 1 ], xMinus1, y, z - 1 ) ),
+ lerp( u, grad( p[ AB + 1 ], x, yMinus1, zMinus1 ),
+ grad( p[ BB + 1 ], xMinus1, yMinus1, zMinus1 ) ) ) );
+
+ }
+ }
+}
+
+var currentRandom = Math.random;
+
+// Pseudo-random generator
+function Marsaglia(i1, i2) {
+// from http://www.math.uni-bielefeld.de/~sillke/ALGORITHMS/random/marsaglia-c
+var z=i1 || 362436069, w= i2 || 521288629;
+var nextInt = function() {
+ z=(36969*(z&65535)+(z>>>16)) & 0xFFFFFFFF;
+ w=(18000*(w&65535)+(w>>>16)) & 0xFFFFFFFF;
+ return (((z&0xFFFF)<<16) | (w&0xFFFF)) & 0xFFFFFFFF;
+};
+
+this.nextDouble = function() {
+ var i = nextInt() / 4294967296;
+ return i < 0 ? 1 + i : i;
+};
+this.nextInt = nextInt;
+}
+Marsaglia.createRandomized = function() {
+var now = new Date();
+return new Marsaglia((now / 60000) & 0xFFFFFFFF, now & 0xFFFFFFFF);
+};
+
+// Noise functions and helpers
+function PerlinNoise(seed) {
+var rnd = seed !== undefined ? new Marsaglia(seed) : Marsaglia.createRandomized();
+var i, j;
+// http://www.noisemachine.com/talk1/17b.html
+// http://mrl.nyu.edu/~perlin/noise/
+// generate permutation
+var p = new Array(512);
+for(i=0;i<256;++i) { p[i] = i; }
+for(i=0;i<256;++i) { var t = p[j = rnd.nextInt() & 0xFF]; p[j] = p[i]; p[i] = t; }
+// copy to avoid taking mod in p[0];
+for(i=0;i<256;++i) { p[i + 256] = p[i]; }
+
+function grad3d(i,x,y,z) {
+ var h = i & 15; // convert into 12 gradient directions
+ var u = h<8 ? x : y,
+ v = h<4 ? y : h===12||h===14 ? x : z;
+ return ((h&1) === 0 ? u : -u) + ((h&2) === 0 ? v : -v);
+}
+
+function grad2d(i,x,y) {
+ var v = (i & 1) === 0 ? x : y;
+ return (i&2) === 0 ? -v : v;
+}
+
+function grad1d(i,x) {
+ return (i&1) === 0 ? -x : x;
+}
+
+function lerp(t,a,b) { return a + t * (b - a); }
+
+this.noise3d = function(x, y, z) {
+ var X = Math.floor(x)&255, Y = Math.floor(y)&255, Z = Math.floor(z)&255;
+ x -= Math.floor(x); y -= Math.floor(y); z -= Math.floor(z);
+ var fx = (3-2*x)*x*x, fy = (3-2*y)*y*y, fz = (3-2*z)*z*z;
+ var p0 = p[X]+Y, p00 = p[p0] + Z, p01 = p[p0 + 1] + Z, p1 = p[X + 1] + Y, p10 = p[p1] + Z, p11 = p[p1 + 1] + Z;
+ return lerp(fz,
+ lerp(fy, lerp(fx, grad3d(p[p00], x, y, z), grad3d(p[p10], x-1, y, z)),
+ lerp(fx, grad3d(p[p01], x, y-1, z), grad3d(p[p11], x-1, y-1,z))),
+ lerp(fy, lerp(fx, grad3d(p[p00 + 1], x, y, z-1), grad3d(p[p10 + 1], x-1, y, z-1)),
+ lerp(fx, grad3d(p[p01 + 1], x, y-1, z-1), grad3d(p[p11 + 1], x-1, y-1,z-1))));
+};
+
+this.noise2d = function(x, y) {
+ var X = Math.floor(x)&255, Y = Math.floor(y)&255;
+ x -= Math.floor(x); y -= Math.floor(y);
+ var fx = (3-2*x)*x*x, fy = (3-2*y)*y*y;
+ var p0 = p[X]+Y, p1 = p[X + 1] + Y;
+ return lerp(fy,
+ lerp(fx, grad2d(p[p0], x, y), grad2d(p[p1], x-1, y)),
+ lerp(fx, grad2d(p[p0 + 1], x, y-1), grad2d(p[p1 + 1], x-1, y-1)));
+};
+
+this.noise1d = function(x) {
+ var X = Math.floor(x)&255;
+ x -= Math.floor(x);
+ var fx = (3-2*x)*x*x;
+ return lerp(fx, grad1d(p[X], x), grad1d(p[X+1], x-1));
+};
+}
+
+// these are lifted from Processing.js
+// processing defaults
+var noiseProfile = { generator: undefined, octaves: 4, fallout: 0.5, seed: undefined};
+
+function noise(x, y, z) {
+if(noiseProfile.generator === undefined) {
+ // caching
+ noiseProfile.generator = new PerlinNoise(noiseProfile.seed);
+}
+var generator = noiseProfile.generator;
+var effect = 1, k = 1, sum = 0;
+for(var i=0; i o2) v = o2;
+ return v;
+ };
+ // Called every frame
+ this.render = function() {
+
+ // What color is the pixel we're sitting on top of?
+ var c = getColor(this.x, this.y);
+
+ // Where should we move?
+ var angle = noise(this.x / noiseScale, this.y / noiseScale) * _this.noiseStrength;
+
+ // Are we within the boundaries of the image?
+ var onScreen = this.x > 0 && this.x < width &&
+ this.y > 0 && this.y < height;
+
+ var isBlack = c != "rgb(255,255,255)" && onScreen;
+
+ // If we're on top of a black pixel, grow.
+ // If not, shrink.
+ if (isBlack) {
+ this.r += _this.growthSpeed;
+ } else {
+ this.r -= _this.growthSpeed;
+ }
+
+ // This velocity is used by the explode function.
+ this.vx *= 0.5;
+ this.vy *= 0.5;
+
+ // Change our position based on the flow field and our
+ // explode velocity.
+ this.x += Math.cos(angle) * _this.speed + this.vx;
+ this.y += -Math.sin(angle) * _this.speed + this.vy;
+
+ this.r = this.constrain(this.r, 0, _this.maxSize);
+
+ // If we're tiny, keep moving around until we find a black
+ // pixel.
+ if (this.r <= 0) {
+ this.x = Math.random() * width;
+ this.y = Math.random() * height;
+ return; // Don't draw!
+ }
+
+ // Draw the circle.
+ g.beginPath();
+ g.arc(this.x, this.y, this.r, 0, Math.PI * 2, false);
+ g.fill();
+
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/public/img/368-3683311_larry-the-lobster-clipart.png b/public/img/368-3683311_larry-the-lobster-clipart.png
new file mode 100644
index 00000000..89d79651
Binary files /dev/null and b/public/img/368-3683311_larry-the-lobster-clipart.png differ
diff --git a/public/img/612-rI+JybL._SY450_.jpg b/public/img/612-rI+JybL._SY450_.jpg
new file mode 100644
index 00000000..cd0daeb7
Binary files /dev/null and b/public/img/612-rI+JybL._SY450_.jpg differ
diff --git a/public/img/Sandy_Cheeks.jpg b/public/img/Sandy_Cheeks.jpg
new file mode 100644
index 00000000..dfca01c2
Binary files /dev/null and b/public/img/Sandy_Cheeks.jpg differ
diff --git a/public/img/SpongeBob_SquarePants_-_Pearl_Krabs_promo_art.png b/public/img/SpongeBob_SquarePants_-_Pearl_Krabs_promo_art.png
new file mode 100644
index 00000000..b579b1d2
Binary files /dev/null and b/public/img/SpongeBob_SquarePants_-_Pearl_Krabs_promo_art.png differ
diff --git a/public/img/YH2qZaMaBk6xp9S5tz8kcC-320-80.png b/public/img/YH2qZaMaBk6xp9S5tz8kcC-320-80.png
new file mode 100644
index 00000000..3ac24b59
Binary files /dev/null and b/public/img/YH2qZaMaBk6xp9S5tz8kcC-320-80.png differ
diff --git a/public/img/avatar-alt.png b/public/img/avatar-alt.png
new file mode 100644
index 00000000..b0bd484b
Binary files /dev/null and b/public/img/avatar-alt.png differ
diff --git a/public/img/avatar.png b/public/img/avatar.png
new file mode 100644
index 00000000..c9e28616
Binary files /dev/null and b/public/img/avatar.png differ
diff --git a/public/img/backgroundLeft.jpg b/public/img/backgroundLeft.jpg
new file mode 100644
index 00000000..bf1dfc30
Binary files /dev/null and b/public/img/backgroundLeft.jpg differ
diff --git a/public/img/backgroundRight.jpg b/public/img/backgroundRight.jpg
new file mode 100644
index 00000000..e16bb505
Binary files /dev/null and b/public/img/backgroundRight.jpg differ
diff --git a/public/img/bg.jpg b/public/img/bg.jpg
new file mode 100644
index 00000000..ff7274e8
Binary files /dev/null and b/public/img/bg.jpg differ
diff --git a/public/img/favicon.png b/public/img/favicon.png
new file mode 100644
index 00000000..163bb613
Binary files /dev/null and b/public/img/favicon.png differ
diff --git a/public/img/login-bg.jpg b/public/img/login-bg.jpg
new file mode 100644
index 00000000..624dec6c
Binary files /dev/null and b/public/img/login-bg.jpg differ
diff --git a/public/img/loginBG.jpg b/public/img/loginBG.jpg
new file mode 100644
index 00000000..a85dc369
Binary files /dev/null and b/public/img/loginBG.jpg differ
diff --git a/public/img/profPic.jpg b/public/img/profPic.jpg
new file mode 100644
index 00000000..5ccf9f15
Binary files /dev/null and b/public/img/profPic.jpg differ
diff --git a/public/img/sea.jpg b/public/img/sea.jpg
new file mode 100644
index 00000000..885f4e8b
Binary files /dev/null and b/public/img/sea.jpg differ
diff --git a/public/img/squidward_tentacles_91.png b/public/img/squidward_tentacles_91.png
new file mode 100644
index 00000000..dac072c3
Binary files /dev/null and b/public/img/squidward_tentacles_91.png differ
diff --git a/public/img/tableBG.jpg b/public/img/tableBG.jpg
new file mode 100644
index 00000000..4bdaa67f
Binary files /dev/null and b/public/img/tableBG.jpg differ
diff --git a/public/index.html b/public/index.html
new file mode 100644
index 00000000..bf5fa3ba
--- /dev/null
+++ b/public/index.html
@@ -0,0 +1,71 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ User Login
+
+
+
+
+
+
+
+

+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/public/main.css b/public/main.css
new file mode 100644
index 00000000..6190093c
--- /dev/null
+++ b/public/main.css
@@ -0,0 +1,62 @@
+body {
+ font-family: 'Roboto', sans-serif;
+ background: url("img/loginBG.jpg") no-repeat;
+}
+.main-section {
+ margin-top: 140px;
+ margin-left: 80px;
+ padding: 0;
+}
+.modal-content {
+ background-color: aliceblue;
+ opacity: .95;
+ padding: 0 18px;
+ box-shadow: 0 0 3px #848484;
+}
+.user-img {
+ margin-top: -50px;
+ margin-bottom: 35px;
+}
+.user-img img {
+ height: 100px;
+ width: 100px;
+ border-radius: 5px;
+ box-shadow: 0 0 2px #848484;
+}
+.form-group {
+ margin-bottom: 25px;
+}
+.form-group input {
+ height: 42px;
+ border-radius: 5px;
+ border: 0;
+ font-size: 18px;
+ padding-left: 54px;
+}
+.form-group::before {
+ font-family: 'Font Awesome\ 5 free', serif;
+ content: "\f007";
+ position: absolute;
+ font-size: 22px;
+ color: #555e60;
+ left: 28px;
+ padding-top: 4px;
+}
+.form-group:last-of-type::before {
+ content: "\f023";
+}
+button {
+ width: 42%;
+ margin: 5px 0 25px;
+}
+.btn {
+ background-color: #008CBA;
+ color: azure;
+ font-size: 17px;
+ padding: 7px 14px;
+ border-radius: 5px;
+}
+.btn:hover, .btn:focus {
+ background-color: #008CFF;
+ color: azure;
+}
\ No newline at end of file
diff --git a/public/main.js b/public/main.js
new file mode 100644
index 00000000..eeb1781a
--- /dev/null
+++ b/public/main.js
@@ -0,0 +1,27 @@
+document.getElementById('loginBtn').onclick = function(e) {
+ fetch('/login', {
+ method: 'POST',
+ body: JSON.stringify({
+ username: document.querySelector('#username').value,
+ password: document.querySelector('#password').value
+ }),
+ headers: { 'Content-Type': 'application/json' }
+ })
+ .then(res => res.json())
+ .then(res => {
+ console.log(res)
+ location.href = 'table/table.html'
+ })
+ .catch(err => {
+ console.log(err)
+ document.getElementById('hint').innerHTML = 'Invalid Input'
+ })
+ e.preventDefault();
+ return false;
+};
+
+document.getElementById('registerBtn').onclick = function(e) {
+ location.href = 'register/register.html';
+ e.preventDefault();
+ return false;
+};
\ No newline at end of file
diff --git a/public/modify/modify.css b/public/modify/modify.css
new file mode 100644
index 00000000..f89fb04b
--- /dev/null
+++ b/public/modify/modify.css
@@ -0,0 +1,58 @@
+#helvetica-demo {
+ display: flex;
+ justify-content: end;
+ margin-bottom: -80px;
+ margin-left: -30px;
+}
+
+body {
+ background: #eaeaea
+}
+
+#register-box {
+ width: 580px;
+ margin: 0 auto;
+ margin-top: 5%;
+ border-radius: 25px;
+ background: rgba(255, 255, 255, 0.9);
+ padding: 40px;
+ box-shadow: 0px 0px 20px #aaaaaa;
+}
+
+#register-form {
+ width: 500px;
+}
+
+#background {
+ /* BOX MODEL */
+ width: 100%;
+ height: 450px;
+ position: absolute;
+ top: 0;
+ left: 0;
+ /* ENHANCEMENT */
+ background-image: url('/img/login-bg.jpg');
+ background-position: center center;
+ background-size: cover;
+ background-repeat: no-repeat;
+ mask-image: linear-gradient(to bottom, rgba(0, 0, 0, 1), rgba(0, 0, 0, 0));
+ -webkit-mask-image: -webkit-gradient(linear, left top, left bottom, from(rgba(0, 0, 0, 1)), to(rgba(0, 0, 0, 0)));
+ z-index: -1;
+}
+
+.image-preview {
+ width: 300px;
+ min-height: 100px;
+ border: 2px solid #dddddd;
+ margin-top: 10px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-weight: bold;
+ color: #cccccc;
+}
+
+.image-preview__image {
+ display: none;
+ width: 100%;
+}
\ No newline at end of file
diff --git a/public/modify/modify.html b/public/modify/modify.html
new file mode 100644
index 00000000..e9d1f3ba
--- /dev/null
+++ b/public/modify/modify.html
@@ -0,0 +1,115 @@
+
+
+
+
+
+ Modify Profile
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/public/modify/modify.js b/public/modify/modify.js
new file mode 100644
index 00000000..1a12418d
--- /dev/null
+++ b/public/modify/modify.js
@@ -0,0 +1,130 @@
+window.onload = function() {
+ let fizzyText = new FizzyText('Modify Profile')
+}
+
+document.getElementById('cancel-btn').onclick = function(e) {
+ location.href = '../table/table.html'
+ e.preventDefault()
+ return false
+}
+
+document.getElementById('delete-btn').onclick = function(e) {
+ swal({
+ title: "Are you sure?",
+ text: "Once deleted, you will not be able to recover your account!",
+ icon: "warning",
+ buttons: true,
+ dangerMode: true,
+ }).then((willDelete) => {
+ if (willDelete) {
+ swal("Goodbye!", {
+ icon: "success",
+ }).then(() => {
+ fetch('/delete', {
+ method: 'POST'
+ }).then(function(response) {
+ console.log("Post sent to server: " + response)
+ location.href = '../index.html'
+ })
+ })
+ } else swal("Great!")
+ })
+ e.preventDefault()
+ return false
+}
+
+fetch('/getYou', {
+ method: 'GET',
+ headers: { 'Content-Type': 'application/json' }
+}).then(function(response) {
+ return response.json()
+}).then(function(you) {
+ const name = document.querySelector('#input-nickname')
+ const age = document.querySelector('#input-age')
+ const whatsUp = document.querySelector('#input-whatsup')
+ const genderS = document.getElementsByName('customRadio')
+ const hobbyS = document.getElementById('select-hobby')
+ const salary = document.querySelector('#input-salary')
+ const loc = document.querySelector('#input-location')
+ const selfIntro = document.querySelector('#input-selfintro')
+ const img = document.querySelector('img')
+
+ name.defaultValue = you.name
+ age.defaultValue = you.age
+ if (you.whatsUp) whatsUp.defaultValue = you.whatsUp
+ for (let i = 0; i < genderS.length; i++) {
+ if (genderS[i].value === you.gender) {
+ genderS[i].checked = true
+ break
+ }
+ }
+ for (let j = 0; j < hobbyS.options.length; j++) {
+ if (hobbyS.options[j].value === you.hobby) {
+ hobbyS.selectedIndex = j
+ break
+ }
+ }
+ if (you.salary) salary.defaultValue = you.salary
+ if (you.location) loc.defaultValue = you.location
+ if (you.selfIntro) selfIntro.defaultValue = you.selfIntro
+
+ let imgSrc
+ const previewContainer = document.getElementById('imagePreview')
+ const previewImage = previewContainer.querySelector('.image-preview__image')
+ const previewDefaultText = previewContainer.querySelector('.image-preview__default-text')
+ if (you.pic) {
+ previewDefaultText.style.display = 'none'
+ previewImage.style.display = 'block'
+ imgSrc = you.pic
+ previewImage.setAttribute('src', you.pic)
+ }
+ document.getElementById('inpFile').addEventListener('change', function(e) {
+ const file = this.files[0]
+ if (file) {
+ const reader = new FileReader()
+ previewDefaultText.style.display = 'none'
+ previewImage.style.display = 'block'
+ reader.addEventListener('load', function() {
+ imgSrc = this.result
+ previewImage.setAttribute('src', this.result)
+ })
+ reader.readAsDataURL(file)
+ } else {
+ previewDefaultText.style.display = null
+ previewImage.style.display = null
+ previewImage.setAttribute('src', '')
+ }
+ e.preventDefault()
+ return false
+ })
+
+ document.getElementById('update-btn').onclick = function(e) {
+ let gender
+ for (let i = 0; i < genderS.length; i++) {
+ if (genderS[i].checked) gender = genderS[i].value
+ }
+ let hobby = hobbyS.options[hobbyS.selectedIndex].value
+ const json = {
+ name: name.value,
+ age: parseInt(age.value),
+ whatsUp: whatsUp.value,
+ gender: gender,
+ hobby: hobby,
+ pic: imgSrc,
+ salary: salary.value,
+ location: loc.value,
+ selfIntro: selfIntro.value
+ }
+ fetch(`/updateInfo`, {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify(json)
+ }).then(function(response) {
+ swal(`Hello ${name.value}!`, `You have successfully updated your profile!`, "success")
+ .then(() => location.href = '../profile/profile.html')
+ console.log("Post sent to server: " + response);
+ })
+ e.preventDefault()
+ return false
+ }
+})
\ No newline at end of file
diff --git a/public/profile/profile.css b/public/profile/profile.css
new file mode 100644
index 00000000..b8245d44
--- /dev/null
+++ b/public/profile/profile.css
@@ -0,0 +1,196 @@
+#background {
+ /* BOX MODEL */
+ width: 100%;
+ height: 450px;
+ /* ENHANCEMENT */
+ background-image: url('/img/bg.jpg');
+ background-position: center center;
+ background-size: cover;
+ background-repeat: no-repeat;
+ mask-image: linear-gradient(to bottom, rgba(0, 0, 0, 1), rgba(0, 0, 0, 0));
+ -webkit-mask-image: -webkit-gradient(linear, left top, left bottom, from(rgba(0, 0, 0, 1)), to(rgba(0, 0, 0, 0)));
+ z-index: -1;
+ position: relative;
+}
+
+#namebox {
+ width: 400px;
+ height: 50px;
+ background: black;
+ color: white;
+ margin: 0 auto;
+ text-align: center;
+ font-size: 24pt;
+ margin-bottom: 20px;
+}
+
+#handwritten {
+ margin: 0 auto;
+ width: 500px;
+ text-align: center;
+ font-style: bold;
+ font-size: 18pt;
+ font-family: 'Great Vibes', cursive;
+ margin-bottom: 100px;
+}
+
+body {
+ font-family: 'Montserrat', sans-serif;
+ background: #eeeeee;
+}
+
+.content {
+ margin: -220px 5% 100px;
+}
+
+.to-top {
+ position: fixed;
+ bottom: 90px;
+ right: 20px;
+}
+
+.center-block {
+ display: block;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+#footer {
+ display: flex;
+ justify-content: space-around;
+ background-color: #3c3d41;
+ color: #fff;
+ padding-top: 20px;
+ padding-bottom: 10px;
+}
+
+#footer a {
+ color: #d2d1d1c0;
+ text-decoration: none;
+}
+
+#footer a:hover {
+ color: #fff;
+}
+
+nav .btn {
+ margin-left: 10px;
+}
+
+#profile-box {
+ margin: 0 auto;
+ /* margin-top: 5%; */
+ width: 90%;
+ border-radius: 25px;
+ background: rgba(255, 255, 255, 0.9);
+ padding: 40px;
+ box-shadow: 0px 0px 20px #aaaaaa;
+}
+
+#avatar {
+ position: absolute;
+ width: 200px;
+ height: 200px;
+ /* background-image: url('/img/avatar.png'); */
+ background-position: center center;
+ background-size: 200px;
+ border-radius: 20px;
+ box-shadow: 0px 0px 15px black;
+ background-color: white;
+ margin-left: 100px;
+ margin-top: -120px;
+}
+
+#personal-msg {
+ font-style: bold;
+ font-size: 20pt;
+ font-family: 'Nothing You Could Do', cursive;
+ margin-left: 380px;
+}
+
+#name {
+ position: absolute;
+ font-family: 'Lato', sans-serif;
+ font-size: 24pt;
+ margin-left: 380px;
+ margin-top: -100px;
+}
+
+#profile {
+ font-size: 20px;
+ padding: 40px;
+}
+
+#profile>div {
+ margin-top: 20px;
+}
+
+#profile h2 {
+ margin-top: 20px;
+ border-bottom: solid 1px #3c3d41;
+ display: flex;
+ justify-content: space-between;
+}
+
+#stats {
+ padding: 0px 100px;
+ display: flex;
+ justify-content: space-around;
+}
+
+#basic-info {
+ padding: 0px 100px;
+}
+
+.toast {
+ margin: 0 auto;
+ max-width: 500px;
+}
+
+.toast img {
+ width: 40px;
+ height: 40px;
+}
+
+
+/* Font Awesome Icon */
+
+#edit-info {
+ color: #5b5b5e;
+}
+
+/* #edit-info:hover {
+ color: black;
+} */
+
+#comment-ico {
+ color: #5b5b5e;
+}
+
+/* #comment-ico:hover {
+ color: black;
+} */
+
+#like-ico {
+ color: rgb(255, 67, 67);
+}
+
+#like-ico:hover {
+ color: rgb(255, 0, 0);
+}
+
+#up-ico {
+ color: rgb(83, 143, 255)
+}
+
+#up-ico:hover {
+ color: rgb(0, 102, 255);
+}
+
+#down-ico {
+ color: rgb(255, 175, 83)
+}
+
+#down-ico:hover {
+ color: rgb(255, 145, 0);
+}
\ No newline at end of file
diff --git a/public/profile/profile.html b/public/profile/profile.html
new file mode 100644
index 00000000..cd7e0a13
--- /dev/null
+++ b/public/profile/profile.html
@@ -0,0 +1,163 @@
+
+
+
+
+
+ Profile
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Basic Info
+
+
+
+
+
+
+
+
+ | Gender |
+ |
+
+
+ | Age |
+ |
+
+
+ | Hobby |
+ |
+
+
+ | Salary |
+ |
+
+
+ | Location |
+ |
+
+
+ | Self-Intro |
+ |
+
+
+
+
+
Comments
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/public/profile/profile.js b/public/profile/profile.js
new file mode 100644
index 00000000..c5f30cc3
--- /dev/null
+++ b/public/profile/profile.js
@@ -0,0 +1,135 @@
+window.onload = function() {
+ $('.toast').toast({ autohide: false })
+ $('.toast').toast('show')
+ document.getElementById('goTop-btn').onclick = function() {
+ document.body.scrollTop = 0
+ document.documentElement.scrollTop = 0
+ }
+}
+
+function refreshProfile() {
+ fetch('/getYou', {
+ method: 'GET',
+ headers: { 'Content-Type': 'application/json' }
+ }).then(function(response) {
+ return response.json();
+ }).then(function(you) {
+ let user
+ fetch('/refreshAll', {
+ method: 'GET',
+ headers: { 'Content-Type': 'application/json' }
+ }).then(function(response) {
+ return response.json()
+ }).then(function(data) {
+ data.map(function(row) {
+ if (row._id === localStorage.id) user = row
+ })
+
+ if (user.pic) document.getElementById('avatar').style.backgroundImage = `url(${user.pic})`
+ document.getElementById('name').innerHTML = user.name
+ document.getElementById('name2').innerHTML = you.name
+ document.getElementById('favCount').innerHTML = user.favCount
+ document.getElementById('likes').innerHTML = user.likes
+ document.getElementById('dislikes').innerHTML = user.dislikes
+ document.getElementById('gender').innerHTML = user.gender
+ document.getElementById('age').innerHTML = user.age
+ document.getElementById('hobby').innerHTML = user.hobby
+ document.getElementById('salary').innerHTML = user.salary
+ document.getElementById('location').innerHTML = user.location
+ document.getElementById('self-intro').innerHTML = user.selfIntro
+ document.getElementById('personal-msg').innerHTML = user.whatsUp
+ document.getElementById('comment-img').src = you.pic
+
+ // const heart = document.getElementById('like-ico')
+ // if (user._id === you._id) {
+ // heart.className = 'fa fa-heart'
+ // heart.style.color = 'red'
+ // } else {
+ // if (you.likedList.includes(user.name)) {
+ // heart.className = 'fa fa-heart'
+ // heart.style.color = 'red'
+ // } else {
+ // console.log('here')
+ // heart.className = 'fa fa-heart-o'
+ // heart.style.color = 'black'
+ // }
+ // }
+ // heart.onclick = function(e) {
+ // if (heart.className === 'fa fa-heart') {
+ // heart.className = 'fa fa-heart-o';
+ // heart.style.color = 'black';
+ // you.favCount -= 1
+ // you.likedList = you.likedList.filter((value => { return value !== user.username }))
+ // } else {
+ // heart.className = 'fa fa-heart';
+ // heart.style.color = 'red';
+ // you.favCount += 1
+ // you.likedList.push(user.username)
+ // }
+ // update(you)
+ // e.preventDefault()
+ // return false
+ // }
+ document.getElementById('up-ico').onclick = function(e) {
+ user.likes += 1
+ update(user)
+ e.preventDefault()
+ return false
+ }
+ document.getElementById('down-ico').onclick = function(e) {
+ user.dislikes += 1
+ update(user)
+ e.preventDefault()
+ return false
+ }
+
+ const update = function(user) {
+ fetch('/updateUser', {
+ method: 'POST',
+ body: JSON.stringify(user),
+ headers: { 'Content-Type': 'application/json' }
+ }).then(function(response) {
+ console.log("Post sent to server: " + response)
+ refreshProfile()
+ })
+ }
+ document.getElementById('comment-btn').onclick = function(e) {
+ user.comments.push([you.pic, you.name, document.getElementById('comment-text').value])
+ update(user)
+ e.preventDefault()
+ return false
+ }
+
+ const comments = document.getElementById('comments')
+ comments.innerHTML = ''
+ const createNode = function(element) { return document.createElement(element) }
+ const append = function(parent, el) { return parent.appendChild(el) }
+ user.comments.map(function(comment) {
+ let img = createNode('img')
+ img.src = comment[0]
+ img.className = 'rounded mr-2'
+
+ let strong = createNode('strong')
+ strong.innerHTML = comment[1]
+ strong.className = 'mr-auto'
+
+ let header = createNode('div')
+ header.className = 'toast-header'
+ append(header, img)
+ append(header, strong)
+
+ let body = createNode('div')
+ body.innerHTML = comment[2]
+ body.className = 'toast-body'
+
+ let toast = createNode('div')
+ toast.role = 'alert'
+ toast.className = 'toast fade show'
+ append(toast, header)
+ append(toast, body)
+ append(comments, toast)
+ })
+ })
+ })
+}
+refreshProfile()
\ No newline at end of file
diff --git a/public/register/register.css b/public/register/register.css
new file mode 100644
index 00000000..3ba212a8
--- /dev/null
+++ b/public/register/register.css
@@ -0,0 +1,57 @@
+body {
+ background: #eaeaea
+}
+
+#register-box {
+ width: 580px;
+ margin: 0 auto;
+ margin-top: 5%;
+ border-radius: 25px;
+ background: rgba(255, 255, 255, 0.9);
+ padding: 40px;
+ box-shadow: 0px 0px 20px #aaaaaa;
+}
+
+#register-form {
+ width: 500px;
+}
+
+#background {
+ /* BOX MODEL */
+ width: 100%;
+ height: 450px;
+ position: absolute;
+ top: 0;
+ left: 0;
+ /* ENHANCEMENT */
+ background-image: url('/img/login-bg.jpg');
+ background-position: center center;
+ background-size: cover;
+ background-repeat: no-repeat;
+ mask-image: linear-gradient(to bottom, rgba(0, 0, 0, 1), rgba(0, 0, 0, 0));
+ -webkit-mask-image: -webkit-gradient(linear, left top, left bottom, from(rgba(0, 0, 0, 1)), to(rgba(0, 0, 0, 0)));
+ z-index: -1;
+}
+
+.image-preview {
+ width: 300px;
+ min-height: 100px;
+ border: 2px solid #dddddd;
+ margin-top: 10px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ font-weight: bold;
+ color: #cccccc;
+}
+
+.image-preview__image {
+ display: none;
+ width: 100%;
+}
+
+#helvetica-demo {
+ display: flex;
+ justify-content: end;
+ margin-bottom: -80px;
+}
\ No newline at end of file
diff --git a/public/register/register.html b/public/register/register.html
new file mode 100644
index 00000000..3f2d50c6
--- /dev/null
+++ b/public/register/register.html
@@ -0,0 +1,105 @@
+
+
+
+
+
+ Personal Information
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/public/register/register.js b/public/register/register.js
new file mode 100644
index 00000000..510ed215
--- /dev/null
+++ b/public/register/register.js
@@ -0,0 +1,79 @@
+window.onload = function() {
+ let fizzyText = new FizzyText('Registration')
+}
+
+document.getElementById('cancel-btn').onclick = function(e) {
+ location.href = '../index.html';
+ e.preventDefault();
+ return false;
+}
+
+const username = document.querySelector('#input-username')
+const password = document.querySelector('#input-password')
+const name = document.querySelector('#input-nickname')
+const age = document.querySelector('#input-age')
+const genderS = document.getElementsByName('customRadio')
+const hobbyS = document.getElementById('select-hobby')
+
+let imgSrc
+const previewContainer = document.getElementById('imagePreview')
+const previewImage = previewContainer.querySelector('.image-preview__image')
+const previewDefaultText = previewContainer.querySelector('.image-preview__default-text')
+document.getElementById('inpFile').addEventListener('change', function(e) {
+ const file = this.files[0]
+ if (file) {
+ const reader = new FileReader()
+ previewDefaultText.style.display = 'none'
+ previewImage.style.display = 'block'
+ reader.addEventListener('load', function() {
+ imgSrc = this.result
+ previewImage.setAttribute('src', this.result)
+ })
+ reader.readAsDataURL(file)
+ } else {
+ previewDefaultText.style.display = null
+ previewImage.style.display = null
+ previewImage.setAttribute('src', '')
+ }
+ e.preventDefault()
+ return false
+})
+
+const registerBtn = document.getElementById('register-btn')
+registerBtn.onclick = function(e) {
+ let gender
+ for (let i = 0; i < genderS.length; i++) {
+ if (genderS[i].checked) gender = genderS[i].value
+ }
+ let hobby = hobbyS.options[hobbyS.selectedIndex].value
+ const json = {
+ username: username.value,
+ password: password.value,
+ name: name.value,
+ age: parseInt(age.value),
+ gender: gender,
+ hobby: hobby,
+ likedList: [],
+ blackList: [],
+ comments: [],
+ likes: 0,
+ dislikes: 0,
+ pic: imgSrc,
+ favCount: 0,
+ whatsUp: null,
+ salary: null,
+ location: null,
+ selfIntro: null
+ }
+ fetch(`/add`, {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify(json)
+ }).then(function(response) {
+ swal(`Hello ${name.value}!`, `You have successfully registered!`, "success")
+ .then(() => location.href = '../index.html')
+ console.log("Post sent to server: " + response)
+ })
+ e.preventDefault()
+ return false
+}
\ No newline at end of file
diff --git a/public/table/table.html b/public/table/table.html
new file mode 100644
index 00000000..06e9e0e5
--- /dev/null
+++ b/public/table/table.html
@@ -0,0 +1,103 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Overview
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
![]()
+
+
+
+
+
+ 123
+
+
+
+ 456
+
+
+
+ 789
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/public/table/tables.css b/public/table/tables.css
new file mode 100644
index 00000000..a883562e
--- /dev/null
+++ b/public/table/tables.css
@@ -0,0 +1,185 @@
+#helvetica-demo {
+ display: flex;
+ justify-content: center;
+ margin-left: 530px;
+ margin-bottom: -80px;
+}
+
+#background {
+ /* BOX MODEL */
+ width: 100%;
+ height: 450px;
+ /* ENHANCEMENT */
+ background-image: url('/img/sea.jpg');
+ background-position: center center;
+ background-size: cover;
+ background-repeat: no-repeat;
+ mask-image: linear-gradient(to bottom, rgba(0, 0, 0, 1), rgba(0, 0, 0, 0));
+ -webkit-mask-image: -webkit-gradient(linear, left top, left bottom, from(rgba(0, 0, 0, 1)), to(rgba(0, 0, 0, 0)));
+ z-index: -1;
+}
+
+#namebox {
+ width: 400px;
+ height: 50px;
+ background: black;
+ color: white;
+ margin: 0 auto;
+ text-align: center;
+ font-size: 24pt;
+ margin-bottom: 20px;
+}
+
+#handwritten {
+ margin: 0 auto;
+ width: 500px;
+ text-align: center;
+ font-style: bold;
+ font-size: 18pt;
+ font-family: 'Great Vibes', cursive;
+ margin-bottom: 100px;
+}
+
+
+/* .avatar {
+ width: 200px;
+ height: 200px;
+ margin: 30px;
+ background-image: url('/img/avatar.png');
+ background-position: center center;
+ background-size: 200px;
+}
+
+.avatar:hover {
+ background-image: url('/img/avatar-alt.png');
+} */
+
+body {
+ font-family: 'Montserrat', sans-serif;
+}
+
+.content {
+ background: white;
+ margin: -220px 5% 100px;
+}
+
+.to-top {
+ position: fixed;
+ bottom: 90px;
+ right: 20px;
+}
+
+.center-block {
+ display: block;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+#table img {
+ width: 60px;
+ height: 60px;
+ background-position: center center;
+ background-size: 60px;
+ border-radius: 30px;
+ box-shadow: 0px 0px 10px #222222;
+ background-color: white;
+}
+
+#table td {
+ vertical-align: middle;
+}
+
+#footer {
+ display: flex;
+ justify-content: space-around;
+ background-color: #3c3d41;
+ color: #fff;
+ padding-top: 20px;
+ padding-bottom: 10px;
+}
+
+#footer a {
+ color: #d2d1d1c0;
+ text-decoration: none;
+}
+
+#footer a:hover {
+ color: #fff;
+}
+
+#modify-group {
+ display: none;
+ text-align: center;
+}
+
+#modify-btn-group {
+ display: flex;
+}
+
+#people-form td {
+ display: flex;
+}
+
+nav .btn {
+ margin-left: 10px;
+}
+
+#info-name {
+ font-size: 28pt;
+}
+
+#info-pic {
+ width: 80px;
+ height: 80px;
+ background-position: center center;
+ background-size: 80px;
+ border-radius: 20px;
+ box-shadow: 0px 0px 15px black;
+ background-color: white;
+}
+
+#stats {
+ display: flex;
+ justify-content: space-around;
+}
+
+#renderer {
+ width: 300px;
+ height: 300px;
+ background-position: center center;
+ background-size: 200px;
+ border-radius: 150px;
+ box-shadow: 0px 0px 15px black;
+ background-color: white;
+}
+
+#playme {
+ position: absolute;
+ margin-left: 110px;
+ margin-top: 110px;
+ width: 80px;
+ height: 80px;
+ text-align: center;
+ padding: 6px 0;
+ line-height: 1.42;
+ border-radius: 80px;
+}
+
+#player {
+ margin: 0 auto;
+ width: 300px;
+}
+
+/* Font Awesome Icon */
+
+#like-ico {
+ color: rgb(255, 67, 67);
+}
+
+#up-ico {
+ color: rgb(83, 143, 255)
+}
+
+#down-ico {
+ color: rgb(255, 175, 83)
+}
\ No newline at end of file
diff --git a/public/table/tables.js b/public/table/tables.js
new file mode 100644
index 00000000..1336ba92
--- /dev/null
+++ b/public/table/tables.js
@@ -0,0 +1,286 @@
+fetch('/getYou', {
+ method: 'GET',
+ headers: { 'Content-Type': 'application/json' }
+}).then(function(response) {
+ return response.json();
+}).then(function(you) {
+ localStorage.id = you._id
+ document.getElementById('handwritten').innerHTML = 'Welcome, ' + you.name + '!'
+ document.getElementById('favCount').innerHTML = you.favCount
+ document.getElementById('likes').innerHTML = you.likes
+ document.getElementById('dislikes').innerHTML = you.dislikes
+
+ document.getElementById('goTop-btn').onclick = function() {
+ document.body.scrollTop = 0
+ document.documentElement.scrollTop = 0
+ }
+ document.getElementById('ovLink').onclick = function() {
+ document.title = 'Overview'
+ refresh()
+ }
+ document.getElementById('favLink').onclick = function() {
+ document.title = 'Favorite'
+ refresh()
+ }
+ document.getElementById('blackLink').onclick = function() {
+ document.title = 'Black List'
+ refresh()
+ }
+
+ const table = document.getElementById('table')
+
+ const createNode = function(element) { return document.createElement(element) }
+ const append = function(parent, el) { return parent.appendChild(el) }
+ const makeHeadings = function() {
+ let thead = createNode('thead')
+ thead.className = 'thead-dark'
+
+ let th1 = createNode('th');
+ let th2 = createNode('th');
+ let th3 = createNode('th');
+ let th4 = createNode('th');
+ let th5 = createNode('th');
+ let th6 = createNode('th');
+ let th7 = createNode('th');
+ let th8 = createNode('th');
+ let th9 = createNode('th');
+
+ th1.innerHTML = 'Picture'
+ th2.innerHTML = 'Name'
+ th3.innerHTML = 'Gender'
+ th4.innerHTML = 'Age'
+ th5.innerHTML = 'Hobby'
+ th6.innerHTML = 'Likes'
+ th7.innerHTML = 'Dislikes'
+ th8.innerHTML = 'Match Score'
+ th9.innerHTML = 'Operations'
+
+ let tr = createNode('tr');
+ append(tr, th1);
+ append(tr, th2);
+ append(tr, th3);
+ append(tr, th4);
+ append(tr, th5);
+ append(tr, th6);
+ append(tr, th7);
+ append(tr, th8);
+ append(tr, th9);
+ append(thead, tr)
+ append(table, thead)
+ }
+
+ const makeGender = function(row) {
+ let gender = createNode('i')
+ if (row.gender === 'Male') gender.className = 'fa fa-male'
+ else gender.className = 'fa fa-female'
+ return gender
+ }
+
+ const update = function(user) {
+ fetch('/updateUser', {
+ method: 'POST',
+ body: JSON.stringify(user),
+ headers: { 'Content-Type': 'application/json' }
+ }).then(function(response) {
+ console.log("Post sent to server: " + response)
+ })
+ }
+
+ const makeHeart = function(row) {
+ let heart = createNode('i');
+ if (you.likedList.includes(row.username)) {
+ heart.className = 'fa fa-heart';
+ heart.style.color = 'red';
+ } else {
+ heart.className = 'fa fa-heart-o';
+ heart.style.color = 'black';
+ }
+
+ heart.onclick = function(e) {
+ console.log(you)
+ if (heart.className === 'fa fa-heart') {
+ heart.className = 'fa fa-heart-o';
+ heart.style.color = 'black';
+ row.favCount -= 1
+ update(row)
+ you.likedList = you.likedList.filter((value => { return value !== row.username }))
+ update(you)
+ refresh()
+ } else {
+ heart.className = 'fa fa-heart';
+ heart.style.color = 'red';
+ row.favCount += 1
+ update(row)
+ you.likedList.push(row.username)
+ update(you)
+ refresh()
+ }
+ e.preventDefault()
+ return false
+ };
+ return heart;
+ };
+ const makeBomb = function(row) {
+ let bomb = createNode('i')
+ if (document.title === 'Black List') bomb.className = 'fa fa-recycle';
+ else bomb.className = 'fa fa-bomb';
+
+ bomb.onclick = function(e) {
+ if (bomb.className === 'fa fa-bomb') {
+ you.blackList.push(row.username)
+ update(you)
+ refresh()
+ } else {
+ you.blackList = you.blackList.filter((value => { return value !== row.username }))
+ update(you)
+ refresh()
+ }
+ e.preventDefault();
+ return false;
+ };
+ return bomb
+ }
+ const makeComment = function(row) {
+ let comment = createNode('i')
+ comment.className = 'fas fa-comments'
+ comment.onclick = function(e) {
+ let comment = prompt("Please enter your comment", "You look hot!")
+ if (comment !== null && comment !== "") {
+ alert("You have made the following comment: \n" + comment)
+ row.comments.push([you.pic, you.name, comment])
+ update(row)
+ } else alert('Comment canceled')
+ e.preventDefault()
+ return false
+ }
+ return comment
+ }
+ const makeLike = function(row) {
+ let like = createNode('i')
+ like.className = 'fa fa-thumbs-o-up'
+ like.onmouseover = function() { like.className = 'fa fa-thumbs-up' }
+ like.onmouseleave = function() { like.className = 'fa fa-thumbs-o-up' }
+ like.onclick = function(e) {
+ row.likes += 1
+ update(row)
+ refresh()
+ e.preventDefault()
+ return false
+ }
+ return like
+ }
+ const makeDislike = function(row) {
+ let dislike = createNode('i')
+ dislike.className = 'fa fa-thumbs-o-down'
+ dislike.onmouseover = function() { dislike.className = 'fa fa-thumbs-down' }
+ dislike.onmouseleave = function() { dislike.className = 'fa fa-thumbs-o-down' }
+ dislike.onclick = function(e) {
+ row.dislikes += 1
+ update(row)
+ refresh()
+ e.preventDefault()
+ return false
+ }
+ return dislike
+ }
+ const calculateScore = function(row) {
+ let score = 0;
+ if (you.gender === row.gender) score -= 30;
+ else score += 30;
+ if (you.hobby === row.hobby) score += 10;
+ else score -= 10;
+ score -= Math.abs(you.age - row.age);
+ return score;
+ }
+ const makeImg = function(row) {
+ let img = createNode('img')
+ if (row.pic) img.src = row.pic
+ img.onclick = function(e) {
+ let id = row._id
+ console.log(id)
+ localStorage.id = id
+ location.href = '../profile/profile.html'
+ e.preventDefault()
+ return false
+ }
+ return img
+ }
+ const makeRow = function(row) {
+ let tr = createNode('tr')
+ let td1 = createNode('th')
+ let td2 = createNode('th')
+ let td3 = createNode('th')
+ let td4 = createNode('th')
+ let td5 = createNode('th')
+ let td6 = createNode('th')
+ let td7 = createNode('th')
+ let td8 = createNode('th')
+ let td9 = createNode('th')
+
+ let space1 = createNode('span')
+ let space2 = createNode('span')
+ space1.innerHTML = '\xa0\xa0'
+ space2.innerHTML = '\xa0\xa0'
+
+ append(td1, makeImg(row))
+ td2.innerHTML = row.name
+ append(td3, makeGender(row))
+ td4.innerHTML = row.age
+ td5.innerHTML = row.hobby
+ td6.innerHTML = row.likes + ' '
+ append(td6, makeLike(row))
+ td7.innerHTML = row.dislikes + ' '
+ append(td7, makeDislike(row))
+ td8.innerHTML = calculateScore(row)
+ append(td9, makeHeart(row))
+ append(td9, space1)
+ append(td9, makeComment(row))
+ append(td9, space2)
+ append(td9, makeBomb(row))
+
+ append(tr, td1)
+ append(tr, td2)
+ append(tr, td3)
+ append(tr, td4)
+ append(tr, td5)
+ append(tr, td6)
+ append(tr, td7)
+ append(tr, td8)
+ append(tr, td9)
+
+ return tr
+ }
+
+ const refresh = function() {
+ fetch('/refreshAll', {
+ method: 'GET',
+ headers: { 'Content-Type': 'application/json' }
+ }).then(function(response) {
+ return response.json()
+ }).then(function(data) {
+ table.innerHTML = "";
+ makeHeadings()
+ data.map(function(row) {
+ if (row.username !== you.username) {
+ switch (document.title) {
+ case 'Overview':
+ if (!you.blackList.includes(row.username)) append(table, makeRow(row));
+ break;
+ case 'Favorite':
+ if (you.likedList.includes(row.username)) append(table, makeRow(row));
+ break;
+ case 'Black List':
+ if (you.blackList.includes(row.username)) append(table, makeRow(row));
+ break;
+ default:
+ console.log('default')
+ }
+ }
+ })
+ })
+ }
+ refresh()
+
+ document.getElementById('info-name').innerHTML = "Hi, " + you.name + "!";
+ document.getElementById('info-pic').src = you.pic;
+})
\ No newline at end of file
diff --git a/server.js b/server.js
new file mode 100644
index 00000000..548804e7
--- /dev/null
+++ b/server.js
@@ -0,0 +1,171 @@
+// Setup
+const express = require('express')
+const app = express()
+
+const bodyParser = require('body-parser')
+app.use(express.static('public'))
+app.use(bodyParser.json({ limit: '10mb', extended: true }))
+app.use(bodyParser.urlencoded({ limit: '10mb', extended: true }))
+
+const morgan = require('morgan')
+app.use(morgan('tiny'))
+
+const favicon = require('serve-favicon')
+app.use(favicon(__dirname + '/public/img/favicon.png'))
+
+const cookieParser = require('cookie-parser')
+app.use(cookieParser())
+
+app.listen(3000)
+
+// ================================================================================
+
+// MongoDB
+const mongodb = require('mongodb')
+const uri = 'mongodb+srv://percy:percy@percy0-a4fle.mongodb.net/admin?retryWrites=true&w=majority'
+
+const client = new mongodb.MongoClient(uri, { useNewUrlParser: true, useUnifiedTopology: true })
+let collection = null
+
+let allUsers
+const copyAllUsers = function() { collection.find({}).toArray().then(result => allUsers = result) }
+client.connect().then(() => {
+ return client.db('percy-a5').createCollection('users')
+}).then(__collection => {
+ collection = __collection
+ return collection.find({}).toArray()
+}).then(result => allUsers = result)
+
+app.use((req, res, next) => {
+ if (collection !== null) next()
+ else res.status(503).send()
+})
+
+// ================================================================================
+
+// Passport
+const passport = require('passport');
+const Local = require('passport-local').Strategy;
+const session = require('express-session');
+
+let you = {};
+
+const myLocalStrategy = function(username, password, done) {
+ const user = allUsers.find(__user => __user.username === username);
+ if (user === undefined) return done(null, false, { message: 'user not found' });
+ else if (user.password === password) return done(null, { username, password });
+ else return done(null, false, { message: 'incorrect password' });
+};
+
+passport.use(new Local(myLocalStrategy))
+passport.initialize()
+
+passport.serializeUser((user, done) => done(null, user.username))
+passport.deserializeUser((username, done) => {
+ const user = allUsers.find(u => u.username === username)
+ if (user !== undefined) done(null, user)
+ else done(null, false, { message: 'user not found; session not restored' })
+})
+app.use(session({ secret: 'cats cats cats', resave: false, saveUninitialized: false }))
+app.use(passport.initialize())
+app.use(passport.session())
+app.post('/test', function(req, res) {
+ console.log('authenticate with cookie?', req.user)
+ res.json({ status: 'success' })
+})
+
+app.post('/login', passport.authenticate('local'), function(req, res) {
+ you = allUsers.find(__user => __user.username === req.user.username)
+ res.json({ status: true })
+})
+
+// ================================================================================
+
+// GET
+app.get('/', function(request, response) {
+ response.sendFile(__dirname + '/index.html');
+})
+app.get('/checkDup', function(request, response) {
+ let usernames = []
+ for (let i = 0; i < allUsers.length; i++) {
+ usernames.push(allUsers[i]['username'])
+ }
+ response.send(usernames)
+})
+app.get('/refreshAll', function(request, response) {
+ collection.find({}).toArray().then(result => response.json(result))
+})
+app.get('/getYou', function(request, response) {
+ you = allUsers.find(__user => __user.username === you.username)
+ response.send(you)
+})
+
+// ================================================================================
+
+// POST
+app.post('/add', function(request, response) {
+ collection.insertOne(request.body).then(result => {
+ response.json(result)
+ copyAllUsers()
+ })
+})
+
+app.post('/delete', function(request, response) {
+ collection.deleteOne({ _id: mongodb.ObjectID(you._id) }).then(result => {
+ response.json(result)
+ copyAllUsers()
+ })
+})
+
+app.post('/updateInfo', function(request, response) {
+ collection.updateOne({ _id: mongodb.ObjectID(you._id) }, {
+ $set: {
+ name: request.body.name,
+ age: request.body.age,
+ gender: request.body.gender,
+ hobby: request.body.hobby,
+ pic: request.body.pic,
+ salary: request.body.salary,
+ whatsUp: request.body.whatsUp,
+ location: request.body.location,
+ selfIntro: request.body.selfIntro
+ }
+ }).then(result => {
+ response.json(result)
+ copyAllUsers()
+ })
+})
+app.post('/updateUser', function(request, response) {
+ // console.log(request.body)
+ collection.updateOne({ _id: mongodb.ObjectID(request.body._id) }, {
+ $set: {
+ likedList: request.body.likedList,
+ blackList: request.body.blackList,
+ comments: request.body.comments,
+ likes: request.body.likes,
+ dislikes: request.body.dislikes,
+ favCount: request.body.favCount
+ }
+ }).then(result => {
+ response.json(result)
+ copyAllUsers()
+ })
+})
+
+// ================================================================================
+
+// Response Time
+const responseTime = require('response-time')
+const StatsD = require('node-statsd')
+const stats = new StatsD()
+stats.socket.on('error', function(error) {
+ console.error(error.stack)
+})
+app.use(responseTime(function(req, res, time) {
+ let stat = (req.method + req.url).toLowerCase()
+ .replace(/[:.]/g, '')
+ .replace(/\//g, '_')
+ stats.timing(stat, time)
+}))
+
+// ================================================================================
\ No newline at end of file