diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..0f15419 Binary files /dev/null and b/.DS_Store differ diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..37d7e73 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +node_modules +.env diff --git a/.sequelizerc b/.sequelizerc new file mode 100644 index 0000000..5e15393 --- /dev/null +++ b/.sequelizerc @@ -0,0 +1,17 @@ +var path = require('path'); + +// Set options +var config = { + "config": "./config/sequelize.json", + "migrations-path": "./migrations/sequelize", + "seeders-path": "./seeds/sequelize", + "models-path": "./models/sequelize" +}; + +// Resolve paths to absolute paths +Object.keys(config).forEach((key) => { + config[key] = path.resolve(config[key]); +}); + +// Export like any normal module +module.exports = config; diff --git a/Procfile b/Procfile new file mode 100644 index 0000000..e1d4131 --- /dev/null +++ b/Procfile @@ -0,0 +1 @@ +web: node app.js diff --git a/README.md b/README.md index 47801d7..36fc481 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,26 @@ -# project_mimirs_market -A Viking eCommerce store for Thunder Gods that like to buy "Antique Wooden Pizzas" +# money burner + +https://money-burner.herokuapp.com/ + +A fun e commerce app that integrates multiple technologies. + +Gregory Alford + +## Technologies used: + +* Node +* Express +* Handlebars +* Mongoose +* Sequelize +* Stripe + +## Deployment + +Check it out: + +https://money-burner.herokuapp.com/ + +## Description + +You can search from 200 dynamically generated products, and filter by search queries, category, and price or sort by name, or price. Add these products to your cart and view similar items. Checkout and enter some fake info, a Visa card number 4242 4242 4242 4242 will pass. View orders from the Admin orders page. View Admin analytics where you can see data such as Revenue by State or category. Looks great on mobile also. diff --git a/app.js b/app.js new file mode 100644 index 0000000..c32893d --- /dev/null +++ b/app.js @@ -0,0 +1,139 @@ +// sequelize model:create --name Products --attributes "name:string sku:string description:string price:integer categoryId:integer" +// sequelize model:create --name Categories --attributes "name:string" +if (process.env.NODE_ENV !== "production") { + require("dotenv").config(); +} + +var express = require("express"); +var app = express(); + +// ---------------------------------------- +// Body Parser +// ---------------------------------------- +var bodyParser = require("body-parser"); +app.use(bodyParser.urlencoded({ extended: true })); + +// ---------------------------------------- +// Sessions/Cookies +// ---------------------------------------- +var cookieSession = require("cookie-session"); + +app.use( + cookieSession({ + name: "session", + keys: ["asdf1234567890qwer"] + }) +); + +app.use((req, res, next) => { + req.session.cart = req.session.cart || []; + res.locals.session = req.session; + res.locals.cart = req.session.cart; + + var cart = req.session.cart; + cart.quantity = cart.length; + next(); +}); + +// ---------------------------------------- +// Flash messages +// ---------------------------------------- + +var flash = require("express-flash-messages"); +app.use(flash()); + +// ---------------------------------------- +// Method Override +// ---------------------------------------- +const methodOverride = require("method-override"); +const getPostSupport = require("express-method-override-get-post-support"); + +app.use( + methodOverride( + getPostSupport.callback, + getPostSupport.options // { methods: ['POST', 'GET'] } + ) +); + +// ---------------------------------------- +// Referrer +// ---------------------------------------- +app.use((req, res, next) => { + req.session.backUrl = req.header("Referer") || "/"; + next(); +}); + +// ---------------------------------------- +// Public +// ---------------------------------------- +app.use(express.static(`${__dirname}/public`)); + +// ---------------------------------------- +// Logging +// ---------------------------------------- +var morgan = require("morgan"); +var morganToolkit = require("morgan-toolkit")(morgan); + +app.use(morganToolkit()); + +// ---------------------------------------- +// Mongoose +// ---------------------------------------- +const mongoose = require("mongoose"); +app.use((req, res, next) => { + if (mongoose.connection.readyState) { + next(); + } else { + require("./mongo")().then(() => next()); + } +}); + +// ---------------------------------------- +// Routes +// ---------------------------------------- +var productsRouter = require("./routers/products"); +app.use("/", productsRouter); + +var cartRouter = require("./routers/cart"); +app.use("/", cartRouter); + +var checkoutRouter = require("./routers/checkout"); +app.use("/", checkoutRouter); + +var adminRouter = require("./routers/admin"); +app.use("/", adminRouter); + +// ---------------------------------------- +// Template Engine +// ---------------------------------------- +var expressHandlebars = require("express-handlebars"); + +var hbs = expressHandlebars.create({ + partialsDir: "views/", + defaultLayout: "application", + helpers: { + photoId: id => Number(id) % 9 + } +}); + +app.engine("handlebars", hbs.engine); +app.set("view engine", "handlebars"); + +// expressHandlebars.registerHelper("photoId", ); + +// ---------------------------------------- +// Server +// ---------------------------------------- +var port = process.env.PORT || process.argv[2] || 3000; +var host = "localhost"; + +var args; +process.env.NODE_ENV === "production" ? (args = [port]) : (args = [port, host]); + +args.push(() => { + console.log(`Listening: http://${host}:${port}`); +}); + +app.listen.apply(app, args); + +module.exports = app; diff --git a/config/mongoose.json b/config/mongoose.json new file mode 100644 index 0000000..eaff31c --- /dev/null +++ b/config/mongoose.json @@ -0,0 +1,13 @@ +{ + "development": { + "database": "project_mimirs_market_development", + "host": "localhost" + }, + "test": { + "database": "project_mimirs_market_test", + "host": "localhost" + }, + "production": { + "use_env_variable": "MONGOLAB_BRONZE_URI" + } +} diff --git a/config/sequelize.json b/config/sequelize.json new file mode 100644 index 0000000..a123a2b --- /dev/null +++ b/config/sequelize.json @@ -0,0 +1,20 @@ +{ + "development": { + "username": "GREG", + "password": null, + "database": "project_mimirs_market_development", + "host": "127.0.0.1", + "dialect": "postgres" + }, + "test": { + "username": "GREG", + "password": null, + "database": "project_mimirs_market_test", + "host": "127.0.0.1", + "dialect": "postgres" + }, + "production": { + "use_env_variable": "DATABASE_URL", + "dialect": "postgres" + } +} diff --git a/migrations/sequelize/20171115015756-create-products.js b/migrations/sequelize/20171115015756-create-products.js new file mode 100644 index 0000000..068350d --- /dev/null +++ b/migrations/sequelize/20171115015756-create-products.js @@ -0,0 +1,41 @@ +"use strict"; +module.exports = { + up: (queryInterface, Sequelize) => { + return queryInterface.createTable("Products", { + id: { + allowNull: false, + autoIncrement: true, + primaryKey: true, + type: Sequelize.INTEGER + }, + name: { + type: Sequelize.STRING + }, + sku: { + type: Sequelize.STRING + }, + description: { + type: Sequelize.STRING + }, + price: { + type: Sequelize.INTEGER + }, + categoryId: { + type: Sequelize.INTEGER + }, + createdAt: { + allowNull: false, + type: Sequelize.DATE, + defaultValue: Sequelize.fn("NOW") + }, + updatedAt: { + allowNull: false, + type: Sequelize.DATE, + defaultValue: Sequelize.fn("NOW") + } + }); + }, + down: (queryInterface, Sequelize) => { + return queryInterface.dropTable("Products"); + } +}; diff --git a/migrations/sequelize/20171115015814-create-categories.js b/migrations/sequelize/20171115015814-create-categories.js new file mode 100644 index 0000000..80fa822 --- /dev/null +++ b/migrations/sequelize/20171115015814-create-categories.js @@ -0,0 +1,29 @@ +"use strict"; +module.exports = { + up: (queryInterface, Sequelize) => { + return queryInterface.createTable("Categories", { + id: { + allowNull: false, + autoIncrement: true, + primaryKey: true, + type: Sequelize.INTEGER + }, + name: { + type: Sequelize.STRING + }, + createdAt: { + allowNull: false, + type: Sequelize.DATE, + defaultValue: Sequelize.fn("NOW") + }, + updatedAt: { + allowNull: false, + type: Sequelize.DATE, + defaultValue: Sequelize.fn("NOW") + } + }); + }, + down: (queryInterface, Sequelize) => { + return queryInterface.dropTable("Categories"); + } +}; diff --git a/models/mongoose/index.js b/models/mongoose/index.js new file mode 100644 index 0000000..9f58b73 --- /dev/null +++ b/models/mongoose/index.js @@ -0,0 +1,11 @@ +const mongoose = require("mongoose"); +const bluebird = require("bluebird"); + +mongoose.Promise = bluebird; + +const models = {}; + +// Load models and attach to models here +models.Order = require("./order"); + +module.exports = models; diff --git a/models/mongoose/order.js b/models/mongoose/order.js new file mode 100644 index 0000000..95a8967 --- /dev/null +++ b/models/mongoose/order.js @@ -0,0 +1,24 @@ +var mongoose = require("mongoose"); +var Schema = mongoose.Schema; + +var OrderSchema = new Schema( + { + fname: String, + lname: String, + address: String, + city: String, + state: String, + zip: String, + total: Number, + orderedProducts: [], + stripe: {}, + stripeToken: String + }, + { + timestamps: true + } +); + +var Order = mongoose.model("Order", OrderSchema); + +module.exports = Order; diff --git a/models/sequelize/categories.js b/models/sequelize/categories.js new file mode 100644 index 0000000..a5486ad --- /dev/null +++ b/models/sequelize/categories.js @@ -0,0 +1,13 @@ +"use strict"; +module.exports = (sequelize, DataTypes) => { + var Categories = sequelize.define("Categories", { + name: DataTypes.STRING + }); + + Categories.associate = function(models) { + Categories.hasMany(models.Products, { + foreignKey: "categoryId" + }); + }; + return Categories; +}; diff --git a/models/sequelize/index.js b/models/sequelize/index.js new file mode 100644 index 0000000..0d4edf8 --- /dev/null +++ b/models/sequelize/index.js @@ -0,0 +1,36 @@ +'use strict'; + +var fs = require('fs'); +var path = require('path'); +var Sequelize = require('sequelize'); +var basename = path.basename(__filename); +var env = process.env.NODE_ENV || 'development'; +var config = require(__dirname + '/../../config/sequelize.json')[env]; +var db = {}; + +if (config.use_env_variable) { + var sequelize = new Sequelize(process.env[config.use_env_variable]); +} else { + var sequelize = new Sequelize(config.database, config.username, config.password, config); +} + +fs + .readdirSync(__dirname) + .filter(file => { + return (file.indexOf('.') !== 0) && (file !== basename) && (file.slice(-3) === '.js'); + }) + .forEach(file => { + var model = sequelize['import'](path.join(__dirname, file)); + db[model.name] = model; + }); + +Object.keys(db).forEach(modelName => { + if (db[modelName].associate) { + db[modelName].associate(db); + } +}); + +db.sequelize = sequelize; +db.Sequelize = Sequelize; + +module.exports = db; diff --git a/models/sequelize/products.js b/models/sequelize/products.js new file mode 100644 index 0000000..69e4d86 --- /dev/null +++ b/models/sequelize/products.js @@ -0,0 +1,17 @@ +"use strict"; +module.exports = (sequelize, DataTypes) => { + var Products = sequelize.define("Products", { + name: DataTypes.STRING, + sku: DataTypes.STRING, + description: DataTypes.STRING, + price: DataTypes.INTEGER, + categoryId: DataTypes.INTEGER + }); + + Products.associate = function(models) { + Products.belongsTo(models.Categories, { + foreignKey: "categoryId" + }); + }; + return Products; +}; diff --git a/mongo.js b/mongo.js new file mode 100644 index 0000000..e34347f --- /dev/null +++ b/mongo.js @@ -0,0 +1,10 @@ +const mongoose = require("mongoose"); +var env = process.env.NODE_ENV || "development"; +var config = require("./config/mongoose")[env]; + +module.exports = () => { + var envUrl = process.env[config.use_env_variable]; + var localUrl = `mongodb://${config.host}/${config.database}`; + var mongoUrl = envUrl ? envUrl : localUrl; + return mongoose.connect(mongoUrl, { useMongoClient: true }); +}; diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..615983d --- /dev/null +++ b/package-lock.json @@ -0,0 +1,2237 @@ +{ + "name": "project_mimirs_market", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@types/geojson": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-1.0.6.tgz", + "integrity": "sha512-Xqg/lIZMrUd0VRmSRbCAewtwGZiAk3mEUDvV4op1tGl+LvyPcb/MIOSxTl9z+9+J+R4/vpjiCAT4xeKzH9ji1w==" + }, + "@types/node": { + "version": "9.4.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-9.4.6.tgz", + "integrity": "sha512-CTUtLb6WqCCgp6P59QintjHWqzf4VL1uPA27bipLAPxFqrtK1gEYllePzTICGqQ8rYsCbpnsNypXjjDzGAAjEQ==" + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "accepts": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.4.tgz", + "integrity": "sha1-hiRnWMfdbSGmR0/whKR0DsBesh8=", + "requires": { + "mime-types": "2.1.17", + "negotiator": "0.6.1" + } + }, + "align-text": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", + "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", + "requires": { + "kind-of": "3.2.2", + "longest": "1.0.1", + "repeat-string": "1.6.1" + } + }, + "amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=" + }, + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=" + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "1.9.1" + } + }, + "any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=" + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" + }, + "asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" + }, + "async": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.1.4.tgz", + "integrity": "sha1-LSFgx3iAMuTdbL4lAvH5osj2zeQ=", + "requires": { + "lodash": "4.17.5" + } + }, + "babel-runtime": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz", + "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=", + "requires": { + "core-js": "2.5.3", + "regenerator-runtime": "0.11.1" + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "basic-auth": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-2.0.0.tgz", + "integrity": "sha1-AV2z81PgLlY3d1X5YnQuiYHnu7o=", + "requires": { + "safe-buffer": "5.1.1" + } + }, + "bluebird": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.0.tgz", + "integrity": "sha1-eRQg1/VR7qKJdFOop3ZT+WYG1nw=" + }, + "body-parser": { + "version": "1.18.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz", + "integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=", + "requires": { + "bytes": "3.0.0", + "content-type": "1.0.4", + "debug": "2.6.9", + "depd": "1.1.1", + "http-errors": "1.6.2", + "iconv-lite": "0.4.19", + "on-finished": "2.3.0", + "qs": "6.5.1", + "raw-body": "2.3.2", + "type-is": "1.6.15" + }, + "dependencies": { + "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" + } + } + } + }, + "brace-expansion": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", + "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", + "requires": { + "balanced-match": "1.0.0", + "concat-map": "0.0.1" + } + }, + "bson": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/bson/-/bson-1.0.5.tgz", + "integrity": "sha512-D4SCtud6mlEb48kXdTHU31DRU0bsgOJ+4St1Dcx30uYNnf/aGc+hC9gHB/z0Eth8HYYs/hr0SFdyZViht19SwA==" + }, + "buffer-shims": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz", + "integrity": "sha1-mXjOMXOIxkmth5MCjDR37wRKi1E=" + }, + "buffer-writer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-1.0.1.tgz", + "integrity": "sha1-Iqk2kB4wKa/NdUfrRIfOtpejvwg=" + }, + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=" + }, + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=" + }, + "camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=" + }, + "center-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", + "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", + "optional": true, + "requires": { + "align-text": "0.1.4", + "lazy-cache": "1.0.4" + } + }, + "chalk": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.2.tgz", + "integrity": "sha512-ZM4j2/ld/YZDc3Ma8PgN7gyAk+kHMMMyzLNryCPGhWrsfAuDVeuid5bpRFTDgMH9JBK2lA4dyyAkkZYF/WcqDQ==", + "requires": { + "ansi-styles": "3.2.1", + "escape-string-regexp": "1.0.5", + "supports-color": "5.3.0" + } + }, + "cli-color": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/cli-color/-/cli-color-1.2.0.tgz", + "integrity": "sha1-OlrnT9drYmevZm5p4q+70B3vNNE=", + "requires": { + "ansi-regex": "2.1.1", + "d": "1.0.0", + "es5-ext": "0.10.39", + "es6-iterator": "2.0.3", + "memoizee": "0.4.12", + "timers-ext": "0.1.3" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + } + } + }, + "cli-highlight": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/cli-highlight/-/cli-highlight-1.2.3.tgz", + "integrity": "sha512-cmc4Y2kJuEpT2KZd9pgWWskpDMMfJu2roIcY1Ya/aIItufF5FKsV/NtA6vvdhSUllR8KJfvQDNmIcskU+MKLDg==", + "requires": { + "chalk": "2.3.2", + "highlight.js": "9.12.0", + "mz": "2.7.0", + "parse5": "3.0.3", + "yargs": "10.1.2" + } + }, + "cliui": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.0.0.tgz", + "integrity": "sha512-nY3W5Gu2racvdDk//ELReY+dHjb9PlIcVDFXP72nVIhq2Gy3LuVXYwJoPVudwQnv1shtohpgkdCKT2YaKY0CKw==", + "requires": { + "string-width": "2.1.1", + "strip-ansi": "4.0.0", + "wrap-ansi": "2.1.0" + } + }, + "cls-bluebird": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cls-bluebird/-/cls-bluebird-2.1.0.tgz", + "integrity": "sha1-N+8eCAqP+1XC9BZPU28ZGeeWiu4=", + "requires": { + "is-bluebird": "1.0.2", + "shimmer": "1.2.0" + } + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=" + }, + "color-convert": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz", + "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "commander": { + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.15.0.tgz", + "integrity": "sha512-7B1ilBwtYSbetCgTY1NJFg+gVpestg0fdA1MhC1Vs4ssyfSXnCAjFr+QcQM9/RedXC0EaUx1sG8Smgw2VfgKEg==" + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "config-chain": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.11.tgz", + "integrity": "sha1-q6CXR9++TD5w52am5BWG4YWfxvI=", + "requires": { + "ini": "1.3.5", + "proto-list": "1.2.4" + } + }, + "content-disposition": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz", + "integrity": "sha1-DPaLud318r55YcOoUXjLhdunjLQ=" + }, + "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-session": { + "version": "2.0.0-beta.3", + "resolved": "https://registry.npmjs.org/cookie-session/-/cookie-session-2.0.0-beta.3.tgz", + "integrity": "sha512-zyqm5tA0z9yMEB/xyP7lnRnqp8eLR2e0dap+9+rBwVigla9yPKn8XTL1jJymog8xjfrowqW2o5LUjixQChkqrw==", + "requires": { + "cookies": "0.7.1", + "debug": "3.1.0", + "on-headers": "1.0.1", + "safe-buffer": "5.1.1" + } + }, + "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.7.1", + "resolved": "https://registry.npmjs.org/cookies/-/cookies-0.7.1.tgz", + "integrity": "sha1-fIphX1SBxhq58WyDNzG8uPZjuZs=", + "requires": { + "depd": "1.1.1", + "keygrip": "1.0.2" + } + }, + "core-js": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.3.tgz", + "integrity": "sha1-isw4NFgk8W2DZbfJtCWRaOjtYD4=" + }, + "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=" + }, + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "requires": { + "lru-cache": "4.1.1", + "shebang-command": "1.2.0", + "which": "1.3.0" + } + }, + "d": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz", + "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=", + "requires": { + "es5-ext": "0.10.39" + } + }, + "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" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" + }, + "define-properties": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.2.tgz", + "integrity": "sha1-g6c/L+pWmJj7c3GTyPhzyvbUXJQ=", + "requires": { + "foreach": "2.0.5", + "object-keys": "1.0.11" + } + }, + "depd": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz", + "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k=" + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "dotenv": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-4.0.0.tgz", + "integrity": "sha1-hk7xN5rO1Vzm+V3r7NzhefegzR0=" + }, + "dottie": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dottie/-/dottie-2.0.0.tgz", + "integrity": "sha1-2hkZgci41xPKARXViYzzl8Lw3dA=" + }, + "editorconfig": { + "version": "0.13.3", + "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.13.3.tgz", + "integrity": "sha512-WkjsUNVCu+ITKDj73QDvi0trvpdDWdkDyHybDGSXPfekLCqwmpD7CP7iPbvBgosNuLcI96XTDwNa75JyFl7tEQ==", + "requires": { + "bluebird": "3.5.0", + "commander": "2.15.0", + "lru-cache": "3.2.0", + "semver": "5.5.0", + "sigmund": "1.0.1" + }, + "dependencies": { + "lru-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-3.2.0.tgz", + "integrity": "sha1-cXibO39Tmb7IVl3aOKow0qCX7+4=", + "requires": { + "pseudomap": "1.0.2" + } + } + } + }, + "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.1", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.1.tgz", + "integrity": "sha1-eePVhlU0aQn+bw9Fpd5oEDspTSA=" + }, + "error-ex": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", + "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", + "requires": { + "is-arrayish": "0.2.1" + } + }, + "es5-ext": { + "version": "0.10.39", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.39.tgz", + "integrity": "sha512-AlaXZhPHl0po/uxMx1tyrlt1O86M6D5iVaDH8UgLfgek4kXTX6vzsRfJQWC2Ku+aG8pkw1XWzh9eTkwfVrsD5g==", + "requires": { + "es6-iterator": "2.0.3", + "es6-symbol": "3.1.1" + } + }, + "es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.39", + "es6-symbol": "3.1.1" + } + }, + "es6-promise": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.2.1.tgz", + "integrity": "sha1-7FYjOGgDKQkgcXDDlEjiREndH8Q=" + }, + "es6-symbol": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", + "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.39" + } + }, + "es6-weak-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.2.tgz", + "integrity": "sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=", + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.39", + "es6-iterator": "2.0.3", + "es6-symbol": "3.1.1" + } + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" + }, + "event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.39" + } + }, + "execa": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", + "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", + "requires": { + "cross-spawn": "5.1.0", + "get-stream": "3.0.0", + "is-stream": "1.1.0", + "npm-run-path": "2.0.2", + "p-finally": "1.0.0", + "signal-exit": "3.0.2", + "strip-eof": "1.0.0" + } + }, + "express": { + "version": "4.16.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.16.2.tgz", + "integrity": "sha1-41xt/i1kt9ygpc1PIXgb4ymeB2w=", + "requires": { + "accepts": "1.3.4", + "array-flatten": "1.1.1", + "body-parser": "1.18.2", + "content-disposition": "0.5.2", + "content-type": "1.0.4", + "cookie": "0.3.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "1.1.1", + "encodeurl": "1.0.1", + "escape-html": "1.0.3", + "etag": "1.8.1", + "finalhandler": "1.1.0", + "fresh": "0.5.2", + "merge-descriptors": "1.0.1", + "methods": "1.1.2", + "on-finished": "2.3.0", + "parseurl": "1.3.2", + "path-to-regexp": "0.1.7", + "proxy-addr": "2.0.2", + "qs": "6.5.1", + "range-parser": "1.2.0", + "safe-buffer": "5.1.1", + "send": "0.16.1", + "serve-static": "1.13.1", + "setprototypeof": "1.1.0", + "statuses": "1.3.1", + "type-is": "1.6.15", + "utils-merge": "1.0.1", + "vary": "1.1.2" + }, + "dependencies": { + "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" + } + } + } + }, + "express-flash-messages": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/express-flash-messages/-/express-flash-messages-0.1.1.tgz", + "integrity": "sha1-QCDOUXjDuzZjlN6QZiILwnBb1vI=" + }, + "express-handlebars": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/express-handlebars/-/express-handlebars-3.0.0.tgz", + "integrity": "sha1-gKBwu4GbCeSvLKbQeA91zgXnXC8=", + "requires": { + "glob": "6.0.4", + "graceful-fs": "4.1.11", + "handlebars": "4.0.11", + "object.assign": "4.0.4", + "promise": "7.3.1" + } + }, + "express-method-override-get-post-support": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/express-method-override-get-post-support/-/express-method-override-get-post-support-1.0.1.tgz", + "integrity": "sha512-TRHJwmYeQQkgsJfzeIO2vQmY4JBlnDo0H2CLKJ03+dG6yl6FPGx0GFv4FAOvrybHqHn1Bs68iJGZr72SFR/UyQ==" + }, + "faker": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/faker/-/faker-4.1.0.tgz", + "integrity": "sha1-HkW7vsxndLPBlfrSg1EJxtdIzD8=" + }, + "finalhandler": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.0.tgz", + "integrity": "sha1-zgtoVbRYU+eRsvzGgARtiCU91/U=", + "requires": { + "debug": "2.6.9", + "encodeurl": "1.0.1", + "escape-html": "1.0.3", + "on-finished": "2.3.0", + "parseurl": "1.3.2", + "statuses": "1.3.1", + "unpipe": "1.0.0" + }, + "dependencies": { + "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" + } + } + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "requires": { + "locate-path": "2.0.0" + } + }, + "foreach": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", + "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=" + }, + "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=" + }, + "fs-extra": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-4.0.3.tgz", + "integrity": "sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg==", + "requires": { + "graceful-fs": "4.1.11", + "jsonfile": "4.0.0", + "universalify": "0.1.1" + } + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" + }, + "generic-pool": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.4.2.tgz", + "integrity": "sha512-H7cUpwCQSiJmAHM4c/aFu6fUfrhWXW1ncyh8ftxEPMu6AiYkHw9K8br720TGPZJbk5eOH2bynjZD1yPvdDAmag==" + }, + "get-caller-file": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz", + "integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U=" + }, + "get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=" + }, + "glob": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz", + "integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=", + "requires": { + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" + }, + "handlebars": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.11.tgz", + "integrity": "sha1-Ywo13+ApS8KB7a5v/F0yn8eYLcw=", + "requires": { + "async": "1.5.2", + "optimist": "0.6.1", + "source-map": "0.4.4", + "uglify-js": "2.8.29" + }, + "dependencies": { + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=" + } + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" + }, + "highlight.js": { + "version": "9.12.0", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.12.0.tgz", + "integrity": "sha1-5tnb5Xy+/mB1HwKvM2GVhwyQwB4=" + }, + "hooks-fixed": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hooks-fixed/-/hooks-fixed-2.0.2.tgz", + "integrity": "sha512-YurCM4gQSetcrhwEtpQHhQ4M7Zo7poNGqY4kQGeBS6eZtOcT3tnNs01ThFa0jYBByAiYt1MjMjP/YApG0EnAvQ==" + }, + "hosted-git-info": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.6.0.tgz", + "integrity": "sha512-lIbgIIQA3lz5XaB6vxakj6sDHADJiZadYEJB+FgA+C4nubM1NwcuvUr9EJPmnH1skZqpqUzWborWo8EIUi0Sdw==" + }, + "http-errors": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz", + "integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=", + "requires": { + "depd": "1.1.1", + "inherits": "2.0.3", + "setprototypeof": "1.0.3", + "statuses": "1.3.1" + }, + "dependencies": { + "setprototypeof": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz", + "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ=" + } + } + }, + "iconv-lite": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", + "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==" + }, + "inflection": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/inflection/-/inflection-1.12.0.tgz", + "integrity": "sha1-ogCTVlbW9fa8TcdQLhrstwMihBY=" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "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==" + }, + "invert-kv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=" + }, + "ipaddr.js": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.5.2.tgz", + "integrity": "sha1-1LUFvemUaYfM8PxY2QEP+WB+P6A=" + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" + }, + "is-bluebird": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-bluebird/-/is-bluebird-1.0.2.tgz", + "integrity": "sha1-CWQ5Bg9KpBGr7hkUOoTWpVNG1uI=" + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "is-builtin-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", + "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", + "requires": { + "builtin-modules": "1.1.1" + } + }, + "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=" + }, + "is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=" + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + }, + "js-beautify": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.7.5.tgz", + "integrity": "sha512-9OhfAqGOrD7hoQBLJMTA+BKuKmoEtTJXzZ7WDF/9gvjtey1koVLuZqIY6c51aPDjbNdNtIXAkiWKVhziawE9Og==", + "requires": { + "config-chain": "1.1.11", + "editorconfig": "0.13.3", + "mkdirp": "0.5.1", + "nopt": "3.0.6" + } + }, + "js-string-escape": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/js-string-escape/-/js-string-escape-1.0.1.tgz", + "integrity": "sha1-4mJbrbwNZ8dTPp7cEGjFh65BN+8=" + }, + "jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "requires": { + "graceful-fs": "4.1.11" + } + }, + "kareem": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/kareem/-/kareem-1.5.0.tgz", + "integrity": "sha1-4+QQHZ3P3imXadr0tNtk2JXRdEg=" + }, + "keygrip": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/keygrip/-/keygrip-1.0.2.tgz", + "integrity": "sha1-rTKXxVcGneqLz+ek+kkbdcXd65E=" + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "1.1.6" + } + }, + "lazy-cache": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", + "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", + "optional": true + }, + "lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "requires": { + "invert-kv": "1.0.0" + } + }, + "load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "requires": { + "graceful-fs": "4.1.11", + "parse-json": "2.2.0", + "pify": "2.3.0", + "strip-bom": "3.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "requires": { + "p-locate": "2.0.0", + "path-exists": "3.0.0" + } + }, + "lodash": { + "version": "4.17.5", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.5.tgz", + "integrity": "sha512-svL3uiZf1RwhH+cWrfZn3A4+U58wbP0tGVTLQPbjplZxZ8ROD9VLuNgsRniTlLe7OlSqR79RUehXgpBW/s0IQw==" + }, + "lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=" + }, + "lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" + }, + "longest": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", + "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=" + }, + "lru-cache": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz", + "integrity": "sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew==", + "requires": { + "pseudomap": "1.0.2", + "yallist": "2.1.2" + } + }, + "lru-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/lru-queue/-/lru-queue-0.1.0.tgz", + "integrity": "sha1-Jzi9nw089PhEkMVzbEhpmsYyzaM=", + "requires": { + "es5-ext": "0.10.39" + } + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "mem": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/mem/-/mem-1.1.0.tgz", + "integrity": "sha1-Xt1StIXKHZAP5kiVUFOZoN+kX3Y=", + "requires": { + "mimic-fn": "1.2.0" + } + }, + "memoizee": { + "version": "0.4.12", + "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.4.12.tgz", + "integrity": "sha512-sprBu6nwxBWBvBOh5v2jcsGqiGLlL2xr2dLub3vR8dnE8YB17omwtm/0NSHl8jjNbcsJd5GMWJAnTSVe/O0Wfg==", + "requires": { + "d": "1.0.0", + "es5-ext": "0.10.39", + "es6-weak-map": "2.0.2", + "event-emitter": "0.3.5", + "is-promise": "2.1.0", + "lru-queue": "0.1.0", + "next-tick": "1.0.0", + "timers-ext": "0.1.3" + } + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" + }, + "method-override": { + "version": "2.3.10", + "resolved": "https://registry.npmjs.org/method-override/-/method-override-2.3.10.tgz", + "integrity": "sha1-49r41d7hDdLc59SuiNYrvud0drQ=", + "requires": { + "debug": "2.6.9", + "methods": "1.1.2", + "parseurl": "1.3.2", + "vary": "1.1.2" + }, + "dependencies": { + "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" + } + } + } + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "mime": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==" + }, + "mime-db": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz", + "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=" + }, + "mime-types": { + "version": "2.1.17", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz", + "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=", + "requires": { + "mime-db": "1.30.0" + } + }, + "mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==" + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "1.1.8" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "requires": { + "minimist": "0.0.8" + } + }, + "moment": { + "version": "2.21.0", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.21.0.tgz", + "integrity": "sha512-TCZ36BjURTeFTM/CwRcViQlfkMvL1/vFISuNLO5GkcVm1+QHfbSiNqZuWeMFjj1/3+uAjXswgRk30j1kkLYJBQ==" + }, + "moment-timezone": { + "version": "0.5.14", + "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.14.tgz", + "integrity": "sha1-TrOP+VOLgBCLpGekWPPtQmjM/LE=", + "requires": { + "moment": "2.21.0" + } + }, + "mongodb": { + "version": "2.2.34", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-2.2.34.tgz", + "integrity": "sha1-o09Zu+thdUrsQy3nLD/iFSakTBo=", + "requires": { + "es6-promise": "3.2.1", + "mongodb-core": "2.1.18", + "readable-stream": "2.2.7" + } + }, + "mongodb-core": { + "version": "2.1.18", + "resolved": "https://registry.npmjs.org/mongodb-core/-/mongodb-core-2.1.18.tgz", + "integrity": "sha1-TEYTm986HwMt7ZHbSfOO7AFlkFA=", + "requires": { + "bson": "1.0.5", + "require_optional": "1.0.1" + } + }, + "mongoose": { + "version": "4.13.11", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-4.13.11.tgz", + "integrity": "sha512-OgXmFc3vzXwq4zWp41XfSBDnKZLqnBc4Kh7mwwGjBE5iWH5tfkixaPK0uFtpEuzDzUvAIg33bgniyTsmc00olA==", + "requires": { + "async": "2.1.4", + "bson": "1.0.5", + "hooks-fixed": "2.0.2", + "kareem": "1.5.0", + "lodash.get": "4.4.2", + "mongodb": "2.2.34", + "mpath": "0.3.0", + "mpromise": "0.5.5", + "mquery": "2.3.3", + "ms": "2.0.0", + "muri": "1.3.0", + "regexp-clone": "0.0.1", + "sliced": "1.0.1" + } + }, + "mongooseeder": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/mongooseeder/-/mongooseeder-2.0.6.tgz", + "integrity": "sha512-pfOCHcor9JUgbsY1awb5w9mG1MmyO7sECjgd9esv70LJC5/zTANmZd3GXWWucdIC6GR+qIqdzjMxWKXq4/eVYA==" + }, + "morgan": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.9.0.tgz", + "integrity": "sha1-0B+mxlhZt2/PMbPLU6OCGjEdgFE=", + "requires": { + "basic-auth": "2.0.0", + "debug": "2.6.9", + "depd": "1.1.1", + "on-finished": "2.3.0", + "on-headers": "1.0.1" + }, + "dependencies": { + "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" + } + } + } + }, + "morgan-toolkit": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/morgan-toolkit/-/morgan-toolkit-1.2.2.tgz", + "integrity": "sha512-RtO6RFFpjquVhgnarw3dEV9sQ0BE3KsRX9mIZRyNHBSat/5nPtZwmOVsjj0s6ZXwEpqJtPqiUpVtLTSXhyH2HA==", + "requires": { + "chalk": "2.3.2", + "cli-highlight": "1.2.3" + } + }, + "mpath": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.3.0.tgz", + "integrity": "sha1-elj3iem1/TyUUgY0FXlg8mvV70Q=" + }, + "mpromise": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mpromise/-/mpromise-0.5.5.tgz", + "integrity": "sha1-9bJCWddjrMIlewoMjG2Gb9UXMuY=" + }, + "mquery": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/mquery/-/mquery-2.3.3.tgz", + "integrity": "sha512-NC8L14kn+qxJbbJ1gbcEMDxF0sC3sv+1cbRReXXwVvowcwY1y9KoVZFq0ebwARibsadu8lx8nWGvm3V0Pf0ZWQ==", + "requires": { + "bluebird": "3.5.0", + "debug": "2.6.9", + "regexp-clone": "0.0.1", + "sliced": "0.0.5" + }, + "dependencies": { + "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" + } + }, + "sliced": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/sliced/-/sliced-0.0.5.tgz", + "integrity": "sha1-XtwETKTrb3gW1Qui/GPiXY/kcH8=" + } + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "muri": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/muri/-/muri-1.3.0.tgz", + "integrity": "sha512-FiaFwKl864onHFFUV/a2szAl7X0fxVlSKNdhTf+BM8i8goEgYut8u5P9MqQqIYwvaMxjzVESsoEm/2kfkFH1rg==" + }, + "mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "requires": { + "any-promise": "1.3.0", + "object-assign": "4.1.1", + "thenify-all": "1.6.0" + } + }, + "negotiator": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz", + "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk=" + }, + "next-tick": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", + "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=" + }, + "nopt": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", + "requires": { + "abbrev": "1.1.1" + } + }, + "normalize-package-data": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", + "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", + "requires": { + "hosted-git-info": "2.6.0", + "is-builtin-module": "1.0.0", + "semver": "5.5.0", + "validate-npm-package-license": "3.0.3" + } + }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "requires": { + "path-key": "2.0.1" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=" + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "object-keys": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.11.tgz", + "integrity": "sha1-xUYBd4rVYPEULODgG8yotW0TQm0=" + }, + "object.assign": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.0.4.tgz", + "integrity": "sha1-scnMBE7xuf5jYG/BQau7MuFHMMw=", + "requires": { + "define-properties": "1.1.2", + "function-bind": "1.1.1", + "object-keys": "1.0.11" + } + }, + "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.1", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.1.tgz", + "integrity": "sha1-ko9dD0cNSTQmUepnlLCFfBAGk/c=" + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1.0.2" + } + }, + "optimist": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "requires": { + "minimist": "0.0.8", + "wordwrap": "0.0.3" + } + }, + "os-locale": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-2.1.0.tgz", + "integrity": "sha512-3sslG3zJbEYcaC4YVAvDorjGxc7tv6KVATnLPZONiljsUncvihe9BQoVCEs0RZ1kmf4Hk9OBqlZfJZWI4GanKA==", + "requires": { + "execa": "0.7.0", + "lcid": "1.0.0", + "mem": "1.1.0" + } + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=" + }, + "p-limit": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.2.0.tgz", + "integrity": "sha512-Y/OtIaXtUPr4/YpMv1pCL5L5ed0rumAaAeBSj12F+bSlMdys7i8oQF/GUJmfpTS/QoaRrS/k6pma29haJpsMng==", + "requires": { + "p-try": "1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "requires": { + "p-limit": "1.2.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=" + }, + "packet-reader": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-0.3.1.tgz", + "integrity": "sha1-zWLmCvjX/qinBexP+ZCHHEaHHyc=" + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "requires": { + "error-ex": "1.3.1" + } + }, + "parse5": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-3.0.3.tgz", + "integrity": "sha512-rgO9Zg5LLLkfJF9E6CCmXlSE4UVceloys8JrFqCcHloC3usd/kJCyPDwH2SOlzix2j3xaP9sUX3e8+kvkuleAA==", + "requires": { + "@types/node": "9.4.6" + } + }, + "parseurl": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz", + "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M=" + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=" + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=" + }, + "path-parse": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", + "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=" + }, + "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=" + }, + "path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "requires": { + "pify": "2.3.0" + } + }, + "pg": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/pg/-/pg-7.4.1.tgz", + "integrity": "sha512-Pi5qYuXro5PAD9xXx8h7bFtmHgAQEG6/SCNyi7gS3rvb/ZQYDmxKchfB0zYtiSJNWq9iXTsYsHjrM+21eBcN1A==", + "requires": { + "buffer-writer": "1.0.1", + "js-string-escape": "1.0.1", + "packet-reader": "0.3.1", + "pg-connection-string": "0.1.3", + "pg-pool": "2.0.3", + "pg-types": "1.12.1", + "pgpass": "1.0.2", + "semver": "4.3.2" + }, + "dependencies": { + "semver": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.2.tgz", + "integrity": "sha1-x6BxWKgL7dBSNVt3DYLWZA+AO+c=" + } + } + }, + "pg-connection-string": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-0.1.3.tgz", + "integrity": "sha1-2hhHsglA5C7hSSvq9l1J2RskXfc=" + }, + "pg-hstore": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/pg-hstore/-/pg-hstore-2.3.2.tgz", + "integrity": "sha1-9+8FPnubiSrphq8vfL6GQy388k8=", + "requires": { + "underscore": "1.8.3" + } + }, + "pg-pool": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-2.0.3.tgz", + "integrity": "sha1-wCIDLIlJ8xKk+R+2QJzgQHa+Mlc=" + }, + "pg-types": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-1.12.1.tgz", + "integrity": "sha1-1kCH45A7WP+q0nnnWVxSIIoUw9I=", + "requires": { + "postgres-array": "1.0.2", + "postgres-bytea": "1.0.0", + "postgres-date": "1.0.3", + "postgres-interval": "1.1.1" + } + }, + "pgpass": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.2.tgz", + "integrity": "sha1-Knu0G2BltnkH6R2hsHwYR8h3swY=", + "requires": { + "split": "1.0.1" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=" + }, + "postgres-array": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-1.0.2.tgz", + "integrity": "sha1-jgsy6wO/d6XAp4UeBEHBaaJWojg=" + }, + "postgres-bytea": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", + "integrity": "sha1-AntTPAqokOJtFy1Hz5zOzFIazTU=" + }, + "postgres-date": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.3.tgz", + "integrity": "sha1-4tiXAu/bJY/52c7g/pG9BpdSV6g=" + }, + "postgres-interval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.1.1.tgz", + "integrity": "sha512-OkuCi9t/3CZmeQreutGgx/OVNv9MKHGIT5jH8KldQ4NLYXkvmT9nDVxEuCENlNwhlGPE374oA/xMqn05G49pHA==", + "requires": { + "xtend": "4.0.1" + } + }, + "process-nextick-args": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=" + }, + "promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "requires": { + "asap": "2.0.6" + } + }, + "proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=" + }, + "proxy-addr": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.2.tgz", + "integrity": "sha1-ZXFQT0e7mI7IGAJT+F3X4UlSvew=", + "requires": { + "forwarded": "0.1.2", + "ipaddr.js": "1.5.2" + } + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" + }, + "qs": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz", + "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A==" + }, + "range-parser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz", + "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4=" + }, + "raw-body": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz", + "integrity": "sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k=", + "requires": { + "bytes": "3.0.0", + "http-errors": "1.6.2", + "iconv-lite": "0.4.19", + "unpipe": "1.0.0" + } + }, + "read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "requires": { + "load-json-file": "2.0.0", + "normalize-package-data": "2.4.0", + "path-type": "2.0.0" + } + }, + "read-pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "requires": { + "find-up": "2.1.0", + "read-pkg": "2.0.0" + } + }, + "readable-stream": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.7.tgz", + "integrity": "sha1-BwV6y+JGeyIELTb5jFrVBwVOlbE=", + "requires": { + "buffer-shims": "1.0.0", + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" + } + }, + "regenerator-runtime": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz", + "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==" + }, + "regexp-clone": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/regexp-clone/-/regexp-clone-0.0.1.tgz", + "integrity": "sha1-p8LgmJH9vzj7sQ03b7cwA+aKxYk=" + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=" + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" + }, + "require-main-filename": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=" + }, + "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.5.0" + } + }, + "resolve": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.5.0.tgz", + "integrity": "sha512-hgoSGrc3pjzAPHNBg+KnFcK2HwlHTs/YrAGUr6qgTVUZmXv1UEXXl0bZNBKMA9fud6lRYFdPGz0xXxycPzmmiw==", + "requires": { + "path-parse": "1.0.5" + } + }, + "resolve-from": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz", + "integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c=" + }, + "retry-as-promised": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/retry-as-promised/-/retry-as-promised-2.3.2.tgz", + "integrity": "sha1-zZdO5P2bX+A8vzGHHuSCIcB3N7c=", + "requires": { + "bluebird": "3.5.0", + "debug": "2.6.9" + }, + "dependencies": { + "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" + } + } + } + }, + "right-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", + "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", + "optional": true, + "requires": { + "align-text": "0.1.4" + } + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==" + }, + "semver": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", + "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==" + }, + "send": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/send/-/send-0.16.1.tgz", + "integrity": "sha512-ElCLJdJIKPk6ux/Hocwhk7NFHpI3pVm/IZOYWqUmoxcgeyM+MpxHHKhb8QmlJDX1pU6WrgaHBkVNm73Sv7uc2A==", + "requires": { + "debug": "2.6.9", + "depd": "1.1.1", + "destroy": "1.0.4", + "encodeurl": "1.0.1", + "escape-html": "1.0.3", + "etag": "1.8.1", + "fresh": "0.5.2", + "http-errors": "1.6.2", + "mime": "1.4.1", + "ms": "2.0.0", + "on-finished": "2.3.0", + "range-parser": "1.2.0", + "statuses": "1.3.1" + }, + "dependencies": { + "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" + } + } + } + }, + "sequelize": { + "version": "4.35.2", + "resolved": "https://registry.npmjs.org/sequelize/-/sequelize-4.35.2.tgz", + "integrity": "sha512-uK1vpgq4OkRdUG1pEGfeCkudQaoDqfX/hNICm7tqsDYHjADEU/E/Bn9+ib2JQkKhIcX4X4Sp1/88/lsofsXPzA==", + "requires": { + "bluebird": "3.5.0", + "cls-bluebird": "2.1.0", + "debug": "3.1.0", + "depd": "1.1.1", + "dottie": "2.0.0", + "generic-pool": "3.4.2", + "inflection": "1.12.0", + "lodash": "4.17.5", + "moment": "2.21.0", + "moment-timezone": "0.5.14", + "retry-as-promised": "2.3.2", + "semver": "5.5.0", + "terraformer-wkt-parser": "1.1.2", + "toposort-class": "1.0.1", + "uuid": "3.2.1", + "validator": "9.4.1", + "wkx": "0.4.4" + } + }, + "sequelize-cli": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/sequelize-cli/-/sequelize-cli-3.2.0.tgz", + "integrity": "sha1-wBMzqYrTZGaXJiS7USId0MWgLfU=", + "requires": { + "bluebird": "3.5.1", + "cli-color": "1.2.0", + "fs-extra": "4.0.3", + "js-beautify": "1.7.5", + "lodash": "4.17.5", + "resolve": "1.5.0", + "umzug": "2.1.0", + "yargs": "8.0.2" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "bluebird": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", + "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==" + }, + "cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "requires": { + "string-width": "1.0.2", + "strip-ansi": "3.0.1", + "wrap-ansi": "2.1.0" + }, + "dependencies": { + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + } + } + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "requires": { + "number-is-nan": "1.0.1" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "2.1.1" + } + }, + "yargs": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-8.0.2.tgz", + "integrity": "sha1-YpmpBVsc78lp/355wdkY3Osiw2A=", + "requires": { + "camelcase": "4.1.0", + "cliui": "3.2.0", + "decamelize": "1.2.0", + "get-caller-file": "1.0.2", + "os-locale": "2.1.0", + "read-pkg-up": "2.0.0", + "require-directory": "2.1.1", + "require-main-filename": "1.0.1", + "set-blocking": "2.0.0", + "string-width": "2.1.1", + "which-module": "2.0.0", + "y18n": "3.2.1", + "yargs-parser": "7.0.0" + } + }, + "yargs-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-7.0.0.tgz", + "integrity": "sha1-jQrELxbqVd69MyyvTEA4s+P139k=", + "requires": { + "camelcase": "4.1.0" + } + } + } + }, + "serve-static": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.1.tgz", + "integrity": "sha512-hSMUZrsPa/I09VYFJwa627JJkNs0NrfL1Uzuup+GqHfToR2KcsXFymXSV90hoyw3M+msjFuQly+YzIH/q0MGlQ==", + "requires": { + "encodeurl": "1.0.1", + "escape-html": "1.0.3", + "parseurl": "1.3.2", + "send": "0.16.1" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "requires": { + "shebang-regex": "1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=" + }, + "shimmer": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.2.0.tgz", + "integrity": "sha512-xTCx2vohXC2EWWDqY/zb4+5Mu28D+HYNSOuFzsyRDRvI/e1ICb69afwaUwfjr+25ZXldbOLyp+iDUZHq8UnTag==" + }, + "sigmund": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", + "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=" + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=" + }, + "sliced": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz", + "integrity": "sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E=" + }, + "source-map": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", + "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", + "requires": { + "amdefine": "1.0.1" + } + }, + "spdx-correct": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.0.0.tgz", + "integrity": "sha512-N19o9z5cEyc8yQQPukRCZ9EUmb4HUpnrmaL/fxS2pBo2jbfcFRVuFZ/oFC+vZz0MNNk0h80iMn5/S6qGZOL5+g==", + "requires": { + "spdx-expression-parse": "3.0.0", + "spdx-license-ids": "3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.1.0.tgz", + "integrity": "sha512-4K1NsmrlCU1JJgUrtgEeTVyfx8VaYea9J9LvARxhbHtVtohPs/gFGG5yy49beySjlIMhhXZ4QqujIZEfS4l6Cg==" + }, + "spdx-expression-parse": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", + "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "requires": { + "spdx-exceptions": "2.1.0", + "spdx-license-ids": "3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.0.tgz", + "integrity": "sha512-2+EPwgbnmOIl8HjGBXXMd9NAu02vLjOO1nWw4kmeRDFyHn+M/ETfHxQUK0oXg8ctgVnl9t3rosNVsZ1jG61nDA==" + }, + "split": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", + "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", + "requires": { + "through": "2.3.8" + } + }, + "statuses": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", + "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=" + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "requires": { + "is-fullwidth-code-point": "2.0.0", + "strip-ansi": "4.0.0" + } + }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "requires": { + "safe-buffer": "5.1.1" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "requires": { + "ansi-regex": "3.0.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=" + }, + "strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=" + }, + "stripe": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/stripe/-/stripe-5.5.0.tgz", + "integrity": "sha512-oy8xNoxv5/4eFsn+W/0KQvG9St7x/xM8TbOIW2prBLd2+zo+2y2V9iyqcNt6B14efcOE2YeCR1s5yw+1cqa2VQ==", + "requires": { + "bluebird": "3.5.0", + "lodash.isplainobject": "4.0.6", + "qs": "6.5.1", + "safe-buffer": "5.1.1" + } + }, + "supports-color": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.3.0.tgz", + "integrity": "sha512-0aP01LLIskjKs3lq52EC0aGBAJhLq7B2Rd8HC/DR/PtNNpcLilNmHC12O+hu0usQpo7wtHNRqtrhBwtDb0+dNg==", + "requires": { + "has-flag": "3.0.0" + } + }, + "terraformer": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/terraformer/-/terraformer-1.0.8.tgz", + "integrity": "sha1-UeCtiXRvzyFh3G9lqnDkI3fItZM=", + "requires": { + "@types/geojson": "1.0.6" + } + }, + "terraformer-wkt-parser": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/terraformer-wkt-parser/-/terraformer-wkt-parser-1.1.2.tgz", + "integrity": "sha1-M2oMj8gglKWv+DKI9prt7NNpvww=", + "requires": { + "terraformer": "1.0.8" + } + }, + "thenify": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.0.tgz", + "integrity": "sha1-5p44obq+lpsBCCB5eLn2K4hgSDk=", + "requires": { + "any-promise": "1.3.0" + } + }, + "thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY=", + "requires": { + "thenify": "3.3.0" + } + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" + }, + "timers-ext": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/timers-ext/-/timers-ext-0.1.3.tgz", + "integrity": "sha512-2iKErlS+NnEr0aQVQS91/mjsqCDO4OFl+5c5RDNtP+acQJTySvNSdbiSbmBD0t2RbErirF2Vq7x5YPQOSva77Q==", + "requires": { + "es5-ext": "0.10.39", + "next-tick": "1.0.0" + } + }, + "toposort-class": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toposort-class/-/toposort-class-1.0.1.tgz", + "integrity": "sha1-f/0feMi+KMO6Rc1OGj9e4ZO9mYg=" + }, + "type-is": { + "version": "1.6.15", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.15.tgz", + "integrity": "sha1-yrEPtJCeRByChC6v4a1kbIGARBA=", + "requires": { + "media-typer": "0.3.0", + "mime-types": "2.1.17" + } + }, + "uglify-js": { + "version": "2.8.29", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", + "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", + "optional": true, + "requires": { + "source-map": "0.5.7", + "uglify-to-browserify": "1.0.2", + "yargs": "3.10.0" + }, + "dependencies": { + "camelcase": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", + "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", + "optional": true + }, + "cliui": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", + "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", + "optional": true, + "requires": { + "center-align": "0.1.3", + "right-align": "0.1.3", + "wordwrap": "0.0.2" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "optional": true + }, + "window-size": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", + "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", + "optional": true + }, + "wordwrap": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", + "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", + "optional": true + }, + "yargs": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", + "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", + "optional": true, + "requires": { + "camelcase": "1.2.1", + "cliui": "2.1.0", + "decamelize": "1.2.0", + "window-size": "0.1.0" + } + } + } + }, + "uglify-to-browserify": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", + "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", + "optional": true + }, + "umzug": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/umzug/-/umzug-2.1.0.tgz", + "integrity": "sha512-BgT+ekpItEWaG+3JjLLj6yVTxw2wIH8Cr6JyKYIzukWAx9nzGhC6BGHb/IRMjpobMM1qtIrReATwLUjKpU2iOQ==", + "requires": { + "babel-runtime": "6.26.0", + "bluebird": "3.5.0", + "lodash": "4.17.5", + "resolve": "1.5.0" + } + }, + "underscore": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz", + "integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=" + }, + "universalify": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.1.tgz", + "integrity": "sha1-+nG63UQ3r0wUiEHjs7Fl+enlkLc=" + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "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.2.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.2.1.tgz", + "integrity": "sha512-jZnMwlb9Iku/O3smGWvZhauCf6cvvpKi4BKRiliS3cxnI+Gz9j5MEpTz2UFuXiKPJocb7gnsLHwiS05ige5BEA==" + }, + "validate-npm-package-license": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz", + "integrity": "sha512-63ZOUnL4SIXj4L0NixR3L1lcjO38crAbgrTpl28t8jjrfuiOBL5Iygm+60qPs/KsZGzPNg6Smnc/oY16QTjF0g==", + "requires": { + "spdx-correct": "3.0.0", + "spdx-expression-parse": "3.0.0" + } + }, + "validator": { + "version": "9.4.1", + "resolved": "https://registry.npmjs.org/validator/-/validator-9.4.1.tgz", + "integrity": "sha512-YV5KjzvRmSyJ1ee/Dm5UED0G+1L4GZnLN3w6/T+zZm8scVua4sOhYKWTUrKa0H/tMiJyO9QLHMPN+9mB/aMunA==" + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + }, + "which": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz", + "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==", + "requires": { + "isexe": "2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" + }, + "wkx": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/wkx/-/wkx-0.4.4.tgz", + "integrity": "sha512-eVVHka2jRaAp9QanKhLpxWs3AGDV0b8cijlavxBnn4ryXzq5N/3Xe3nkQsI0XMRA16RURwviCWuOCj4mXCmrxw==", + "requires": { + "@types/node": "9.4.6" + } + }, + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=" + }, + "wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "requires": { + "string-width": "1.0.2", + "strip-ansi": "3.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "requires": { + "number-is-nan": "1.0.1" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "requires": { + "code-point-at": "1.1.0", + "is-fullwidth-code-point": "1.0.0", + "strip-ansi": "3.0.1" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "2.1.1" + } + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "xtend": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" + }, + "y18n": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=" + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" + }, + "yargs": { + "version": "10.1.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-10.1.2.tgz", + "integrity": "sha512-ivSoxqBGYOqQVruxD35+EyCFDYNEFL/Uo6FcOnz+9xZdZzK0Zzw4r4KhbrME1Oo2gOggwJod2MnsdamSG7H9ig==", + "requires": { + "cliui": "4.0.0", + "decamelize": "1.2.0", + "find-up": "2.1.0", + "get-caller-file": "1.0.2", + "os-locale": "2.1.0", + "require-directory": "2.1.1", + "require-main-filename": "1.0.1", + "set-blocking": "2.0.0", + "string-width": "2.1.1", + "which-module": "2.0.0", + "y18n": "3.2.1", + "yargs-parser": "8.1.0" + } + }, + "yargs-parser": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-8.1.0.tgz", + "integrity": "sha512-yP+6QqN8BmrgW2ggLtTbdrOyBNSI7zBa4IykmiV5R1wl1JWNxQvWhMfMdmzIYtKU7oP3OOInY/tl2ov3BDjnJQ==", + "requires": { + "camelcase": "4.1.0" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..8335daf --- /dev/null +++ b/package.json @@ -0,0 +1,49 @@ +{ + "name": "project_mimirs_market", + "version": "1.0.0", + "description": "A Viking eCommerce store for Thunder Gods that like to buy \"Antique Wooden Pizzas\"", + "main": "index.js", + "dependencies": { + "cookie-session": "^2.0.0-beta.3", + "dotenv": "^4.0.0", + "express": "^4.16.2", + "express-flash-messages": "^0.1.1", + "express-handlebars": "^3.0.0", + "express-method-override-get-post-support": "^1.0.1", + "faker": "^4.1.0", + "lodash": "^4.17.5", + "method-override": "^2.3.10", + "mongoose": "^4.13.11", + "mongooseeder": "^2.0.6", + "morgan": "^1.9.0", + "morgan-toolkit": "^1.2.2", + "pg": "^7.4.1", + "pg-hstore": "^2.3.2", + "sequelize": "^4.35.2", + "sequelize-cli": "^3.2.0", + "stripe": "^5.5.0" + }, + "devDependencies": {}, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "sql:migrate:undo": "npm run sql db:migrate:undo:all", + "sql:migrate": "npm run sql db:migrate", + "sql:seed:undo": "npm run sql db:seed:undo:all", + "sql:seed": "sequelize db:migrate:undo:all && sequelize db:migrate && sequelize db:seed:all", + "sql:s": "npm run sql:migrate:undo && npm run sql:migrate && npm run sql:seed", + "mg:seed": "node seeds/mongoose", + "console": "node repl.js", + "c": "node repl.js", + "sql": "./node_modules/sequelize-cli/bin/sequelize" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/coelacanth7/project_mimirs_market.git" + }, + "author": "", + "license": "ISC", + "bugs": { + "url": "https://github.com/coelacanth7/project_mimirs_market/issues" + }, + "homepage": "https://github.com/coelacanth7/project_mimirs_market#readme" +} diff --git a/public/.DS_Store b/public/.DS_Store new file mode 100644 index 0000000..4857093 Binary files /dev/null and b/public/.DS_Store differ diff --git a/public/css/style.css b/public/css/style.css new file mode 100644 index 0000000..853073a --- /dev/null +++ b/public/css/style.css @@ -0,0 +1,3 @@ +.btn { + cursor: pointer; +} diff --git a/public/icons/briefcase.svg b/public/icons/briefcase.svg new file mode 100755 index 0000000..2e41654 --- /dev/null +++ b/public/icons/briefcase.svg @@ -0,0 +1,4 @@ + + + diff --git a/public/icons/cart.svg b/public/icons/cart.svg new file mode 100755 index 0000000..b55e66e --- /dev/null +++ b/public/icons/cart.svg @@ -0,0 +1,4 @@ + + + diff --git a/public/icons/dashboard.svg b/public/icons/dashboard.svg new file mode 100755 index 0000000..af4bb9f --- /dev/null +++ b/public/icons/dashboard.svg @@ -0,0 +1,4 @@ + + + diff --git a/public/icons/fire.svg b/public/icons/fire.svg new file mode 100755 index 0000000..e2ba5b3 --- /dev/null +++ b/public/icons/fire.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/icons/graph.svg b/public/icons/graph.svg new file mode 100755 index 0000000..ec9da9e --- /dev/null +++ b/public/icons/graph.svg @@ -0,0 +1,3 @@ + + + diff --git a/public/images/0.jpg b/public/images/0.jpg new file mode 100644 index 0000000..18bbaa8 Binary files /dev/null and b/public/images/0.jpg differ diff --git a/public/images/1.jpg b/public/images/1.jpg new file mode 100644 index 0000000..cc42216 Binary files /dev/null and b/public/images/1.jpg differ diff --git a/public/images/10.jpg b/public/images/10.jpg new file mode 100644 index 0000000..c0a494c Binary files /dev/null and b/public/images/10.jpg differ diff --git a/public/images/2.jpg b/public/images/2.jpg new file mode 100644 index 0000000..d75049e Binary files /dev/null and b/public/images/2.jpg differ diff --git a/public/images/3.jpg b/public/images/3.jpg new file mode 100644 index 0000000..ef3c020 Binary files /dev/null and b/public/images/3.jpg differ diff --git a/public/images/4.jpg b/public/images/4.jpg new file mode 100644 index 0000000..90af951 Binary files /dev/null and b/public/images/4.jpg differ diff --git a/public/images/5.jpg b/public/images/5.jpg new file mode 100644 index 0000000..1958ce4 Binary files /dev/null and b/public/images/5.jpg differ diff --git a/public/images/6.jpg b/public/images/6.jpg new file mode 100644 index 0000000..ada6d04 Binary files /dev/null and b/public/images/6.jpg differ diff --git a/public/images/7.jpg b/public/images/7.jpg new file mode 100644 index 0000000..043671f Binary files /dev/null and b/public/images/7.jpg differ diff --git a/public/images/8.jpg b/public/images/8.jpg new file mode 100644 index 0000000..2378357 Binary files /dev/null and b/public/images/8.jpg differ diff --git a/public/images/9.jpg b/public/images/9.jpg new file mode 100644 index 0000000..3be15f9 Binary files /dev/null and b/public/images/9.jpg differ diff --git a/repl.js b/repl.js new file mode 100644 index 0000000..43713e4 --- /dev/null +++ b/repl.js @@ -0,0 +1,45 @@ +var mongoose = require("mongoose"); +var repl = require("repl").start({}); +var models = { + mongoose: require("./models/mongoose"), + sequelize: require("./models/sequelize") +}; +// var helpers = require("./helpers"); + +require("./mongo")().then(() => { + repl.context.models = models; + // repl.context.helpers = helpers; + + // ---------------------------------------- + // Helpers + // ---------------------------------------- + // Object.keys(helpers).forEach(key => { + // repl.context[key] = helpers[key]; + // }); + + // ---------------------------------------- + // Mongoose + // ---------------------------------------- + Object.keys(models.mongoose).forEach(modelName => { + repl.context[modelName] = mongoose.model(modelName); + }); + + // ---------------------------------------- + // Sequelize + // ---------------------------------------- + Object.keys(models.sequelize).forEach(modelName => { + repl.context[modelName] = models.sequelize[modelName]; + }); + + // ---------------------------------------- + // Logging + // ---------------------------------------- + repl.context.lg = data => { + if (Array.isArray(data)) { + if (data.length && data[0].dataValues) { + data = data.map(item => item.dataValues); + } + } + console.log(data); + }; +}); diff --git a/routers/admin.js b/routers/admin.js new file mode 100644 index 0000000..0e494d6 --- /dev/null +++ b/routers/admin.js @@ -0,0 +1,36 @@ +var express = require("express"); +var router = express.Router(); + +const mongoose = require("mongoose"); +var models = require("./../models/mongoose"); +var Order = mongoose.model("Order"); + +const analytics = require("./../services/analytics"); + +// index table +router.get("/admin", (req, res) => { + Order.find() + .then(orders => { + // console.log("orders", JSON.stringify(orders, 0, 2)); + res.render("admin/index", { orders }); + }) + .catch(e => res.status(500).send(e.stack)); +}); + +//order show +router.get("/order/:id", (req, res) => { + Order.findById(req.params.id) + .then(order => { + res.render("admin/show", { order }); + }) + .catch(e => res.status(500).send(e.stack)); +}); + +router.get("/analytics", (req, res) => { + analytics.getAll().then(data => { + console.log("data", JSON.stringify(data, 0, 2)); + res.render("admin/analytics", { data }); + }); +}); + +module.exports = router; diff --git a/routers/cart.js b/routers/cart.js new file mode 100644 index 0000000..9a64d0a --- /dev/null +++ b/routers/cart.js @@ -0,0 +1,120 @@ +var express = require("express"); +var router = express.Router(); + +const seqeulize = require("sequelize"); +var models = require("./../models/sequelize"); +var sequelize = models.sequelize; +var Products = models.Products; +var Categories = models.Categories; + +var findCartItem = function(cart, id) { + return cart.findIndex(i => i.id == id); +}; + +// Add to cart +router.get("/cart/:id/:name", (req, res) => { + var id = req.params.id; + var name = req.params.name; + + if (req.session.cart == null || req.session.cart == undefined) { + req.session.cart = []; + req.session.cart.push({ + name: name, + id: id, + quantity: 1 + }); + } else if (findCartItem(req.session.cart, id) == -1) { + req.session.cart.push({ + name: name, + id: id, + quantity: 1 + }); + } else { + req.session.cart.forEach(obj => { + if (obj.id == id) { + obj.quantity += 1; + } + }); + } + + req.flash('success', `${name} added to cart`) + res.redirect(`/product/${id}`); +}); + +// cart index +router.get("/mycart", (req, res) => { + if (req.session.cart.length == 0) { + // if cart is empty + var nothing = true; + res.render("cart/index", { nothing }); + } else { + // get item ids from cart + var ids = req.session.cart.map(k => k.id); + + // get quantities from cart + var quantities = req.session.cart.map(k => k.quantity); + + Products.findAll({ + include: [{ model: Categories }], + where: { id: { $in: ids } } + }) + .then(cartProducts => { + //get a total + var total = 0; + for (var i = 0; i < cartProducts.length; i++) { + total += cartProducts[i].price * quantities[i]; + } + + //assign quantities + // https://stackoverflow.com/questions/35903850/combine-json-arrays-by-key-javascript + var result = cartProducts.map(x => + Object.assign(x, req.session.cart.find(y => y.id == x.id)) + ); + + res.render("cart/index", { result, total }); + // console.log("result: ", JSON.stringify(result, 0, 2)); + }) + .catch(e => { + res.status(500).send(e.stack); + }); + } +}); + +// clear the entire cart +router.get("/mycart/delete", (req, res) => { + req.session.cart = null; + console.log("delete cart"); + req.flash('info', "No more items in your cart") + res.redirect("/"); +}); + +// clear one product from cart +router.get("/clear/:id", (req, res) => { + //clear + var id = req.params.id; + var index = findCartItem(req.session.cart, id); + req.session.cart.splice(index, 1); + req.flash('info', "Item removed from your cart") + res.redirect("back"); +}); + +// update quantity +router.post("/mycart/updateitem", (req, res) => { + //update + var id = req.body.id; + var quantity = req.body.quantity; + var index = findCartItem(req.session.cart, id); + + if (quantity <= 0) { + req.session.cart.splice(index, 1); + } else { + req.session.cart[index].quantity = quantity; + } + + req.flash("info", "Cart updated") + res.redirect("back"); +}); + +module.exports = router; + +// diff --git a/routers/checkout.js b/routers/checkout.js new file mode 100644 index 0000000..da41345 --- /dev/null +++ b/routers/checkout.js @@ -0,0 +1,130 @@ +var express = require("express"); +var router = express.Router(); + +const seqeulize = require("sequelize"); +var models = require("./../models/sequelize"); +var sequelize = models.sequelize; +var Products = models.Products; +var Categories = models.Categories; + +const mongoose = require("mongoose"); +var MongooseModels = require("./../models/mongoose"); +var Order = mongoose.model("Order"); + +var { STRIPE_SK, STRIPE_PK } = process.env; +var stripe = require("stripe")(STRIPE_SK); + +// checkout form +router.get("/checkout", (req, res) => { + // get item ids from cart + var ids = req.session.cart.map(k => k.id); + + // get quantities from cart + var quantities = req.session.cart.map(k => k.quantity); + + Products.findAll({ + include: [{ model: Categories }], + where: { id: { $in: ids } } + }) + .then(cartProducts => { + var total = 0; + for (var i = 0; i < cartProducts.length; i++) { + total += cartProducts[i].price * quantities[i]; + } + + // assign quantities + // https://stackoverflow.com/questions/35903850/combine-json-arrays-by-key-javascript + var result = cartProducts.map(x => + Object.assign(x, req.session.cart.find(y => y.id == x.id)) + ); + + result.forEach(obj => { + obj.total = obj.quantity * obj.price; + }); + + res.render("checkout/new", { result, total, STRIPE_PK }); + // console.log("result: ", JSON.stringify(result, 0, 2)); + }) + .catch(e => { + res.status(500).send(e.stack); + }); +}); + +// pay submit +router.post("/pay", (req, res) => { + // get item ids from cart + var ids = req.session.cart.map(k => k.id); + + // get quantities from cart + var quantities = req.session.cart.map(k => k.quantity); + // console.log("req.body: ", JSON.stringify(req.body, 0, 2)); + + var total = 0; + let orderedProducts = []; + + Products.findAll({ + include: [{ model: Categories }], + where: { id: { $in: ids } } + }) + .then(cartProducts => { + //get a total + for (var i = 0; i < cartProducts.length; i++) { + total += cartProducts[i].price * quantities[i]; + } + + //assign quantities + // https://stackoverflow.com/questions/35903850/combine-json-arrays-by-key-javascript + var result = cartProducts.map(x => + Object.assign(x, req.session.cart.find(y => y.id == x.id)) + ); + + // console.log("cartProducts: ", JSON.stringify(cartProducts, 0, 2)); + // build order object + cartProducts.forEach(product => { + orderedProducts.push({ + id: product.id, + name: product.name, + sku: product.sku, + description: product.description, + price: product.price, + category: product.Category.name, + quantity: product.quantity + }); + }); + + return stripe.charges.create({ + amount: req.body.price * 100, + currency: "usd", + description: req.body.description, + source: req.body.stripeToken + }); + }) + .then(charge => { + var newOrder = new Order({ + fname: req.body.fname, + lname: req.body.lname, + address: req.body.address, + city: req.body.city, + state: req.body.state, + zip: req.body.zip, + total: req.body.price, + orderedProducts: orderedProducts, + stripe: charge, + stripeToken: req.body.stripeToken + }); + + return newOrder.save(); + // console.log("charge: ", JSON.stringify(charge, 0, 2)); + }) + .then(order => { + req.session.cart = []; + // console.log("order: ", JSON.stringify(order, 0, 2)); + req.flash("success", "We've got your money") + res.render("checkout/show", { order }); + }) + .catch(e => { + res.status(500).send(e.stack); + }); +}); + +module.exports = router; diff --git a/routers/products.js b/routers/products.js new file mode 100644 index 0000000..fc20fea --- /dev/null +++ b/routers/products.js @@ -0,0 +1,50 @@ +var express = require("express"); +var router = express.Router(); + +const seqeulize = require("sequelize"); +var models = require("./../models/sequelize"); +var sequelize = models.sequelize; +var Products = models.Products; +var Categories = models.Categories; + +const search = require("./../services/search"); + +//index +router.get("/", (req, res) => { + // Find all products + search.findEverything(req, res); +}); + +// search +router.post("/search", (req, res) => { + // serch and filer params + var params = {}; + params.search = req.body.search; + params.category = req.body.category; + params.priceMin = req.body.priceMin; + params.priceMax = req.body.priceMax; + params.sortVal = req.body.sortVal; + params.sortDirection = req.body.sortDirection; + + req.method = "get"; + + // Find search params + if (params.category == "" && params.search == "") { + //if the search params and categories are empty then find findEverything + search.filter(req, res, params); + } else if (params.category != "" && params.search == "%%") { + search.findCategoriesButNotText(req, res, params); + } else if (params.category == "") { + search.findTextButNotCategories(req, res, params); + } else { + search.findTextandCategories(req, res, params); + } +}); + +// product show page +router.get("/product/:id", (req, res) => { + //find one product + search.findOneProduct(req, res); +}); + +module.exports = router; diff --git a/seeds/mongoose/index.js b/seeds/mongoose/index.js new file mode 100644 index 0000000..8f56b64 --- /dev/null +++ b/seeds/mongoose/index.js @@ -0,0 +1,176 @@ +var faker = require("faker"); + +// mongoose +const mongoose = require("mongoose"); +mongoose.Promise = require("bluebird"); +const models = require("./../../models/mongoose"); +var env = process.env.NODE_ENV || "development"; +var config = require("./../../config/mongoose")[env]; +const mongooseeder = require("mongooseeder"); +const { Order } = models; + +// sequelize +const seqeulize = require("sequelize"); +var seqeulizeModels = require("./../../models/sequelize"); +var sequelize = seqeulizeModels.sequelize; +var Products = seqeulizeModels.Products; +var Categories = seqeulizeModels.Categories; + +const MULTIPLIER = 1; + +function randomId() { + return Math.floor(Math.random() * 200); +} + +function getProduct(productId, i) { + return Products.findOne({ + include: [{ model: Categories }], + where: { id: productId } + }).then((err, product) => { + if (err) console.error(err); + if (product) { + product.quantity = i % 8; + } + return product; + }); +} + +const seeds = () => { + // ---------------------------------------- + // Create Oders + // ---------------------------------------- + console.log("Creating Orders"); + var orders = []; + for (let i = 1; i < 222; i++) { + var productId = randomId(); + + return new Promise(function(resolve, reject) { + getProduct(productId, i) + .then(product => { + var order = new Order({ + fname: faker.name.firstName(), + lname: faker.name.lastName(), + address: faker.address.streetAddress(), + city: faker.address.city(), + state: faker.address.state(), + zip: faker.address.zipCode(), + total: i * 86, + orderedProducts: [product], + stripe: { + transfer_group: null, + status: "succeeded", + statement_descriptor: null, + source_transfer: null, + source: { + tokenization_method: null, + name: faker.internet.email(), + last4: "4242", + funding: "credit", + fingerprint: "CnRCuVZss2LTEKEz", + exp_year: 2018, + exp_month: 1, + dynamic_last4: null, + cvc_check: "pass", + customer: null, + country: "US", + brand: "Visa", + address_zip_check: null, + address_zip: null, + address_state: null, + address_line2: null, + address_line1_check: null, + address_line1: null, + address_country: null, + address_city: null, + object: "card", + id: "card_1BQirYGRxzsP4XGrMXaJ7W99" + }, + shipping: null, + review: null, + refunds: { + url: "/v1/charges/ch_1BQirbGRxzsP4XGrdb1m7o6r/refunds", + total_count: 0, + has_more: false, + data: [], + object: "list" + }, + refunded: false, + receipt_number: null, + receipt_email: null, + paid: true, + outcome: { + type: "authorized", + seller_message: "Payment complete.", + risk_level: "normal", + reason: null, + network_status: "approved_by_network" + }, + order: null, + on_behalf_of: null, + livemode: false, + invoice: null, + failure_message: null, + failure_code: null, + dispute: null, + destination: null, + description: "Refined Rubber Hat", + customer: null, + currency: "usd", + created: 1511298063, + captured: true, + balance_transaction: "txn_1BQirbGRxzsP4XGrDiJ1MSv5", + application_fee: null, + application: null, + amount_refunded: 0, + amount: i * 86, + object: "charge", + id: "ch_1BQirbGRxzsP4XGrdb1m7o6r" + }, + stripeToken: faker.random.uuid() + }); + + resolve(orders.push(order)); + }) + .catch(error => { + console.error(error); + reject(error); + }); + }); + } + + // ---------------------------------------- + // Finish + // ---------------------------------------- + + var promises = []; + + console.log("Saving..."); + + orders.forEach(model => { + promises.push(model.save()); + }); + + return Promise.all(promises); +}; + +// Always use the MongoDB URL to allow +// easy connection in all environments +const mongodbUrl = + process.env.NODE_ENV === "production" + ? process.env[config.use_env_variable] + : `mongodb://${config.host}/${config.database}`; + +mongooseeder.seed({ + mongodbUrl: mongodbUrl, + seeds: seeds, + clean: true, + models: models, + mongoose: mongoose +}); + +// mongooseeder.clean({ +// database: config.database, +// host: config.host, +// models: models, +// mongoose: mongoose +// }); diff --git a/seeds/sequelize/20171115020351-products.js b/seeds/sequelize/20171115020351-products.js new file mode 100644 index 0000000..787d6ff --- /dev/null +++ b/seeds/sequelize/20171115020351-products.js @@ -0,0 +1,36 @@ +"use strict"; + +const faker = require("faker"); + +module.exports = { + up: (queryInterface, Sequelize) => { + var products = []; + + console.log("creating products"); + for (var i = 1; i <= 200; i++) { + var name = faker.commerce.productName(); + var sku = faker.random.uuid(); + var description = faker.random.words(10); + var price = i; + var categoryId = i % 15; + + if (categoryId === 0) { + categoryId = 15; + } + + products.push({ + name: name, + sku: sku, + description: description, + price: price, + categoryId: categoryId + }); + } + + return queryInterface.bulkInsert("Products", products); + }, + + down: (queryInterface, Sequelize) => { + return queryInterface.bulkDelete("Products", null, {}, models.Products); + } +}; diff --git a/seeds/sequelize/20171115213248-Categories.js b/seeds/sequelize/20171115213248-Categories.js new file mode 100644 index 0000000..3ca243a --- /dev/null +++ b/seeds/sequelize/20171115213248-Categories.js @@ -0,0 +1,24 @@ +"use strict"; + +const faker = require("faker"); + +module.exports = { + up: (queryInterface, Sequelize) => { + var categories = []; + + console.log("crating categories"); + for (var i = 1; i <= 15; i++) { + var name = faker.commerce.department(); + + categories.push({ + name: name + }); + } + + return queryInterface.bulkInsert("Categories", categories); + }, + + down: (queryInterface, Sequelize) => { + return queryInterface.bulkDelete("Categories", null, {}, models.Categories); + } +}; diff --git a/services/analytics.js b/services/analytics.js new file mode 100644 index 0000000..cb33fbf --- /dev/null +++ b/services/analytics.js @@ -0,0 +1,119 @@ +const seqeulize = require("sequelize"); +var models = require("./../models/sequelize"); +var sequelize = models.sequelize; +var Products = models.Products; +var Categories = models.Categories; + +const mongoose = require("mongoose"); +var MongooseModels = require("./../models/mongoose"); +var Order = mongoose.model("Order"); + +const analytics = {}; + +analytics.totalTransactions = () => { + return Order.count(); +}; + +analytics.totalRevenueEver = () => { + return Order.aggregate([ + { + $group: { + _id: null, + total: { $sum: "$total" } + } + } + ]); +}; + +analytics.totalUniqueStates = () => { + return Order.distinct("state"); +}; + +analytics.totalUniqueCustomers = () => { + return Order.distinct("stripe.source.name"); +}; + +analytics.totalCategories = () => { + return Categories.count(); +}; + +analytics.totalProducts = () => { + return Products.count(); +}; + +analytics.totalItemsSold = () => { + return Order.aggregate([ + { $unwind: "$orderedProducts" }, + { + $group: { + _id: null, + total: { $sum: "$orderedProducts.quantity" } + } + } + ]); +}; + +analytics.revenueByState = () => { + return Order.aggregate([ + { + $group: { + _id: "$state", + sum: { $sum: "$total" } + } + }, + { $sort: { sum: -1 } } + ]); +}; + +analytics.revenueByCategory = () => { + return Order.aggregate([ + { $unwind: "$orderedProducts" }, + { + $group: { + _id: "$orderedProducts.category", + sum: { $sum: "$total" } + } + }, + { $sort: { sum: -1 } } + ]); +}; + +analytics.revenueByProduct = () => { + return Order.aggregate([ + { $unwind: "$orderedProducts" }, + { + $group: { + _id: "$orderedProducts.id", + name: { $first: "$orderedProducts.name" }, + price: { $first: "$orderedProducts.price" }, + quantity: { $sum: "$orderedProducts.quantity" } + } + }, + { + $project: { + _id: 0, + name: 1, + sum: { $multiply: ["$price", "$quantity"] } + } + }, + { $sort: { sum: -1 } }, + { $limit: 8 } + ]); +}; + +analytics.getAll = async () => { + var data = {}; + data.totalTransactions = await analytics.totalTransactions(); + data.totalRevenueEver = (await analytics.totalRevenueEver())[0]; + data.totalUniqueStates = (await analytics.totalUniqueStates()).length; + data.totalUniqueCustomers = (await analytics.totalUniqueCustomers()).length; + data.totalCategories = await analytics.totalCategories(); + data.totalProducts = await analytics.totalProducts(); + data.totalItemsSold = (await analytics.totalItemsSold())[0]; + data.revenueByState = await analytics.revenueByState(); + data.revenueByCategory = await analytics.revenueByCategory(); + data.revenueByProduct = await analytics.revenueByProduct(); + return data; +}; + +module.exports = analytics; diff --git a/services/search.js b/services/search.js new file mode 100644 index 0000000..9dfac00 --- /dev/null +++ b/services/search.js @@ -0,0 +1,190 @@ +const seqeulize = require("sequelize"); +var models = require("./../models/sequelize"); +var sequelize = models.sequelize; +var Products = models.Products; +var Categories = models.Categories; + +const search = {}; + +search.findEverything = (req, res) => { + Categories.findAll({}).then(categories => { + Products.findAll({ + include: [{ model: Categories }], + limit: 20 + }) + .then(products => { + res.render("products/index", { products, categories }); + // console.log("categories: ", JSON.stringify(categories, 0, 2)); + }) + .catch(e => { + res.status(500).send(e.stack); + }); + }); +}; + +search.filter = (req, res, params) => { + Categories.findAll({}).then(categories => { + Products.findAll({ + include: [{ model: Categories }], + where: { + price: { + $gte: params.priceMin, + $lte: params.priceMax + } + }, + order: [[params.sortVal, params.sortDirection]], + limit: 20 + }) + .then(products => { + res.render("products/index", { products, categories }); + // console.log("categories: ", JSON.stringify(categories, 0, 2)); + }) + .catch(e => { + res.status(500).send(e.stack); + }); + }); +}; + +search.findCategoriesButNotText = (req, res, params) => { + Categories.findAll({}).then(categories => { + Products.findAll({ + include: [ + { + model: Categories, + where: { + name: { + $like: `${params.category}%` + }, + price: { + $gte: params.priceMin, + $lte: params.priceMax + } + } + } + ], + order: [[params.sortVal, params.sortDirection]] + }) + .then(products => { + res.render("products/index", { products, params, categories }); + // console.log("products: ", JSON.stringify(products, 0, 2)); + }) + .catch(e => { + res.status(500).send(e.stack); + }); + }); +}; + +search.findTextButNotCategories = (req, res, params) => { + Categories.findAll({}).then(categories => { + Products.findAll({ + include: [ + { + model: Categories + } + ], + where: { + $or: [ + { + name: { + $ilike: `%${params.search}%` + } + }, + { + description: { + $ilike: `%${params.search}%` + } + } + ], + price: { + $gte: params.priceMin, + $lte: params.priceMax + } + }, + order: [[params.sortVal, params.sortDirection]] + }) + .then(products => { + res.render("products/index", { products, params, categories }); + // console.log("products: ", JSON.stringify(products, 0, 2)); + }) + .catch(e => { + res.status(500).send(e.stack); + }); + }); +}; + +search.findTextandCategories = (req, res, params) => { + Categories.findAll({}).then(categories => { + Products.findAll({ + include: [ + { + model: Categories, + where: { + name: { + $ilike: `${params.category}%` + } + } + } + ], + where: { + $or: [ + { + name: { + $ilike: `%${params.search}%` + } + }, + { + description: { + $ilike: `%${params.search}%` + } + } + ], + price: { + $gte: params.priceMin, + $lte: params.priceMax + } + }, + order: [[params.sortVal, params.sortDirection]] + }) + .then(products => { + res.render("products/index", { products, params, categories }); + // console.log("products: ", JSON.stringify(products, 0, 2)); + }) + .catch(e => { + res.status(500).send(e.stack); + }); + }); +}; + +search.findOneProduct = function(req, res) { + Products.findOne({ + include: [ + { + model: Categories + } + ], + where: { + id: req.params.id + } + }).then(product => { + //find the products related to it + Products.findAll({ + include: [ + { + model: Categories, + where: { + name: product.Category.name + } + } + ], + limit: 12 + }) + .then(relatedProducts => { + res.render("products/show", { product, relatedProducts }); + }) + .catch(e => { + res.status(500).send(e.stack); + }); + }); +}; + +module.exports = search; diff --git a/views/admin/analytics.handlebars b/views/admin/analytics.handlebars new file mode 100644 index 0000000..e68ea79 --- /dev/null +++ b/views/admin/analytics.handlebars @@ -0,0 +1,82 @@ +

