├── .gitignore ├── README.md ├── index.js ├── lib ├── address.js ├── ip.js └── result.js ├── package.json ├── test └── test.js └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Directory for instrumented libs generated by jscoverage/JSCover 11 | lib-cov 12 | 13 | # Coverage directory used by tools like istanbul 14 | coverage 15 | 16 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 17 | .grunt 18 | 19 | # node-waf configuration 20 | .lock-wscript 21 | 22 | # Compiled binary addons (http://nodejs.org/api/addons.html) 23 | build/Release 24 | 25 | # Dependency directory 26 | # https://docs.npmjs.com/misc/faq#should-i-check-my-node-modules-folder-into-git 27 | node_modules 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # node-where 2 | 3 | [![Dependency Status](https://david-dm.org/venables/node-where.png)](https://david-dm.org/venables/node-where) 4 | 5 | A basic geolocation library for node.js. 6 | 7 | Uses [freegeoip.net](http://freegeoip.net) and the [Google Maps Geocoding API](https://developers.google.com/maps/documentation/geocoding/intro) 8 | 9 | ## Installation 10 | 11 | ``` 12 | npm install node-where --save 13 | ``` 14 | 15 | ## Usage 16 | 17 | Where can search by Postal Address, landmark or IP Address: 18 | 19 | ### Search by Postal Address: 20 | 21 | ```javascript 22 | var where = require('node-where'); 23 | 24 | where.is('4 yawkey way boston ma', function(err, result) { 25 | if (result) { 26 | console.log('Address: ' + result.get('address')); 27 | console.log('Street Number: ' + result.get('streetNumber')); 28 | console.log('Street: ' + result.get('street')); 29 | console.log('Full Street: ' + result.get('streetAddress')); 30 | console.log('City: ' + result.get('city')); 31 | console.log('State / Region: ' + result.get('region')); 32 | console.log('State / Region Code: ' + result.get('regionCode')); 33 | console.log('Zip: ' + result.get('postalCode')); 34 | console.log('Country: ' + result.get('country')); 35 | console.log('Country Code: ' + result.get('countryCode')); 36 | console.log('Lat: ' + result.get('lat')); 37 | console.log('Lng: ' + result.get('lng')); 38 | } 39 | }); 40 | ``` 41 | 42 | ### Search by Landmark: 43 | 44 | ```javascript 45 | var where = require('node-where'); 46 | 47 | where.is('Fenway Park', function(err, result) { 48 | if (result) { 49 | // Same result as address search 50 | // ... 51 | } 52 | }); 53 | ``` 54 | 55 | 56 | ### Search by IP Address (both IPv4 and IPv6): 57 | 58 | ```javascript 59 | var where = require('node-where'); 60 | 61 | where.is('173.194.33.104', function(err, result) { 62 | if (result) { 63 | console.log('City: ' + result.get('city')); 64 | console.log('State / Region: ' + result.get('region')); 65 | console.log('State / Region Code: ' + result.get('regionCode')); 66 | console.log('Zip: ' + result.get('postalCode')); 67 | console.log('Country: ' + result.get('country')); 68 | console.log('Country Code: ' + result.get('countryCode')); 69 | console.log('Lat: ' + result.get('lat')); 70 | console.log('Lng: ' + result.get('lng')); 71 | } 72 | }); 73 | ``` 74 | 75 | NOTE: IP address lookups do not include any street address information. 76 | 77 | ## Usage as Express middleware: 78 | 79 | ```javascript 80 | var where = require('node-where'); 81 | 82 | app.use(function(req, res, next) { 83 | where.is(req.ip, function(err, result) { 84 | req.geoip = result; 85 | next(); 86 | }); 87 | }); 88 | ``` 89 | 90 | ## Testing 91 | 92 | Run the spec suite by running: 93 | 94 | ``` 95 | npm test 96 | ``` 97 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var isIP = require('validator').isIP; 4 | var Address = require('./lib/address'); 5 | var IP = require('./lib/ip'); 6 | var request = require('request'); 7 | var Result = require('./lib/result'); 8 | 9 | /* 10 | * callback: fn(err, result); 11 | */ 12 | var is = function(ipOrAddress, callback) { 13 | var locator; 14 | var opts; 15 | 16 | if (!ipOrAddress) { 17 | return callback(null, new Result()); 18 | } else if (isIP(ipOrAddress)) { 19 | locator = new IP(ipOrAddress); 20 | } else { 21 | locator = new Address(ipOrAddress); 22 | } 23 | 24 | opts = { 25 | method: 'GET', 26 | url: locator.url, 27 | json: true 28 | }; 29 | 30 | request(opts, function(err, res, body) { 31 | if (err) { 32 | return callback(err); 33 | } 34 | 35 | callback(null, locator.buildResult(body)); 36 | }); 37 | }; 38 | 39 | module.exports = { 40 | is: is 41 | }; 42 | -------------------------------------------------------------------------------- /lib/address.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _ = require('lodash'); 4 | var Result = require('./result'); 5 | 6 | function Address(address) { 7 | this.address = address; 8 | this.url = 'http://maps.googleapis.com/maps/api/geocode/json?sensor=false&address=' + encodeURIComponent(this.address); 9 | } 10 | 11 | _.extend(Address.prototype, { 12 | buildResult: function(body) { 13 | body = body || {}; 14 | 15 | if (body && body.results) { 16 | body = body.results[0]; 17 | } 18 | 19 | var country = _resultAddressComponent(body, 'country'); 20 | var postalCode = _resultAddressComponent(body, 'postal_code'); 21 | var region = _resultAddressComponent(body, 'administrative_area_level_1'); 22 | var city = _resultAddressComponent(body, 'locality'); 23 | var neighborhood = _resultAddressComponent(body, 'neighborhood'); 24 | var streetNumber = _resultAddressComponent(body, 'street_number'); 25 | var street = _resultAddressComponent(body, 'route'); 26 | var county = _resultAddressComponent(body, 'administrative_area_level_2'); 27 | 28 | return new Result({ 29 | countryCode: country.short_name, 30 | country: country.long_name, 31 | regionCode: region.short_name, 32 | region: region.long_name, 33 | city: city.long_name, 34 | postalCode: postalCode.long_name, 35 | lat: body.geometry.location.lat, 36 | lng: body.geometry.location.lng, 37 | 38 | streetNumber: streetNumber.long_name, 39 | street: street.long_name, 40 | neighborhood: neighborhood.long_name, 41 | county: county.long_name 42 | }); 43 | }, 44 | 45 | }); 46 | 47 | function _resultAddressComponent(body, componentName) { 48 | var components = body.address_components || {}; 49 | 50 | return _.find(components, function(component) { 51 | return _.includes(component.types, componentName); 52 | }) || {}; 53 | } 54 | 55 | 56 | module.exports = Address; 57 | -------------------------------------------------------------------------------- /lib/ip.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _ = require('lodash'); 4 | var Result = require('./result'); 5 | 6 | function IP(ip) { 7 | this.ip = ip; 8 | this.url = 'http://freegeoip.net/json/' + this.ip; 9 | } 10 | 11 | _.extend(IP.prototype, { 12 | buildResult: function(body) { 13 | body = body || {}; 14 | 15 | return new Result({ 16 | countryCode: body.country_code, 17 | country: body.country_name, 18 | regionCode: body.region_code, 19 | region: body.region_name, 20 | city: body.city, 21 | postalCode: body.zip_code, 22 | lat: body.latitude, 23 | lng: body.longitude 24 | }); 25 | } 26 | }); 27 | 28 | module.exports = IP; 29 | -------------------------------------------------------------------------------- /lib/result.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var _ = require('lodash'); 4 | 5 | function Result(attrs) { 6 | this.attributes = attrs || {}; 7 | } 8 | 9 | _.extend(Result.prototype, { 10 | get: function(attr) { 11 | return _.isFunction(this[attr]) ? this[attr]() : this.attributes[attr]; 12 | }, 13 | 14 | streetAddress: function() { 15 | var arr = _.compact([this.get('streetNumber'), this.get('street')]); 16 | return _.isEmpty(arr) ? undefined : arr.join(' '); 17 | }, 18 | 19 | address: function() { 20 | var arr = _.compact([this.get('streetAddress'), this.get('city'), this.get('regionCode'), this.get('postalCode'), this.get('countryCode')]); 21 | return _.isEmpty(arr) ? undefined: arr.join(', '); 22 | }, 23 | 24 | state: function() { 25 | return this.get('region'); 26 | }, 27 | 28 | stateCode: function() { 29 | return this.get('regionCode'); 30 | }, 31 | 32 | zipCode: function() { 33 | return this.get('postalCode'); 34 | } 35 | }); 36 | 37 | module.exports = Result; 38 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-where", 3 | "version": "1.1.0", 4 | "description": "A very simple geolocation library in node.js", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "./node_modules/.bin/mocha test/test.js" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/venables/node-where.git" 12 | }, 13 | "keywords": [ 14 | "where", 15 | "geolocation", 16 | "geoip", 17 | "ip", 18 | "country", 19 | "city", 20 | "lat", 21 | "lng", 22 | "latitude", 23 | "longitude" 24 | ], 25 | "author": "Matt Venables ", 26 | "license": "MIT", 27 | "bugs": { 28 | "url": "https://github.com/venables/node-where/issues" 29 | }, 30 | "homepage": "https://github.com/venables/node-where#readme", 31 | "dependencies": { 32 | "lodash": "^4.17.4", 33 | "request": "^2.81.0", 34 | "validator": "^7.0.0" 35 | }, 36 | "devDependencies": { 37 | "chai": "^3.5.0", 38 | "mocha": "^3.4.1" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var expect = require('chai').expect; 4 | var where = require('../'); 5 | 6 | describe('where.is', function() { 7 | 8 | it('returns an empty Result if given no address', function(done) { 9 | var result = where.is(null, function(err, result) { 10 | expect(err).to.equal(null); 11 | expect(result.get('address')).to.equal(undefined); 12 | expect(result.get('streetNumber')).to.equal(undefined); 13 | expect(result.get('streetAddress')).to.equal(undefined); 14 | expect(result.get('street')).to.equal(undefined); 15 | expect(result.get('city')).to.equal(undefined); 16 | expect(result.get('region')).to.equal(undefined); 17 | expect(result.get('regionCode')).to.equal(undefined); 18 | expect(result.get('postalCode')).to.equal(undefined); 19 | expect(result.get('country')).to.equal(undefined); 20 | expect(result.get('countryCode')).to.equal(undefined); 21 | expect(result.get('lat')).to.equal(undefined); 22 | expect(result.get('lng')).to.equal(undefined); 23 | done(); 24 | }); 25 | }); 26 | 27 | it('geolocates an IPv4 address', function(done) { 28 | var result = where.is('173.194.33.104', function(err, result) { 29 | expect(err).to.equal(null); 30 | expect(result.get('address')).to.equal('Mountain View, CA, 94043, US'); 31 | expect(result.get('streetNumber')).to.equal(undefined); 32 | expect(result.get('street')).to.equal(undefined); 33 | expect(result.get('streetAddress')).to.equal(undefined); 34 | expect(result.get('city')).to.equal('Mountain View'); 35 | expect(result.get('region')).to.equal('California'); 36 | expect(result.get('regionCode')).to.equal('CA'); 37 | expect(result.get('postalCode')).to.equal('94043'); 38 | expect(result.get('country')).to.equal('United States'); 39 | expect(result.get('countryCode')).to.equal('US'); 40 | expect(result.get('lat')).to.equal(37.4192); 41 | expect(result.get('lng')).to.equal(-122.0574); 42 | done(); 43 | }); 44 | }); 45 | 46 | it('geolocates a postal address', function(done) { 47 | var result = where.is('4 yawkey way boston ma', function(err, result) { 48 | expect(err).to.equal(null); 49 | expect(result.get('address')).to.equal('4 Yawkey Way, Boston, MA, 02215, US'); 50 | expect(result.get('streetNumber')).to.equal('4'); 51 | expect(result.get('street')).to.equal('Yawkey Way'); 52 | expect(result.get('streetAddress')).to.equal('4 Yawkey Way'); 53 | expect(result.get('city')).to.equal('Boston'); 54 | expect(result.get('region')).to.equal('Massachusetts'); 55 | expect(result.get('regionCode')).to.equal('MA'); 56 | expect(result.get('postalCode')).to.equal('02215'); 57 | expect(result.get('country')).to.equal('United States'); 58 | expect(result.get('countryCode')).to.equal('US'); 59 | expect(result.get('lat')).to.equal(42.34584359999999); 60 | expect(result.get('lng')).to.equal(-71.09878189999999); 61 | done(); 62 | }); 63 | }); 64 | 65 | it('geolocates a landmark', function(done) { 66 | var result = where.is('Fenway Park', function(err, result) { 67 | expect(err).to.equal(null); 68 | expect(result.get('address')).to.equal('4 Yawkey Way, Boston, MA, 02215, US'); 69 | expect(result.get('streetNumber')).to.equal('4'); 70 | expect(result.get('street')).to.equal('Yawkey Way'); 71 | expect(result.get('streetAddress')).to.equal('4 Yawkey Way'); 72 | expect(result.get('city')).to.equal('Boston'); 73 | expect(result.get('region')).to.equal('Massachusetts'); 74 | expect(result.get('regionCode')).to.equal('MA'); 75 | expect(result.get('postalCode')).to.equal('02215'); 76 | expect(result.get('country')).to.equal('United States'); 77 | expect(result.get('countryCode')).to.equal('US'); 78 | expect(result.get('lat')).to.equal(42.3466764); 79 | expect(result.get('lng')).to.equal(-71.0972178); 80 | done(); 81 | }); 82 | }); 83 | }); 84 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | ajv@^4.9.1: 6 | version "4.11.8" 7 | resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536" 8 | dependencies: 9 | co "^4.6.0" 10 | json-stable-stringify "^1.0.1" 11 | 12 | asn1@~0.2.3: 13 | version "0.2.3" 14 | resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" 15 | 16 | assert-plus@1.0.0, assert-plus@^1.0.0: 17 | version "1.0.0" 18 | resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" 19 | 20 | assert-plus@^0.2.0: 21 | version "0.2.0" 22 | resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" 23 | 24 | assertion-error@^1.0.1: 25 | version "1.0.2" 26 | resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.0.2.tgz#13ca515d86206da0bac66e834dd397d87581094c" 27 | 28 | asynckit@^0.4.0: 29 | version "0.4.0" 30 | resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" 31 | 32 | aws-sign2@~0.6.0: 33 | version "0.6.0" 34 | resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" 35 | 36 | aws4@^1.2.1: 37 | version "1.6.0" 38 | resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e" 39 | 40 | balanced-match@^0.4.1: 41 | version "0.4.2" 42 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" 43 | 44 | bcrypt-pbkdf@^1.0.0: 45 | version "1.0.1" 46 | resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d" 47 | dependencies: 48 | tweetnacl "^0.14.3" 49 | 50 | boom@2.x.x: 51 | version "2.10.1" 52 | resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" 53 | dependencies: 54 | hoek "2.x.x" 55 | 56 | brace-expansion@^1.1.7: 57 | version "1.1.7" 58 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.7.tgz#3effc3c50e000531fb720eaff80f0ae8ef23cf59" 59 | dependencies: 60 | balanced-match "^0.4.1" 61 | concat-map "0.0.1" 62 | 63 | browser-stdout@1.3.0: 64 | version "1.3.0" 65 | resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.0.tgz#f351d32969d32fa5d7a5567154263d928ae3bd1f" 66 | 67 | caseless@~0.12.0: 68 | version "0.12.0" 69 | resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" 70 | 71 | chai@^3.5.0: 72 | version "3.5.0" 73 | resolved "https://registry.yarnpkg.com/chai/-/chai-3.5.0.tgz#4d02637b067fe958bdbfdd3a40ec56fef7373247" 74 | dependencies: 75 | assertion-error "^1.0.1" 76 | deep-eql "^0.1.3" 77 | type-detect "^1.0.0" 78 | 79 | co@^4.6.0: 80 | version "4.6.0" 81 | resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" 82 | 83 | combined-stream@^1.0.5, combined-stream@~1.0.5: 84 | version "1.0.5" 85 | resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009" 86 | dependencies: 87 | delayed-stream "~1.0.0" 88 | 89 | commander@2.9.0: 90 | version "2.9.0" 91 | resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4" 92 | dependencies: 93 | graceful-readlink ">= 1.0.0" 94 | 95 | concat-map@0.0.1: 96 | version "0.0.1" 97 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 98 | 99 | cryptiles@2.x.x: 100 | version "2.0.5" 101 | resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" 102 | dependencies: 103 | boom "2.x.x" 104 | 105 | dashdash@^1.12.0: 106 | version "1.14.1" 107 | resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" 108 | dependencies: 109 | assert-plus "^1.0.0" 110 | 111 | debug@2.6.0: 112 | version "2.6.0" 113 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.0.tgz#bc596bcabe7617f11d9fa15361eded5608b8499b" 114 | dependencies: 115 | ms "0.7.2" 116 | 117 | deep-eql@^0.1.3: 118 | version "0.1.3" 119 | resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-0.1.3.tgz#ef558acab8de25206cd713906d74e56930eb69f2" 120 | dependencies: 121 | type-detect "0.1.1" 122 | 123 | delayed-stream@~1.0.0: 124 | version "1.0.0" 125 | resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" 126 | 127 | diff@3.2.0: 128 | version "3.2.0" 129 | resolved "https://registry.yarnpkg.com/diff/-/diff-3.2.0.tgz#c9ce393a4b7cbd0b058a725c93df299027868ff9" 130 | 131 | ecc-jsbn@~0.1.1: 132 | version "0.1.1" 133 | resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" 134 | dependencies: 135 | jsbn "~0.1.0" 136 | 137 | escape-string-regexp@1.0.5: 138 | version "1.0.5" 139 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" 140 | 141 | extend@~3.0.0: 142 | version "3.0.1" 143 | resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" 144 | 145 | extsprintf@1.0.2: 146 | version "1.0.2" 147 | resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.0.2.tgz#e1080e0658e300b06294990cc70e1502235fd550" 148 | 149 | forever-agent@~0.6.1: 150 | version "0.6.1" 151 | resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" 152 | 153 | form-data@~2.1.1: 154 | version "2.1.4" 155 | resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.4.tgz#33c183acf193276ecaa98143a69e94bfee1750d1" 156 | dependencies: 157 | asynckit "^0.4.0" 158 | combined-stream "^1.0.5" 159 | mime-types "^2.1.12" 160 | 161 | fs.realpath@^1.0.0: 162 | version "1.0.0" 163 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 164 | 165 | getpass@^0.1.1: 166 | version "0.1.7" 167 | resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" 168 | dependencies: 169 | assert-plus "^1.0.0" 170 | 171 | glob@7.1.1: 172 | version "7.1.1" 173 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" 174 | dependencies: 175 | fs.realpath "^1.0.0" 176 | inflight "^1.0.4" 177 | inherits "2" 178 | minimatch "^3.0.2" 179 | once "^1.3.0" 180 | path-is-absolute "^1.0.0" 181 | 182 | "graceful-readlink@>= 1.0.0": 183 | version "1.0.1" 184 | resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" 185 | 186 | growl@1.9.2: 187 | version "1.9.2" 188 | resolved "https://registry.yarnpkg.com/growl/-/growl-1.9.2.tgz#0ea7743715db8d8de2c5ede1775e1b45ac85c02f" 189 | 190 | har-schema@^1.0.5: 191 | version "1.0.5" 192 | resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e" 193 | 194 | har-validator@~4.2.1: 195 | version "4.2.1" 196 | resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-4.2.1.tgz#33481d0f1bbff600dd203d75812a6a5fba002e2a" 197 | dependencies: 198 | ajv "^4.9.1" 199 | har-schema "^1.0.5" 200 | 201 | has-flag@^1.0.0: 202 | version "1.0.0" 203 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" 204 | 205 | hawk@~3.1.3: 206 | version "3.1.3" 207 | resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" 208 | dependencies: 209 | boom "2.x.x" 210 | cryptiles "2.x.x" 211 | hoek "2.x.x" 212 | sntp "1.x.x" 213 | 214 | hoek@2.x.x: 215 | version "2.16.3" 216 | resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" 217 | 218 | http-signature@~1.1.0: 219 | version "1.1.1" 220 | resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" 221 | dependencies: 222 | assert-plus "^0.2.0" 223 | jsprim "^1.2.2" 224 | sshpk "^1.7.0" 225 | 226 | inflight@^1.0.4: 227 | version "1.0.6" 228 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 229 | dependencies: 230 | once "^1.3.0" 231 | wrappy "1" 232 | 233 | inherits@2: 234 | version "2.0.3" 235 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" 236 | 237 | is-typedarray@~1.0.0: 238 | version "1.0.0" 239 | resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" 240 | 241 | isstream@~0.1.2: 242 | version "0.1.2" 243 | resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" 244 | 245 | jodid25519@^1.0.0: 246 | version "1.0.2" 247 | resolved "https://registry.yarnpkg.com/jodid25519/-/jodid25519-1.0.2.tgz#06d4912255093419477d425633606e0e90782967" 248 | dependencies: 249 | jsbn "~0.1.0" 250 | 251 | jsbn@~0.1.0: 252 | version "0.1.1" 253 | resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" 254 | 255 | json-schema@0.2.3: 256 | version "0.2.3" 257 | resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" 258 | 259 | json-stable-stringify@^1.0.1: 260 | version "1.0.1" 261 | resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" 262 | dependencies: 263 | jsonify "~0.0.0" 264 | 265 | json-stringify-safe@~5.0.1: 266 | version "5.0.1" 267 | resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" 268 | 269 | json3@3.3.2: 270 | version "3.3.2" 271 | resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1" 272 | 273 | jsonify@~0.0.0: 274 | version "0.0.0" 275 | resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" 276 | 277 | jsprim@^1.2.2: 278 | version "1.4.0" 279 | resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.0.tgz#a3b87e40298d8c380552d8cc7628a0bb95a22918" 280 | dependencies: 281 | assert-plus "1.0.0" 282 | extsprintf "1.0.2" 283 | json-schema "0.2.3" 284 | verror "1.3.6" 285 | 286 | lodash._baseassign@^3.0.0: 287 | version "3.2.0" 288 | resolved "https://registry.yarnpkg.com/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz#8c38a099500f215ad09e59f1722fd0c52bfe0a4e" 289 | dependencies: 290 | lodash._basecopy "^3.0.0" 291 | lodash.keys "^3.0.0" 292 | 293 | lodash._basecopy@^3.0.0: 294 | version "3.0.1" 295 | resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36" 296 | 297 | lodash._basecreate@^3.0.0: 298 | version "3.0.3" 299 | resolved "https://registry.yarnpkg.com/lodash._basecreate/-/lodash._basecreate-3.0.3.tgz#1bc661614daa7fc311b7d03bf16806a0213cf821" 300 | 301 | lodash._getnative@^3.0.0: 302 | version "3.9.1" 303 | resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" 304 | 305 | lodash._isiterateecall@^3.0.0: 306 | version "3.0.9" 307 | resolved "https://registry.yarnpkg.com/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz#5203ad7ba425fae842460e696db9cf3e6aac057c" 308 | 309 | lodash.create@3.1.1: 310 | version "3.1.1" 311 | resolved "https://registry.yarnpkg.com/lodash.create/-/lodash.create-3.1.1.tgz#d7f2849f0dbda7e04682bb8cd72ab022461debe7" 312 | dependencies: 313 | lodash._baseassign "^3.0.0" 314 | lodash._basecreate "^3.0.0" 315 | lodash._isiterateecall "^3.0.0" 316 | 317 | lodash.isarguments@^3.0.0: 318 | version "3.1.0" 319 | resolved "https://registry.yarnpkg.com/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz#2f573d85c6a24289ff00663b491c1d338ff3458a" 320 | 321 | lodash.isarray@^3.0.0: 322 | version "3.0.4" 323 | resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" 324 | 325 | lodash.keys@^3.0.0: 326 | version "3.1.2" 327 | resolved "https://registry.yarnpkg.com/lodash.keys/-/lodash.keys-3.1.2.tgz#4dbc0472b156be50a0b286855d1bd0b0c656098a" 328 | dependencies: 329 | lodash._getnative "^3.0.0" 330 | lodash.isarguments "^3.0.0" 331 | lodash.isarray "^3.0.0" 332 | 333 | lodash@^4.17.4: 334 | version "4.17.4" 335 | resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" 336 | 337 | mime-db@~1.27.0: 338 | version "1.27.0" 339 | resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.27.0.tgz#820f572296bbd20ec25ed55e5b5de869e5436eb1" 340 | 341 | mime-types@^2.1.12, mime-types@~2.1.7: 342 | version "2.1.15" 343 | resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.15.tgz#a4ebf5064094569237b8cf70046776d09fc92aed" 344 | dependencies: 345 | mime-db "~1.27.0" 346 | 347 | minimatch@^3.0.2: 348 | version "3.0.4" 349 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" 350 | dependencies: 351 | brace-expansion "^1.1.7" 352 | 353 | minimist@0.0.8: 354 | version "0.0.8" 355 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" 356 | 357 | mkdirp@0.5.1: 358 | version "0.5.1" 359 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" 360 | dependencies: 361 | minimist "0.0.8" 362 | 363 | mocha@^3.4.1: 364 | version "3.4.2" 365 | resolved "https://registry.yarnpkg.com/mocha/-/mocha-3.4.2.tgz#d0ef4d332126dbf18d0d640c9b382dd48be97594" 366 | dependencies: 367 | browser-stdout "1.3.0" 368 | commander "2.9.0" 369 | debug "2.6.0" 370 | diff "3.2.0" 371 | escape-string-regexp "1.0.5" 372 | glob "7.1.1" 373 | growl "1.9.2" 374 | json3 "3.3.2" 375 | lodash.create "3.1.1" 376 | mkdirp "0.5.1" 377 | supports-color "3.1.2" 378 | 379 | ms@0.7.2: 380 | version "0.7.2" 381 | resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765" 382 | 383 | oauth-sign@~0.8.1: 384 | version "0.8.2" 385 | resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" 386 | 387 | once@^1.3.0: 388 | version "1.4.0" 389 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 390 | dependencies: 391 | wrappy "1" 392 | 393 | path-is-absolute@^1.0.0: 394 | version "1.0.1" 395 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 396 | 397 | performance-now@^0.2.0: 398 | version "0.2.0" 399 | resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5" 400 | 401 | punycode@^1.4.1: 402 | version "1.4.1" 403 | resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" 404 | 405 | qs@~6.4.0: 406 | version "6.4.0" 407 | resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" 408 | 409 | request@^2.81.0: 410 | version "2.81.0" 411 | resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0" 412 | dependencies: 413 | aws-sign2 "~0.6.0" 414 | aws4 "^1.2.1" 415 | caseless "~0.12.0" 416 | combined-stream "~1.0.5" 417 | extend "~3.0.0" 418 | forever-agent "~0.6.1" 419 | form-data "~2.1.1" 420 | har-validator "~4.2.1" 421 | hawk "~3.1.3" 422 | http-signature "~1.1.0" 423 | is-typedarray "~1.0.0" 424 | isstream "~0.1.2" 425 | json-stringify-safe "~5.0.1" 426 | mime-types "~2.1.7" 427 | oauth-sign "~0.8.1" 428 | performance-now "^0.2.0" 429 | qs "~6.4.0" 430 | safe-buffer "^5.0.1" 431 | stringstream "~0.0.4" 432 | tough-cookie "~2.3.0" 433 | tunnel-agent "^0.6.0" 434 | uuid "^3.0.0" 435 | 436 | safe-buffer@^5.0.1: 437 | version "5.0.1" 438 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.0.1.tgz#d263ca54696cd8a306b5ca6551e92de57918fbe7" 439 | 440 | sntp@1.x.x: 441 | version "1.0.9" 442 | resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" 443 | dependencies: 444 | hoek "2.x.x" 445 | 446 | sshpk@^1.7.0: 447 | version "1.13.0" 448 | resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.13.0.tgz#ff2a3e4fd04497555fed97b39a0fd82fafb3a33c" 449 | dependencies: 450 | asn1 "~0.2.3" 451 | assert-plus "^1.0.0" 452 | dashdash "^1.12.0" 453 | getpass "^0.1.1" 454 | optionalDependencies: 455 | bcrypt-pbkdf "^1.0.0" 456 | ecc-jsbn "~0.1.1" 457 | jodid25519 "^1.0.0" 458 | jsbn "~0.1.0" 459 | tweetnacl "~0.14.0" 460 | 461 | stringstream@~0.0.4: 462 | version "0.0.5" 463 | resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" 464 | 465 | supports-color@3.1.2: 466 | version "3.1.2" 467 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.1.2.tgz#72a262894d9d408b956ca05ff37b2ed8a6e2a2d5" 468 | dependencies: 469 | has-flag "^1.0.0" 470 | 471 | tough-cookie@~2.3.0: 472 | version "2.3.2" 473 | resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.2.tgz#f081f76e4c85720e6c37a5faced737150d84072a" 474 | dependencies: 475 | punycode "^1.4.1" 476 | 477 | tunnel-agent@^0.6.0: 478 | version "0.6.0" 479 | resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" 480 | dependencies: 481 | safe-buffer "^5.0.1" 482 | 483 | tweetnacl@^0.14.3, tweetnacl@~0.14.0: 484 | version "0.14.5" 485 | resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" 486 | 487 | type-detect@0.1.1: 488 | version "0.1.1" 489 | resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-0.1.1.tgz#0ba5ec2a885640e470ea4e8505971900dac58822" 490 | 491 | type-detect@^1.0.0: 492 | version "1.0.0" 493 | resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-1.0.0.tgz#762217cc06db258ec48908a1298e8b95121e8ea2" 494 | 495 | uuid@^3.0.0: 496 | version "3.0.1" 497 | resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.1.tgz#6544bba2dfda8c1cf17e629a3a305e2bb1fee6c1" 498 | 499 | validator@^7.0.0: 500 | version "7.0.0" 501 | resolved "https://registry.yarnpkg.com/validator/-/validator-7.0.0.tgz#c74deb8063512fac35547938e6f0b1504a282fd2" 502 | 503 | verror@1.3.6: 504 | version "1.3.6" 505 | resolved "https://registry.yarnpkg.com/verror/-/verror-1.3.6.tgz#cff5df12946d297d2baaefaa2689e25be01c005c" 506 | dependencies: 507 | extsprintf "1.0.2" 508 | 509 | wrappy@1: 510 | version "1.0.2" 511 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 512 | --------------------------------------------------------------------------------