From 101952a457c6c3c010c24f346c9a506aa80d89bf Mon Sep 17 00:00:00 2001 From: "Glitch (fcc-metric-imperial)" Date: Thu, 10 Jan 2019 02:15:41 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=8E=AA=F0=9F=99=85=20Updated=20with=20Gli?= =?UTF-8?q?tch?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitconfig | 2 + .hyperdev-assets | 5 + README.md | 10 +- assertion-analyser.js | 131 +++ controllers/convertHandler.js | 162 ++++ package.json | 36 + public/style.css | 0 routes/api.js | 42 + routes/fcctesting.js | 103 +++ server.js | 61 ++ shrinkwrap.yaml | 1476 +++++++++++++++++++++++++++++++++ test-runner.js | 106 +++ tests/1_unit-tests.js | 145 ++++ tests/2_functional-tests.js | 84 ++ views/index.html | 76 ++ 15 files changed, 2438 insertions(+), 1 deletion(-) create mode 100644 .gitconfig create mode 100644 .hyperdev-assets create mode 100644 assertion-analyser.js create mode 100644 controllers/convertHandler.js create mode 100644 package.json create mode 100644 public/style.css create mode 100644 routes/api.js create mode 100644 routes/fcctesting.js create mode 100644 server.js create mode 100644 shrinkwrap.yaml create mode 100644 test-runner.js create mode 100644 tests/1_unit-tests.js create mode 100644 tests/2_functional-tests.js create mode 100644 views/index.html diff --git a/.gitconfig b/.gitconfig new file mode 100644 index 0000000..07b56d1 --- /dev/null +++ b/.gitconfig @@ -0,0 +1,2 @@ +[core] + excludesfile = /etc/.gitignore-global diff --git a/.hyperdev-assets b/.hyperdev-assets new file mode 100644 index 0000000..4d4c4f5 --- /dev/null +++ b/.hyperdev-assets @@ -0,0 +1,5 @@ +{"name":"drag-in-files.svg","date":"2016-10-22T16:17:49.954Z","url":"https://cdn.hyperdev.com/drag-in-files.svg","type":"image/svg","size":7646,"imageWidth":276,"imageHeight":276,"thumbnail":"https://cdn.hyperdev.com/drag-in-files.svg","thumbnailWidth":276,"thumbnailHeight":276,"dominantColor":"rgb(102, 153, 205)","uuid":"adSBq97hhhpFNUna"} +{"name":"click-me.svg","date":"2016-10-23T16:17:49.954Z","url":"https://cdn.hyperdev.com/click-me.svg","type":"image/svg","size":7116,"imageWidth":276,"imageHeight":276,"thumbnail":"https://cdn.hyperdev.com/click-me.svg","thumbnailWidth":276,"thumbnailHeight":276,"dominantColor":"rgb(243, 185, 186)","uuid":"adSBq97hhhpFNUnb"} +{"name":"paste-me.svg","date":"2016-10-24T16:17:49.954Z","url":"https://cdn.hyperdev.com/paste-me.svg","type":"image/svg","size":7242,"imageWidth":276,"imageHeight":276,"thumbnail":"https://cdn.hyperdev.com/paste-me.svg","thumbnailWidth":276,"thumbnailHeight":276,"dominantColor":"rgb(42, 179, 185)","uuid":"adSBq97hhhpFNUnc"} +{"name":"Screen Shot 2016-12-16 at 1.35.56 AM.png","date":"2016-12-16T06:36:32.934Z","url":"https://cdn.gomix.com/d7932c52-287f-4dae-b175-631fef453000%2FScreen%20Shot%202016-12-16%20at%201.35.56%20AM.png","type":"image/png","size":18223,"imageWidth":499,"imageHeight":80,"thumbnail":"https://cdn.gomix.com/d7932c52-287f-4dae-b175-631fef453000%2Fthumbnails%2FScreen%20Shot%202016-12-16%20at%201.35.56%20AM.png","thumbnailWidth":330,"thumbnailHeight":53,"dominantColor":"rgb(236,236,236)","uuid":"IHJDL7lzupnoDep4"} +{"uuid":"IHJDL7lzupnoDep4","deleted":true} diff --git a/README.md b/README.md index 5372602..5eed063 100644 --- a/README.md +++ b/README.md @@ -1 +1,9 @@ -A metric <-> imperial converter for a freeCodeCamp assignment: https://learn.freecodecamp.org/information-security-and-quality-assurance/information-security-and-quality-assurance-projects/metric-imperial-converter +**FreeCodeCamp**- Information Security and Quality Assurance +------ + +1) SET NODE_ENV to `test` without quotes +2) Most logic will need done in `controllers/convertHandler.js` but do complete `routes/api.js` +3) You will add any security features to `server.js` +4) You will create all of the functional/unit tests in `tests/2_functional-tests.js` and `tests/1_unit-tests.js` + + diff --git a/assertion-analyser.js b/assertion-analyser.js new file mode 100644 index 0000000..dd5682b --- /dev/null +++ b/assertion-analyser.js @@ -0,0 +1,131 @@ +/* +* +* +* +* +* +* +* +* +* +* +* +* DO NOT EDIT THIS FILE +* For FCC testing purposes! +* +* +* +* +* +* +* +* +* +* +* +*/ + +function objParser(str, init) { + // finds objects, arrays, strings, and function arguments + // between parens, because they may contain ',' + var openSym = ['[', '{', '"', "'", '(']; + var closeSym = [']', '}', '"', "'", ')']; + var type; + for(var i = (init || 0); i < str.length; i++ ) { + type = openSym.indexOf(str[i]); + if( type !== -1) break; + } + if (type === -1) return null; + var open = openSym[type]; + var close = closeSym[type]; + var count = 1; + for(var k = i+1; k < str.length; k++) { + if(open === '"' || open === "'") { + if(str[k] === close) count--; + if(str[k] === '\\') k++; + } else { + if(str[k] === open) count++; + if(str[k] === close) count--; + } + if(count === 0) break; + } + if(count !== 0) return null; + var obj = str.slice(i, k+1); + return { + start : i, + end: k, + obj: obj + }; +} + +function replacer(str) { + // replace objects with a symbol ( __#n) + var obj; + var cnt = 0; + var data = []; + while(obj = objParser(str)) { + data[cnt] = obj.obj; + str = str.substring(0, obj.start) + '__#' + cnt++ + str.substring(obj.end+1) + } + return { + str : str, + dictionary : data + } +} + +function splitter(str) { + // split on commas, then restore the objects + var strObj = replacer(str); + var args = strObj.str.split(','); + args = args.map(function(a){ + var m = a.match(/__#(\d+)/); + while (m) { + a = a.replace(/__#(\d+)/, strObj.dictionary[m[1]]); + m = a.match(/__#(\d+)/); + } + return a.trim(); + }) + return args; +} + +function assertionAnalyser(body) { + + // already filtered in the test runner + // // remove comments + // body = body.replace(/\/\/.*\n|\/\*.*\*\//g, ''); + // // get test function body + // body = body.match(/\{\s*([\s\S]*)\}\s*$/)[1]; + + if(!body) return "invalid assertion"; + // replace assertions bodies, so that they cannot + // contain the word 'assertion' + + var body = body.match(/(?:browser\s*\.\s*)?assert\s*\.\s*\w*\([\s\S]*\)/)[0]; + var s = replacer(body); + // split on 'assertion' + var splittedAssertions = s.str.split('assert'); + var assertions = splittedAssertions.slice(1); + // match the METHODS + + var assertionBodies = []; + var methods = assertions.map(function(a, i){ + var m = a.match(/^\s*\.\s*(\w+)__#(\d+)/); + assertionBodies.push(parseInt(m[2])); + var pre = splittedAssertions[i].match(/browser\s*\.\s*/) ? 'browser.' : ''; + return pre + m[1]; + }); + if(methods.some(function(m){ return !m })) return "invalid assertion"; + // remove parens from the assertions bodies + var bodies = assertionBodies.map(function(b){ + return s.dictionary[b].slice(1,-1).trim(); + }); + assertions = methods.map(function(m, i) { + return { + method: m, + args: splitter(bodies[i]) //replace objects, split on ',' ,then restore objects + } + }) + return assertions; +} + +module.exports = assertionAnalyser; diff --git a/controllers/convertHandler.js b/controllers/convertHandler.js new file mode 100644 index 0000000..922b1af --- /dev/null +++ b/controllers/convertHandler.js @@ -0,0 +1,162 @@ +/* +* +* +* Complete the handler logic below +* +* +*/ + +function ConvertHandler() { + + this.getNum = function(input) { + // const numberRegex = /([0-9\/\.]*)(lbs?|kgs?|gals?|Ls?|mis?|kms?)*$/ + // const numberRegex = /([0-9\/\.]*)(.*)$/ + // const numberRegex = /([0-9\/\.]*)([A-Za-z]*)$/ + const numberRegex = /^([0-9\.]+\/?[0-9\.]+|[0-9\.]*)([A-Za-z]*)$/ + + const numberMatch = input.match(numberRegex) + + // console.log('this is numberMatch: ', numberMatch) + + if (input.match(/^(lbs?|kgs?|gals?|Ls?|mis?|kms?)*$/)) { + return 1 + } + + if (!numberMatch) { + return undefined + } + + return eval(numberMatch[1]); + }; + + this.getUnit = function(input) { + const unitRegex = /(lbs?|kgs?|gals?|Ls?|mis?|kms?)*$/i + const unitMatch = input.match(unitRegex) + + // console.log('this is unitMatch: ', unitMatch) + + if (!unitMatch || !unitMatch[0]) { + return undefined + } + + return unitMatch[0]; + }; + + this.stripPlural = function(initUnit) { + if (initUnit.substr(initUnit.length - 1, 1) === 's') { + return initUnit.substring(0, initUnit.length - 1) + } + + return initUnit + } + + this.getReturnUnit = function(initUnit) { + initUnit = this.stripPlural(initUnit).toLowerCase() + + switch(initUnit) { + case "lb": + return "kg"; + break; + + case "kg": + return "lbs"; + break; + + case "gal": + return "l"; + break; + + case "l": + return "gal"; + break; + + case "mi": + return "km"; + break; + + case "km": + return "mi"; + break; + + default: + return undefined + } + }; + + this.spellOutUnit = function(unit) { + unit = this.stripPlural(unit).toLowerCase() + + switch(unit) { + case "lb": + return "pound(s)"; + break; + + case "kg": + return "kilogram(s)"; + break; + + case "gal": + return "gallon(s)"; + break; + + case "l": + return "liter(s)"; + break; + + case "mi": + return "mile(s)"; + break; + + case "km": + return "kilometer(s)"; + break; + + default: + return undefined + } + }; + + this.convert = function(initNum, initUnit) { + const galToL = 3.78541; // 1 gal is 3.78 L + const lbsToKg = 0.453592; // 1 lb is .45 kilos + const miToKm = 1.60934; // 1 mi is 1.6 km + + initUnit = this.stripPlural(initUnit) + + switch (initUnit) { + case "lb": + return parseFloat((initNum * lbsToKg).toFixed(5)); + break; + + case "kg": + return parseFloat((initNum / lbsToKg).toFixed(5)); + break; + + case "gal": + return parseFloat((initNum * galToL).toFixed(5)); + break; + + case "L": + return parseFloat((initNum / galToL).toFixed(5)); + break; + + case "mi": + return parseFloat((initNum * miToKm).toFixed(5)); + break; + + case "km": + return parseFloat((initNum / miToKm).toFixed(5)); + break; + + default: + return undefined + } + }; + + this.getString = function(initNum, initUnit, returnNum, returnUnit) { + return initNum + ' ' + this.spellOutUnit(initUnit) + ' converts to ' + returnNum + ' ' + this.spellOutUnit(returnUnit) + }; + +} + +module.exports = ConvertHandler; diff --git a/package.json b/package.json new file mode 100644 index 0000000..c6c1cf8 --- /dev/null +++ b/package.json @@ -0,0 +1,36 @@ +{ + "//1": "describes your app and its dependencies", + "//2": "https://docs.npmjs.com/files/package.json", + "//3": "updating this file will download and update your packages", + "name": "my-hyperdev-app", + "version": "0.0.1", + "description": "What am I about?", + "main": "server.js", + "scripts": { + "start": "node server.js" + }, + "dependencies": { + "express": "^4.14.0", + "cors": "^2.8.1", + "body-parser": "^1.15.2", + "chai": "^3.5.0", + "mongodb": "^2.2.16", + "chai-http": "^3.0.0", + "mocha": "^3.2.0", + "zombie": "^5.0.5", + "helmet": "^3.1.0" + }, + "engines": { + "node": "4.4.3" + }, + "repository": { + "type": "git", + "url": "https://hyperdev.com/#!/project/welcome-project" + }, + "keywords": [ + "node", + "hyperdev", + "express" + ], + "license": "MIT" +} \ No newline at end of file diff --git a/public/style.css b/public/style.css new file mode 100644 index 0000000..e69de29 diff --git a/routes/api.js b/routes/api.js new file mode 100644 index 0000000..3d32062 --- /dev/null +++ b/routes/api.js @@ -0,0 +1,42 @@ +/* +* +* +* Complete the API routing below +* +* +*/ + +'use strict'; + +var expect = require('chai').expect; +var ConvertHandler = require('../controllers/convertHandler.js'); + +module.exports = function (app) { + + var convertHandler = new ConvertHandler(); + + app.route('/api/convert') + .get(function (req, res){ + var input = req.query.input; + var initNum = convertHandler.getNum(input); + var initUnit = convertHandler.getUnit(input); + + // console.log('initNum: ', initNum) + // console.log('initUnit: ', initUnit) + + if (!initNum && !initUnit) { + res.send('invalid number and unit') + } else if (!initNum) { + res.send('invalid number.') + } else if (!initUnit) { + res.send('invalid unit.') + } else { + var returnNum = convertHandler.convert(initNum, initUnit); + var returnUnit = convertHandler.getReturnUnit(initUnit); + var toString = convertHandler.getString(initNum, initUnit, returnNum, returnUnit); + + res.json({ input, initNum, initUnit, returnNum, returnUnit, string: toString }) + } + }); + +}; diff --git a/routes/fcctesting.js b/routes/fcctesting.js new file mode 100644 index 0000000..f1af277 --- /dev/null +++ b/routes/fcctesting.js @@ -0,0 +1,103 @@ +/* +* +* +* +* +* +* +* +* +* +* +* +* DO NOT EDIT THIS FILE +* For FCC testing purposes! +* +* +* +* +* +* +* +* +* +* +* +*/ + +'use strict'; + +var cors = require('cors'); +var fs = require('fs'); +var runner = require('../test-runner'); + +module.exports = function (app) { + + app.route('/_api/server.js') + .get(function(req, res, next) { + console.log('requested'); + fs.readFile(__dirname + '/server.js', function(err, data) { + if(err) return next(err); + res.send(data.toString()); + }); + }); + app.route('/_api/routes/api.js') + .get(function(req, res, next) { + console.log('requested'); + fs.readFile(__dirname + '/routes/api.js', function(err, data) { + if(err) return next(err); + res.type('txt').send(data.toString()); + }); + }); + app.route('/_api/controllers/convertHandler.js') + .get(function(req, res, next) { + console.log('requested'); + fs.readFile(__dirname + '/controllers/convertHandler.js', function(err, data) { + if(err) return next(err); + res.type('txt').send(data.toString()); + }); + }); + + var error; + app.get('/_api/get-tests', cors(), function(req, res, next){ + console.log(error); + if(!error && process.env.NODE_ENV === 'test') return next(); + res.json({status: 'unavailable'}); + }, + function(req, res, next){ + if(!runner.report) return next(); + res.json(testFilter(runner.report, req.query.type, req.query.n)); + }, + function(req, res){ + runner.on('done', function(report){ + process.nextTick(() => res.json(testFilter(runner.report, req.query.type, req.query.n))); + }); + }); + app.get('/_api/app-info', function(req, res) { + var hs = Object.keys(res._headers) + .filter(h => !h.match(/^access-control-\w+/)); + var hObj = {}; + hs.forEach(h => {hObj[h] = res._headers[h]}); + delete res._headers['strict-transport-security']; + res.json({headers: hObj}); + }); + +}; + +function testFilter(tests, type, n) { + var out; + switch (type) { + case 'unit' : + out = tests.filter(t => t.context.match('Unit Tests')); + break; + case 'functional': + out = tests.filter(t => t.context.match('Functional Tests') && !t.title.match('#example')); + break; + default: + out = tests; + } + if(n !== undefined) { + return out[n] || out; + } + return out; +} \ No newline at end of file diff --git a/server.js b/server.js new file mode 100644 index 0000000..51b92f7 --- /dev/null +++ b/server.js @@ -0,0 +1,61 @@ +'use strict'; + +var express = require('express'); +var bodyParser = require('body-parser'); +var expect = require('chai').expect; +var cors = require('cors'); +var helmet = require('helmet'); + +var apiRoutes = require('./routes/api.js'); +var fccTestingRoutes = require('./routes/fcctesting.js'); +var runner = require('./test-runner'); + +var app = express(); + +app.use('/public', express.static(process.cwd() + '/public')); + +app.use(cors({origin: '*'})); //For FCC testing purposes only + +app.use(helmet.xssFilter()) +app.use(helmet.noSniff()) + +app.use(bodyParser.json()); +app.use(bodyParser.urlencoded({ extended: true })); + +//Index page (static HTML) +app.route('/') + .get(function (req, res) { + res.sendFile(process.cwd() + '/views/index.html'); + }); + +//For FCC testing purposes +fccTestingRoutes(app); + +//Routing for API +apiRoutes(app); + +//404 Not Found Middleware +app.use(function(req, res, next) { + res.status(404) + .type('text') + .send('Not Found') +}); + +//Start our server and tests! +app.listen(process.env.PORT || 3000, function () { + console.log("Listening on port " + process.env.PORT); + if(process.env.NODE_ENV==='test') { + console.log('Running Tests...'); + setTimeout(function () { + try { + runner.run(); + } catch(e) { + var error = e; + console.log('Tests are not valid:'); + console.log(error); + } + }, 1500); + } +}); + +module.exports = app; //for testing diff --git a/shrinkwrap.yaml b/shrinkwrap.yaml new file mode 100644 index 0000000..f46b89f --- /dev/null +++ b/shrinkwrap.yaml @@ -0,0 +1,1476 @@ +dependencies: + body-parser: 1.18.3 + chai: 3.5.0 + chai-http: 3.0.0 + cors: 2.8.5 + express: 4.16.4 + helmet: 3.15.0 + mocha: 3.5.3 + mongodb: 2.2.36 + zombie: 5.0.8 +packages: + /abab/1.0.4: + dev: false + resolution: + integrity: sha1-X6rZwsB/YN12dw9xzwJbYqY8/U4= + /accepts/1.3.5: + dependencies: + mime-types: 2.1.21 + negotiator: 0.6.1 + dev: false + engines: + node: '>= 0.6' + resolution: + integrity: sha1-63d99gEXI6OxTopywIBcjoZ0a9I= + /acorn-globals/1.0.9: + dependencies: + acorn: 2.7.0 + dev: false + resolution: + integrity: sha1-VbtemGkVB7dFedBRNBMhfDgMVM8= + /acorn/2.7.0: + dev: false + engines: + node: '>=0.4.0' + hasBin: true + resolution: + integrity: sha1-q259nYhqrKiwhbwzEreaGYQz8Oc= + /ajv/6.6.2: + dependencies: + fast-deep-equal: 2.0.1 + fast-json-stable-stringify: 2.0.0 + json-schema-traverse: 0.4.1 + uri-js: 4.2.2 + dev: false + resolution: + integrity: sha512-FBHEW6Jf5TB9MGBgUUA9XHkTbjXYfAUjY43ACMfmdMRHniyoMHjHjzD50OK8LGDWQwp4rWEsIq5kEqq7rvIM1g== + /array-flatten/1.1.1: + dev: false + resolution: + integrity: sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= + /asn1/0.2.4: + dependencies: + safer-buffer: 2.1.2 + dev: false + resolution: + integrity: sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg== + /assert-plus/1.0.0: + dev: false + engines: + node: '>=0.8' + resolution: + integrity: sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= + /assertion-error/1.1.0: + dev: false + resolution: + integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== + /async/1.5.2: + dev: false + resolution: + integrity: sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo= + /asynckit/0.4.0: + dev: false + resolution: + integrity: sha1-x57Zf380y48robyXkLzDZkdLS3k= + /aws-sign2/0.7.0: + dev: false + resolution: + integrity: sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= + /aws4/1.8.0: + dev: false + resolution: + integrity: sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ== + /babel-runtime/5.8.29: + dependencies: + core-js: 1.2.7 + dev: false + resolution: + integrity: sha1-SiBSy8/1MXiNOp1rA81/RIKF+CU= + /balanced-match/1.0.0: + dev: false + resolution: + integrity: sha1-ibTRmasr7kneFk6gK4nORi1xt2c= + /bcrypt-pbkdf/1.0.2: + dependencies: + tweetnacl: 0.14.5 + dev: false + resolution: + integrity: sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= + /bluebird/3.5.3: + dev: false + resolution: + integrity: sha512-/qKPUQlaW1OyR51WeCPBvRnAlnZFUJkCSG5HzGnuIqhgyJtF+T94lFnn33eiazjRm2LAHVy2guNnaq48X9SJuw== + /body-parser/1.18.3: + dependencies: + bytes: 3.0.0 + content-type: 1.0.4 + debug: 2.6.9 + depd: 1.1.2 + http-errors: 1.6.3 + iconv-lite: 0.4.23 + on-finished: 2.3.0 + qs: 6.5.2 + raw-body: 2.3.3 + type-is: 1.6.16 + dev: false + engines: + node: '>= 0.8' + resolution: + integrity: sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ= + /brace-expansion/1.1.11: + dependencies: + balanced-match: 1.0.0 + concat-map: 0.0.1 + dev: false + resolution: + integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + /browser-stdout/1.3.0: + dev: false + resolution: + integrity: sha1-81HTKWnTL6XXpVZxVCY9korjvR8= + /bson/1.0.9: + dev: false + engines: + node: '>=0.6.19' + resolution: + integrity: sha512-IQX9/h7WdMBIW/q/++tGd+emQr0XMdeZ6icnT/74Xk9fnabWn+gZgpE+9V+gujL3hhJOoNrnDVY7tWdzc7NUTg== + /buffer-shims/1.0.0: + dev: false + resolution: + integrity: sha1-mXjOMXOIxkmth5MCjDR37wRKi1E= + /bytes/3.0.0: + dev: false + engines: + node: '>= 0.8' + resolution: + integrity: sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg= + /camelize/1.0.0: + dev: false + resolution: + integrity: sha1-FkpUg+Yw+kMh5a8HAg5TGDGyYJs= + /caseless/0.12.0: + dev: false + resolution: + integrity: sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= + /chai-http/3.0.0: + dependencies: + cookiejar: 2.0.6 + is-ip: 1.0.0 + methods: 1.1.2 + qs: 6.6.0 + superagent: 2.3.0 + dev: false + engines: + node: '>= 0.6.0' + resolution: + integrity: sha1-VGDYA24fGhKwtbXL1Snm3B0x60s= + /chai/3.5.0: + dependencies: + assertion-error: 1.1.0 + deep-eql: 0.1.3 + type-detect: 1.0.0 + dev: false + engines: + node: '>= 0.4.0' + resolution: + integrity: sha1-TQJjewZ/6Vi9v906QOxW/vc3Mkc= + /combined-stream/1.0.7: + dependencies: + delayed-stream: 1.0.0 + dev: false + engines: + node: '>= 0.8' + resolution: + integrity: sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w== + /commander/2.9.0: + dependencies: + graceful-readlink: 1.0.1 + dev: false + engines: + node: '>= 0.6.x' + resolution: + integrity: sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q= + /component-emitter/1.2.1: + dev: false + resolution: + integrity: sha1-E3kY1teCg/ffemt8WmPhQOaUJeY= + /concat-map/0.0.1: + dev: false + resolution: + integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + /content-disposition/0.5.2: + dev: false + engines: + node: '>= 0.6' + resolution: + integrity: sha1-DPaLud318r55YcOoUXjLhdunjLQ= + /content-security-policy-builder/2.0.0: + dev: false + resolution: + integrity: sha512-j+Nhmj1yfZAikJLImCvPJFE29x/UuBi+/MWqggGGc515JKaZrjuei2RhULJmy0MsstW3E3htl002bwmBNMKr7w== + /content-type/1.0.4: + dev: false + engines: + node: '>= 0.6' + resolution: + integrity: sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== + /cookie-signature/1.0.6: + dev: false + resolution: + integrity: sha1-4wOogrNCzD7oylE6eZmXNNqzriw= + /cookie/0.3.1: + dev: false + engines: + node: '>= 0.6' + resolution: + integrity: sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s= + /cookiejar/2.0.6: + dev: false + resolution: + integrity: sha1-Cr81atANHFohnYjURRgEbdAmrP4= + /cookiejar/2.1.2: + dev: false + resolution: + integrity: sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA== + /core-js/1.2.7: + dev: false + resolution: + integrity: sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY= + /core-util-is/1.0.2: + dev: false + resolution: + integrity: sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= + /cors/2.8.5: + dependencies: + object-assign: 4.1.1 + vary: 1.1.2 + dev: false + engines: + node: '>= 0.10' + resolution: + integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g== + /cssom/0.3.4: + dev: false + resolution: + integrity: sha512-+7prCSORpXNeR4/fUP3rL+TzqtiFfhMvTd7uEqMdgPvLPt4+uzFUeufx5RHjGTACCargg/DiEt/moMQmvnfkog== + /cssstyle/0.2.37: + dependencies: + cssom: 0.3.4 + dev: false + resolution: + integrity: sha1-VBCXI0yyUTyDzu06zdwn/yeYfVQ= + /dashdash/1.14.1: + dependencies: + assert-plus: 1.0.0 + dev: false + engines: + node: '>=0.10' + resolution: + integrity: sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= + /dasherize/2.0.0: + dev: false + resolution: + integrity: sha1-bYCcnNDPe7iVLYD8hPoT1H3bEwg= + /debug/2.6.8: + dependencies: + ms: 2.0.0 + dev: false + resolution: + integrity: sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw= + /debug/2.6.9: + dependencies: + ms: 2.0.0 + dev: false + resolution: + integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + /deep-eql/0.1.3: + dependencies: + type-detect: 0.1.1 + dev: false + resolution: + integrity: sha1-71WKyrjeJSBs1xOQbXTlaTDrafI= + /deep-is/0.1.3: + dev: false + resolution: + integrity: sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= + /delayed-stream/1.0.0: + dev: false + engines: + node: '>=0.4.0' + resolution: + integrity: sha1-3zrhmayt+31ECqrgsp4icrJOxhk= + /depd/1.1.2: + dev: false + engines: + node: '>= 0.6' + resolution: + integrity: sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= + /destroy/1.0.4: + dev: false + resolution: + integrity: sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= + /diff/3.2.0: + dev: false + engines: + node: '>=0.3.1' + resolution: + integrity: sha1-yc45Okt8vQsFinJck98pkCeGj/k= + /dns-prefetch-control/0.1.0: + dev: false + resolution: + integrity: sha1-YN20V3dOF48flBXwyrsOhbCzALI= + /dont-sniff-mimetype/1.0.0: + dev: false + resolution: + integrity: sha1-WTKJDcn04vGeXrAqIAJuXl78j1g= + /ecc-jsbn/0.1.2: + dependencies: + jsbn: 0.1.1 + safer-buffer: 2.1.2 + dev: false + resolution: + integrity: sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= + /ee-first/1.1.1: + dev: false + resolution: + integrity: sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= + /encodeurl/1.0.2: + dev: false + engines: + node: '>= 0.8' + resolution: + integrity: sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= + /es6-promise/3.2.1: + dev: false + resolution: + integrity: sha1-7FYjOGgDKQkgcXDDlEjiREndH8Q= + /escape-html/1.0.3: + dev: false + resolution: + integrity: sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= + /escape-string-regexp/1.0.5: + dev: false + engines: + node: '>=0.8.0' + resolution: + integrity: sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= + /escodegen/1.11.0: + dependencies: + esprima: 3.1.3 + estraverse: 4.2.0 + esutils: 2.0.2 + optionator: 0.8.2 + dev: false + engines: + node: '>=4.0' + hasBin: true + optionalDependencies: + source-map: 0.6.1 + resolution: + integrity: sha512-IeMV45ReixHS53K/OmfKAIztN/igDHzTJUhZM3k1jMhIZWjk45SMwAtBsEXiJp3vSPmTcu6CXn7mDvFHRN66fw== + /esprima/3.1.3: + dev: false + engines: + node: '>=4' + hasBin: true + resolution: + integrity: sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM= + /estraverse/4.2.0: + dev: false + engines: + node: '>=0.10.0' + resolution: + integrity: sha1-De4/7TH81GlhjOc0IJn8GvoL2xM= + /esutils/2.0.2: + dev: false + engines: + node: '>=0.10.0' + resolution: + integrity: sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs= + /etag/1.8.1: + dev: false + engines: + node: '>= 0.6' + resolution: + integrity: sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= + /eventsource/0.1.6: + dependencies: + original: 1.0.2 + dev: false + engines: + node: '>=0.8.0' + resolution: + integrity: sha1-Cs7ehJ7X3RzMMsgRuxG5RNTykjI= + /expect-ct/0.1.1: + dev: false + resolution: + integrity: sha512-ngXzTfoRGG7fYens3/RMb6yYoVLvLMfmsSllP/mZPxNHgFq41TmPSLF/nLY7fwoclI2vElvAmILFWGUYqdjfCg== + /express/4.16.4: + dependencies: + accepts: 1.3.5 + array-flatten: 1.1.1 + body-parser: 1.18.3 + 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.2 + encodeurl: 1.0.2 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 1.1.1 + 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.4 + qs: 6.5.2 + range-parser: 1.2.0 + safe-buffer: 5.1.2 + send: 0.16.2 + serve-static: 1.13.2 + setprototypeof: 1.1.0 + statuses: 1.4.0 + type-is: 1.6.16 + utils-merge: 1.0.1 + vary: 1.1.2 + dev: false + engines: + node: '>= 0.10.0' + resolution: + integrity: sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg== + /extend/3.0.2: + dev: false + resolution: + integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== + /extsprintf/1.3.0: + dev: false + engines: + '0': node >=0.6.0 + resolution: + integrity: sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= + /extsprintf/1.4.0: + dev: false + engines: + '0': node >=0.6.0 + resolution: + integrity: sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= + /fast-deep-equal/2.0.1: + dev: false + resolution: + integrity: sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= + /fast-json-stable-stringify/2.0.0: + dev: false + resolution: + integrity: sha1-1RQsDK7msRifh9OnYREGT4bIu/I= + /fast-levenshtein/2.0.6: + dev: false + resolution: + integrity: sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= + /feature-policy/0.2.0: + dev: false + resolution: + integrity: sha512-2hGrlv6efG4hscYVZeaYjpzpT6I2OZgYqE2yDUzeAcKj2D1SH0AsEzqJNXzdoglEddcIXQQYop3lD97XpG75Jw== + /finalhandler/1.1.1: + dependencies: + debug: 2.6.9 + encodeurl: 1.0.2 + escape-html: 1.0.3 + on-finished: 2.3.0 + parseurl: 1.3.2 + statuses: 1.4.0 + unpipe: 1.0.0 + dev: false + engines: + node: '>= 0.8' + resolution: + integrity: sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg== + /forever-agent/0.6.1: + dev: false + resolution: + integrity: sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= + /form-data/1.0.0-rc4: + dependencies: + async: 1.5.2 + combined-stream: 1.0.7 + mime-types: 2.1.21 + dev: false + engines: + node: '>= 0.10' + resolution: + integrity: sha1-BaxrwiIntD5EYfSIFhVUaZ1Pi14= + /form-data/2.3.3: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.7 + mime-types: 2.1.21 + dev: false + engines: + node: '>= 0.12' + resolution: + integrity: sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== + /formidable/1.2.1: + dev: false + resolution: + integrity: sha512-Fs9VRguL0gqGHkXS5GQiMCr1VhZBxz0JnJs4JmMp/2jL18Fmbzvv7vOFRU+U8TBkHEE/CX1qDXzJplVULgsLeg== + /forwarded/0.1.2: + dev: false + engines: + node: '>= 0.6' + resolution: + integrity: sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ= + /frameguard/3.0.0: + dev: false + resolution: + integrity: sha1-e8rUae57lukdEs6zlZx4I1qScuk= + /fresh/0.5.2: + dev: false + engines: + node: '>= 0.6' + resolution: + integrity: sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= + /fs.realpath/1.0.0: + dev: false + resolution: + integrity: sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + /getpass/0.1.7: + dependencies: + assert-plus: 1.0.0 + dev: false + resolution: + integrity: sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= + /glob/7.1.1: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.3 + minimatch: 3.0.4 + once: 1.4.0 + path-is-absolute: 1.0.1 + dev: false + resolution: + integrity: sha1-gFIR3wT6rxxjo2ADBs31reULLsg= + /graceful-readlink/1.0.1: + dev: false + resolution: + integrity: sha1-TK+tdrxi8C+gObL5Tpo906ORpyU= + /growl/1.9.2: + dev: false + resolution: + integrity: sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8= + /har-schema/2.0.0: + dev: false + engines: + node: '>=4' + resolution: + integrity: sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= + /har-validator/5.1.3: + dependencies: + ajv: 6.6.2 + har-schema: 2.0.0 + dev: false + engines: + node: '>=6' + resolution: + integrity: sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g== + /has-flag/1.0.0: + dev: false + engines: + node: '>=0.10.0' + resolution: + integrity: sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo= + /he/1.1.1: + dev: false + hasBin: true + resolution: + integrity: sha1-k0EP0hsAlzUVH4howvJx80J+I/0= + /helmet-crossdomain/0.3.0: + dev: false + engines: + node: '>= 6' + resolution: + integrity: sha512-YiXhj0E35nC4Na5EPE4mTfoXMf9JTGpN4OtB4aLqShKuH9d2HNaJX5MQoglO6STVka0uMsHyG5lCut5Kzsy7Lg== + /helmet-csp/2.7.1: + dependencies: + camelize: 1.0.0 + content-security-policy-builder: 2.0.0 + dasherize: 2.0.0 + platform: 1.3.5 + dev: false + resolution: + integrity: sha512-sCHwywg4daQ2mY0YYwXSZRsgcCeerUwxMwNixGA7aMLkVmPTYBl7gJoZDHOZyXkqPrtuDT3s2B1A+RLI7WxSdQ== + /helmet/3.15.0: + dependencies: + dns-prefetch-control: 0.1.0 + dont-sniff-mimetype: 1.0.0 + expect-ct: 0.1.1 + feature-policy: 0.2.0 + frameguard: 3.0.0 + helmet-crossdomain: 0.3.0 + helmet-csp: 2.7.1 + hide-powered-by: 1.0.0 + hpkp: 2.0.0 + hsts: 2.1.0 + ienoopen: 1.0.0 + nocache: 2.0.0 + referrer-policy: 1.1.0 + x-xss-protection: 1.1.0 + dev: false + engines: + node: '>= 0.10.0' + resolution: + integrity: sha512-j9JjtAnWJj09lqe/PEICrhuDaX30TeokXJ9tW6ZPhVH0+LMoihDeJ58CdWeTGzM66p6EiIODmgAaWfdeIWI4Gg== + /hide-powered-by/1.0.0: + dev: false + resolution: + integrity: sha1-SoWtZYgfYoV/xwr3F0oRhNzM4ys= + /hpkp/2.0.0: + dev: false + resolution: + integrity: sha1-EOFCJk52IVpdMMROxD3mTe5tFnI= + /hsts/2.1.0: + dev: false + resolution: + integrity: sha512-zXhh/DqgrTXJ7erTN6Fh5k/xjMhDGXCqdYN3wvxUvGUQvnxcFfUd8E+6vLg/nk3ss1TYMb+DhRl25fYABioTvA== + /http-errors/1.6.3: + dependencies: + depd: 1.1.2 + inherits: 2.0.3 + setprototypeof: 1.1.0 + statuses: 1.5.0 + dev: false + engines: + node: '>= 0.6' + resolution: + integrity: sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0= + /http-signature/1.2.0: + dependencies: + assert-plus: 1.0.0 + jsprim: 1.4.1 + sshpk: 1.16.0 + dev: false + engines: + node: '>=0.8' + npm: '>=1.3.7' + resolution: + integrity: sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= + /iconv-lite/0.4.23: + dependencies: + safer-buffer: 2.1.2 + dev: false + engines: + node: '>=0.10.0' + resolution: + integrity: sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA== + /iconv-lite/0.4.24: + dependencies: + safer-buffer: 2.1.2 + dev: false + engines: + node: '>=0.10.0' + resolution: + integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + /ienoopen/1.0.0: + dev: false + resolution: + integrity: sha1-NGpCj0dKrI9QzzeE6i0PFvYr2ms= + /inflight/1.0.6: + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + dev: false + resolution: + integrity: sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + /inherits/2.0.3: + dev: false + resolution: + integrity: sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= + /ip-regex/1.0.3: + dev: false + engines: + node: '>=0.10.0' + resolution: + integrity: sha1-3FiQdvZZ9BnCIgOaMzFvHHOH7/0= + /ipaddr.js/1.8.0: + dev: false + engines: + node: '>= 0.10' + resolution: + integrity: sha1-6qM9bd16zo9/b+DJygRA5wZzix4= + /is-ip/1.0.0: + dependencies: + ip-regex: 1.0.3 + dev: false + engines: + node: '>=0.10.0' + resolution: + integrity: sha1-K7aVn3l8zW+f3IEnWLy8h8TFkHQ= + /is-typedarray/1.0.0: + dev: false + resolution: + integrity: sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= + /isarray/1.0.0: + dev: false + resolution: + integrity: sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= + /isstream/0.1.2: + dev: false + resolution: + integrity: sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= + /jsbn/0.1.1: + dev: false + resolution: + integrity: sha1-peZUwuWi3rXyAdls77yoDA7y9RM= + /jsdom/7.2.2: + dependencies: + abab: 1.0.4 + acorn: 2.7.0 + acorn-globals: 1.0.9 + cssom: 0.3.4 + cssstyle: 0.2.37 + escodegen: 1.11.0 + nwmatcher: 1.4.4 + parse5: 1.5.1 + request: 2.88.0 + sax: 1.2.4 + symbol-tree: 3.2.2 + tough-cookie: 2.5.0 + webidl-conversions: 2.0.1 + whatwg-url-compat: 0.6.5 + xml-name-validator: 2.0.1 + dev: false + resolution: + integrity: sha1-QLQCdwwr2iNGkJa+6Rq2deOx/G4= + /json-schema-traverse/0.4.1: + dev: false + resolution: + integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + /json-schema/0.2.3: + dev: false + resolution: + integrity: sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= + /json-stringify-safe/5.0.1: + dev: false + resolution: + integrity: sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= + /json3/3.3.2: + dev: false + resolution: + integrity: sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE= + /jsprim/1.4.1: + dependencies: + assert-plus: 1.0.0 + extsprintf: 1.3.0 + json-schema: 0.2.3 + verror: 1.10.0 + dev: false + engines: + '0': node >=0.6.0 + resolution: + integrity: sha1-MT5mvB5cwG5Di8G3SZwuXFastqI= + /levn/0.3.0: + dependencies: + prelude-ls: 1.1.2 + type-check: 0.3.2 + dev: false + engines: + node: '>= 0.8.0' + resolution: + integrity: sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= + /lodash._baseassign/3.2.0: + dependencies: + lodash._basecopy: 3.0.1 + lodash.keys: 3.1.2 + dev: false + resolution: + integrity: sha1-jDigmVAPIVrQnlnxci/QxSv+Ck4= + /lodash._basecopy/3.0.1: + dev: false + resolution: + integrity: sha1-jaDmqHbPNEwK2KVIghEd08XHyjY= + /lodash._basecreate/3.0.3: + dev: false + resolution: + integrity: sha1-G8ZhYU2qf8MRt9A78WgGoCE8+CE= + /lodash._getnative/3.9.1: + dev: false + resolution: + integrity: sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U= + /lodash._isiterateecall/3.0.9: + dev: false + resolution: + integrity: sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw= + /lodash.create/3.1.1: + dependencies: + lodash._baseassign: 3.2.0 + lodash._basecreate: 3.0.3 + lodash._isiterateecall: 3.0.9 + dev: false + resolution: + integrity: sha1-1/KEnw29p+BGgruM1yqwIkYd6+c= + /lodash.isarguments/3.1.0: + dev: false + resolution: + integrity: sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo= + /lodash.isarray/3.0.4: + dev: false + resolution: + integrity: sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U= + /lodash.keys/3.1.2: + dependencies: + lodash._getnative: 3.9.1 + lodash.isarguments: 3.1.0 + lodash.isarray: 3.0.4 + dev: false + resolution: + integrity: sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo= + /lodash/3.10.1: + dev: false + resolution: + integrity: sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y= + /media-typer/0.3.0: + dev: false + engines: + node: '>= 0.6' + resolution: + integrity: sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= + /merge-descriptors/1.0.1: + dev: false + resolution: + integrity: sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= + /methods/1.1.2: + dev: false + engines: + node: '>= 0.6' + resolution: + integrity: sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= + /mime-db/1.37.0: + dev: false + engines: + node: '>= 0.6' + resolution: + integrity: sha512-R3C4db6bgQhlIhPU48fUtdVmKnflq+hRdad7IyKhtFj06VPNVdk2RhiYL3UjQIlso8L+YxAtFkobT0VK+S/ybg== + /mime-types/2.1.21: + dependencies: + mime-db: 1.37.0 + dev: false + engines: + node: '>= 0.6' + resolution: + integrity: sha512-3iL6DbwpyLzjR3xHSFNFeb9Nz/M8WDkX33t1GFQnFOllWk8pOrh/LSrB5OXlnlW5P9LH73X6loW/eogc+F5lJg== + /mime/1.4.1: + dev: false + hasBin: true + resolution: + integrity: sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ== + /mime/1.6.0: + dev: false + engines: + node: '>=4' + hasBin: true + resolution: + integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== + /minimatch/3.0.4: + dependencies: + brace-expansion: 1.1.11 + dev: false + resolution: + integrity: sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== + /minimist/0.0.8: + dev: false + resolution: + integrity: sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= + /mkdirp/0.5.1: + dependencies: + minimist: 0.0.8 + dev: false + hasBin: true + resolution: + integrity: sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= + /mocha/3.5.3: + dependencies: + browser-stdout: 1.3.0 + commander: 2.9.0 + debug: 2.6.8 + diff: 3.2.0 + escape-string-regexp: 1.0.5 + glob: 7.1.1 + growl: 1.9.2 + he: 1.1.1 + json3: 3.3.2 + lodash.create: 3.1.1 + mkdirp: 0.5.1 + supports-color: 3.1.2 + dev: false + engines: + node: '>= 0.10.x' + npm: '>= 1.4.x' + hasBin: true + resolution: + integrity: sha512-/6na001MJWEtYxHOV1WLfsmR4YIynkUEhBwzsb+fk2qmQ3iqsi258l/Q2MWHJMImAcNpZ8DEdYAK72NHoIQ9Eg== + /mongodb-core/2.1.20: + dependencies: + bson: 1.0.9 + require_optional: 1.0.1 + dev: false + resolution: + integrity: sha512-IN57CX5/Q1bhDq6ShAR6gIv4koFsZP7L8WOK1S0lR0pVDQaScffSMV5jxubLsmZ7J+UdqmykKw4r9hG3XQEGgQ== + /mongodb/2.2.36: + dependencies: + es6-promise: 3.2.1 + mongodb-core: 2.1.20 + readable-stream: 2.2.7 + dev: false + engines: + node: '>=0.10.3' + resolution: + integrity: sha512-P2SBLQ8Z0PVx71ngoXwo12+FiSfbNfGOClAao03/bant5DgLNkOPAck5IaJcEk4gKlQhDEURzfR3xuBG1/B+IA== + /ms/0.7.3: + dev: false + resolution: + integrity: sha1-cIFVpeROM/X9D8U+gdDUCpG+H/8= + /ms/2.0.0: + dev: false + resolution: + integrity: sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= + /negotiator/0.6.1: + dev: false + engines: + node: '>= 0.6' + resolution: + integrity: sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk= + /nocache/2.0.0: + dev: false + resolution: + integrity: sha1-ICtIAhoMTL3i34DeFaF0Q8i0OYA= + /nwmatcher/1.4.4: + dev: false + resolution: + integrity: sha512-3iuY4N5dhgMpCUrOVnuAdGrgxVqV2cJpM+XNccjR2DKOB1RUP0aA+wGXEiNziG/UKboFyGBIoKOaNlJxx8bciQ== + /oauth-sign/0.9.0: + dev: false + resolution: + integrity: sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== + /object-assign/4.1.1: + dev: false + engines: + node: '>=0.10.0' + resolution: + integrity: sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= + /on-finished/2.3.0: + dependencies: + ee-first: 1.1.1 + dev: false + engines: + node: '>= 0.8' + resolution: + integrity: sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= + /once/1.4.0: + dependencies: + wrappy: 1.0.2 + dev: false + resolution: + integrity: sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + /optionator/0.8.2: + dependencies: + deep-is: 0.1.3 + fast-levenshtein: 2.0.6 + levn: 0.3.0 + prelude-ls: 1.1.2 + type-check: 0.3.2 + wordwrap: 1.0.0 + dev: false + engines: + node: '>= 0.8.0' + resolution: + integrity: sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q= + /options/0.0.6: + dev: false + engines: + node: '>=0.4.0' + resolution: + integrity: sha1-7CLTEoBrtT5zF3Pnza788cZDEo8= + /original/1.0.2: + dependencies: + url-parse: 1.4.4 + dev: false + resolution: + integrity: sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg== + /parse5/1.5.1: + dev: false + resolution: + integrity: sha1-m387DeMr543CQBsXVzzK8Pb1nZQ= + /parseurl/1.3.2: + dev: false + engines: + node: '>= 0.8' + resolution: + integrity: sha1-/CidTtiZMRlGDBViUyYs3I3mW/M= + /path-is-absolute/1.0.1: + dev: false + engines: + node: '>=0.10.0' + resolution: + integrity: sha1-F0uSaHNVNP+8es5r9TpanhtcX18= + /path-to-regexp/0.1.7: + dev: false + resolution: + integrity: sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= + /performance-now/2.1.0: + dev: false + resolution: + integrity: sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= + /platform/1.3.5: + dev: false + resolution: + integrity: sha512-TuvHS8AOIZNAlE77WUDiR4rySV/VMptyMfcfeoMgs4P8apaZM3JrnbzBiixKUv+XR6i+BXrQh8WAnjaSPFO65Q== + /prelude-ls/1.1.2: + dev: false + engines: + node: '>= 0.8.0' + resolution: + integrity: sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= + /process-nextick-args/1.0.7: + dev: false + resolution: + integrity: sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M= + /process-nextick-args/2.0.0: + dev: false + resolution: + integrity: sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw== + /proxy-addr/2.0.4: + dependencies: + forwarded: 0.1.2 + ipaddr.js: 1.8.0 + dev: false + engines: + node: '>= 0.10' + resolution: + integrity: sha512-5erio2h9jp5CHGwcybmxmVqHmnCBZeewlfJ0pex+UW7Qny7OOZXTtH56TGNyBizkgiOwhJtMKrVzDTeKcySZwA== + /psl/1.1.31: + dev: false + resolution: + integrity: sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw== + /punycode/1.4.1: + dev: false + resolution: + integrity: sha1-wNWmOycYgArY4esPpSachN1BhF4= + /punycode/2.1.1: + dev: false + engines: + node: '>=6' + resolution: + integrity: sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== + /qs/6.5.2: + dev: false + engines: + node: '>=0.6' + resolution: + integrity: sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== + /qs/6.6.0: + dev: false + engines: + node: '>=0.6' + resolution: + integrity: sha512-KIJqT9jQJDQx5h5uAVPimw6yVg2SekOKu959OCtktD3FjzbpvaPr8i4zzg07DOMz+igA4W/aNM7OV8H37pFYfA== + /querystringify/2.1.0: + dev: false + resolution: + integrity: sha512-sluvZZ1YiTLD5jsqZcDmFyV2EwToyXZBfpoVOmktMmW+VEnhgakFHnasVph65fOjGPTWN0Nw3+XQaSeMayr0kg== + /range-parser/1.2.0: + dev: false + engines: + node: '>= 0.6' + resolution: + integrity: sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4= + /raw-body/2.3.3: + dependencies: + bytes: 3.0.0 + http-errors: 1.6.3 + iconv-lite: 0.4.23 + unpipe: 1.0.0 + dev: false + engines: + node: '>= 0.8' + resolution: + integrity: sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw== + /readable-stream/2.2.7: + dependencies: + 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 + dev: false + resolution: + integrity: sha1-BwV6y+JGeyIELTb5jFrVBwVOlbE= + /readable-stream/2.3.6: + dependencies: + core-util-is: 1.0.2 + inherits: 2.0.3 + isarray: 1.0.0 + process-nextick-args: 2.0.0 + safe-buffer: 5.1.2 + string_decoder: 1.1.1 + util-deprecate: 1.0.2 + dev: false + resolution: + integrity: sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw== + /referrer-policy/1.1.0: + dev: false + resolution: + integrity: sha1-NXdOtzW/UPtsB46DM0tHI1AgfXk= + /request/2.88.0: + dependencies: + aws-sign2: 0.7.0 + aws4: 1.8.0 + caseless: 0.12.0 + combined-stream: 1.0.7 + extend: 3.0.2 + forever-agent: 0.6.1 + form-data: 2.3.3 + har-validator: 5.1.3 + http-signature: 1.2.0 + is-typedarray: 1.0.0 + isstream: 0.1.2 + json-stringify-safe: 5.0.1 + mime-types: 2.1.21 + oauth-sign: 0.9.0 + performance-now: 2.1.0 + qs: 6.5.2 + safe-buffer: 5.1.2 + tough-cookie: 2.4.3 + tunnel-agent: 0.6.0 + uuid: 3.3.2 + dev: false + engines: + node: '>= 4' + resolution: + integrity: sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg== + /require_optional/1.0.1: + dependencies: + resolve-from: 2.0.0 + semver: 5.6.0 + dev: false + resolution: + integrity: sha512-qhM/y57enGWHAe3v/NcwML6a3/vfESLe/sGM2dII+gEO0BpKRUkWZow/tyloNqJyN6kXSl3RyyM8Ll5D/sJP8g== + /requires-port/1.0.0: + dev: false + resolution: + integrity: sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8= + /resolve-from/2.0.0: + dev: false + engines: + node: '>=0.10.0' + resolution: + integrity: sha1-lICrIOlP+h2egKgEx+oUdhGWa1c= + /safe-buffer/5.1.2: + dev: false + resolution: + integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + /safer-buffer/2.1.2: + dev: false + resolution: + integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + /sax/1.2.4: + dev: false + resolution: + integrity: sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== + /semver/5.6.0: + dev: false + hasBin: true + resolution: + integrity: sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg== + /send/0.16.2: + dependencies: + debug: 2.6.9 + depd: 1.1.2 + destroy: 1.0.4 + encodeurl: 1.0.2 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 0.5.2 + http-errors: 1.6.3 + mime: 1.4.1 + ms: 2.0.0 + on-finished: 2.3.0 + range-parser: 1.2.0 + statuses: 1.4.0 + dev: false + engines: + node: '>= 0.8.0' + resolution: + integrity: sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw== + /serve-static/1.13.2: + dependencies: + encodeurl: 1.0.2 + escape-html: 1.0.3 + parseurl: 1.3.2 + send: 0.16.2 + dev: false + engines: + node: '>= 0.8.0' + resolution: + integrity: sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw== + /setprototypeof/1.1.0: + dev: false + resolution: + integrity: sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ== + /source-map/0.6.1: + dev: false + engines: + node: '>=0.10.0' + optional: true + resolution: + integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + /sshpk/1.16.0: + dependencies: + asn1: 0.2.4 + assert-plus: 1.0.0 + bcrypt-pbkdf: 1.0.2 + dashdash: 1.14.1 + ecc-jsbn: 0.1.2 + getpass: 0.1.7 + jsbn: 0.1.1 + safer-buffer: 2.1.2 + tweetnacl: 0.14.5 + dev: false + engines: + node: '>=0.10.0' + hasBin: true + resolution: + integrity: sha512-Zhev35/y7hRMcID/upReIvRse+I9SVhyVre/KTJSJQWMz3C3+G+HpO7m1wK/yckEtujKZ7dS4hkVxAnmHaIGVQ== + /statuses/1.4.0: + dev: false + engines: + node: '>= 0.6' + resolution: + integrity: sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew== + /statuses/1.5.0: + dev: false + engines: + node: '>= 0.6' + resolution: + integrity: sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= + /string_decoder/1.0.3: + dependencies: + safe-buffer: 5.1.2 + dev: false + resolution: + integrity: sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ== + /string_decoder/1.1.1: + dependencies: + safe-buffer: 5.1.2 + dev: false + resolution: + integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + /superagent/2.3.0: + dependencies: + component-emitter: 1.2.1 + cookiejar: 2.1.2 + debug: 2.6.9 + extend: 3.0.2 + form-data: 1.0.0-rc4 + formidable: 1.2.1 + methods: 1.1.2 + mime: 1.6.0 + qs: 6.6.0 + readable-stream: 2.3.6 + dev: false + engines: + node: '>= 0.10' + resolution: + integrity: sha1-cDUpoHFOV+EjlZ3e+84ZOy5Q0RU= + /supports-color/3.1.2: + dependencies: + has-flag: 1.0.0 + dev: false + engines: + node: '>=0.8.0' + resolution: + integrity: sha1-cqJiiU2dQIuVbKBf83su2KbiotU= + /symbol-tree/3.2.2: + dev: false + resolution: + integrity: sha1-rifbOPZgp64uHDt9G8KQgZuFGeY= + /tough-cookie/2.4.3: + dependencies: + psl: 1.1.31 + punycode: 1.4.1 + dev: false + engines: + node: '>=0.8' + resolution: + integrity: sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ== + /tough-cookie/2.5.0: + dependencies: + psl: 1.1.31 + punycode: 2.1.1 + dev: false + engines: + node: '>=0.8' + resolution: + integrity: sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== + /tr46/0.0.3: + dev: false + resolution: + integrity: sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o= + /tunnel-agent/0.6.0: + dependencies: + safe-buffer: 5.1.2 + dev: false + resolution: + integrity: sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= + /tweetnacl/0.14.5: + dev: false + resolution: + integrity: sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= + /type-check/0.3.2: + dependencies: + prelude-ls: 1.1.2 + dev: false + engines: + node: '>= 0.8.0' + resolution: + integrity: sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= + /type-detect/0.1.1: + dev: false + resolution: + integrity: sha1-C6XsKohWQORw6k6FBZcZANrFiCI= + /type-detect/1.0.0: + dev: false + resolution: + integrity: sha1-diIXzAbbJY7EiQihKY6LlRIejqI= + /type-is/1.6.16: + dependencies: + media-typer: 0.3.0 + mime-types: 2.1.21 + dev: false + engines: + node: '>= 0.6' + resolution: + integrity: sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q== + /ultron/1.0.2: + dev: false + resolution: + integrity: sha1-rOEWq1V80Zc4ak6I9GhTeMiy5Po= + /unpipe/1.0.0: + dev: false + engines: + node: '>= 0.8' + resolution: + integrity: sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= + /uri-js/4.2.2: + dependencies: + punycode: 2.1.1 + dev: false + resolution: + integrity: sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ== + /url-parse/1.4.4: + dependencies: + querystringify: 2.1.0 + requires-port: 1.0.0 + dev: false + resolution: + integrity: sha512-/92DTTorg4JjktLNLe6GPS2/RvAd/RGr6LuktmWSMLEOa6rjnlrFXNgSbSmkNvCoL2T028A0a1JaJLzRMlFoHg== + /util-deprecate/1.0.2: + dev: false + resolution: + integrity: sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + /utils-merge/1.0.1: + dev: false + engines: + node: '>= 0.4.0' + resolution: + integrity: sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= + /uuid/3.3.2: + dev: false + hasBin: true + resolution: + integrity: sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA== + /vary/1.1.2: + dev: false + engines: + node: '>= 0.8' + resolution: + integrity: sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= + /verror/1.10.0: + dependencies: + assert-plus: 1.0.0 + core-util-is: 1.0.2 + extsprintf: 1.4.0 + dev: false + engines: + '0': node >=0.6.0 + resolution: + integrity: sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= + /webidl-conversions/2.0.1: + dev: false + resolution: + integrity: sha1-O/glj30xjHRDw28uFpQCoaZwNQY= + /whatwg-url-compat/0.6.5: + dependencies: + tr46: 0.0.3 + dev: false + resolution: + integrity: sha1-AImBEa9om7CXVBzVpFymyHmERb8= + /wordwrap/1.0.0: + dev: false + resolution: + integrity: sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= + /wrappy/1.0.2: + dev: false + resolution: + integrity: sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + /ws/1.1.5: + dependencies: + options: 0.0.6 + ultron: 1.0.2 + dev: false + resolution: + integrity: sha512-o3KqipXNUdS7wpQzBHSe180lBGO60SoK0yVo3CYJgb2MkobuWuBX6dhkYP5ORCLd55y+SaflMOV5fqAB53ux4w== + /x-xss-protection/1.1.0: + dev: false + resolution: + integrity: sha512-rx3GzJlgEeZ08MIcDsU2vY2B1QEriUKJTSiNHHUIem6eg9pzVOr2TL3Y4Pd6TMAM5D5azGjcxqI62piITBDHVg== + /xml-name-validator/2.0.1: + dev: false + resolution: + integrity: sha1-TYuPHszTQZqjYgYb7O9RXh5VljU= + /zombie/5.0.8: + dependencies: + babel-runtime: 5.8.29 + bluebird: 3.5.3 + debug: 2.6.9 + eventsource: 0.1.6 + iconv-lite: 0.4.24 + jsdom: 7.2.2 + lodash: 3.10.1 + mime: 1.6.0 + ms: 0.7.3 + request: 2.88.0 + tough-cookie: 2.5.0 + ws: 1.1.5 + dev: false + engines: + node: '>=4.0.0' + resolution: + integrity: sha512-b634oIFJ2SFHnWEdntljrBeEroF1piyTiPmZPqsZwwy2KC5MLazq97eHPw1Qz77VPujQTEnbhOUvMssjpak2WQ== +registry: 'https://registry.npmjs.org/' +shrinkwrapMinorVersion: 9 +shrinkwrapVersion: 3 +specifiers: + body-parser: ^1.15.2 + chai: ^3.5.0 + chai-http: ^3.0.0 + cors: ^2.8.1 + express: ^4.14.0 + helmet: ^3.1.0 + mocha: ^3.2.0 + mongodb: ^2.2.16 + zombie: ^5.0.5 diff --git a/test-runner.js b/test-runner.js new file mode 100644 index 0000000..06cfad5 --- /dev/null +++ b/test-runner.js @@ -0,0 +1,106 @@ +/* +* +* +* +* +* +* +* +* +* +* +* +* DO NOT EDIT THIS FILE +* For FCC testing purposes! +* +* +* +* +* +* +* +* +* +* +* +*/ + +var analyser = require('./assertion-analyser'); +var EventEmitter = require('events').EventEmitter; + +var Mocha = require('mocha'), + fs = require('fs'), + path = require('path'); + +var mocha = new Mocha(); +var testDir = './tests' + + +// Add each .js file to the mocha instance +fs.readdirSync(testDir).filter(function(file){ + // Only keep the .js files + return file.substr(-3) === '.js'; + +}).forEach(function(file){ + mocha.addFile( + path.join(testDir, file) + ); +}); + +var emitter = new EventEmitter(); +emitter.run = function() { + + var tests = []; + var context = ""; + var separator = ' -> '; + // Run the tests. + try { + var runner = mocha.ui('tdd').run() + .on('test end', function(test) { + // remove comments + var body = test.body.replace(/\/\/.*\n|\/\*.*\*\//g, ''); + // collapse spaces + body = body.replace(/\s+/g,' '); + var obj = { + title: test.title, + context: context.slice(0, -separator.length), + state: test.state, + // body: body, + assertions: analyser(body) + }; + tests.push(obj); + }) + .on('end', function() { + emitter.report = tests; + emitter.emit('done', tests) + }) + .on('suite', function(s) { + context += (s.title + separator); + + }) + .on('suite end', function(s) { + context = context.slice(0, -(s.title.length + separator.length)) + }) + } catch(e) { + throw(e); + } +}; + +module.exports = emitter; + +/* + * Mocha.runner Events: + * can be used to build a better custom report + * + * - `start` execution started + * - `end` execution complete + * - `suite` (suite) test suite execution started + * - `suite end` (suite) all tests (and sub-suites) have finished + * - `test` (test) test execution started + * - `test end` (test) test completed + * - `hook` (hook) hook execution started + * - `hook end` (hook) hook complete + * - `pass` (test) test passed + * - `fail` (test, err) test failed + * - `pending` (test) test pending + */ \ No newline at end of file diff --git a/tests/1_unit-tests.js b/tests/1_unit-tests.js new file mode 100644 index 0000000..a2df967 --- /dev/null +++ b/tests/1_unit-tests.js @@ -0,0 +1,145 @@ +/* +* +* +* FILL IN EACH UNIT TEST BELOW COMPLETELY +* -----[Keep the tests in the same order!]---- +* (if additional are added, keep them at the very end!) +*/ + +var chai = require('chai'); +var assert = chai.assert; +var ConvertHandler = require('../controllers/convertHandler.js'); + +var convertHandler = new ConvertHandler(); + +suite('Unit Tests', function(){ + + suite('Function convertHandler.getNum(input)', function() { + + test('Whole number input', function(done) { + var input = '32L'; + assert.equal(convertHandler.getNum(input),32); + done(); + }); + + test('Decimal Input', function(done) { + assert.equal(convertHandler.getNum('3.2'), 3.2) + done() + }); + + test('Fractional Input', function(done) { + assert.equal(convertHandler.getNum('3/2'), 1.5) + done(); + }); + + test('Fractional Input w/ Decimal', function(done) { + assert.equal(convertHandler.getNum('1.5/3'), .5) + done(); + }); + + test('Invalid Input (double fraction)', function(done) { + assert.isUndefined(convertHandler.getNum('5/4/3')) + done(); + }); + + test('No Numerical Input', function(done) { + assert.equal(convertHandler.getNum('lb'), 1) + done(); + }); + + }); + + suite('Function convertHandler.getUnit(input)', function() { + + test('For Each Valid Unit Inputs', function(done) { + var input = ['gal','l','mi','km','lbs','kg','GAL','L','MI','KM','LBS','KG']; + input.forEach(function(ele) { + assert.equal(convertHandler.getUnit(ele), ele) + }); + done(); + }); + + test('Unknown Unit Input', function(done) { + assert.isUndefined(convertHandler.getUnit('1xb')) + done(); + }); + + }); + + suite('Function convertHandler.getReturnUnit(initUnit)', function() { + + test('For Each Valid Unit Inputs', function(done) { + var input = ['gal','l','mi','km','lbs','kg']; + var expect = ['l','gal','km','mi','kg','lbs']; + input.forEach(function(ele, i) { + // console.log('output: ' + convertHandler.getReturnUnit(ele) + ', expected: ' + expect[i]) + assert.equal(convertHandler.getReturnUnit(ele), expect[i]); + }); + done(); + }); + + }); + + suite('Function convertHandler.spellOutUnit(unit)', function() { + + test('For Each Valid Unit Inputs', function(done) { + var input = ['gal', 'l', 'mi', 'km', 'lbs', 'kg'] + var expect = ['gallon(s)', 'liter(s)', 'mile(s)', 'kilometer(s)', 'pound(s)', 'kilogram(s)'] + input.forEach(function(ele, i) { + // console.log('output: ' + convertHandler.spellOutUnit(ele) + ', expected: ' + expect[i]) + + assert.equal(convertHandler.spellOutUnit(ele), expect[i]) + }) + done() + }); + + }); + + suite('Function convertHandler.convert(num, unit)', function() { + + test('Gal to L', function(done) { + var input = [5, 'gal']; + var expected = 18.9271; + // var expected = 1 + assert.approximately(convertHandler.convert(input[0],input[1]),expected,0.1); //0.1 tolerance + done(); + }); + + test('L to Gal', function(done) { + var input = [5, 'L'] + var expected = 1.32 + assert.approximately(convertHandler.convert(input[0], input[1]), expected, 0.1); + done(); + }); + + test('Mi to Km', function(done) { + var input = [5, 'mi'] + var expected = 8.05 + assert.approximately(convertHandler.convert(input[0], input[1]), expected, 0.1); + done(); + }); + + test('Km to Mi', function(done) { + var input = [5, 'km'] + var expected = 3.107 + assert.approximately(convertHandler.convert(input[0], input[1]), expected, 0.1); + done(); + }); + + test('Lbs to Kg', function(done) { + var input = [5, 'lb'] + var expected = 2.27 + assert.approximately(convertHandler.convert(input[0], input[1]), expected, 0.1); + done(); + }); + + test('Kg to Lbs', function(done) { + var input = [5, 'kg'] + var expected = 11.02 + assert.approximately(convertHandler.convert(input[0], input[1]), expected, 0.1); + done(); + }); + + }); + +}); \ No newline at end of file diff --git a/tests/2_functional-tests.js b/tests/2_functional-tests.js new file mode 100644 index 0000000..d7ac214 --- /dev/null +++ b/tests/2_functional-tests.js @@ -0,0 +1,84 @@ +/* +* +* +* FILL IN EACH FUNCTIONAL TEST BELOW COMPLETELY +* -----[Keep the tests in the same order!]----- +* (if additional are added, keep them at the very end!) +*/ + +var chaiHttp = require('chai-http'); +var chai = require('chai'); +var assert = chai.assert; +var server = require('../server'); + +chai.use(chaiHttp); + +suite('Functional Tests', function() { + + suite('Routing Tests', function() { + + suite('GET /api/convert => conversion object', function() { + + test('Convert 10L (valid input)', function(done) { + chai.request(server) + .get('/api/convert') + .query({input: '10L'}) + .end(function(err, res){ + assert.equal(res.status, 200); + assert.equal(res.body.initNum, 10); + assert.equal(res.body.initUnit, 'L'); + assert.approximately(res.body.returnNum, 2.64172, 0.1); + assert.equal(res.body.returnUnit, 'gal'); + done(); + }); + }); + + test('Convert 32g (invalid input unit)', function(done) { + chai.request(server) + .get('/api/convert') + .query({ input: '32g' }) + .end(function(err, res) { + assert.equal(res.status, 200) + assert.equal(res.text, 'invalid unit.') + }) + done(); + }); + + test('Convert 3/7.2/4kg (invalid number)', function(done) { + chai.request(server) + .get('/api/convert') + .query({ input: '3/7/2/4kg' }) + .end(function(err, res) { + assert.equal(res.status, 200) + assert.equal(res.text, 'invalid number.') + }) + done(); + }); + + test('Convert 3/7.2/4kilomegagram (invalid number and unit)', function(done) { + chai.request(server) + .get('/api/convert') + .query({ input: '3/7.2/4kilomegagram ' }) + .end(function(err, res) { + assert.equal(res.status, 200) + assert.equal(res.text, 'invalid number and unit') + }) + done(); + }); + + test('Convert kg (no number)', function(done) { + chai.request(server) + .get('/api/convert') + .query({ input: 'kg' }) + .end(function(err, res) { + assert.equal(res.status, 200) + assert.equal(res.initNum, 1) + }) + done(); + }); + + }); + + }); + +}); diff --git a/views/index.html b/views/index.html new file mode 100644 index 0000000..f257121 --- /dev/null +++ b/views/index.html @@ -0,0 +1,76 @@ + + + + Welcome to HyperDev! + + + + + + + + +
+