admin analytics

+ +
+
+

Totals

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Total totalTransactions{{data.totalTransactions}}
Total totalRevenueEver${{data.totalRevenueEver.total}}.00
States sold to{{data.totalUniqueStates}}
total customers{{data.totalUniqueCustomers}}
Total Categories{{data.totalCategories}}
Total Products{{data.totalProducts}}
Total Products SOLD{{data.totalItemsSold.total}}
+
+
+
+

Revenue by State

+
+ + + {{#each data.revenueByState as |state|}} + + + + + {{/each}} + +
{{state._id}}${{state.sum}}.00
+
+

Revenue by Category

+
+ + + {{#each data.revenueByCategory as |category|}} + + + + + {{/each}} + +
{{category._id}}${{category.sum}}.00
+
+

Revenue by Product

+
+ + + {{#each data.revenueByProduct as |product|}} + + + + + {{/each}} + +
{{product.name}}${{product.sum}}.00
+
+
+
diff --git a/views/admin/index.handlebars b/views/admin/index.handlebars new file mode 100644 index 0000000..337a46d --- /dev/null +++ b/views/admin/index.handlebars @@ -0,0 +1,26 @@ +
+ + + + + + + + + + + + + {{#each orders as |order|}} + + + + + + + + + {{/each}} + +
#NameRevenueEmailCustomer StateCheckout Date
{{order.id}}{{order.fname}} {{order.lname}}${{order.total}}.00{{order.stripe.source.name}}{{order.state}}{{order.createdAt}}
+
diff --git a/views/admin/show.handlebars b/views/admin/show.handlebars new file mode 100644 index 0000000..0cf2e72 --- /dev/null +++ b/views/admin/show.handlebars @@ -0,0 +1,90 @@ +
+
+

Ordered Items

+ {{#each order.orderedProducts as |product|}} +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
name{{product.name}}
price${{product.price}}.00
SKU{{product.sku}}
description{{product.description}}
Category{{product.category}}
quantity{{product.quantity}}
+
+ {{/each}} +
+
+

Customer Info

+
+ + + + + + + + + + + + + + + + + + + + + + + +
name{{order.fname}} {{order.lname}}
email{{order.stripe.source.name}}
address{{order.address}}
city{{order.city}}
state{{order.state}}
+
+ +

Order Info

+
+ + + + + + + + + + + + + + + + + + + +
Total${{order.total}}.00
Checkout Date{{order.createdAt}}
Stripe Token{{order.stripeToken}}
Card Type{{order.stripe.source.brand}}
+
+
+
diff --git a/views/cart/index.handlebars b/views/cart/index.handlebars new file mode 100644 index 0000000..40d90d8 --- /dev/null +++ b/views/cart/index.handlebars @@ -0,0 +1,41 @@ +

My Shopping Cart

+{{#if nothing}} +

Your cart is empty

+{{else}} +{{#each result as |product|}} + + +{{/each}} + +
+

Total: ${{total}}

+ Clear Cart + Checkout +
+{{/if}} diff --git a/views/checkout/new.handlebars b/views/checkout/new.handlebars new file mode 100644 index 0000000..f8540ad --- /dev/null +++ b/views/checkout/new.handlebars @@ -0,0 +1,124 @@ +

Checkout

+
+
+

Enter Billing Info

+
+
+
+ +
+
+ +
+
+
+ + +
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ + + + + +
+
+
+

Order Items

+ {{#each result as |product|}} +
+
+
{{product.name}}
+
{{product.Category.name}}
+
+
+
Each: ${{product.price}}.00
+
{{product.quantity}} items
+
subtotal: ${{product.total}}
+
+
+ {{/each}} +
PAY ${{total}}.00
+
+ +
diff --git a/views/checkout/show.handlebars b/views/checkout/show.handlebars new file mode 100644 index 0000000..cd1a1a7 --- /dev/null +++ b/views/checkout/show.handlebars @@ -0,0 +1,29 @@ +

We got ur money

+

Thanks

+ +
+
+
{{order.fname}} {{order.lname}}
+
{{order.address}}
+
{{order.city}}, {{order.zip}}, {{order.state}}
+

Total: ${{order.total}}.00

+
+ +
+ {{#each order.orderedProducts as |product|}} +
+
+ +
+
+
{{product.name}}
+
{{product.Category.name}}
+
+
+
Each: ${{product.price}}.00
+
{{product.quantity}} items
+
+
+ {{/each}} +
+
diff --git a/views/layouts/application.handlebars b/views/layouts/application.handlebars new file mode 100644 index 0000000..3cfb274 --- /dev/null +++ b/views/layouts/application.handlebars @@ -0,0 +1,34 @@ + + + + + + + + money burner + + + + + + + + + {{> shared/_nav }} + {{> shared/_flash }} + +
+ {{{ body }}} +
+ +
+ + + + + + + + diff --git a/views/products/index.handlebars b/views/products/index.handlebars new file mode 100644 index 0000000..49450b6 --- /dev/null +++ b/views/products/index.handlebars @@ -0,0 +1,83 @@ + +
+
+ + +
+
+ +
+ +
+ +
+ +
+ + +
+ +
+ +
+ +
+ +
+
+ + + +
+
+ +
+ {{#each products as |product|}} +
+
+ Card image cap +
+
{{product.name}}
+
${{product.price}}.00
+
{{product.Category.name}}
+ + +
+
+
+ {{/each}} +
diff --git a/views/products/show.handlebars b/views/products/show.handlebars new file mode 100644 index 0000000..fb622d6 --- /dev/null +++ b/views/products/show.handlebars @@ -0,0 +1,47 @@ +

Product

+
+
+ +
+
+

{{product.name}}

+
{{product.Category.name}}
+

${{product.price}}.00

+ {{product.description}}
+ + + +
+
+
+

Related Products

+
+ {{#each relatedProducts as |product|}} +
+
+ Card image cap +
+
{{product.name}}
+
${{product.price}}
+
{{product.Category.name}}
+ + + +
+
+
+ {{/each}} +
diff --git a/views/shared/_flash.handlebars b/views/shared/_flash.handlebars new file mode 100644 index 0000000..f08f64c --- /dev/null +++ b/views/shared/_flash.handlebars @@ -0,0 +1,10 @@ +{{#each getMessages as |messages key|}} + {{#each messages as |message|}} + + {{/each}} +{{/each}} diff --git a/views/shared/_nav.handlebars b/views/shared/_nav.handlebars new file mode 100644 index 0000000..d80368a --- /dev/null +++ b/views/shared/_nav.handlebars @@ -0,0 +1,49 @@ +