diff --git a/config.mjs b/config.mjs new file mode 100644 index 0000000..b63c5aa --- /dev/null +++ b/config.mjs @@ -0,0 +1,9 @@ +const config = { + "wwwPort": 3000, + "dbHost": "127.0.0.1", + "dbPort": 27017, + "dbName": "floorplan", + "mountPoint": "/" +} + +export default config; diff --git a/index.js b/index.js deleted file mode 100644 index 8182bf4..0000000 --- a/index.js +++ /dev/null @@ -1,2 +0,0 @@ -process.chdir(__dirname); -require('./lib/server'); \ No newline at end of file diff --git a/index.mjs b/index.mjs new file mode 100644 index 0000000..50750c3 --- /dev/null +++ b/index.mjs @@ -0,0 +1,9 @@ +// From https://thewebdev.info/2022/02/27/how-to-use-__dirname-in-node-js-when-using-es6-modules/ +import { dirname } from 'path'; +import { chdir } from 'process'; +import { fileURLToPath } from 'url'; +const __dirname = dirname(fileURLToPath(import.meta.url)); + +// Load server +chdir(__dirname); +import server from './lib/server.mjs'; diff --git a/lib/database.js b/lib/database.mjs similarity index 52% rename from lib/database.js rename to lib/database.mjs index fb4c874..6285076 100644 --- a/lib/database.js +++ b/lib/database.mjs @@ -1,28 +1,30 @@ -var config = require('../config'); -var logger = console; -var mongo = require('mongodb'); -var ObjectID = mongo.ObjectID; -var Q = require('q'); +import config from '../config.mjs'; +const logger = console; +import mongo from 'mongodb'; +const { ObjectID } = mongo; +import Q from 'q'; -var dbOptions = { +const dbOptions = { journal: true, numberOfRetries: Number.POSITIVE_INFINITY }; -var serverOptions = { +const serverOptions = { auto_reconnect: true }; -var server = new mongo.Server(config.dbHost, config.dbPort, serverOptions); -server.allServerInstances().forEach(function(serverInstance){ +const server = new mongo.Server(config.dbHost, config.dbPort, serverOptions); +server.allServerInstances().forEach(serverInstance => { serverInstance.dbInstances = serverInstance.dbInstances || []; }); -var db = module.exports = new mongo.Db(config.dbName, server, dbOptions); +const db = new mongo.Db(config.dbName, server, dbOptions); -var dbPromise; +export default db; -module.exports.OID = function(objectIdOrHexString){ +let dbPromise; + +export const OID = function(objectIdOrHexString){ if(!objectIdOrHexString){ return null; } else if(objectIdOrHexString instanceof ObjectID){ @@ -30,24 +32,24 @@ module.exports.OID = function(objectIdOrHexString){ } else { return new ObjectID(objectIdOrHexString); } -} +}; -module.exports.connect = function(){ +export const connect = function(){ return Q.ninvoke(db, "open") .then(onConnect) - .fail(function(err){ + .fail(err => { logger.error(err.message); }); }; -module.exports.shutdown = function(){ +export const shutdown = function(){ return dbPromise - .then(function(){ - var deferred = Q.defer(); + .then(() => { + const deferred = Q.defer(); db.close(deferred.makeNodeResolver()); return deferred.promise; }) - .finally(function(){ + .finally(() => { logger.log("Shut down."); }); }; diff --git a/lib/personRepository.js b/lib/personRepository.js deleted file mode 100644 index 14e42f6..0000000 --- a/lib/personRepository.js +++ /dev/null @@ -1,62 +0,0 @@ -var _ = require('lodash'); -var db = require('./database'); -var Q = require('q'); -var OID = db.OID; - -var peopleCollection = db.collection('people'); -var deletedPeopleCollection = db.collection('people_deleted'); - -var find = exports.find = function(query){ - var cursor; - - return Q.ninvoke(peopleCollection, 'find', query) - .then(function(_cursor){ - cursor = _cursor; - return Q.ninvoke(cursor, 'toArray'); - }) - .finally(function(){ - cursor && cursor.close(); - }); -}; - -exports.findAll = function(){ - return find({}); -}; - -/** - * @param id The object ID to search for. Can be a String or an ObjectID instance - * @returns the result object, or null if no result was found - */ -exports.findOne = function(id){ - return Q.ninvoke(peopleCollection, 'findOne', { _id: OID(id) }) -}; - -exports.findByOffice = function(office){ - return find({ office: office }); -}; - -/* - * Currently performs full updates, not deltas. If we want PATCH support on the API, we'll need to - * use $set to avoid deleting the attributes omitted from the delta. - */ -exports.save = function(attrs){ - var id = OID(attrs._id); - delete attrs._id; - return Q.ninvoke(peopleCollection, 'update', { _id: id }, attrs, { upsert: true }) - .then(function(report){ - var id2 = id || report[1].upserted; - return exports.findOne(id2); - }); -}; - -exports.remove = function(id){ - var person; - return exports.findOne(id) - .then(function(person_){ - person = person_; - return Q.ninvoke(deletedPeopleCollection, 'insert', person); - }) - .then(function(){ - return Q.ninvoke(peopleCollection, 'remove', person); - }); -} \ No newline at end of file diff --git a/lib/personRepository.mjs b/lib/personRepository.mjs new file mode 100644 index 0000000..3673d9b --- /dev/null +++ b/lib/personRepository.mjs @@ -0,0 +1,59 @@ +import db from './database.mjs'; +import Q from 'q'; +const { OID } = db; + +const peopleCollection = db.collection('people'); +const deletedPeopleCollection = db.collection('people_deleted'); + +const find = exports.find = function(query){ + let cursor; + + return Q.ninvoke(peopleCollection, 'find', query) + .then(_cursor => { + cursor = _cursor; + return Q.ninvoke(cursor, 'toArray'); + }) + .finally(() => { + cursor && cursor.close(); + }); +}; + +export const findAll = function(){ + return find({}); +}; + +/** + * @param id The object ID to search for. Can be a String or an ObjectID instance + * @returns the result object, or null if no result was found + */ +export const findOne = function(id){ + return Q.ninvoke(peopleCollection, 'findOne', { _id: OID(id) }) +}; + +export const findByOffice = function(office){ + return find({ office }); +}; + +/* + * Currently performs full updates, not deltas. If we want PATCH support on the API, we'll need to + * use $set to avoid deleting the attributes omitted from the delta. + */ +export const save = function(attrs){ + const id = OID(attrs._id); + delete attrs._id; + return Q.ninvoke(peopleCollection, 'update', { _id: id }, attrs, { upsert: true }) + .then(report => { + const id2 = id || report[1].upserted; + return findOne(id2); + }); +}; + +export const remove = function(id){ + let person; + return findOne(id) + .then(person_ => { + person = person_; + return Q.ninvoke(deletedPeopleCollection, 'insert', person); + }) + .then(() => Q.ninvoke(peopleCollection, 'remove', person)); +}; \ No newline at end of file diff --git a/lib/photoManager.js b/lib/photoManager.mjs similarity index 68% rename from lib/photoManager.js rename to lib/photoManager.mjs index 39afb8a..3f67362 100644 --- a/lib/photoManager.js +++ b/lib/photoManager.mjs @@ -1,32 +1,22 @@ -var _ = require('lodash'); -var fs = require('fs'); -var gm = require('gm'); -var path = require('path'); -var Q = require('q'); -var verror = require('verror'); - -var PHOTO_DIR = './data/photos/'; -var MAX_PHOTO_EDGE_LENGTH = 618; -var QUALITY = 75; //0 to 100 (best) - -exports.importPhoto = function(originPath, destinationFilename){ +import extend from 'lodash-es'; +import fs from 'fs'; +import gm from 'gm'; +import path from 'path'; +import Q from 'q'; +import verror from 'verror'; + +const PHOTO_DIR = './data/photos/'; +const MAX_PHOTO_EDGE_LENGTH = 618; +const QUALITY = 75; //0 to 100 (best) + +export const importPhoto = function(originPath, destinationFilename){ return getImageInfo(originPath) - .then(function(imageInfo){ - if(isProcessingRequired(imageInfo)){ - return processImage(originPath, imageInfo) - .then(function(processedImage){ - return saveProcessedImage(processedImage, destinationFilename); - }); - } else { - return moveUnprocessedImage(originPath, destinationFilename); - } - }) - .then(function(){ - return { - path: getDestinationPath(destinationFilename) - }; - }) - .fail(function(err){ + .then(imageInfo => isProcessingRequired(imageInfo) ? processImage(originPath, imageInfo) + .then(processedImage => saveProcessedImage(processedImage, destinationFilename)) : moveUnprocessedImage(originPath, destinationFilename)) + .then(() => ({ + path: getDestinationPath(destinationFilename) + })) + .fail(err => { throw new verror.VError(err, "unable to import photo"); }); }; @@ -51,17 +41,17 @@ Orientation=1 * JSON metadata. */ function getImageInfo(originPath){ - var image = gm(originPath); + const image = gm(originPath); return Q.all([ Q.ninvoke(image, 'identify', '{ "width": %w, "height": %h, "format": "%m" }'), Q.ninvoke(image, 'identify', '%[EXIF:Orientation]') ]) - .spread(function(rawInfo, orientation){ - var result; + .spread((rawInfo, orientation) => { + let result; try { result = JSON.parse(rawInfo); } catch(err){ - throw new verror.VError(err, "gm.identify returned invalid JSON: "+rawInfo); + throw new verror.VError(err, `gm.identify returned invalid JSON: ${rawInfo}`); } result.orientation = parseInt(orientation, 10) || undefined; return result; @@ -94,7 +84,7 @@ function isStandardOrientation(imageInfo){ } function processImage(originPath, imageInfo){ - var image = gm(originPath); + const image = gm(originPath); // Apply orientation from flag if(!isStandardOrientation(imageInfo)){ @@ -103,7 +93,7 @@ function processImage(originPath, imageInfo){ //We can't call size() to read these, because gm is a builder that queues all changes to be applied later. //size() would just return the stale original data because we haven't written yet. if(imageInfo.orientation >= 5){ - _.extend(imageInfo, { + extend(imageInfo, { width: imageInfo.height, height: imageInfo.width }); @@ -114,16 +104,15 @@ function processImage(originPath, imageInfo){ // Crop to center square if(!isSquare(imageInfo)){ - var inWidth = imageInfo.width; - var inHeight = imageInfo.height; - var outWidth = Math.min(inWidth, inHeight); - var outHeight = outWidth; - var halfDimensionDifference = Math.abs((inWidth-inHeight)/2); - var x = (inWidth > inHeight) ? halfDimensionDifference : 0; - var y = (inHeight > inWidth) ? halfDimensionDifference : 0; + const inWidth = imageInfo.width; + const inHeight = imageInfo.height; + const outWidth = Math.min(inWidth, inHeight); + const halfDimensionDifference = Math.abs((inWidth-inHeight)/2); + const x = (inWidth > inHeight) ? halfDimensionDifference : 0; + const y = (inHeight > inWidth) ? halfDimensionDifference : 0; imageInfo.width = imageInfo.height = outWidth; - image.crop(outWidth, outHeight, x, y); + image.crop(outWidth, outWidth, x, y); } // Resize to <= max size diff --git a/lib/server.js b/lib/server.mjs similarity index 63% rename from lib/server.js rename to lib/server.mjs index 6453c73..c75a412 100644 --- a/lib/server.js +++ b/lib/server.mjs @@ -1,13 +1,13 @@ -var _ = require('lodash'); -var config = require('../config'); -var cors = require('cors'); -var database = require('./database'); -var express = require('express'); -var http = require('http'); -var path = require('path'); -var slash = require('express-slash'); +import config from '../config.mjs'; +import defaults from 'lodash-es'; +import cors from 'cors'; +import database from './database.mjs'; +import express from 'express'; +import http from 'http'; +import path from 'path'; +import slash from 'express-slash'; -_.defaults(config, { +defaults(config, { wwwPort: 3000, dbHost: "127.0.0.1", dbPort: 27017, @@ -19,12 +19,13 @@ config.mountPoint = config.mountPoint.replace(/\/+$/, ""); database.connect().done(); -var server = module.exports = express(); -var publicDir = path.join(__dirname, '../public'); +const server = express(); +export default server; +const publicDir = path.join(__dirname, '../public'); server.set('env', 'production'); server.set('port', config.wwwPort); -server.set('views', __dirname + '/../views'); +server.set('views', `${__dirname}/../views`); server.set('view engine', 'hbs'); server.enable('strict routing'); server.use(express.compress()); @@ -34,14 +35,14 @@ server.use(express.bodyParser()); server.use(cors()); server.use(config.mountPoint, server.router); server.use(config.mountPoint, slash()); -server.use(function(err, req, res, next){ +server.use((err, req, res, next) => { console.error(err.stack || err.message); res.type('text'); res.send(500, err.message); }); server.use(config.mountPoint, require('less-middleware')({ src: publicDir })); server.use(config.mountPoint, express.static(publicDir, { maxAge: 4*60*60*1000 })); -server.use(config.mountPoint, function(req, res, next){ +server.use(config.mountPoint, (req, res, next) => { if(/^\/photos\/[0-9a-f]+\.jpg$/.test(req.path)){ res.redirect('/images/missing_photo.jpg'); } else { @@ -50,8 +51,8 @@ server.use(config.mountPoint, function(req, res, next){ } }); -http.createServer(server).listen(server.get('port'), function(){ +http.createServer(server).listen(server.get('port'), () => { console.log('Listening on http://*:%d%s', server.get('port'), config.mountPoint); }); -require('../routes/'); +import '../routes/index.mjs'; diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..45fe275 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,1303 @@ +{ + "name": "floorplan", + "version": "2.10.4", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "floorplan", + "version": "2.10.4", + "dependencies": { + "cache-manager": "0.7.1", + "cors": "1.0.1", + "express": "3.3.4", + "express-slash": "0.2.0", + "gm": "1.11.1", + "hbs": "2.3.1", + "less-middleware": "0.1.12", + "lodash-es": "^4.17.21", + "mongodb": "1.3.15", + "q": "0.9.6", + "request": "2.36.0", + "verror": "1.3.6" + } + }, + "node_modules/after": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/after/-/after-0.8.1.tgz", + "integrity": "sha512-SuI3vWhCFeSmkmmJ3efyuOkrhGyp/AuHthh3F5DinGYh2kR9t/0xUlm3/Vn2qMScfgg+cKho5fW7TUEYUhYeiA==" + }, + "node_modules/amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg==", + "engines": { + "node": ">=0.4.2" + } + }, + "node_modules/array-parallel": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/array-parallel/-/array-parallel-0.1.3.tgz", + "integrity": "sha512-TDPTwSWW5E4oiFiKmz6RGJ/a80Y91GuLgUYuLd49+XBS75tYo8PNgaT2K/OxuQYqkoI852MDGBorg9OcUSTQ8w==" + }, + "node_modules/array-series": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/array-series/-/array-series-0.1.5.tgz", + "integrity": "sha512-L0XlBwfx9QetHOsbLDrE/vh2t018w9462HM3iaFfxRiK83aJjAt/Ja3NMkOW7FICwWTlQBa3ZbL5FKhuQWkDrg==" + }, + "node_modules/asn1": { + "version": "0.1.11", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz", + "integrity": "sha512-Fh9zh3G2mZ8qM/kwsiKwL2U2FmXxVsboP4x1mXjnhKHv3SmzaBZoYvxEQJz/YS2gnCgd8xlAVWcZnQyC9qZBsA==", + "optional": true, + "engines": { + "node": ">=0.4.9" + } + }, + "node_modules/assert-plus": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz", + "integrity": "sha512-brU24g7ryhRwGCI2y+1dGQmQXiZF7TtIj583S96y0jjdajIe6wn8BuXyELYhvD22dtIxDQVFk04YTJwwdwOYJw==", + "optional": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/async": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", + "integrity": "sha512-l6ToIJIotphWahxxHyzK9bnLR6kM4jJIIgLShZeqLY7iboHoGkdgFl7W2/Ivi4SkMJYGKqW8vSuk0uKUj6qsSw==" + }, + "node_modules/aws-sign2": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.5.0.tgz", + "integrity": "sha512-oqUX0DM5j7aPWPCnpWebiyNIj2wiNI87ZxnOMoGv0aE4TGlBy2N+5iWc6dQ/NOKZaBD2W6PVz8jtOGkWzSC5EA==", + "optional": true, + "engines": { + "node": "*" + } + }, + "node_modules/boom": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/boom/-/boom-0.4.2.tgz", + "integrity": "sha512-OvfN8y1oAxxphzkl2SnCS+ztV/uVKTATtgLjWYg/7KwcNyf3rzpHxNQJZCKtsZd4+MteKczhWbSjtEX4bGgU9g==", + "deprecated": "This version has been deprecated in accordance with the hapi support policy (hapi.im/support). Please upgrade to the latest version to get the best features, bug fixes, and security patches. If you are unable to upgrade at this time, paid support is available for older versions (hapi.im/commercial).", + "optional": true, + "dependencies": { + "hoek": "0.9.x" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/bson": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/bson/-/bson-0.2.2.tgz", + "integrity": "sha512-lL3VqRQ3bNAHRTFvY+r3SRnbicZgmXq+YNEYTLEwx4OmObCc0bx/SkjAS8ZsdxZUVb238F3bTdFYJ6WVdeWVFg==", + "deprecated": "Fixed a critical issue with BSON serialization documented in CVE-2019-2391, see https://bit.ly/2KcpXdo for more details", + "hasInstallScript": true, + "engines": { + "node": ">=0.6.19" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.1.tgz", + "integrity": "sha512-vMfBIRp/wjlpueSz7Sb0OmO7C5SH58SSmbsT8G4D48YfO/Zgbr29xNXMpZVSC14ujVJfrZZH1Bl+kXYRQPuvfQ==", + "engines": { + "node": "*" + } + }, + "node_modules/bytes": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-0.2.0.tgz", + "integrity": "sha512-qH6XVfDizpXcxZisRfVo6rtnGQC2EoF88+p29KDyGN/0VQXFJ+ot8pkYiD673sUgeTirO42UVBitFOFzjVOIrQ==" + }, + "node_modules/cache-manager": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cache-manager/-/cache-manager-0.7.1.tgz", + "integrity": "sha512-UTDO6k/78AhNPk7acjweumeVrJueB28FOyEMoDUOv9yTNUL8n1Pu9sV9Su7opqsu+vSHfJzq+dZxuksepVNEbQ==", + "dependencies": { + "async": "^0.9.0", + "lru-cache": "^2.5.0" + } + }, + "node_modules/combined-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-0.0.7.tgz", + "integrity": "sha512-qfexlmLp9MyrkajQVyjEDb0Vj+KhRgR/rxLiVhaihlT+ZkX0lReqtH6Ack40CvMDERR4b5eFp3CreskpBs1Pig==", + "optional": true, + "dependencies": { + "delayed-stream": "0.0.5" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-1.2.0.tgz", + "integrity": "sha512-4AzfHvT/zLkvp+LVOHxZ02sHTuNrtoTnu8qEoJbpcL3nTnFhoNmAml1UV+96k9y5Tgz7jIjsom546WIi2iif0g==", + "dependencies": { + "keypress": "0.1.x" + }, + "engines": { + "node": ">= 0.6.x" + } + }, + "node_modules/connect": { + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/connect/-/connect-2.8.4.tgz", + "integrity": "sha512-ePqNZKEZrmFkRk0PJuk/SX4vHKAxkb57V1Fpr3mcPX/DwNbF5D4RbO7eKE6G/FFxdG8XumyFcey6sSA4pXseyw==", + "deprecated": "connect 2.x series is deprecated", + "dependencies": { + "buffer-crc32": "0.2.1", + "bytes": "0.2.0", + "cookie": "0.1.0", + "cookie-signature": "1.0.1", + "debug": "*", + "formidable": "1.0.14", + "fresh": "0.1.0", + "methods": "0.0.1", + "pause": "0.0.1", + "qs": "0.6.5", + "send": "0.1.3", + "uid2": "0.0.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/cookie": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.1.0.tgz", + "integrity": "sha512-YSNOBX085/nzHvrTLEHYHoNdkvpLU1MPjU3r1IGawudZJjfuqnRNIFrcOJJ7bfwC+HWbHL1Y4yMkC0O+HWjV7w==", + "engines": { + "node": "*" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.1.tgz", + "integrity": "sha512-FMG5ziBzXZ5d4j5obbWOH1X7AtIpsU9ce9mQ+lHo/I1++kzz/isNarOj6T1lBPRspP3mZpuIutc7OVDVcaN1Kg==" + }, + "node_modules/cors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cors/-/cors-1.0.1.tgz", + "integrity": "sha512-ZeuCU/xztHR2OfehqFP8B+l/1fgVu+qtBeXg5T8iQSUKHObmCpjcAXw4Z7U8lW+pv8cHwT8xHDIYJRoaFaK2Hw==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/cryptiles": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-0.2.2.tgz", + "integrity": "sha512-gvWSbgqP+569DdslUiCelxIv3IYK5Lgmq1UrRnk+s1WxQOQ16j3GPDcjdtgL5Au65DU/xQi6q3xPtf5Kta+3IQ==", + "deprecated": "This version has been deprecated in accordance with the hapi support policy (hapi.im/support). Please upgrade to the latest version to get the best features, bug fixes, and security patches. If you are unable to upgrade at this time, paid support is available for older versions (hapi.im/commercial).", + "optional": true, + "dependencies": { + "boom": "0.4.x" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/ctype": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/ctype/-/ctype-0.5.3.tgz", + "integrity": "sha512-T6CEkoSV4q50zW3TlTHMbzy1E5+zlnNcY+yb7tWVYlTwPhx9LpnfAkd4wecpWknDyptp4k97LUZeInlf6jdzBg==", + "optional": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/delayed-stream": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-0.0.5.tgz", + "integrity": "sha512-v+7uBd1pqe5YtgPacIIbZ8HuHeLFVNe4mUEyFDXL6KiqzEykjbw+5mXZXpGFgNVasdL4jWKgaKIXrEHiynN1LA==", + "optional": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/express": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/express/-/express-3.3.4.tgz", + "integrity": "sha512-kRxUCxqeMMhoPsZt4RX8DWGDca7APwJyCRHgCiCVJyO6VF5uTL2ChXVBE08rRgvDnScy6kuFO3AWfAeNg6UklQ==", + "dependencies": { + "buffer-crc32": "0.2.1", + "commander": "1.2.0", + "connect": "2.8.4", + "cookie": "0.1.0", + "cookie-signature": "1.0.1", + "debug": "*", + "fresh": "0.1.0", + "methods": "0.0.1", + "mkdirp": "0.3.5", + "range-parser": "0.0.4", + "send": "0.1.3" + }, + "bin": { + "express": "bin/express" + }, + "engines": { + "node": "*" + } + }, + "node_modules/express-slash": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/express-slash/-/express-slash-0.2.0.tgz", + "integrity": "sha512-IdRXrO50IW1YSfZaJJbBZLoNp39UrN60VBHnuVkTqd7uAo3oPDPPwVkBBz92/Q0w0PcfhOfOD34sg5d3DI+Ygw==", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/extsprintf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz", + "integrity": "sha512-g21Br4ELmVaKCVSUSSTXecKG+MiLcHFoby5RPPUmfZdhQTontXUOPf0QK/TvreRjgItRiyO928zxR4TCrnuwmA==", + "engines": [ + "node >=0.6.0" + ] + }, + "node_modules/forever-agent": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.5.2.tgz", + "integrity": "sha512-PDG5Ef0Dob/JsZUxUltJOhm/Y9mlteAE+46y3M9RBz/Rd3QVENJ75aGRhN56yekTUboaBIkd8KVWX2NjF6+91A==", + "engines": { + "node": "*" + } + }, + "node_modules/form-data": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-0.1.4.tgz", + "integrity": "sha512-x8eE+nzFtAMA0YYlSxf/Qhq6vP1f8wSoZ7Aw1GuctBcmudCNuTUmmx45TfEplyb6cjsZO/jvh6+1VpZn24ez+w==", + "optional": true, + "dependencies": { + "async": "~0.9.0", + "combined-stream": "~0.0.4", + "mime": "~1.2.11" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/formidable": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.0.14.tgz", + "integrity": "sha512-aOskFHEfYwkSKSzGui5jhQ+uyLo2NTwpzhndggz2YZHlv0HkAi+zG5ZEBCL3GTvqLyr/FzX9Mvx9DueCmu2HzQ==", + "deprecated": "Please upgrade to latest, formidable@v2 or formidable@v3! Check these notes: https://bit.ly/2ZEqIau", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/fresh": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.1.0.tgz", + "integrity": "sha512-ROG9M8tikYOuOJsvRBggh10WiQ/JebnldAwuCaQyFoiAUIE9XrYVnpznIjOQGZfCMzxzEBYHQr/LHJp3tcndzQ==", + "engines": { + "node": "*" + } + }, + "node_modules/gm": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/gm/-/gm-1.11.1.tgz", + "integrity": "sha512-Vof0aEfkPXn29xzmcuJaAhW9y5AOVCVgVQbTn4FrrOUImRyc5ABY1V7EPkK38xfD70v0Mt+L8dvvfiRFZ0+h2g==", + "dependencies": { + "array-parallel": "~0.1.0", + "array-series": "~0.1.0", + "debug": "0.7.0", + "stream-to-buffer": "~0.0.1", + "through": "~2.3.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/gm/node_modules/debug": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-0.7.0.tgz", + "integrity": "sha512-UWZnvGiX9tQgtrsA+mhGLKnUFvr1moempl9IvqQKyFnEgN0T4kpCE+KJcqTLcVxQjRVRnLF3VSE1Hchki5N98g==", + "engines": { + "node": "*" + } + }, + "node_modules/handlebars": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-1.0.12.tgz", + "integrity": "sha512-lI6MusMTp9cP1nI2cbSKxAWW6mTkuBqGD3RLHaTBfUaDCFtyJ1RMcEunXiGrlsEObuOQ1oruzaI0i8PqEbu1/Q==", + "dependencies": { + "optimist": "~0.3", + "uglify-js": "~2.3" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + } + }, + "node_modules/hawk": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-1.0.0.tgz", + "integrity": "sha512-Sg+VzrI7TjUomO0rjD6UXawsj50ykn5sB/xKNW/IenxzRVyw/wt9A2FLzYpGL/r0QG5hyXY8nLx/2m8UutoDcg==", + "deprecated": "This module moved to @hapi/hawk. Please make sure to switch over as this distribution is no longer supported and may contain bugs and critical security issues.", + "optional": true, + "dependencies": { + "boom": "0.4.x", + "cryptiles": "0.2.x", + "hoek": "0.9.x", + "sntp": "0.2.x" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/hbs": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/hbs/-/hbs-2.3.1.tgz", + "integrity": "sha512-oLzr2snhKQ15bnxE9cPJBNpZe2R/i2JdVqu2NQBWadMnPvW7hQfHbiJdFQb66B21/pbf1HZ5pdXUY4z6Go94Bg==", + "dependencies": { + "after": "0.8.1", + "handlebars": "1.0.12" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/hoek": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-0.9.1.tgz", + "integrity": "sha512-ZZ6eGyzGjyMTmpSPYVECXy9uNfqBR7x5CavhUaLOeD6W0vWK1mp/b7O3f86XE0Mtfo9rZ6Bh3fnuw9Xr8MF9zA==", + "deprecated": "This version has been deprecated in accordance with the hapi support policy (hapi.im/support). Please upgrade to the latest version to get the best features, bug fixes, and security patches. If you are unable to upgrade at this time, paid support is available for older versions (hapi.im/commercial).", + "optional": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/http-signature": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-0.10.1.tgz", + "integrity": "sha512-coK8uR5rq2IMj+Hen+sKPA5ldgbCc1/spPdKCL1Fw6h+D0s/2LzMcRK0Cqufs1h0ryx/niwBHGFu8HC3hwU+lA==", + "optional": true, + "dependencies": { + "asn1": "0.1.11", + "assert-plus": "^0.1.5", + "ctype": "0.5.3" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==" + }, + "node_modules/kerberos": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/kerberos/-/kerberos-0.0.3.tgz", + "integrity": "sha512-F9z+7FT9Fa68tesrXMreEneHWgLvmQhvjfxsXYvlnByuTGJKNy70c8yGjmsk3TJA/glNKQ3zoqTlwfmaI4eQIA==", + "hasInstallScript": true, + "optional": true + }, + "node_modules/keypress": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/keypress/-/keypress-0.1.0.tgz", + "integrity": "sha512-x0yf9PL/nx9Nw9oLL8ZVErFAk85/lslwEP7Vz7s5SI1ODXZIgit3C5qyWjw4DxOuO/3Hb4866SQh28a1V1d+WA==" + }, + "node_modules/less": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/less/-/less-1.4.2.tgz", + "integrity": "sha512-mJy2f4cQ5cjog3xErRXkUziR7X+99wpH1Zzt/KLEplVhWzCb5fCY3hwBhbA2xEHRVBR/rKCB0yyMUNiaKEpzgg==", + "bin": { + "lessc": "bin/lessc" + }, + "engines": { + "node": ">=0.4.2" + }, + "optionalDependencies": { + "mime": "1.2.x", + "mkdirp": "~0.3.4", + "request": ">=2.12.0", + "ycssmin": ">=1.0.1" + } + }, + "node_modules/less-middleware": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/less-middleware/-/less-middleware-0.1.12.tgz", + "integrity": "sha512-qDzrQUoqih6jbGbLJaUHIsTanDuRp8Sf6FG3/JOINaW9tDxjrxhebKGlPAF/IWko649VqtAQgm++cztJgqZxbQ==", + "deprecated": "Updated API and improved functionality.", + "dependencies": { + "less": "~1.4", + "mkdirp": "~0.3" + }, + "engines": { + "node": ">= 0.7.1" + } + }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" + }, + "node_modules/lru-cache": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", + "integrity": "sha512-WpibWJ60c3AgAz8a2iYErDrcT2C7OmKnsWhIcHOjkUHFjkXncJhtLxNSqUmxRxRunpb5I8Vprd7aNSd2NtksJQ==" + }, + "node_modules/methods": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/methods/-/methods-0.0.1.tgz", + "integrity": "sha512-pB8oFfci/xcfUgM6DTxc7lbTKifPPgs3mZUOsEgaH+1TTWpmcmv3sHl+5sUHIj2X2W8aPYa2+nJealRHK+Lo6A==" + }, + "node_modules/mime": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz", + "integrity": "sha512-Ysa2F/nqTNGHhhm9MV8ure4+Hc+Y8AWiqUdHxsO7xu8zc92ND9f3kpALHjaP026Ft17UfxrMt95c50PLUeynBw==" + }, + "node_modules/mkdirp": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz", + "integrity": "sha512-8OCq0De/h9ZxseqzCH8Kw/Filf5pF/vMI6+BH7Lu0jXz2pqYCjTAQRolSxRIi+Ax+oCCjlxoJMP0YQ4XlrQNHg==", + "deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)" + }, + "node_modules/mongodb": { + "version": "1.3.15", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-1.3.15.tgz", + "integrity": "sha512-R9Ainfl6zpACMLweUKtdyIFm/1h44bvxsx/OsqpUfl//SZ8u2/KiAAYDgEdgavgABWfe7gDxEB1uO5uBVzfBKw==", + "deprecated": "Please upgrade to 2.2.19 or higher", + "dependencies": { + "bson": "0.2.2" + }, + "engines": { + "node": ">=0.6.19" + }, + "optionalDependencies": { + "kerberos": "0.0.3" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/node-uuid": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz", + "integrity": "sha512-TkCET/3rr9mUuRp+CpO7qfgT++aAxfDRaalQhwPFzI9BY/2rCDn6OfpZOVggi1AXfTPpfkTrg5f5WQx5G1uLxA==", + "deprecated": "Use uuid module instead", + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/oauth-sign": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.3.0.tgz", + "integrity": "sha512-Tr31Sh5FnK9YKm7xTUPyDMsNOvMqkVDND0zvK/Wgj7/H9q8mpye0qG2nVzrnsvLhcsX5DtqXD0la0ks6rkPCGQ==", + "optional": true, + "engines": { + "node": "*" + } + }, + "node_modules/optimist": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.3.7.tgz", + "integrity": "sha512-TCx0dXQzVtSCg2OgY/bO9hjM9cV4XYx09TVK+s3+FhkjT6LovsLe+pPMzpWf+6yXK/hUizs2gUoTw3jHM0VaTQ==", + "dependencies": { + "wordwrap": "~0.0.2" + } + }, + "node_modules/pause": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", + "integrity": "sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==" + }, + "node_modules/psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", + "optional": true + }, + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/q": { + "version": "0.9.6", + "resolved": "https://registry.npmjs.org/q/-/q-0.9.6.tgz", + "integrity": "sha512-TaGjvSySjLlrPpEaKcwUnyYo/xfeB1Ue5GlrgTAWaLEMzcwSopQExRId0HJ3pxeTOVFdzI7Hpl2g2mmptrMEHA==", + "engines": { + "node": ">=0.6.0", + "teleport": ">=0.2.0" + } + }, + "node_modules/qs": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/qs/-/qs-0.6.5.tgz", + "integrity": "sha512-n7wA/f30O3SsOw2BVkGUDzjWMw7kXvQJWKtDdgfq5HJvDoad+Jbc6osN1AQ0Iain5plo9e7Cs5fE+xR+DVkPTw==", + "engines": { + "node": "*" + } + }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "optional": true + }, + "node_modules/range-parser": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-0.0.4.tgz", + "integrity": "sha512-okJVEq9DbZyg+5lD8pr6ooQmeA0uu8DYIyAU7VK1WUUK7hctI1yw2ZHhKiKjB6RXaDrYRmTR4SsIHkyiQpaLMA==", + "engines": { + "node": "*" + } + }, + "node_modules/request": { + "version": "2.36.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.36.0.tgz", + "integrity": "sha512-iVii/ruMH9i8k++HYYPqi+nb1Pbgz7UOTGbFEiyhl7uDN8PhyFV2lGJa8XLIUS5tyt5scERcLkwqvCNF84Vv2Q==", + "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", + "engines": [ + "node >= 0.8.0" + ], + "dependencies": { + "forever-agent": "~0.5.0", + "json-stringify-safe": "~5.0.0", + "mime": "~1.2.9", + "node-uuid": "~1.4.0", + "qs": "~0.6.0" + }, + "optionalDependencies": { + "aws-sign2": "~0.5.0", + "form-data": "~0.1.0", + "hawk": "~1.0.0", + "http-signature": "~0.10.0", + "oauth-sign": "~0.3.0", + "tough-cookie": ">=0.12.0", + "tunnel-agent": "~0.4.0" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "optional": true + }, + "node_modules/send": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/send/-/send-0.1.3.tgz", + "integrity": "sha512-FqBloej/3p6+mr88cqdh0bC7AYOpOrXBP3lqbOGnQDyatiHxgmPfpBOkN2sXUuFhpJpwiab5FPh+rCOxsBYgvg==", + "dependencies": { + "debug": "*", + "fresh": "0.1.0", + "mime": "~1.2.9", + "range-parser": "0.0.4" + } + }, + "node_modules/sntp": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-0.2.4.tgz", + "integrity": "sha512-bDLrKa/ywz65gCl+LmOiIhteP1bhEsAAzhfMedPoiHP3dyYnAevlaJshdqb9Yu0sRifyP/fRqSt8t+5qGIWlGQ==", + "deprecated": "This module moved to @hapi/sntp. Please make sure to switch over as this distribution is no longer supported and may contain bugs and critical security issues.", + "optional": true, + "dependencies": { + "hoek": "0.9.x" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/source-map": { + "version": "0.1.43", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", + "integrity": "sha512-VtCvB9SIQhk3aF6h+N85EaqIaBFIAfZ9Cu+NJHHVvc8BbEcnvDcFw6sqQ2dQrT6SlOrZq3tIvyD9+EGq/lJryQ==", + "dependencies": { + "amdefine": ">=0.0.4" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/stream-to-buffer": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/stream-to-buffer/-/stream-to-buffer-0.0.1.tgz", + "integrity": "sha512-LsvisgE3iThboRqA+XLmtnY9ktPLVPOj3zZxXMhlezeCcAh0RhomquXJgB8H+lb/RR/pPcbNVGHVKFUwjpoRtw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" + }, + "node_modules/tough-cookie": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.2.tgz", + "integrity": "sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ==", + "optional": true, + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tunnel-agent": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz", + "integrity": "sha512-e0IoVDWx8SDHc/hwFTqJDQ7CCDTEeGhmcT9jkWJjoGQSpgBz20nAMr80E3Tpk7PatJ1b37DQDgJR3CNSzcMOZQ==", + "optional": true, + "engines": { + "node": "*" + } + }, + "node_modules/uglify-js": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.3.6.tgz", + "integrity": "sha512-T2LWWydxf5+Btpb0S/Gg/yKFmYjnX9jtQ4mdN9YRq73BhN21EhU0Dvw3wYDLqd3TooGUJlCKf3Gfyjjy/RTcWA==", + "dependencies": { + "async": "~0.2.6", + "optimist": "~0.3.5", + "source-map": "~0.1.7" + }, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/uglify-js/node_modules/async": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", + "integrity": "sha512-eAkdoKxU6/LkKDBzLpT+t6Ff5EtfSF4wx1WfJiPEEV7WNLnDaRXk0oVysiEPm262roaachGexwUv94WhSgN5TQ==" + }, + "node_modules/uid2": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/uid2/-/uid2-0.0.2.tgz", + "integrity": "sha512-FjCp6IusuzzbZG8y0MDDsXcPwYuDAD6jK/0uzxwTFZy2/WaJEFCpQevYE9DPJsJQLMZSxX5x4HY3W7uTKhhI6Q==" + }, + "node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "optional": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "optional": true, + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "node_modules/verror": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz", + "integrity": "sha512-i8GFYwImt5D5B8CPpi2jrDTy/faq4OEW+NkOTLSKcIdPfdYJvWv3VZddDKl0ByvBe6cJ2s5Mm2XDtv5c2pj/Eg==", + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "extsprintf": "1.0.2" + } + }, + "node_modules/wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha512-1tMA907+V4QmxV7dbRvb4/8MaRALK6q9Abid3ndMYnbyo8piisCmeONVqVSXqQA3KaP4SLt5b7ud6E2sqP8TFw==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ycssmin": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ycssmin/-/ycssmin-1.0.1.tgz", + "integrity": "sha512-nSBxAfGA/RlALXyqijYUnIjMXNXWxYHrQJSYwNqypeULl44J8Z/eN5larw7ZEdYLeUHBgPyilve6hqQtWVVs9g==", + "optional": true, + "bin": { + "ycssmin": "bin/cssmin" + } + } + }, + "dependencies": { + "after": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/after/-/after-0.8.1.tgz", + "integrity": "sha512-SuI3vWhCFeSmkmmJ3efyuOkrhGyp/AuHthh3F5DinGYh2kR9t/0xUlm3/Vn2qMScfgg+cKho5fW7TUEYUhYeiA==" + }, + "amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg==" + }, + "array-parallel": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/array-parallel/-/array-parallel-0.1.3.tgz", + "integrity": "sha512-TDPTwSWW5E4oiFiKmz6RGJ/a80Y91GuLgUYuLd49+XBS75tYo8PNgaT2K/OxuQYqkoI852MDGBorg9OcUSTQ8w==" + }, + "array-series": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/array-series/-/array-series-0.1.5.tgz", + "integrity": "sha512-L0XlBwfx9QetHOsbLDrE/vh2t018w9462HM3iaFfxRiK83aJjAt/Ja3NMkOW7FICwWTlQBa3ZbL5FKhuQWkDrg==" + }, + "asn1": { + "version": "0.1.11", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz", + "integrity": "sha512-Fh9zh3G2mZ8qM/kwsiKwL2U2FmXxVsboP4x1mXjnhKHv3SmzaBZoYvxEQJz/YS2gnCgd8xlAVWcZnQyC9qZBsA==", + "optional": true + }, + "assert-plus": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz", + "integrity": "sha512-brU24g7ryhRwGCI2y+1dGQmQXiZF7TtIj583S96y0jjdajIe6wn8BuXyELYhvD22dtIxDQVFk04YTJwwdwOYJw==", + "optional": true + }, + "async": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", + "integrity": "sha512-l6ToIJIotphWahxxHyzK9bnLR6kM4jJIIgLShZeqLY7iboHoGkdgFl7W2/Ivi4SkMJYGKqW8vSuk0uKUj6qsSw==" + }, + "aws-sign2": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.5.0.tgz", + "integrity": "sha512-oqUX0DM5j7aPWPCnpWebiyNIj2wiNI87ZxnOMoGv0aE4TGlBy2N+5iWc6dQ/NOKZaBD2W6PVz8jtOGkWzSC5EA==", + "optional": true + }, + "boom": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/boom/-/boom-0.4.2.tgz", + "integrity": "sha512-OvfN8y1oAxxphzkl2SnCS+ztV/uVKTATtgLjWYg/7KwcNyf3rzpHxNQJZCKtsZd4+MteKczhWbSjtEX4bGgU9g==", + "optional": true, + "requires": { + "hoek": "0.9.x" + } + }, + "bson": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/bson/-/bson-0.2.2.tgz", + "integrity": "sha512-lL3VqRQ3bNAHRTFvY+r3SRnbicZgmXq+YNEYTLEwx4OmObCc0bx/SkjAS8ZsdxZUVb238F3bTdFYJ6WVdeWVFg==" + }, + "buffer-crc32": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.1.tgz", + "integrity": "sha512-vMfBIRp/wjlpueSz7Sb0OmO7C5SH58SSmbsT8G4D48YfO/Zgbr29xNXMpZVSC14ujVJfrZZH1Bl+kXYRQPuvfQ==" + }, + "bytes": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-0.2.0.tgz", + "integrity": "sha512-qH6XVfDizpXcxZisRfVo6rtnGQC2EoF88+p29KDyGN/0VQXFJ+ot8pkYiD673sUgeTirO42UVBitFOFzjVOIrQ==" + }, + "cache-manager": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cache-manager/-/cache-manager-0.7.1.tgz", + "integrity": "sha512-UTDO6k/78AhNPk7acjweumeVrJueB28FOyEMoDUOv9yTNUL8n1Pu9sV9Su7opqsu+vSHfJzq+dZxuksepVNEbQ==", + "requires": { + "async": "^0.9.0", + "lru-cache": "^2.5.0" + } + }, + "combined-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-0.0.7.tgz", + "integrity": "sha512-qfexlmLp9MyrkajQVyjEDb0Vj+KhRgR/rxLiVhaihlT+ZkX0lReqtH6Ack40CvMDERR4b5eFp3CreskpBs1Pig==", + "optional": true, + "requires": { + "delayed-stream": "0.0.5" + } + }, + "commander": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-1.2.0.tgz", + "integrity": "sha512-4AzfHvT/zLkvp+LVOHxZ02sHTuNrtoTnu8qEoJbpcL3nTnFhoNmAml1UV+96k9y5Tgz7jIjsom546WIi2iif0g==", + "requires": { + "keypress": "0.1.x" + } + }, + "connect": { + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/connect/-/connect-2.8.4.tgz", + "integrity": "sha512-ePqNZKEZrmFkRk0PJuk/SX4vHKAxkb57V1Fpr3mcPX/DwNbF5D4RbO7eKE6G/FFxdG8XumyFcey6sSA4pXseyw==", + "requires": { + "buffer-crc32": "0.2.1", + "bytes": "0.2.0", + "cookie": "0.1.0", + "cookie-signature": "1.0.1", + "debug": "*", + "formidable": "1.0.14", + "fresh": "0.1.0", + "methods": "0.0.1", + "pause": "0.0.1", + "qs": "0.6.5", + "send": "0.1.3", + "uid2": "0.0.2" + } + }, + "cookie": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.1.0.tgz", + "integrity": "sha512-YSNOBX085/nzHvrTLEHYHoNdkvpLU1MPjU3r1IGawudZJjfuqnRNIFrcOJJ7bfwC+HWbHL1Y4yMkC0O+HWjV7w==" + }, + "cookie-signature": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.1.tgz", + "integrity": "sha512-FMG5ziBzXZ5d4j5obbWOH1X7AtIpsU9ce9mQ+lHo/I1++kzz/isNarOj6T1lBPRspP3mZpuIutc7OVDVcaN1Kg==" + }, + "cors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cors/-/cors-1.0.1.tgz", + "integrity": "sha512-ZeuCU/xztHR2OfehqFP8B+l/1fgVu+qtBeXg5T8iQSUKHObmCpjcAXw4Z7U8lW+pv8cHwT8xHDIYJRoaFaK2Hw==" + }, + "cryptiles": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-0.2.2.tgz", + "integrity": "sha512-gvWSbgqP+569DdslUiCelxIv3IYK5Lgmq1UrRnk+s1WxQOQ16j3GPDcjdtgL5Au65DU/xQi6q3xPtf5Kta+3IQ==", + "optional": true, + "requires": { + "boom": "0.4.x" + } + }, + "ctype": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/ctype/-/ctype-0.5.3.tgz", + "integrity": "sha512-T6CEkoSV4q50zW3TlTHMbzy1E5+zlnNcY+yb7tWVYlTwPhx9LpnfAkd4wecpWknDyptp4k97LUZeInlf6jdzBg==", + "optional": true + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "requires": { + "ms": "2.1.2" + } + }, + "delayed-stream": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-0.0.5.tgz", + "integrity": "sha512-v+7uBd1pqe5YtgPacIIbZ8HuHeLFVNe4mUEyFDXL6KiqzEykjbw+5mXZXpGFgNVasdL4jWKgaKIXrEHiynN1LA==", + "optional": true + }, + "express": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/express/-/express-3.3.4.tgz", + "integrity": "sha512-kRxUCxqeMMhoPsZt4RX8DWGDca7APwJyCRHgCiCVJyO6VF5uTL2ChXVBE08rRgvDnScy6kuFO3AWfAeNg6UklQ==", + "requires": { + "buffer-crc32": "0.2.1", + "commander": "1.2.0", + "connect": "2.8.4", + "cookie": "0.1.0", + "cookie-signature": "1.0.1", + "debug": "*", + "fresh": "0.1.0", + "methods": "0.0.1", + "mkdirp": "0.3.5", + "range-parser": "0.0.4", + "send": "0.1.3" + } + }, + "express-slash": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/express-slash/-/express-slash-0.2.0.tgz", + "integrity": "sha512-IdRXrO50IW1YSfZaJJbBZLoNp39UrN60VBHnuVkTqd7uAo3oPDPPwVkBBz92/Q0w0PcfhOfOD34sg5d3DI+Ygw==" + }, + "extsprintf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz", + "integrity": "sha512-g21Br4ELmVaKCVSUSSTXecKG+MiLcHFoby5RPPUmfZdhQTontXUOPf0QK/TvreRjgItRiyO928zxR4TCrnuwmA==" + }, + "forever-agent": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.5.2.tgz", + "integrity": "sha512-PDG5Ef0Dob/JsZUxUltJOhm/Y9mlteAE+46y3M9RBz/Rd3QVENJ75aGRhN56yekTUboaBIkd8KVWX2NjF6+91A==" + }, + "form-data": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-0.1.4.tgz", + "integrity": "sha512-x8eE+nzFtAMA0YYlSxf/Qhq6vP1f8wSoZ7Aw1GuctBcmudCNuTUmmx45TfEplyb6cjsZO/jvh6+1VpZn24ez+w==", + "optional": true, + "requires": { + "async": "~0.9.0", + "combined-stream": "~0.0.4", + "mime": "~1.2.11" + } + }, + "formidable": { + "version": "1.0.14", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.0.14.tgz", + "integrity": "sha512-aOskFHEfYwkSKSzGui5jhQ+uyLo2NTwpzhndggz2YZHlv0HkAi+zG5ZEBCL3GTvqLyr/FzX9Mvx9DueCmu2HzQ==" + }, + "fresh": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.1.0.tgz", + "integrity": "sha512-ROG9M8tikYOuOJsvRBggh10WiQ/JebnldAwuCaQyFoiAUIE9XrYVnpznIjOQGZfCMzxzEBYHQr/LHJp3tcndzQ==" + }, + "gm": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/gm/-/gm-1.11.1.tgz", + "integrity": "sha512-Vof0aEfkPXn29xzmcuJaAhW9y5AOVCVgVQbTn4FrrOUImRyc5ABY1V7EPkK38xfD70v0Mt+L8dvvfiRFZ0+h2g==", + "requires": { + "array-parallel": "~0.1.0", + "array-series": "~0.1.0", + "debug": "0.7.0", + "stream-to-buffer": "~0.0.1", + "through": "~2.3.1" + }, + "dependencies": { + "debug": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-0.7.0.tgz", + "integrity": "sha512-UWZnvGiX9tQgtrsA+mhGLKnUFvr1moempl9IvqQKyFnEgN0T4kpCE+KJcqTLcVxQjRVRnLF3VSE1Hchki5N98g==" + } + } + }, + "handlebars": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-1.0.12.tgz", + "integrity": "sha512-lI6MusMTp9cP1nI2cbSKxAWW6mTkuBqGD3RLHaTBfUaDCFtyJ1RMcEunXiGrlsEObuOQ1oruzaI0i8PqEbu1/Q==", + "requires": { + "optimist": "~0.3", + "uglify-js": "~2.3" + } + }, + "hawk": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-1.0.0.tgz", + "integrity": "sha512-Sg+VzrI7TjUomO0rjD6UXawsj50ykn5sB/xKNW/IenxzRVyw/wt9A2FLzYpGL/r0QG5hyXY8nLx/2m8UutoDcg==", + "optional": true, + "requires": { + "boom": "0.4.x", + "cryptiles": "0.2.x", + "hoek": "0.9.x", + "sntp": "0.2.x" + } + }, + "hbs": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/hbs/-/hbs-2.3.1.tgz", + "integrity": "sha512-oLzr2snhKQ15bnxE9cPJBNpZe2R/i2JdVqu2NQBWadMnPvW7hQfHbiJdFQb66B21/pbf1HZ5pdXUY4z6Go94Bg==", + "requires": { + "after": "0.8.1", + "handlebars": "1.0.12" + } + }, + "hoek": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-0.9.1.tgz", + "integrity": "sha512-ZZ6eGyzGjyMTmpSPYVECXy9uNfqBR7x5CavhUaLOeD6W0vWK1mp/b7O3f86XE0Mtfo9rZ6Bh3fnuw9Xr8MF9zA==", + "optional": true + }, + "http-signature": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-0.10.1.tgz", + "integrity": "sha512-coK8uR5rq2IMj+Hen+sKPA5ldgbCc1/spPdKCL1Fw6h+D0s/2LzMcRK0Cqufs1h0ryx/niwBHGFu8HC3hwU+lA==", + "optional": true, + "requires": { + "asn1": "0.1.11", + "assert-plus": "^0.1.5", + "ctype": "0.5.3" + } + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==" + }, + "kerberos": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/kerberos/-/kerberos-0.0.3.tgz", + "integrity": "sha512-F9z+7FT9Fa68tesrXMreEneHWgLvmQhvjfxsXYvlnByuTGJKNy70c8yGjmsk3TJA/glNKQ3zoqTlwfmaI4eQIA==", + "optional": true + }, + "keypress": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/keypress/-/keypress-0.1.0.tgz", + "integrity": "sha512-x0yf9PL/nx9Nw9oLL8ZVErFAk85/lslwEP7Vz7s5SI1ODXZIgit3C5qyWjw4DxOuO/3Hb4866SQh28a1V1d+WA==" + }, + "less": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/less/-/less-1.4.2.tgz", + "integrity": "sha512-mJy2f4cQ5cjog3xErRXkUziR7X+99wpH1Zzt/KLEplVhWzCb5fCY3hwBhbA2xEHRVBR/rKCB0yyMUNiaKEpzgg==", + "requires": { + "mime": "1.2.x", + "mkdirp": "~0.3.4", + "request": ">=2.12.0", + "ycssmin": ">=1.0.1" + } + }, + "less-middleware": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/less-middleware/-/less-middleware-0.1.12.tgz", + "integrity": "sha512-qDzrQUoqih6jbGbLJaUHIsTanDuRp8Sf6FG3/JOINaW9tDxjrxhebKGlPAF/IWko649VqtAQgm++cztJgqZxbQ==", + "requires": { + "less": "~1.4", + "mkdirp": "~0.3" + } + }, + "lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" + }, + "lru-cache": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", + "integrity": "sha512-WpibWJ60c3AgAz8a2iYErDrcT2C7OmKnsWhIcHOjkUHFjkXncJhtLxNSqUmxRxRunpb5I8Vprd7aNSd2NtksJQ==" + }, + "methods": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/methods/-/methods-0.0.1.tgz", + "integrity": "sha512-pB8oFfci/xcfUgM6DTxc7lbTKifPPgs3mZUOsEgaH+1TTWpmcmv3sHl+5sUHIj2X2W8aPYa2+nJealRHK+Lo6A==" + }, + "mime": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.2.11.tgz", + "integrity": "sha512-Ysa2F/nqTNGHhhm9MV8ure4+Hc+Y8AWiqUdHxsO7xu8zc92ND9f3kpALHjaP026Ft17UfxrMt95c50PLUeynBw==" + }, + "mkdirp": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz", + "integrity": "sha512-8OCq0De/h9ZxseqzCH8Kw/Filf5pF/vMI6+BH7Lu0jXz2pqYCjTAQRolSxRIi+Ax+oCCjlxoJMP0YQ4XlrQNHg==" + }, + "mongodb": { + "version": "1.3.15", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-1.3.15.tgz", + "integrity": "sha512-R9Ainfl6zpACMLweUKtdyIFm/1h44bvxsx/OsqpUfl//SZ8u2/KiAAYDgEdgavgABWfe7gDxEB1uO5uBVzfBKw==", + "requires": { + "bson": "0.2.2", + "kerberos": "0.0.3" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node-uuid": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.8.tgz", + "integrity": "sha512-TkCET/3rr9mUuRp+CpO7qfgT++aAxfDRaalQhwPFzI9BY/2rCDn6OfpZOVggi1AXfTPpfkTrg5f5WQx5G1uLxA==" + }, + "oauth-sign": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.3.0.tgz", + "integrity": "sha512-Tr31Sh5FnK9YKm7xTUPyDMsNOvMqkVDND0zvK/Wgj7/H9q8mpye0qG2nVzrnsvLhcsX5DtqXD0la0ks6rkPCGQ==", + "optional": true + }, + "optimist": { + "version": "0.3.7", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.3.7.tgz", + "integrity": "sha512-TCx0dXQzVtSCg2OgY/bO9hjM9cV4XYx09TVK+s3+FhkjT6LovsLe+pPMzpWf+6yXK/hUizs2gUoTw3jHM0VaTQ==", + "requires": { + "wordwrap": "~0.0.2" + } + }, + "pause": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", + "integrity": "sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==" + }, + "psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", + "optional": true + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "optional": true + }, + "q": { + "version": "0.9.6", + "resolved": "https://registry.npmjs.org/q/-/q-0.9.6.tgz", + "integrity": "sha512-TaGjvSySjLlrPpEaKcwUnyYo/xfeB1Ue5GlrgTAWaLEMzcwSopQExRId0HJ3pxeTOVFdzI7Hpl2g2mmptrMEHA==" + }, + "qs": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/qs/-/qs-0.6.5.tgz", + "integrity": "sha512-n7wA/f30O3SsOw2BVkGUDzjWMw7kXvQJWKtDdgfq5HJvDoad+Jbc6osN1AQ0Iain5plo9e7Cs5fE+xR+DVkPTw==" + }, + "querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "optional": true + }, + "range-parser": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-0.0.4.tgz", + "integrity": "sha512-okJVEq9DbZyg+5lD8pr6ooQmeA0uu8DYIyAU7VK1WUUK7hctI1yw2ZHhKiKjB6RXaDrYRmTR4SsIHkyiQpaLMA==" + }, + "request": { + "version": "2.36.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.36.0.tgz", + "integrity": "sha512-iVii/ruMH9i8k++HYYPqi+nb1Pbgz7UOTGbFEiyhl7uDN8PhyFV2lGJa8XLIUS5tyt5scERcLkwqvCNF84Vv2Q==", + "requires": { + "aws-sign2": "~0.5.0", + "forever-agent": "~0.5.0", + "form-data": "~0.1.0", + "hawk": "~1.0.0", + "http-signature": "~0.10.0", + "json-stringify-safe": "~5.0.0", + "mime": "~1.2.9", + "node-uuid": "~1.4.0", + "oauth-sign": "~0.3.0", + "qs": "~0.6.0", + "tough-cookie": ">=0.12.0", + "tunnel-agent": "~0.4.0" + } + }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", + "optional": true + }, + "send": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/send/-/send-0.1.3.tgz", + "integrity": "sha512-FqBloej/3p6+mr88cqdh0bC7AYOpOrXBP3lqbOGnQDyatiHxgmPfpBOkN2sXUuFhpJpwiab5FPh+rCOxsBYgvg==", + "requires": { + "debug": "*", + "fresh": "0.1.0", + "mime": "~1.2.9", + "range-parser": "0.0.4" + } + }, + "sntp": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-0.2.4.tgz", + "integrity": "sha512-bDLrKa/ywz65gCl+LmOiIhteP1bhEsAAzhfMedPoiHP3dyYnAevlaJshdqb9Yu0sRifyP/fRqSt8t+5qGIWlGQ==", + "optional": true, + "requires": { + "hoek": "0.9.x" + } + }, + "source-map": { + "version": "0.1.43", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", + "integrity": "sha512-VtCvB9SIQhk3aF6h+N85EaqIaBFIAfZ9Cu+NJHHVvc8BbEcnvDcFw6sqQ2dQrT6SlOrZq3tIvyD9+EGq/lJryQ==", + "requires": { + "amdefine": ">=0.0.4" + } + }, + "stream-to-buffer": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/stream-to-buffer/-/stream-to-buffer-0.0.1.tgz", + "integrity": "sha512-LsvisgE3iThboRqA+XLmtnY9ktPLVPOj3zZxXMhlezeCcAh0RhomquXJgB8H+lb/RR/pPcbNVGHVKFUwjpoRtw==" + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" + }, + "tough-cookie": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.2.tgz", + "integrity": "sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ==", + "optional": true, + "requires": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + } + }, + "tunnel-agent": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz", + "integrity": "sha512-e0IoVDWx8SDHc/hwFTqJDQ7CCDTEeGhmcT9jkWJjoGQSpgBz20nAMr80E3Tpk7PatJ1b37DQDgJR3CNSzcMOZQ==", + "optional": true + }, + "uglify-js": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.3.6.tgz", + "integrity": "sha512-T2LWWydxf5+Btpb0S/Gg/yKFmYjnX9jtQ4mdN9YRq73BhN21EhU0Dvw3wYDLqd3TooGUJlCKf3Gfyjjy/RTcWA==", + "requires": { + "async": "~0.2.6", + "optimist": "~0.3.5", + "source-map": "~0.1.7" + }, + "dependencies": { + "async": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz", + "integrity": "sha512-eAkdoKxU6/LkKDBzLpT+t6Ff5EtfSF4wx1WfJiPEEV7WNLnDaRXk0oVysiEPm262roaachGexwUv94WhSgN5TQ==" + } + } + }, + "uid2": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/uid2/-/uid2-0.0.2.tgz", + "integrity": "sha512-FjCp6IusuzzbZG8y0MDDsXcPwYuDAD6jK/0uzxwTFZy2/WaJEFCpQevYE9DPJsJQLMZSxX5x4HY3W7uTKhhI6Q==" + }, + "universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "optional": true + }, + "url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "optional": true, + "requires": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "verror": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz", + "integrity": "sha512-i8GFYwImt5D5B8CPpi2jrDTy/faq4OEW+NkOTLSKcIdPfdYJvWv3VZddDKl0ByvBe6cJ2s5Mm2XDtv5c2pj/Eg==", + "requires": { + "extsprintf": "1.0.2" + } + }, + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha512-1tMA907+V4QmxV7dbRvb4/8MaRALK6q9Abid3ndMYnbyo8piisCmeONVqVSXqQA3KaP4SLt5b7ud6E2sqP8TFw==" + }, + "ycssmin": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ycssmin/-/ycssmin-1.0.1.tgz", + "integrity": "sha512-nSBxAfGA/RlALXyqijYUnIjMXNXWxYHrQJSYwNqypeULl44J8Z/eN5larw7ZEdYLeUHBgPyilve6hqQtWVVs9g==", + "optional": true + } + } +} diff --git a/package.json b/package.json index 7484f25..5133f9f 100644 --- a/package.json +++ b/package.json @@ -3,17 +3,17 @@ "version": "2.10.4", "author": "Ben Hutchison ", "dependencies": { - "cache-manager" : "0.7.1", - "cors" : "1.0.1", - "express" : "3.3.4", - "express-slash" : "0.2.0", - "gm" : "1.11.1", - "hbs" : "2.3.1", - "less-middleware" : "0.1.12", - "lodash" : "1.3.1", - "mongodb" : "1.3.15", - "q" : "0.9.6", - "request" : "2.36.0", - "verror" : "1.3.6" + "cache-manager": "0.7.1", + "cors": "1.0.1", + "express": "3.3.4", + "express-slash": "0.2.0", + "gm": "1.11.1", + "hbs": "2.3.1", + "less-middleware": "0.1.12", + "lodash-es": "^4.17.21", + "mongodb": "1.3.15", + "q": "0.9.6", + "request": "2.36.0", + "verror": "1.3.6" } } diff --git a/routes/admin.js b/routes/admin.js deleted file mode 100644 index 4d7c4e3..0000000 --- a/routes/admin.js +++ /dev/null @@ -1,39 +0,0 @@ -var _ = require('lodash'); -var config = require('../config'); -var fs = require('fs'); -var path = require('path'); -var Q = require('q'); -var server = require('../lib/server'); - -var MAPS_PATH = path.join(server.get('views'), 'maps'); -var OFFICE_IDS; - -fs.readdir(MAPS_PATH, function(err, files){ - if (err) throw err; - OFFICE_IDS = files.map(function(filename){ - return path.basename(filename, '.svg'); - }); -}); - -var renderAdmin = function(req, res, next){ - var svgReadPromises = OFFICE_IDS.map(function(officeId){ - var svgPath = path.join(MAPS_PATH, officeId+'.svg'); - return Q.nfcall(fs.readFile, svgPath); - }); - - Q.all(svgReadPromises) - .then(function(svgs){ - var svgMap = _.zipObject(OFFICE_IDS, svgs); - - var context = { - svgs: svgMap, - config: JSON.stringify({ - mountPoint: config.mountPoint - }) - }; - res.render('admin', context); - }).fail(next); -}; - -server.get('/admin/', renderAdmin); -server.get('/admin/:id', renderAdmin); \ No newline at end of file diff --git a/routes/admin.mjs b/routes/admin.mjs new file mode 100644 index 0000000..703335c --- /dev/null +++ b/routes/admin.mjs @@ -0,0 +1,37 @@ +import config from '../config.mjs'; +import zipObject from 'lodash-es'; +import fs from 'fs'; +import path from 'path'; +import Q from 'q'; +import server from '../lib/server.mjs'; + +const MAPS_PATH = path.join(server.get('views'), 'maps'); +let OFFICE_IDS; + +fs.readdir(MAPS_PATH, (err, files) => { + if (err) throw err; + OFFICE_IDS = files.map(filename => path.basename(filename, '.svg')); +}); + +const renderAdmin = function(req, res, next){ + const svgReadPromises = OFFICE_IDS.map(officeId => { + const svgPath = path.join(MAPS_PATH, `${officeId}.svg`); + return Q.nfcall(fs.readFile, svgPath); + }); + + Q.all(svgReadPromises) + .then(svgs => { + const svgMap = zipObject(OFFICE_IDS, svgs); + + const context = { + svgs: svgMap, + config: JSON.stringify({ + mountPoint: config.mountPoint + }) + }; + res.render('admin', context); + }).fail(next); +}; + +server.get('/admin/', renderAdmin); +server.get('/admin/:id', renderAdmin); \ No newline at end of file diff --git a/routes/endpoints.js b/routes/endpoints.js deleted file mode 100644 index 284c9c7..0000000 --- a/routes/endpoints.js +++ /dev/null @@ -1,72 +0,0 @@ -var _ = require('lodash'); -var cache_manager = require('cache-manager'); -var config = require('../config'); -var express = require('express'); -var request = require('request'); -var server = require('../lib/server'); - -var photoStaticHandler = express.static('./data', { maxAge: 4*60*60*1000 }); -var memory_cache = cache_manager.caching({ - store: 'memory', - max: 100, - ttl: 5 //seconds -}); - -var stormRequestOptions = { - auth: { - 'username': config.stormUsername, - 'password': config.stormPassword, - 'sendImmediately': true - }, - json: true, - // proxy: 'http://10.4.5.181:9998', - // strictSSL: false, - timeout: 3000 -}; - -server.get('/endpoints', function(req, res, next){ - var url = config.stormApiRoot+'endpoints'; - // console.log("request to storm ("+url+")..."); - if(isStormIntegrationEnabled){ - request(url, stormRequestOptions, function(err, stormResponse, body){ - // console.log("response from storm", stormResponse); - if(err != null){ - console.warn("failed to get endpoints from Storm", err); - res.json(500, err); - } else { - res.json(body); - } - }); - } else { - res.json([]); - } -}); - -server.get('/endpoints/status', function(req, res, next){ - if(isStormIntegrationEnabled()){ - memory_cache.wrap('bjn-endpoints', function(cacheResult){ - console.log("Requesting endpoint status from Storm..."); - request(config.stormApiRoot+'endpoints/status', stormRequestOptions, function(err, res, body){ - cacheResult(err, body); - }); - }, function(err, result){ - if(err != null){ - console.warn("failed to get endpoint status from Storm", err); - res.json(500, err); - } else { - res.json(result); - } - }); - } else { - res.json([]); - } -}); - -server.get('/endpoints/:id/photo', function(req, res, next){ - req.url = '/photos/'+req.params.id+'.jpg'; - photoStaticHandler(req, res, next); -}); - -function isStormIntegrationEnabled(){ - return config.stormUsername && config.stormUsername.length && config.stormPassword && config.stormPassword.length; -} \ No newline at end of file diff --git a/routes/endpoints.mjs b/routes/endpoints.mjs new file mode 100644 index 0000000..75c2495 --- /dev/null +++ b/routes/endpoints.mjs @@ -0,0 +1,71 @@ +import config from '../config.mjs'; +import cache_manager from 'cache-manager'; +import express from 'express'; +import request from 'request'; +import server from '../lib/server.mjs'; + +const photoStaticHandler = express.static('./data', { maxAge: 4*60*60*1000 }); +const memory_cache = cache_manager.caching({ + store: 'memory', + max: 100, + ttl: 5 //seconds +}); + +const stormRequestOptions = { + auth: { + username: config.stormUsername, + password: config.stormPassword, + sendImmediately: true + }, + json: true, + // proxy: 'http://10.4.5.181:9998', + // strictSSL: false, + timeout: 3000 +}; + +server.get('/endpoints', (req, res, next) => { + const url = `${config.stormApiRoot}endpoints`; + // console.log("request to storm ("+url+")..."); + if(isStormIntegrationEnabled){ + request(url, stormRequestOptions, (err, stormResponse, body) => { + // console.log("response from storm", stormResponse); + if(err == null){ + res.json(body); + } else { + console.warn("failed to get endpoints from Storm", err); + res.json(500, err); + } + }); + } else { + res.json([]); + } +}); + +server.get('/endpoints/status', (req, res, next) => { + if(isStormIntegrationEnabled()){ + memory_cache.wrap('bjn-endpoints', cacheResult => { + console.log("Requesting endpoint status from Storm..."); + request(`${config.stormApiRoot}endpoints/status`, stormRequestOptions, (err, res, body) => { + cacheResult(err, body); + }); + }, (err, result) => { + if(err == null){ + res.json(result); + } else { + console.warn("failed to get endpoint status from Storm", err); + res.json(500, err); + } + }); + } else { + res.json([]); + } +}); + +server.get('/endpoints/:id/photo', (req, res, next) => { + req.url = `/photos/${req.params.id}.jpg`; + photoStaticHandler(req, res, next); +}); + +function isStormIntegrationEnabled(){ + return config.stormUsername && config.stormUsername.length && config.stormPassword && config.stormPassword.length; +} \ No newline at end of file diff --git a/routes/floorplan.js b/routes/floorplan.js deleted file mode 100644 index 3bceb0a..0000000 --- a/routes/floorplan.js +++ /dev/null @@ -1,61 +0,0 @@ -var _ = require('lodash'); -var config = require('../config'); -var fs = require('fs'); -var path = require('path'); -var personRepository = require('../lib/personRepository'); -var Q = require('q'); -var server = require('../lib/server'); - -var MAPS_PATH = path.join(server.get('views'), 'maps'); -var OFFICE_IDS; -var OFFICE_NAMES = { - mv: "Mountain View", - sf: "San Francisco", - oc: "Orange County", - blr: "Bangalore", - ln: "London", - chi: "Chicago", - aus: "Australia", - nz: "New Zealand", - remote: "remote workers" -}; -OFFICE_NAMES.mv2 = OFFICE_NAMES.mv; -OFFICE_NAMES.mv3 = OFFICE_NAMES.mv; - -fs.readdir(MAPS_PATH, function(err, files){ - if (err) throw err; - OFFICE_IDS = files.map(function(filename){ - return path.basename(filename, '.svg'); - }); -}); - -var renderFloorplan = function(req, res, next){ - var officeId = req.params.office || "mv"; - - if(_.contains(OFFICE_IDS, officeId)) { - - var svgPath = path.join(MAPS_PATH, officeId+'.svg'); - var svgReadPromise = Q.nfcall(fs.readFile, svgPath); - - Q.all([ - svgReadPromise - ]).spread(function(svg){ - var context = { - officeId: officeId, - officeName: OFFICE_NAMES[officeId], - svg: svg, - config: JSON.stringify(_.pick(config, ['mountPoint', 'stormApiRoot'])) - }; - res.render('floorplan', context); - }).fail(next); - - } else { - next(); - } -}; - -server.get('/:office', renderFloorplan); - -server.get('/', function(req, res){ - res.redirect('mv'); -}); diff --git a/routes/floorplan.mjs b/routes/floorplan.mjs new file mode 100644 index 0000000..fe726aa --- /dev/null +++ b/routes/floorplan.mjs @@ -0,0 +1,59 @@ +import pick from 'lodash-es'; +import fs from 'fs'; +import path from 'path'; +import * as personRepository from '../lib/personRepository.mjs'; +import Q from 'q'; +import server from '../lib/server.mjs'; +import config from '../config.mjs'; + +const MAPS_PATH = path.join(server.get('views'), 'maps'); +let OFFICE_IDS; +const OFFICE_NAMES = { + mv: "Mountain View", + sf: "San Francisco", + oc: "Orange County", + blr: "Bangalore", + ln: "London", + chi: "Chicago", + aus: "Australia", + nz: "New Zealand", + remote: "remote workers" +}; +OFFICE_NAMES.mv2 = OFFICE_NAMES.mv; +OFFICE_NAMES.mv3 = OFFICE_NAMES.mv; + +fs.readdir(MAPS_PATH, (err, files) => { + if (err) throw err; + OFFICE_IDS = files.map(filename => path.basename(filename, '.svg')); +}); + +const renderFloorplan = function(req, res, next){ + const officeId = req.params.office || "mv"; + + if(contains(OFFICE_IDS, officeId)) { + + const svgPath = path.join(MAPS_PATH, `${officeId}.svg`); + const svgReadPromise = Q.nfcall(fs.readFile, svgPath); + + Q.all([ + svgReadPromise + ]).spread(svg => { + const context = { + officeId, + officeName: OFFICE_NAMES[officeId], + svg, + config: JSON.stringify(pick(config, ['mountPoint', 'stormApiRoot'])) + }; + res.render('floorplan', context); + }).fail(next); + + } else { + next(); + } +}; + +server.get('/:office', renderFloorplan); + +server.get('/', (req, res) => { + res.redirect('mv'); +}); diff --git a/routes/index.js b/routes/index.js deleted file mode 100644 index 0c3a047..0000000 --- a/routes/index.js +++ /dev/null @@ -1,4 +0,0 @@ -require('./admin'); -require('./people'); -require('./endpoints'); -require('./floorplan'); \ No newline at end of file diff --git a/routes/index.mjs b/routes/index.mjs new file mode 100644 index 0000000..d258e5b --- /dev/null +++ b/routes/index.mjs @@ -0,0 +1,4 @@ +import './admin.mjs'; +import './people.mjs'; +import './endpoints.mjs'; +import './floorplan.mjs'; \ No newline at end of file diff --git a/routes/people.js b/routes/people.js deleted file mode 100644 index cc73ee4..0000000 --- a/routes/people.js +++ /dev/null @@ -1,105 +0,0 @@ -var _ = require('lodash'); -var config = require('../config'); -var express = require('express'); -var path = require('path'); -var personRepository = require('../lib/personRepository'); -var photoManager = require('../lib/photoManager'); -var Q = require('q'); -var server = require('../lib/server'); -var url = require('url'); -var verror = require('verror'); - -var FIELD_WRITE_WHITELIST = ['fullname', 'desk', 'office', 'email', 'title', 'tags', 'linkedInId', 'mobilePhone', 'workPhone']; - -var photoStaticHandler = express.static('./data', { maxAge: 4*60*60*1000 }); - -server.get('/people', function(req, res, next){ - personRepository.find(req.query) - .then(res.send.bind(res)) - .fail(next); -}); - -server.get('/people/:id', function(req, res, next){ - personRepository.findOne(req.params.id) - .then(function(result){ - if(!result){ - res.send(404, "No one has id "+req.params.id+'.'); - } else { - res.send(result); - } - }) - .fail(next); -}); - -server.post('/people', function(req, res, next){ - var sanitizedBody = _.pick(req.body, FIELD_WRITE_WHITELIST); - personRepository.save(sanitizedBody) - .then(res.send.bind(res)) - .fail(next); -}); - -server.put('/people/:id', function(req, res, next){ - var sanitizedBody = _.pick(req.body, FIELD_WRITE_WHITELIST); - sanitizedBody._id = req.params.id; - personRepository.save(sanitizedBody) - .then(res.send.bind(res)) - .fail(next); -}); - -server.delete('/people/:id', function(req, res, next){ - personRepository.remove(req.params.id) - .then(function(numRemoved){ - res.send(204); - }) - .fail(next); -}); - -server.get(/^\/people\/(\w+)\/photo(?:\.jpg)?$/, function(req, res, next){ - var id = req.params[0]; - req.url = '/photos/'+id+'.jpg'; - photoStaticHandler(req, res, next); -}); - -server.post('/people/:id/photo', function(req, res, next){ - var uploadedFile = req.files.photo; - var tempPath = uploadedFile.path; - var personId = req.params.id; - - return photoManager.importPhoto(tempPath, personId + '.jpg') - .then(function(imgInfo){ - var basename = path.basename(imgInfo.path); - - var imageUrl = url.format({ - protocol : req.protocol, - host : req.get('host'), - pathname : config.mountPoint + '/people/' + personId + '/photo' - }); - - var payload = { files: [{ - name : basename, - url : imageUrl, - thumbnailUrl : imageUrl, - // size : imgInfo.size - }]}; - - /** - * Browsers that upload using iframes require text/html or text/plain, - * because application/json will create a download dialog. - * - * @see https://github.com/blueimp/jQuery-File-Upload/wiki/Setup#content-type-negotiation - */ - res.format({ - json: function(){ - res.send(payload); - }, - default: function(){ - res.send(JSON.stringify(payload)); - } - }); - }) - .fail(function(err){ - res.type('text'); - res.send(400, err.stack || err.message || err); - }) - .fail(next); -}); \ No newline at end of file diff --git a/routes/people.mjs b/routes/people.mjs new file mode 100644 index 0000000..7d6f9b9 --- /dev/null +++ b/routes/people.mjs @@ -0,0 +1,103 @@ +import config from '../config.mjs'; +import pick from 'lodash-es'; +import express from 'express'; +import path from 'path'; +import * as personRepository from '../lib/personRepository.mjs'; +import * as photoManager from '../lib/photoManager.mjs'; +import server from '../lib/server.mjs'; +import url from 'url'; + +const FIELD_WRITE_WHITELIST = ['fullname', 'desk', 'office', 'email', 'title', 'tags', 'linkedInId', 'mobilePhone', 'workPhone']; + +const photoStaticHandler = express.static('./data', { maxAge: 4*60*60*1000 }); + +server.get('/people', (req, res, next) => { + personRepository.find(req.query) + .then(res.send.bind(res)) + .fail(next); +}); + +server.get('/people/:id', (req, res, next) => { + personRepository.findOne(req.params.id) + .then(result => { + if(result){ + res.send(result); + } else { + res.send(404, `No one has id ${req.params.id}.`); + } + }) + .fail(next); +}); + +server.post('/people', (req, res, next) => { + const sanitizedBody = pick(req.body, FIELD_WRITE_WHITELIST); + personRepository.save(sanitizedBody) + .then(res.send.bind(res)) + .fail(next); +}); + +server.put('/people/:id', (req, res, next) => { + const sanitizedBody = pick(req.body, FIELD_WRITE_WHITELIST); + sanitizedBody._id = req.params.id; + personRepository.save(sanitizedBody) + .then(res.send.bind(res)) + .fail(next); +}); + +server.delete('/people/:id', (req, res, next) => { + personRepository.remove(req.params.id) + .then(numRemoved => { + res.send(204); + }) + .fail(next); +}); + +server.get(/^\/people\/(\w+)\/photo(?:\.jpg)?$/, (req, res, next) => { + const id = req.params[0]; + req.url = `/photos/${id}.jpg`; + photoStaticHandler(req, res, next); +}); + +server.post('/people/:id/photo', (req, res, next) => { + const uploadedFile = req.files.photo; + const tempPath = uploadedFile.path; + const personId = req.params.id; + + return photoManager.importPhoto(tempPath, `${personId}.jpg`) + .then(imgInfo => { + const basename = path.basename(imgInfo.path); + + const imageUrl = url.format({ + protocol : req.protocol, + host : req.get('host'), + pathname : `${config.mountPoint}/people/${personId}/photo` + }); + + const payload = { files: [{ + name : basename, + url : imageUrl, + thumbnailUrl : imageUrl, + // size : imgInfo.size + }]}; + + /** + * Browsers that upload using iframes require text/html or text/plain, + * because application/json will create a download dialog. + * + * @see https://github.com/blueimp/jQuery-File-Upload/wiki/Setup#content-type-negotiation + */ + res.format({ + json() { + res.send(payload); + }, + default() { + res.send(JSON.stringify(payload)); + } + }); + }) + .fail(err => { + res.type('text'); + res.send(400, err.stack || err.message || err); + }) + .fail(next); +}); \ No newline at end of file diff --git a/routes/user.js b/routes/user.mjs similarity index 64% rename from routes/user.js rename to routes/user.mjs index d5b34aa..97c3b4d 100644 --- a/routes/user.js +++ b/routes/user.mjs @@ -3,6 +3,6 @@ * GET users listing. */ -exports.list = function(req, res){ +export const list = function(req, res){ res.send("respond with a resource"); }; \ No newline at end of file