+ ISQA_2 - Metric/Imp Converter +

+
+
+

User Stories

+
    +
  1. I will help prevent the client from trying to guess(sniff) the MIME type.
  2. +
  3. I will prevent cross-site scripting (XSS) attacks.
  4. +
  5. I can GET /api/convert with a single parameter containing an accepted number and unit and have it converted.
  6. +
  7. Hint: Split the input by looking for the index of the first character.
  8. +
  9. I can convert 'gal' to 'L' and vice versa. (1 gal to 3.78541 L)
  10. +
  11. I can convert 'lbs' to 'kg' and vice versa. (1 lbs to 0.453592 kg)
  12. +
  13. I can convert 'mi' to 'km' and vice versa. (1 mi to 1.60934 km)
  14. +
  15. If my unit of measurement is invalid, returned will be 'invalid unit'.
  16. +
  17. If my number is invalid, returned with will 'invalid number'.
  18. +
  19. If both are invalid, return will be 'invalid number and unit'.
  20. +
  21. I can use fractions, decimals or both in my parameter(ie. 5, 1/2, 2.5/6), but if nothing is provided it will default to 1.
  22. +
  23. My return will consist of the initNum, initUnit, returnNum, returnUnit, and string spelling out units in format {initNum} {initial_Units} converts to {returnNum} {return_Units} with the result rounded to 5 decimals.
  24. +
  25. All 16 unit tests are complete and passing.
  26. +
  27. All 5 functional tests are complete and passing.
  28. +
+

Example usage:

+ /api/convert?input=4gal
+ /api/convert?input=1/2km
+ /api/convert?input=5.4/3lbs
+ /api/convert?input=kg
+

Example return:

+ {initNum: 3.1, initUnit: 'mi', returnNum: 5.0000008, returnUnit: 'km', string: '3.1 miles converts to 5.00002 kilometers'} +
+
+
+

Front-End:

+
+ + +
+

+ +
+
+ + + + +