├── .gitignore ├── lib ├── README ├── soda-js.js └── soda-js.bundle.js ├── .travis.yml ├── sample ├── basic_query.js ├── browser.html └── basic_producer.js ├── test ├── connection_tests.coffee ├── consumer_tests.coffee ├── producer_tests.coffee ├── query_tests.coffee └── operation_tests.coffee ├── package.json ├── README.textile ├── Cakefile └── src └── soda-js.coffee /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | *.swp 3 | *.swo 4 | node_modules/ 5 | -------------------------------------------------------------------------------- /lib/README: -------------------------------------------------------------------------------- 1 | this directory contains autogenerated files. do not edit them! edit the files in src/ instead. 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 0.8 4 | before_install: 5 | - npm install -g npm@'>=1.4.3' 6 | -------------------------------------------------------------------------------- /sample/basic_query.js: -------------------------------------------------------------------------------- 1 | var soda = require('../lib/soda-js'); 2 | 3 | var consumer = new soda.Consumer('open.whitehouse.gov'); 4 | 5 | consumer.query() 6 | .withDataset('p86s-ychb') 7 | .limit(5) 8 | .where({ namelast: 'SMITH' }) 9 | .order('namelast') 10 | .getRows() 11 | .on('success', function(rows) { console.log(rows); }) 12 | .on('error', function(error) { console.error(error); }); 13 | 14 | -------------------------------------------------------------------------------- /test/connection_tests.coffee: -------------------------------------------------------------------------------- 1 | 2 | soda = require('../lib/soda-js') 3 | 4 | module.exports = 5 | 6 | 'basic construction': (beforeExit, assert) -> 7 | connection = new soda._internal.Connection('opendata.socrata.com') 8 | assert.eql(connection.dataSite, 'opendata.socrata.com') 9 | 10 | 'failed construction': (beforeExit, assert) -> 11 | caught = false 12 | try 13 | connection = new soda._internal.Connection('http://data.cityofchicago.org') 14 | catch ex 15 | caught = true 16 | assert.ok(caught) -------------------------------------------------------------------------------- /test/consumer_tests.coffee: -------------------------------------------------------------------------------- 1 | 2 | soda = require('../lib/soda-js') 3 | 4 | module.exports = 5 | 'create consumer connection': (beforeExit, assert) -> 6 | consumer = new soda.Producer('data.seattle.gov') 7 | assert.ok(consumer.connection instanceof soda._internal.Connection) 8 | assert.eql(consumer.connection.dataSite, 'data.seattle.gov') 9 | 10 | 'create query': (beforeExit, assert) -> 11 | consumer = new soda.Consumer('data.seattle.gov') 12 | query = consumer.query() 13 | assert.ok(query instanceof soda._internal.Query) 14 | assert.eql(query.consumer, consumer) 15 | 16 | -------------------------------------------------------------------------------- /sample/browser.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | soda-js sample 6 | 7 | 8 | 9 | 21 | 22 | -------------------------------------------------------------------------------- /test/producer_tests.coffee: -------------------------------------------------------------------------------- 1 | 2 | soda = require('../lib/soda-js') 3 | 4 | module.exports = 5 | 'create producer connection': (beforeExit, assert) -> 6 | producer = new soda.Producer('data.seattle.gov') 7 | assert.ok(producer.connection instanceof soda._internal.Connection) 8 | assert.eql(producer.connection.dataSite, 'data.seattle.gov') 9 | 10 | 'create producer operation': (beforeExit, assert) -> 11 | producer = new soda.Producer('data.seattle.gov') 12 | operation = producer.operation() 13 | assert.ok(operation instanceof soda._internal.Operation) 14 | assert.eql(operation.producer, producer) -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "soda-js", 3 | "description": "js library for accessing a soda2 api", 4 | "homepage": "https://github.com/socrata/soda-js", 5 | "keywords": [ 6 | "socrata", 7 | "soda", 8 | "api", 9 | "opendata", 10 | "open data" 11 | ], 12 | "contributors": [ 13 | { 14 | "name": "Clint Tseng", 15 | "email": "clint.tseng@socrata.com" 16 | } 17 | ], 18 | "dependencies": { 19 | "eventemitter2": "~0.4.14", 20 | "superagent": "^3.7.0" 21 | }, 22 | "devDependencies": { 23 | "coffee-script": "~1.6.3", 24 | "expresso": "~0.9.2", 25 | "browserify": "^12.0.1" 26 | }, 27 | "licenses": [ 28 | { 29 | "type": "MIT" 30 | } 31 | ], 32 | "scripts": { 33 | "test": "node_modules/expresso/bin/expresso test/*", 34 | "coffee": "node_modules/coffee-script/bin/cake build", 35 | "bundle": "browserify lib/soda-js.js --standalone soda > lib/soda-js.bundle.js", 36 | "build": "npm run coffee && npm run bundle" 37 | }, 38 | "main": "./lib/soda-js.js", 39 | "version": "0.2.4" 40 | } 41 | -------------------------------------------------------------------------------- /sample/basic_producer.js: -------------------------------------------------------------------------------- 1 | var soda = require('../lib/soda-js'); 2 | 3 | var sodaOpts = { 4 | "username": "testuser@gmail.com", 5 | "password" : "OpenData", 6 | "apiToken" : "D8Atrg62F2j017ZTdkMpuZ9vY" 7 | } 8 | var producer = new soda.Producer('sandbox.demo.socrata.com', sodaOpts); 9 | 10 | 11 | var addSample = function() { 12 | var data = { 13 | mynum : 42, 14 | mytext: "hello world", 15 | mymoney: 999.99 16 | } 17 | 18 | console.log("Adding Sample") 19 | producer.operation() 20 | .withDataset('rphc-ayt9') 21 | .add(data) 22 | .on('success', function(row) { console.log(row); updateSample(row[':id']); }) 23 | .on('error', function(error) { console.error(error); }) 24 | } 25 | 26 | var updateSample = function(id) { 27 | var data = { mytext: "goodbye world" } 28 | 29 | console.log("\nUpdating Sample") 30 | producer.operation() 31 | .withDataset('rphc-ayt9') 32 | .update(id, data) 33 | .on('success', function(row) { console.log(row); deleteSample(row[':id']); }) 34 | .on('error', function(error) { console.error(error); }) 35 | } 36 | 37 | 38 | var deleteSample = function(id) { 39 | console.log("\nDeleting Sample") 40 | producer.operation() 41 | .withDataset('rphc-ayt9') 42 | .delete(id) 43 | .on('success', function(row) { console.log(row); }) 44 | .on('error', function(error) { console.error(error); }) 45 | } 46 | 47 | 48 | 49 | addSample(); -------------------------------------------------------------------------------- /README.textile: -------------------------------------------------------------------------------- 1 | h1. soda-js "!https://secure.travis-ci.org/socrata/soda-js.png!":http://travis-ci.org/socrata/soda-js 2 | 3 | A client implementation of the Socrata Open Data API in Coffeescript and Javascript. 4 | 5 | h2. Important Note 6 | 7 | In order to access the SODA API via HTTPS, clients must now "support the Server Name Indication (SNI)":https://dev.socrata.com/changelog/2016/08/24/sni-now-required-for-https-connections.html extension to the TLS protocol. What does this mean? It means that if you're using @soda-js@, you must use a JavaScript VM that supports SNI: 8 | 9 | * "Internet Explorer 7+":https://en.wikipedia.org/wiki/Server_Name_Indication#Support 10 | * "Mozilla Firefox 2+":https://en.wikipedia.org/wiki/Server_Name_Indication#Support 11 | * "Apple Safari (all versions)":https://en.wikipedia.org/wiki/Server_Name_Indication#Support 12 | * "Google Chrome 6.0+":https://en.wikipedia.org/wiki/Server_Name_Indication#Support 13 | * "node.js 0.5.3+":https://github.com/nodejs/node/blob/e1643ccc5a5ecf7cb779472d244459469c9971a1/doc/changelogs/CHANGELOG_ARCHIVE.md#20110801-version-053-unstable 14 | 15 | h2. Supported Operations 16 | 17 | Supports both consumer and producer API, but does not currently support creating datasets or the import workflow. 18 | 19 | h2. Usage 20 | 21 | See the @sample/@ directory for sample code, but here's the general idea: 22 | 23 | bc.. var soda = require('soda-js'); 24 | 25 | h3. Consumer API 26 | 27 | You can query a dataset by SODA2 clauses, or supply a custom SoQL query to be run. 28 | 29 | bc.. var consumer = new soda.Consumer('explore.data.gov'); 30 | 31 | consumer.query() 32 | .withDataset('644b-gaut') 33 | .limit(5) 34 | .where({ namelast: 'SMITH' }) 35 | .order('namelast') 36 | .getRows() 37 | .on('success', function(rows) { console.log(rows); }) 38 | .on('error', function(error) { console.error(error); }); 39 | 40 | p. Using 'like' in a where clause: 41 | 42 | bc.. .where("namelast like '%MITH'") 43 | 44 | h3. Producer API 45 | 46 | You can add, update, replace, delete, and upsert rows, as well as truncate a dataset. 47 | 48 | bc.. var producer = new soda.Producer('sandbox.demo.socrata.com', sodaConnectionOptions); 49 | 50 | var data = { mynum : 42, mytext: "hello world" } 51 | 52 | producer.operation() 53 | .withDataset('rphc-ayt9') 54 | .add(data) 55 | .on('success', function(row) { console.log(row); }) 56 | .on('error', function(error) { console.error(error); }) 57 | 58 | h2. License 59 | 60 | Provided under the MIT license. 61 | 62 | -------------------------------------------------------------------------------- /test/query_tests.coffee: -------------------------------------------------------------------------------- 1 | 2 | soda = require('../lib/soda-js') 3 | 4 | # fixture generator to allow injecting verifiers as networkers 5 | consumer = (verifier) -> 6 | connection: 7 | networker: ((opts) -> verifier(opts); -> null), 8 | emitterOpts: 9 | wildcard: true, 10 | delimiter: '.', 11 | maxListeners: 15 12 | 13 | # convenience func for using the above fixture with a query 14 | queryWith = (networker) -> new soda._internal.Query(consumer(networker)) 15 | 16 | module.exports = 17 | 18 | 'basic query': (beforeExit, assert) -> 19 | verifier = (opts) -> 20 | assert.eql(opts.path, '/resource/hospitals.json') 21 | 22 | queryWith(verifier) 23 | .withDataset('hospitals') 24 | .getRows() 25 | 26 | 'col select': (beforeExit, assert) -> 27 | verifier = (opts) -> 28 | assert.eql(opts.query, { $select: 'street, city, state, zip' }) 29 | 30 | queryWith(verifier) 31 | .withDataset('hospitals') 32 | .select('street', 'city', 'state', 'zip') 33 | .getRows() 34 | 35 | 'string expr': (beforeExit, assert) -> 36 | expr = soda.expr.eq('name', 'bob') 37 | assert.eql(expr, "name = 'bob'") 38 | 39 | 'number expr': (beforeExit, assert) -> 40 | expr = soda.expr.eq('age', 15) 41 | assert.eql(expr, "age = 15") 42 | 43 | 'compound expr': (beforeExit, assert) -> 44 | expr = soda.expr.and(soda.expr.eq('columnone', 1), soda.expr.eq('columntwo', 2)) 45 | assert.eql(expr, '(columnone = 1) and (columntwo = 2)') 46 | 47 | 'string where': (beforeExit, assert) -> 48 | verifier = (opts) -> 49 | assert.eql(opts.query, { $where: '(salary > 35000) and (yearsWorked >= 5)' }) 50 | 51 | queryWith(verifier) 52 | .withDataset('salaries') 53 | .where('salary > 35000', 'yearsWorked >= 5') 54 | .getRows() 55 | 56 | 'obj where': (beforeExit, assert) -> 57 | verifier = (opts) -> 58 | assert.eql(opts.query, { $where: "(firstname = 'abed') and (lastname = 'nadir')" }) 59 | 60 | queryWith(verifier) 61 | .withDataset('people') 62 | .where({ firstname: 'abed', lastname: 'nadir' }) 63 | .getRows() 64 | 65 | 'groupby': (beforeExit, assert) -> 66 | verifier = (opts) -> 67 | assert.eql(opts.query, { $group: 'department, type' }) 68 | 69 | queryWith(verifier) 70 | .withDataset('payments') 71 | .group('department', 'type') 72 | .getRows() 73 | 74 | 'having': (beforeExit, assert) -> 75 | # having is the same implementation as where, so just test a maxiquery 76 | verifier = (opts) -> 77 | assert.eql(opts.query, 78 | $group: 'firstname, lastname, total_salary', 79 | $having: "((firstname = 'jeff') or (lastname = 'winger')) and (total_salary > 100000)") 80 | 81 | queryWith(verifier) 82 | .withDataset('salaries') 83 | .group('firstname', 'lastname', 'total_salary') # of course in reality total_salary would be an aggr func.. 84 | .having(soda.expr.or(soda.expr.eq('firstname', 'jeff'), soda.expr.eq('lastname', 'winger')), 'total_salary > 100000') 85 | .getRows() 86 | 87 | 'orderby': (beforeExit, assert) -> 88 | verifier = (opts) -> 89 | assert.eql(opts.query, { $order: 'lastname asc, firstname desc' }) 90 | 91 | queryWith(verifier) 92 | .withDataset('salaries') 93 | .order('lastname', 'firstname desc') 94 | .getRows() 95 | 96 | 'offset and limit': (beforeExit, assert) -> 97 | verifier = (opts) -> 98 | assert.eql(opts.query, { $offset: 5, $limit: 10 }) 99 | 100 | queryWith(verifier) 101 | .withDataset('hospitals') 102 | .offset(5) 103 | .limit(10) 104 | .getRows() 105 | 106 | -------------------------------------------------------------------------------- /test/operation_tests.coffee: -------------------------------------------------------------------------------- 1 | 2 | soda = require('../lib/soda-js') 3 | 4 | # fixture generator to allow injecting verifiers as networkers 5 | producer = (verifier) -> 6 | connection: 7 | networker: ((opts, data) -> verifier(opts, data); -> null), 8 | emitterOpts: 9 | wildcard: true, 10 | delimiter: '.', 11 | maxListeners: 15 12 | 13 | 14 | # convenience func for using the above fixture with an operation 15 | operateWith = (networker) -> new soda._internal.Operation(producer(networker)) 16 | 17 | module.exports = 18 | 'basic add': (beforeExit, assert) -> 19 | verifier = (opts, data) -> 20 | assert.eql(opts.method, "post") 21 | assert.eql(opts.path, "/resource/abcd-1234") 22 | assert.eql(data, { hello: "world" }) 23 | 24 | operateWith(verifier) 25 | .withDataset('abcd-1234') 26 | .add( {hello: "world" }) 27 | 28 | 'multiple add': (beforeExit, assert) -> 29 | verifier = (opts, data) -> 30 | assert.eql(opts.method, "post") 31 | assert.eql(opts.path, "/resource/abcd-1234") 32 | assert.eql(data.length, 3) 33 | 34 | operateWith(verifier) 35 | .withDataset('abcd-1234') 36 | .add( [{col:"a"}, {col:"b"}, {col:"c"}] ) 37 | 38 | 'add prevents upsert of object': (beforeExit, assert) -> 39 | verifier = (opts, data) -> 40 | assert.eql(opts.method, "post") 41 | assert.eql(opts.path, "/resource/abcd-1234") 42 | assert.eql(data, { col: "c" }) 43 | 44 | operateWith(verifier) 45 | .withDataset('abcd-1234') 46 | .add( { ":id": 3, ":delete": true, col:"c"} ) 47 | 48 | 'add prevents upsert of array': (beforeExit, assert) -> 49 | verifier = (opts, data) -> 50 | assert.eql(opts.method, "post") 51 | assert.eql(opts.path, "/resource/abcd-1234") 52 | assert.eql(data, [ 53 | {col:"a"}, 54 | {col:"b"}, 55 | {col:"c"}, 56 | {col:"d"} 57 | ]) 58 | 59 | operateWith(verifier) 60 | .withDataset('abcd-1234') 61 | .add([ 62 | { ":id": 1, col: "a"}, 63 | { col: "b", ":delete": true }, 64 | { ":id": 3, ":delete": true, col:"c"}, 65 | { col: "d" } 66 | ]) 67 | 68 | 69 | 'upsert array': (beforeExit, assert) -> 70 | verifier = (opts, data) -> 71 | assert.eql(opts.method, "post") 72 | assert.eql(opts.path, "/resource/abcd-1234") 73 | assert.eql(data, [ 74 | { col: "a", ":id": 1}, 75 | { col: "b", ":delete": true }, 76 | { col: "c", ":id": 3, ":delete": true }, 77 | { col: "d" } 78 | ]) 79 | 80 | operateWith(verifier) 81 | .withDataset('abcd-1234') 82 | .upsert([ 83 | { ":id": 1, col: "a"}, 84 | { col: "b", ":delete": true }, 85 | { ":id": 3, ":delete": true, col:"c"}, 86 | { col: "d" } 87 | ]) 88 | 89 | 'basic truncate': (beforeExit, assert) -> 90 | verifier = (opts, data) -> 91 | assert.eql(opts.method, "delete") 92 | assert.eql(opts.path, "/resource/lmno-9876") 93 | assert.isUndefined(data) 94 | 95 | operateWith(verifier) 96 | .withDataset('lmno-9876') 97 | .truncate() 98 | 99 | 'basic delete': (beforeExit, assert) -> 100 | verifier = (opts, data) -> 101 | assert.eql(opts.method, "delete") 102 | assert.eql(opts.path, "/resource/lmno-9876/123") 103 | assert.isUndefined(data) 104 | 105 | operateWith(verifier) 106 | .withDataset('lmno-9876') 107 | .delete(123) 108 | 109 | 'basic update': (beforeExit, assert) -> 110 | verifier = (opts, data) -> 111 | assert.eql(opts.method, "post") # seriously, why isn't this patch? 112 | assert.eql(opts.path, "/resource/lmno-9876/123") 113 | assert.eql(data, { num : 987 }) 114 | 115 | operateWith(verifier) 116 | .withDataset("lmno-9876") 117 | .update(123, { num : 987 }) 118 | 119 | 'basic replace': (beforeExit, assert) -> 120 | verifier = (opts, data) -> 121 | assert.eql(opts.method, "put") 122 | assert.eql(opts.path, "/resource/lmno-1234/987") 123 | assert.eql(data, { num : 456 }) 124 | 125 | operateWith(verifier) 126 | .withDataset("lmno-1234") 127 | .replace(987, { num : 456 }) 128 | 129 | -------------------------------------------------------------------------------- /Cakefile: -------------------------------------------------------------------------------- 1 | # Taken almost entirely from https://github.com/twilson63/cakefile-template 2 | # 3 | # Il y a 5 tasks: 4 | # 5 | # * build - compiles your src directory to your lib directory 6 | # * watch - watches any changes in your src directory and automatically compiles to the lib directory 7 | # * test - runs mocha test framework, you can edit this task to use your favorite test framework 8 | # * docs - generates annotated documentation using docco 9 | # * clean - clean generated .js files 10 | files = [ 11 | 'lib' 12 | 'src' 13 | ] 14 | 15 | fs = require 'fs' 16 | {print} = require 'util' 17 | {spawn, exec} = require 'child_process' 18 | 19 | try 20 | which = require('which').sync 21 | catch err 22 | which = null 23 | 24 | # ANSI Terminal Colors 25 | bold = '\x1b[0;1m' 26 | green = '\x1b[0;32m' 27 | reset = '\x1b[0m' 28 | red = '\x1b[0;31m' 29 | 30 | # Cakefile Tasks 31 | # 32 | # ## *docs* 33 | # 34 | # Generate Annotated Documentation 35 | # 36 | # Usage 37 | # 38 | # ``` 39 | # cake docs 40 | # ``` 41 | task 'docs', 'generate documentation', -> docco() 42 | 43 | # ## *build* 44 | # 45 | # Builds Source 46 | # 47 | # Usage 48 | # 49 | # ``` 50 | # cake build 51 | # ``` 52 | task 'build', 'compile source', -> build -> log ":)", green 53 | 54 | # ## *watch* 55 | # 56 | # Builds your source whenever it changes 57 | # 58 | # Usage 59 | # 60 | # ``` 61 | # cake watch 62 | # ``` 63 | task 'watch', 'compile and watch', -> build true, -> log ":-)", green 64 | 65 | # ## *test* 66 | # 67 | # Runs your test suite. 68 | # 69 | # Usage 70 | # 71 | # ``` 72 | # cake test 73 | # ``` 74 | task 'test', 'run tests', -> build -> expresso [ 'test/*' ], -> log ":)", green 75 | 76 | # ## *clean* 77 | # 78 | # Cleans up generated js files 79 | # 80 | # Ussage 81 | # 82 | # ``` 83 | # cake clean 84 | # ``` 85 | task 'clean', 'clean generated files', -> clean -> log ";)", green 86 | 87 | 88 | # Internal Functions 89 | # 90 | # ## *walk* 91 | # 92 | # **given** string as dir which represents a directory in relation to local directory 93 | # **and** callback as done in the form of (err, results) 94 | # **then** recurse through directory returning an array of files 95 | walk = (dir, done) -> 96 | results = [] 97 | fs.readdir dir, (err, list) -> 98 | return done(err, []) if err 99 | pending = list.length 100 | return done(null, results) unless pending 101 | for name in list 102 | file = "#{dir}/#{name}" 103 | try 104 | stat = fs.statSync file 105 | catch err 106 | stat = null 107 | if stat?.isDirectory() 108 | walk file, (err, res) -> 109 | results.push name for name in res 110 | done(null, results) unless --pending 111 | else 112 | results.push file 113 | done(null, results) unless --pending 114 | 115 | # ## *log* 116 | # 117 | # **given** string as a message 118 | # **and** string as a color 119 | # **and** optional string as an explaination 120 | # **then** builds a statement and logs to console. 121 | log = (message, color, explanation) -> console.log color + message + reset + ' ' + (explanation or '') 122 | 123 | # ## *launch* 124 | # 125 | # **given** string as a cmd 126 | # **and** optional array and option flags 127 | # **and** optional callback 128 | # **then** spawn cmd with options 129 | # **and** pipe to process stdout and stderr respectively 130 | # **and** on child process exit emit callback if set and status is 0 131 | launch = (cmd, options=[], callback) -> 132 | cmd = which(cmd) if which 133 | app = spawn cmd, options 134 | app.stdout.pipe(process.stdout) 135 | app.stderr.pipe(process.stderr) 136 | app.on 'exit', (status) -> callback?() if status is 0 137 | 138 | # ## *build* 139 | # 140 | # **given** optional boolean as watch 141 | # **and** optional function as callback 142 | # **then** invoke launch passing coffee command 143 | # **and** defaulted options to compile src to lib 144 | build = (watch, callback) -> 145 | if typeof watch is 'function' 146 | callback = watch 147 | watch = false 148 | 149 | options = ['-c', '-b', '-o' ] 150 | options = options.concat files 151 | options.unshift '-w' if watch 152 | launch 'coffee', options, callback 153 | 154 | # ## *unlinkIfCoffeeFile* 155 | # 156 | # **given** string as file 157 | # **and** file ends in '.coffee' 158 | # **then** convert '.coffee' to '.js' 159 | # **and** remove the result 160 | unlinkIfCoffeeFile = (file) -> 161 | if file.match /\.coffee$/ 162 | fs.unlink file.replace(/\.coffee$/, '.js') 163 | true 164 | else false 165 | 166 | # ## *clean* 167 | # 168 | # **given** optional function as callback 169 | # **then** loop through files variable 170 | # **and** call unlinkIfCoffeeFile on each 171 | clean = (callback) -> 172 | try 173 | for file in files 174 | unless unlinkIfCoffeeFile file 175 | walk file, (err, results) -> 176 | for f in results 177 | unlinkIfCoffeeFile f 178 | 179 | callback?() 180 | catch err 181 | 182 | # ## *moduleExists* 183 | # 184 | # **given** name for module 185 | # **when** trying to require module 186 | # **and** not found 187 | # **then* print not found message with install helper in red 188 | # **and* return false if not found 189 | moduleExists = (name) -> 190 | try 191 | require name 192 | catch err 193 | log "#{name} required: npm install #{name}", red 194 | false 195 | 196 | 197 | # ## *expresso* 198 | # 199 | # **given** optional array of option flags 200 | # **and** optional function as callback 201 | # **then** invoke launch passing expresso command 202 | expresso = (options, callback) -> 203 | if typeof options is 'function' 204 | callback = options 205 | options = [] 206 | 207 | launch './node_modules/expresso/bin/expresso', options, callback 208 | 209 | # ## *docco* 210 | # 211 | # **given** optional function as callback 212 | # **then** invoke launch passing docco command 213 | docco = (callback) -> 214 | #if moduleExists('docco') 215 | walk 'src', (err, files) -> launch 'docco', files, callback 216 | 217 | -------------------------------------------------------------------------------- /src/soda-js.coffee: -------------------------------------------------------------------------------- 1 | # soda.coffee -- chained, evented, buzzworded library for accessing SODA via JS. 2 | 3 | # sodaOpts options: 4 | # username: https basic auth username 5 | # password: https basic auth password 6 | # apiToken: socrata api token 7 | # 8 | # emitterOpts: options to override EventEmitter2 declaration options 9 | 10 | # TODO: 11 | # * we're inconsistent about validating query correctness. do we continue with catch-what-we-can, 12 | # or do we just back off and leave all failures to the api to return? 13 | 14 | eelib = require('eventemitter2') 15 | EventEmitter = eelib.EventEmitter2 || eelib 16 | httpClient = require('superagent') 17 | 18 | # internal util funcs 19 | isString = (obj) -> typeof obj == 'string' 20 | isArray = (obj) -> Array.isArray(obj) 21 | isNumber = (obj) -> !isNaN(parseFloat(obj)) 22 | extend = (target, sources...) -> (target[k] = v for k, v of source) for source in sources; null 23 | 24 | # it's really, really, really stupid that i have to solve this problem here 25 | toBase64 = 26 | if Buffer? 27 | (str) -> new Buffer(str).toString('base64') 28 | else 29 | # adapted/modified from https://github.com/rwz/base64.coffee 30 | base64Lookup = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='.split('') 31 | rawToBase64 = btoa ? (str) -> 32 | result = [] 33 | i = 0 34 | while i < str.length 35 | chr1 = str.charCodeAt(i++) 36 | chr2 = str.charCodeAt(i++) 37 | chr3 = str.charCodeAt(i++) 38 | throw new Error('Invalid character!') if Math.max(chr1, chr2, chr3) > 0xFF 39 | 40 | enc1 = chr1 >> 2 41 | enc2 = ((chr1 & 3) << 4) | (chr2 >> 4) 42 | enc3 = ((chr2 & 15) << 2) | (chr3 >> 6) 43 | enc4 = chr3 & 63 44 | 45 | if isNaN(chr2) 46 | enc3 = enc4 = 64 47 | else if isNaN(chr3) 48 | enc4 = 64 49 | 50 | result.push(base64Lookup[enc1]) 51 | result.push(base64Lookup[enc2]) 52 | result.push(base64Lookup[enc3]) 53 | result.push(base64Lookup[enc4]) 54 | result.join('') 55 | (str) -> rawToBase64(unescape(encodeURIComponent(str))) 56 | 57 | handleLiteral = (literal) -> 58 | if isString(literal) 59 | "'#{literal}'" 60 | else if isNumber(literal) 61 | # TODO: possibly ensure number cleanliness for sending to the api? sci not? 62 | literal 63 | else 64 | literal 65 | 66 | handleOrder = (order) -> 67 | if /( asc$| desc$)/i.test(order) 68 | order 69 | else 70 | order + ' asc' 71 | 72 | addExpr = (target, args) -> 73 | for arg in args 74 | if isString(arg) 75 | target.push(arg) 76 | else 77 | target.push("#{k} = #{handleLiteral(v)}") for k, v of arg 78 | 79 | # extern util funcs 80 | 81 | # convenience functions for building where clauses, if so desired 82 | expr = 83 | and: (clauses...) -> ("(#{clause})" for clause in clauses).join(' and ') 84 | or: (clauses...) -> ("(#{clause})" for clause in clauses).join(' or ') 85 | 86 | gt: (column, literal) -> "#{column} > #{handleLiteral(literal)}" 87 | gte: (column, literal) -> "#{column} >= #{handleLiteral(literal)}" 88 | lt: (column, literal) -> "#{column} < #{handleLiteral(literal)}" 89 | lte: (column, literal) -> "#{column} <= #{handleLiteral(literal)}" 90 | eq: (column, literal) -> "#{column} = #{handleLiteral(literal)}" 91 | 92 | # serialize object to querystring 93 | toQuerystring = (obj) -> 94 | str = [] 95 | for own key, val of obj 96 | str.push encodeURIComponent(key) + '=' + encodeURIComponent(val) 97 | str.join '&' 98 | 99 | class Connection 100 | constructor: (@dataSite, @sodaOpts = {}) -> 101 | throw new Error('dataSite does not appear to be valid! Please supply a domain name, eg data.seattle.gov') unless /^[a-z0-9-_.]+(:[0-9]+)?$/i.test(@dataSite) 102 | 103 | # options passed directly into EventEmitter2 construction 104 | @emitterOpts = @sodaOpts.emitterOpts ? 105 | wildcard: true, 106 | delimiter: '.', 107 | maxListeners: 15 108 | 109 | @networker = (opts, data) -> 110 | url = "https://#{@dataSite}#{opts.path}" 111 | 112 | client = httpClient(opts.method, url) 113 | 114 | client.set('Accept', "application/json") if data? 115 | client.set('Content-type', "application/json") if data? 116 | client.set('X-App-Token', @sodaOpts.apiToken) if @sodaOpts.apiToken? 117 | client.set('Authorization', "Basic " + toBase64("#{@sodaOpts.username}:#{@sodaOpts.password}")) if @sodaOpts.username? and @sodaOpts.password? 118 | client.set('Authorization', "OAuth " + accessToken) if @sodaOpts.accessToken? 119 | 120 | client.query(opts.query) if opts.query? 121 | client.send(data) if data? 122 | 123 | (responseHandler) => client.end(responseHandler || @getDefaultHandler()) 124 | 125 | getDefaultHandler: -> 126 | # instance variable for easy chaining 127 | @emitter = emitter = new EventEmitter(@emitterOpts) 128 | 129 | # return the handler 130 | handler = (error, response) -> 131 | # TODO: possibly more granular handling? 132 | if response.ok 133 | if response.accepted 134 | # handle 202 by remaking request. inform of possible progress. 135 | emitter.emit('progress', response.body) 136 | setTimeout((-> @consumer.networker(opts)(handler)), 5000) 137 | else 138 | emitter.emit('success', response.body) 139 | else 140 | emitter.emit('error', response.body ? response.text) 141 | 142 | # just emit the raw superagent obj if they just want complete event 143 | emitter.emit('complete', response) 144 | 145 | 146 | 147 | 148 | # main class 149 | class Consumer 150 | constructor: (@dataSite, @sodaOpts = {}) -> 151 | @connection = new Connection(@dataSite, @sodaOpts) 152 | 153 | query: -> 154 | new Query(this) 155 | 156 | getDataset: (id) -> 157 | emitter = new EventEmitter(@emitterOpts) 158 | # TODO: implement me 159 | 160 | # Producer class 161 | class Producer 162 | constructor: (@dataSite, @sodaOpts = {}) -> 163 | @connection = new Connection(@dataSite, @sodaOpts) 164 | 165 | operation: -> 166 | new Operation(this) 167 | 168 | class Operation 169 | constructor: (@producer) -> 170 | 171 | withDataset: (datasetId) -> @_datasetId = datasetId; this 172 | 173 | # truncate the entire dataset 174 | truncate: -> 175 | opts = method: 'delete' 176 | opts.path = "/resource/#{@_datasetId}" 177 | this._exec(opts) 178 | 179 | # add a new row - explicitly avoids upserting (updating/deleting existing rows) 180 | add: (data) -> 181 | opts = method: 'post' 182 | opts.path = "/resource/#{@_datasetId}" 183 | 184 | _data = JSON.parse(JSON.stringify(data)) 185 | delete _data[':id'] 186 | delete _data[':delete'] 187 | for obj in _data 188 | delete obj[':id'] 189 | delete obj[':delete'] 190 | 191 | this._exec(opts, _data) 192 | 193 | # modify existing rows 194 | delete: (id) -> 195 | opts = method: 'delete' 196 | opts.path = "/resource/#{@_datasetId}/#{id}" 197 | this._exec(opts) 198 | update: (id, data) -> 199 | opts = method: 'post' 200 | opts.path = "/resource/#{@_datasetId}/#{id}" 201 | this._exec(opts, data) 202 | replace: (id, data) -> 203 | opts = method: 'put' 204 | opts.path = "/resource/#{@_datasetId}/#{id}" 205 | this._exec(opts, data) 206 | 207 | # add objects, update if existing, delete if :delete=true 208 | upsert: (data) -> 209 | opts = method: 'post' 210 | opts.path = "/resource/#{@_datasetId}" 211 | this._exec(opts, data) 212 | 213 | _exec: (opts, data) -> 214 | throw new Error('no dataset given to work against!') unless @_datasetId? 215 | @producer.connection.networker(opts, data)() 216 | @producer.connection.emitter 217 | 218 | 219 | # querybuilder class 220 | class Query 221 | constructor: (@consumer) -> 222 | @_select = [] 223 | @_where = [] 224 | @_group = [] 225 | @_having = [] 226 | @_order = [] 227 | @_offset = @_limit = @_q = null 228 | 229 | withDataset: (datasetId) -> @_datasetId = datasetId; this 230 | 231 | # for passing in a fully formed soql query. all other params will be ignored 232 | soql: (query) -> @_soql = query; this 233 | 234 | select: (selects...) -> @_select.push(select) for select in selects; this 235 | 236 | # args: ('clause', [...]) 237 | # ({ column: value1, columnb: value2 }, [...]]) 238 | # multiple calls are assumed to be and-chained 239 | where: (args...) -> addExpr(@_where, args); this 240 | having: (args...) -> addExpr(@_having, args); this 241 | 242 | group: (groups...) -> @_group.push(group) for group in groups; this 243 | 244 | # args: ("column direction", ["column direction", [...]]) 245 | order: (orders...) -> @_order.push(handleOrder(order)) for order in orders; this 246 | 247 | offset: (offset) -> @_offset = offset; this 248 | 249 | limit: (limit) -> @_limit = limit; this 250 | 251 | q: (q) -> @_q = q; this 252 | 253 | getOpts: -> 254 | opts = method: 'get' 255 | 256 | throw new Error('no dataset given to work against!') unless @_datasetId? 257 | opts.path = "/resource/#{@_datasetId}.json" 258 | 259 | queryComponents = this._buildQueryComponents() 260 | opts.query = {} 261 | opts.query['$' + k] = v for k, v of queryComponents 262 | 263 | opts 264 | 265 | getURL: -> 266 | opts = this.getOpts() 267 | query = toQuerystring(opts.query) 268 | 269 | "https://#{@consumer.dataSite}#{opts.path}" + (if query then "?#{query}" else "") 270 | 271 | getRows: -> 272 | opts = this.getOpts() 273 | 274 | @consumer.connection.networker(opts)() 275 | @consumer.connection.emitter 276 | 277 | _buildQueryComponents: -> 278 | query = {} 279 | 280 | if @_soql? 281 | query.query = @_soql 282 | else 283 | query.select = @_select.join(', ') if @_select.length > 0 284 | 285 | query.where = expr.and.apply(this, @_where) if @_where.length > 0 286 | 287 | query.group = @_group.join(', ') if @_group.length > 0 288 | 289 | if @_having.length > 0 290 | throw new Error('Having provided without group by!') unless @_group.length > 0 291 | query.having = expr.and.apply(this, @_having) 292 | 293 | query.order = @_order.join(', ') if @_order.length > 0 294 | 295 | query.offset = @_offset if isNumber(@_offset) 296 | query.limit = @_limit if isNumber(@_limit) 297 | 298 | query.q = @_q if @_q 299 | 300 | query 301 | 302 | class Dataset 303 | constructor: (@data, @client) -> 304 | # TODO: implement me 305 | 306 | extend(exports ? this.soda, 307 | Consumer: Consumer, 308 | Producer: Producer, 309 | expr: expr, 310 | 311 | # exported for testing reasons 312 | _internal: 313 | Connection: Connection, 314 | Query: Query, 315 | Operation: Operation, 316 | util: 317 | toBase64: toBase64, 318 | handleLiteral: handleLiteral, 319 | handleOrder: handleOrder 320 | ) 321 | 322 | -------------------------------------------------------------------------------- /lib/soda-js.js: -------------------------------------------------------------------------------- 1 | // Generated by CoffeeScript 1.6.3 2 | var Connection, Consumer, Dataset, EventEmitter, Operation, Producer, Query, addExpr, base64Lookup, eelib, expr, extend, handleLiteral, handleOrder, httpClient, isArray, isNumber, isString, rawToBase64, toBase64, toQuerystring, 3 | __slice = [].slice, 4 | __hasProp = {}.hasOwnProperty; 5 | 6 | eelib = require('eventemitter2'); 7 | 8 | EventEmitter = eelib.EventEmitter2 || eelib; 9 | 10 | httpClient = require('superagent'); 11 | 12 | isString = function(obj) { 13 | return typeof obj === 'string'; 14 | }; 15 | 16 | isArray = function(obj) { 17 | return Array.isArray(obj); 18 | }; 19 | 20 | isNumber = function(obj) { 21 | return !isNaN(parseFloat(obj)); 22 | }; 23 | 24 | extend = function() { 25 | var k, source, sources, target, v, _i, _len; 26 | target = arguments[0], sources = 2 <= arguments.length ? __slice.call(arguments, 1) : []; 27 | for (_i = 0, _len = sources.length; _i < _len; _i++) { 28 | source = sources[_i]; 29 | for (k in source) { 30 | v = source[k]; 31 | target[k] = v; 32 | } 33 | } 34 | return null; 35 | }; 36 | 37 | toBase64 = typeof Buffer !== "undefined" && Buffer !== null ? function(str) { 38 | return new Buffer(str).toString('base64'); 39 | } : (base64Lookup = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='.split(''), rawToBase64 = typeof btoa !== "undefined" && btoa !== null ? btoa : function(str) { 40 | var chr1, chr2, chr3, enc1, enc2, enc3, enc4, i, result; 41 | result = []; 42 | i = 0; 43 | while (i < str.length) { 44 | chr1 = str.charCodeAt(i++); 45 | chr2 = str.charCodeAt(i++); 46 | chr3 = str.charCodeAt(i++); 47 | if (Math.max(chr1, chr2, chr3) > 0xFF) { 48 | throw new Error('Invalid character!'); 49 | } 50 | enc1 = chr1 >> 2; 51 | enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); 52 | enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); 53 | enc4 = chr3 & 63; 54 | if (isNaN(chr2)) { 55 | enc3 = enc4 = 64; 56 | } else if (isNaN(chr3)) { 57 | enc4 = 64; 58 | } 59 | result.push(base64Lookup[enc1]); 60 | result.push(base64Lookup[enc2]); 61 | result.push(base64Lookup[enc3]); 62 | result.push(base64Lookup[enc4]); 63 | } 64 | return result.join(''); 65 | }, function(str) { 66 | return rawToBase64(unescape(encodeURIComponent(str))); 67 | }); 68 | 69 | handleLiteral = function(literal) { 70 | if (isString(literal)) { 71 | return "'" + literal + "'"; 72 | } else if (isNumber(literal)) { 73 | return literal; 74 | } else { 75 | return literal; 76 | } 77 | }; 78 | 79 | handleOrder = function(order) { 80 | if (/( asc$| desc$)/i.test(order)) { 81 | return order; 82 | } else { 83 | return order + ' asc'; 84 | } 85 | }; 86 | 87 | addExpr = function(target, args) { 88 | var arg, k, v, _i, _len, _results; 89 | _results = []; 90 | for (_i = 0, _len = args.length; _i < _len; _i++) { 91 | arg = args[_i]; 92 | if (isString(arg)) { 93 | _results.push(target.push(arg)); 94 | } else { 95 | _results.push((function() { 96 | var _results1; 97 | _results1 = []; 98 | for (k in arg) { 99 | v = arg[k]; 100 | _results1.push(target.push("" + k + " = " + (handleLiteral(v)))); 101 | } 102 | return _results1; 103 | })()); 104 | } 105 | } 106 | return _results; 107 | }; 108 | 109 | expr = { 110 | and: function() { 111 | var clause, clauses; 112 | clauses = 1 <= arguments.length ? __slice.call(arguments, 0) : []; 113 | return ((function() { 114 | var _i, _len, _results; 115 | _results = []; 116 | for (_i = 0, _len = clauses.length; _i < _len; _i++) { 117 | clause = clauses[_i]; 118 | _results.push("(" + clause + ")"); 119 | } 120 | return _results; 121 | })()).join(' and '); 122 | }, 123 | or: function() { 124 | var clause, clauses; 125 | clauses = 1 <= arguments.length ? __slice.call(arguments, 0) : []; 126 | return ((function() { 127 | var _i, _len, _results; 128 | _results = []; 129 | for (_i = 0, _len = clauses.length; _i < _len; _i++) { 130 | clause = clauses[_i]; 131 | _results.push("(" + clause + ")"); 132 | } 133 | return _results; 134 | })()).join(' or '); 135 | }, 136 | gt: function(column, literal) { 137 | return "" + column + " > " + (handleLiteral(literal)); 138 | }, 139 | gte: function(column, literal) { 140 | return "" + column + " >= " + (handleLiteral(literal)); 141 | }, 142 | lt: function(column, literal) { 143 | return "" + column + " < " + (handleLiteral(literal)); 144 | }, 145 | lte: function(column, literal) { 146 | return "" + column + " <= " + (handleLiteral(literal)); 147 | }, 148 | eq: function(column, literal) { 149 | return "" + column + " = " + (handleLiteral(literal)); 150 | } 151 | }; 152 | 153 | toQuerystring = function(obj) { 154 | var key, str, val; 155 | str = []; 156 | for (key in obj) { 157 | if (!__hasProp.call(obj, key)) continue; 158 | val = obj[key]; 159 | str.push(encodeURIComponent(key) + '=' + encodeURIComponent(val)); 160 | } 161 | return str.join('&'); 162 | }; 163 | 164 | Connection = (function() { 165 | function Connection(dataSite, sodaOpts) { 166 | var _ref; 167 | this.dataSite = dataSite; 168 | this.sodaOpts = sodaOpts != null ? sodaOpts : {}; 169 | if (!/^[a-z0-9-_.]+(:[0-9]+)?$/i.test(this.dataSite)) { 170 | throw new Error('dataSite does not appear to be valid! Please supply a domain name, eg data.seattle.gov'); 171 | } 172 | this.emitterOpts = (_ref = this.sodaOpts.emitterOpts) != null ? _ref : { 173 | wildcard: true, 174 | delimiter: '.', 175 | maxListeners: 15 176 | }; 177 | this.networker = function(opts, data) { 178 | var client, url, 179 | _this = this; 180 | url = "https://" + this.dataSite + opts.path; 181 | client = httpClient(opts.method, url); 182 | if (data != null) { 183 | client.set('Accept', "application/json"); 184 | } 185 | if (data != null) { 186 | client.set('Content-type', "application/json"); 187 | } 188 | if (this.sodaOpts.apiToken != null) { 189 | client.set('X-App-Token', this.sodaOpts.apiToken); 190 | } 191 | if ((this.sodaOpts.username != null) && (this.sodaOpts.password != null)) { 192 | client.set('Authorization', "Basic " + toBase64("" + this.sodaOpts.username + ":" + this.sodaOpts.password)); 193 | } 194 | if (this.sodaOpts.accessToken != null) { 195 | client.set('Authorization', "OAuth " + accessToken); 196 | } 197 | if (opts.query != null) { 198 | client.query(opts.query); 199 | } 200 | if (data != null) { 201 | client.send(data); 202 | } 203 | return function(responseHandler) { 204 | return client.end(responseHandler || _this.getDefaultHandler()); 205 | }; 206 | }; 207 | } 208 | 209 | Connection.prototype.getDefaultHandler = function() { 210 | var emitter, handler; 211 | this.emitter = emitter = new EventEmitter(this.emitterOpts); 212 | return handler = function(error, response) { 213 | var _ref; 214 | if (response.ok) { 215 | if (response.accepted) { 216 | emitter.emit('progress', response.body); 217 | setTimeout((function() { 218 | return this.consumer.networker(opts)(handler); 219 | }), 5000); 220 | } else { 221 | emitter.emit('success', response.body); 222 | } 223 | } else { 224 | emitter.emit('error', (_ref = response.body) != null ? _ref : response.text); 225 | } 226 | return emitter.emit('complete', response); 227 | }; 228 | }; 229 | 230 | return Connection; 231 | 232 | })(); 233 | 234 | Consumer = (function() { 235 | function Consumer(dataSite, sodaOpts) { 236 | this.dataSite = dataSite; 237 | this.sodaOpts = sodaOpts != null ? sodaOpts : {}; 238 | this.connection = new Connection(this.dataSite, this.sodaOpts); 239 | } 240 | 241 | Consumer.prototype.query = function() { 242 | return new Query(this); 243 | }; 244 | 245 | Consumer.prototype.getDataset = function(id) { 246 | var emitter; 247 | return emitter = new EventEmitter(this.emitterOpts); 248 | }; 249 | 250 | return Consumer; 251 | 252 | })(); 253 | 254 | Producer = (function() { 255 | function Producer(dataSite, sodaOpts) { 256 | this.dataSite = dataSite; 257 | this.sodaOpts = sodaOpts != null ? sodaOpts : {}; 258 | this.connection = new Connection(this.dataSite, this.sodaOpts); 259 | } 260 | 261 | Producer.prototype.operation = function() { 262 | return new Operation(this); 263 | }; 264 | 265 | return Producer; 266 | 267 | })(); 268 | 269 | Operation = (function() { 270 | function Operation(producer) { 271 | this.producer = producer; 272 | } 273 | 274 | Operation.prototype.withDataset = function(datasetId) { 275 | this._datasetId = datasetId; 276 | return this; 277 | }; 278 | 279 | Operation.prototype.truncate = function() { 280 | var opts; 281 | opts = { 282 | method: 'delete' 283 | }; 284 | opts.path = "/resource/" + this._datasetId; 285 | return this._exec(opts); 286 | }; 287 | 288 | Operation.prototype.add = function(data) { 289 | var obj, opts, _data, _i, _len; 290 | opts = { 291 | method: 'post' 292 | }; 293 | opts.path = "/resource/" + this._datasetId; 294 | _data = JSON.parse(JSON.stringify(data)); 295 | delete _data[':id']; 296 | delete _data[':delete']; 297 | for (_i = 0, _len = _data.length; _i < _len; _i++) { 298 | obj = _data[_i]; 299 | delete obj[':id']; 300 | delete obj[':delete']; 301 | } 302 | return this._exec(opts, _data); 303 | }; 304 | 305 | Operation.prototype["delete"] = function(id) { 306 | var opts; 307 | opts = { 308 | method: 'delete' 309 | }; 310 | opts.path = "/resource/" + this._datasetId + "/" + id; 311 | return this._exec(opts); 312 | }; 313 | 314 | Operation.prototype.update = function(id, data) { 315 | var opts; 316 | opts = { 317 | method: 'post' 318 | }; 319 | opts.path = "/resource/" + this._datasetId + "/" + id; 320 | return this._exec(opts, data); 321 | }; 322 | 323 | Operation.prototype.replace = function(id, data) { 324 | var opts; 325 | opts = { 326 | method: 'put' 327 | }; 328 | opts.path = "/resource/" + this._datasetId + "/" + id; 329 | return this._exec(opts, data); 330 | }; 331 | 332 | Operation.prototype.upsert = function(data) { 333 | var opts; 334 | opts = { 335 | method: 'post' 336 | }; 337 | opts.path = "/resource/" + this._datasetId; 338 | return this._exec(opts, data); 339 | }; 340 | 341 | Operation.prototype._exec = function(opts, data) { 342 | if (this._datasetId == null) { 343 | throw new Error('no dataset given to work against!'); 344 | } 345 | this.producer.connection.networker(opts, data)(); 346 | return this.producer.connection.emitter; 347 | }; 348 | 349 | return Operation; 350 | 351 | })(); 352 | 353 | Query = (function() { 354 | function Query(consumer) { 355 | this.consumer = consumer; 356 | this._select = []; 357 | this._where = []; 358 | this._group = []; 359 | this._having = []; 360 | this._order = []; 361 | this._offset = this._limit = this._q = null; 362 | } 363 | 364 | Query.prototype.withDataset = function(datasetId) { 365 | this._datasetId = datasetId; 366 | return this; 367 | }; 368 | 369 | Query.prototype.soql = function(query) { 370 | this._soql = query; 371 | return this; 372 | }; 373 | 374 | Query.prototype.select = function() { 375 | var select, selects, _i, _len; 376 | selects = 1 <= arguments.length ? __slice.call(arguments, 0) : []; 377 | for (_i = 0, _len = selects.length; _i < _len; _i++) { 378 | select = selects[_i]; 379 | this._select.push(select); 380 | } 381 | return this; 382 | }; 383 | 384 | Query.prototype.where = function() { 385 | var args; 386 | args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; 387 | addExpr(this._where, args); 388 | return this; 389 | }; 390 | 391 | Query.prototype.having = function() { 392 | var args; 393 | args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; 394 | addExpr(this._having, args); 395 | return this; 396 | }; 397 | 398 | Query.prototype.group = function() { 399 | var group, groups, _i, _len; 400 | groups = 1 <= arguments.length ? __slice.call(arguments, 0) : []; 401 | for (_i = 0, _len = groups.length; _i < _len; _i++) { 402 | group = groups[_i]; 403 | this._group.push(group); 404 | } 405 | return this; 406 | }; 407 | 408 | Query.prototype.order = function() { 409 | var order, orders, _i, _len; 410 | orders = 1 <= arguments.length ? __slice.call(arguments, 0) : []; 411 | for (_i = 0, _len = orders.length; _i < _len; _i++) { 412 | order = orders[_i]; 413 | this._order.push(handleOrder(order)); 414 | } 415 | return this; 416 | }; 417 | 418 | Query.prototype.offset = function(offset) { 419 | this._offset = offset; 420 | return this; 421 | }; 422 | 423 | Query.prototype.limit = function(limit) { 424 | this._limit = limit; 425 | return this; 426 | }; 427 | 428 | Query.prototype.q = function(q) { 429 | this._q = q; 430 | return this; 431 | }; 432 | 433 | Query.prototype.getOpts = function() { 434 | var k, opts, queryComponents, v; 435 | opts = { 436 | method: 'get' 437 | }; 438 | if (this._datasetId == null) { 439 | throw new Error('no dataset given to work against!'); 440 | } 441 | opts.path = "/resource/" + this._datasetId + ".json"; 442 | queryComponents = this._buildQueryComponents(); 443 | opts.query = {}; 444 | for (k in queryComponents) { 445 | v = queryComponents[k]; 446 | opts.query['$' + k] = v; 447 | } 448 | return opts; 449 | }; 450 | 451 | Query.prototype.getURL = function() { 452 | var opts, query; 453 | opts = this.getOpts(); 454 | query = toQuerystring(opts.query); 455 | return ("https://" + this.consumer.dataSite + opts.path) + (query ? "?" + query : ""); 456 | }; 457 | 458 | Query.prototype.getRows = function() { 459 | var opts; 460 | opts = this.getOpts(); 461 | this.consumer.connection.networker(opts)(); 462 | return this.consumer.connection.emitter; 463 | }; 464 | 465 | Query.prototype._buildQueryComponents = function() { 466 | var query; 467 | query = {}; 468 | if (this._soql != null) { 469 | query.query = this._soql; 470 | } else { 471 | if (this._select.length > 0) { 472 | query.select = this._select.join(', '); 473 | } 474 | if (this._where.length > 0) { 475 | query.where = expr.and.apply(this, this._where); 476 | } 477 | if (this._group.length > 0) { 478 | query.group = this._group.join(', '); 479 | } 480 | if (this._having.length > 0) { 481 | if (!(this._group.length > 0)) { 482 | throw new Error('Having provided without group by!'); 483 | } 484 | query.having = expr.and.apply(this, this._having); 485 | } 486 | if (this._order.length > 0) { 487 | query.order = this._order.join(', '); 488 | } 489 | if (isNumber(this._offset)) { 490 | query.offset = this._offset; 491 | } 492 | if (isNumber(this._limit)) { 493 | query.limit = this._limit; 494 | } 495 | if (this._q) { 496 | query.q = this._q; 497 | } 498 | } 499 | return query; 500 | }; 501 | 502 | return Query; 503 | 504 | })(); 505 | 506 | Dataset = (function() { 507 | function Dataset(data, client) { 508 | this.data = data; 509 | this.client = client; 510 | } 511 | 512 | return Dataset; 513 | 514 | })(); 515 | 516 | extend(typeof exports !== "undefined" && exports !== null ? exports : this.soda, { 517 | Consumer: Consumer, 518 | Producer: Producer, 519 | expr: expr, 520 | _internal: { 521 | Connection: Connection, 522 | Query: Query, 523 | Operation: Operation, 524 | util: { 525 | toBase64: toBase64, 526 | handleLiteral: handleLiteral, 527 | handleOrder: handleOrder 528 | } 529 | } 530 | }); 531 | -------------------------------------------------------------------------------- /lib/soda-js.bundle.js: -------------------------------------------------------------------------------- 1 | (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.soda = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o 0xFF) { 50 | throw new Error('Invalid character!'); 51 | } 52 | enc1 = chr1 >> 2; 53 | enc2 = ((chr1 & 3) << 4) | (chr2 >> 4); 54 | enc3 = ((chr2 & 15) << 2) | (chr3 >> 6); 55 | enc4 = chr3 & 63; 56 | if (isNaN(chr2)) { 57 | enc3 = enc4 = 64; 58 | } else if (isNaN(chr3)) { 59 | enc4 = 64; 60 | } 61 | result.push(base64Lookup[enc1]); 62 | result.push(base64Lookup[enc2]); 63 | result.push(base64Lookup[enc3]); 64 | result.push(base64Lookup[enc4]); 65 | } 66 | return result.join(''); 67 | }, function(str) { 68 | return rawToBase64(unescape(encodeURIComponent(str))); 69 | }); 70 | 71 | handleLiteral = function(literal) { 72 | if (isString(literal)) { 73 | return "'" + literal + "'"; 74 | } else if (isNumber(literal)) { 75 | return literal; 76 | } else { 77 | return literal; 78 | } 79 | }; 80 | 81 | handleOrder = function(order) { 82 | if (/( asc$| desc$)/i.test(order)) { 83 | return order; 84 | } else { 85 | return order + ' asc'; 86 | } 87 | }; 88 | 89 | addExpr = function(target, args) { 90 | var arg, k, v, _i, _len, _results; 91 | _results = []; 92 | for (_i = 0, _len = args.length; _i < _len; _i++) { 93 | arg = args[_i]; 94 | if (isString(arg)) { 95 | _results.push(target.push(arg)); 96 | } else { 97 | _results.push((function() { 98 | var _results1; 99 | _results1 = []; 100 | for (k in arg) { 101 | v = arg[k]; 102 | _results1.push(target.push("" + k + " = " + (handleLiteral(v)))); 103 | } 104 | return _results1; 105 | })()); 106 | } 107 | } 108 | return _results; 109 | }; 110 | 111 | expr = { 112 | and: function() { 113 | var clause, clauses; 114 | clauses = 1 <= arguments.length ? __slice.call(arguments, 0) : []; 115 | return ((function() { 116 | var _i, _len, _results; 117 | _results = []; 118 | for (_i = 0, _len = clauses.length; _i < _len; _i++) { 119 | clause = clauses[_i]; 120 | _results.push("(" + clause + ")"); 121 | } 122 | return _results; 123 | })()).join(' and '); 124 | }, 125 | or: function() { 126 | var clause, clauses; 127 | clauses = 1 <= arguments.length ? __slice.call(arguments, 0) : []; 128 | return ((function() { 129 | var _i, _len, _results; 130 | _results = []; 131 | for (_i = 0, _len = clauses.length; _i < _len; _i++) { 132 | clause = clauses[_i]; 133 | _results.push("(" + clause + ")"); 134 | } 135 | return _results; 136 | })()).join(' or '); 137 | }, 138 | gt: function(column, literal) { 139 | return "" + column + " > " + (handleLiteral(literal)); 140 | }, 141 | gte: function(column, literal) { 142 | return "" + column + " >= " + (handleLiteral(literal)); 143 | }, 144 | lt: function(column, literal) { 145 | return "" + column + " < " + (handleLiteral(literal)); 146 | }, 147 | lte: function(column, literal) { 148 | return "" + column + " <= " + (handleLiteral(literal)); 149 | }, 150 | eq: function(column, literal) { 151 | return "" + column + " = " + (handleLiteral(literal)); 152 | } 153 | }; 154 | 155 | toQuerystring = function(obj) { 156 | var key, str, val; 157 | str = []; 158 | for (key in obj) { 159 | if (!__hasProp.call(obj, key)) continue; 160 | val = obj[key]; 161 | str.push(encodeURIComponent(key) + '=' + encodeURIComponent(val)); 162 | } 163 | return str.join('&'); 164 | }; 165 | 166 | Connection = (function() { 167 | function Connection(dataSite, sodaOpts) { 168 | var _ref; 169 | this.dataSite = dataSite; 170 | this.sodaOpts = sodaOpts != null ? sodaOpts : {}; 171 | if (!/^[a-z0-9-_.]+(:[0-9]+)?$/i.test(this.dataSite)) { 172 | throw new Error('dataSite does not appear to be valid! Please supply a domain name, eg data.seattle.gov'); 173 | } 174 | this.emitterOpts = (_ref = this.sodaOpts.emitterOpts) != null ? _ref : { 175 | wildcard: true, 176 | delimiter: '.', 177 | maxListeners: 15 178 | }; 179 | this.networker = function(opts, data) { 180 | var client, url, 181 | _this = this; 182 | url = "https://" + this.dataSite + opts.path; 183 | client = httpClient(opts.method, url); 184 | if (data != null) { 185 | client.set('Accept', "application/json"); 186 | } 187 | if (data != null) { 188 | client.set('Content-type', "application/json"); 189 | } 190 | if (this.sodaOpts.apiToken != null) { 191 | client.set('X-App-Token', this.sodaOpts.apiToken); 192 | } 193 | if ((this.sodaOpts.username != null) && (this.sodaOpts.password != null)) { 194 | client.set('Authorization', "Basic " + toBase64("" + this.sodaOpts.username + ":" + this.sodaOpts.password)); 195 | } 196 | if (this.sodaOpts.accessToken != null) { 197 | client.set('Authorization', "OAuth " + accessToken); 198 | } 199 | if (opts.query != null) { 200 | client.query(opts.query); 201 | } 202 | if (data != null) { 203 | client.send(data); 204 | } 205 | return function(responseHandler) { 206 | return client.end(responseHandler || _this.getDefaultHandler()); 207 | }; 208 | }; 209 | } 210 | 211 | Connection.prototype.getDefaultHandler = function() { 212 | var emitter, handler; 213 | this.emitter = emitter = new EventEmitter(this.emitterOpts); 214 | return handler = function(error, response) { 215 | var _ref; 216 | if (response.ok) { 217 | if (response.accepted) { 218 | emitter.emit('progress', response.body); 219 | setTimeout((function() { 220 | return this.consumer.networker(opts)(handler); 221 | }), 5000); 222 | } else { 223 | emitter.emit('success', response.body); 224 | } 225 | } else { 226 | emitter.emit('error', (_ref = response.body) != null ? _ref : response.text); 227 | } 228 | return emitter.emit('complete', response); 229 | }; 230 | }; 231 | 232 | return Connection; 233 | 234 | })(); 235 | 236 | Consumer = (function() { 237 | function Consumer(dataSite, sodaOpts) { 238 | this.dataSite = dataSite; 239 | this.sodaOpts = sodaOpts != null ? sodaOpts : {}; 240 | this.connection = new Connection(this.dataSite, this.sodaOpts); 241 | } 242 | 243 | Consumer.prototype.query = function() { 244 | return new Query(this); 245 | }; 246 | 247 | Consumer.prototype.getDataset = function(id) { 248 | var emitter; 249 | return emitter = new EventEmitter(this.emitterOpts); 250 | }; 251 | 252 | return Consumer; 253 | 254 | })(); 255 | 256 | Producer = (function() { 257 | function Producer(dataSite, sodaOpts) { 258 | this.dataSite = dataSite; 259 | this.sodaOpts = sodaOpts != null ? sodaOpts : {}; 260 | this.connection = new Connection(this.dataSite, this.sodaOpts); 261 | } 262 | 263 | Producer.prototype.operation = function() { 264 | return new Operation(this); 265 | }; 266 | 267 | return Producer; 268 | 269 | })(); 270 | 271 | Operation = (function() { 272 | function Operation(producer) { 273 | this.producer = producer; 274 | } 275 | 276 | Operation.prototype.withDataset = function(datasetId) { 277 | this._datasetId = datasetId; 278 | return this; 279 | }; 280 | 281 | Operation.prototype.truncate = function() { 282 | var opts; 283 | opts = { 284 | method: 'delete' 285 | }; 286 | opts.path = "/resource/" + this._datasetId; 287 | return this._exec(opts); 288 | }; 289 | 290 | Operation.prototype.add = function(data) { 291 | var obj, opts, _data, _i, _len; 292 | opts = { 293 | method: 'post' 294 | }; 295 | opts.path = "/resource/" + this._datasetId; 296 | _data = JSON.parse(JSON.stringify(data)); 297 | delete _data[':id']; 298 | delete _data[':delete']; 299 | for (_i = 0, _len = _data.length; _i < _len; _i++) { 300 | obj = _data[_i]; 301 | delete obj[':id']; 302 | delete obj[':delete']; 303 | } 304 | return this._exec(opts, _data); 305 | }; 306 | 307 | Operation.prototype["delete"] = function(id) { 308 | var opts; 309 | opts = { 310 | method: 'delete' 311 | }; 312 | opts.path = "/resource/" + this._datasetId + "/" + id; 313 | return this._exec(opts); 314 | }; 315 | 316 | Operation.prototype.update = function(id, data) { 317 | var opts; 318 | opts = { 319 | method: 'post' 320 | }; 321 | opts.path = "/resource/" + this._datasetId + "/" + id; 322 | return this._exec(opts, data); 323 | }; 324 | 325 | Operation.prototype.replace = function(id, data) { 326 | var opts; 327 | opts = { 328 | method: 'put' 329 | }; 330 | opts.path = "/resource/" + this._datasetId + "/" + id; 331 | return this._exec(opts, data); 332 | }; 333 | 334 | Operation.prototype.upsert = function(data) { 335 | var opts; 336 | opts = { 337 | method: 'post' 338 | }; 339 | opts.path = "/resource/" + this._datasetId; 340 | return this._exec(opts, data); 341 | }; 342 | 343 | Operation.prototype._exec = function(opts, data) { 344 | if (this._datasetId == null) { 345 | throw new Error('no dataset given to work against!'); 346 | } 347 | this.producer.connection.networker(opts, data)(); 348 | return this.producer.connection.emitter; 349 | }; 350 | 351 | return Operation; 352 | 353 | })(); 354 | 355 | Query = (function() { 356 | function Query(consumer) { 357 | this.consumer = consumer; 358 | this._select = []; 359 | this._where = []; 360 | this._group = []; 361 | this._having = []; 362 | this._order = []; 363 | this._offset = this._limit = this._q = null; 364 | } 365 | 366 | Query.prototype.withDataset = function(datasetId) { 367 | this._datasetId = datasetId; 368 | return this; 369 | }; 370 | 371 | Query.prototype.soql = function(query) { 372 | this._soql = query; 373 | return this; 374 | }; 375 | 376 | Query.prototype.select = function() { 377 | var select, selects, _i, _len; 378 | selects = 1 <= arguments.length ? __slice.call(arguments, 0) : []; 379 | for (_i = 0, _len = selects.length; _i < _len; _i++) { 380 | select = selects[_i]; 381 | this._select.push(select); 382 | } 383 | return this; 384 | }; 385 | 386 | Query.prototype.where = function() { 387 | var args; 388 | args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; 389 | addExpr(this._where, args); 390 | return this; 391 | }; 392 | 393 | Query.prototype.having = function() { 394 | var args; 395 | args = 1 <= arguments.length ? __slice.call(arguments, 0) : []; 396 | addExpr(this._having, args); 397 | return this; 398 | }; 399 | 400 | Query.prototype.group = function() { 401 | var group, groups, _i, _len; 402 | groups = 1 <= arguments.length ? __slice.call(arguments, 0) : []; 403 | for (_i = 0, _len = groups.length; _i < _len; _i++) { 404 | group = groups[_i]; 405 | this._group.push(group); 406 | } 407 | return this; 408 | }; 409 | 410 | Query.prototype.order = function() { 411 | var order, orders, _i, _len; 412 | orders = 1 <= arguments.length ? __slice.call(arguments, 0) : []; 413 | for (_i = 0, _len = orders.length; _i < _len; _i++) { 414 | order = orders[_i]; 415 | this._order.push(handleOrder(order)); 416 | } 417 | return this; 418 | }; 419 | 420 | Query.prototype.offset = function(offset) { 421 | this._offset = offset; 422 | return this; 423 | }; 424 | 425 | Query.prototype.limit = function(limit) { 426 | this._limit = limit; 427 | return this; 428 | }; 429 | 430 | Query.prototype.q = function(q) { 431 | this._q = q; 432 | return this; 433 | }; 434 | 435 | Query.prototype.getOpts = function() { 436 | var k, opts, queryComponents, v; 437 | opts = { 438 | method: 'get' 439 | }; 440 | if (this._datasetId == null) { 441 | throw new Error('no dataset given to work against!'); 442 | } 443 | opts.path = "/resource/" + this._datasetId + ".json"; 444 | queryComponents = this._buildQueryComponents(); 445 | opts.query = {}; 446 | for (k in queryComponents) { 447 | v = queryComponents[k]; 448 | opts.query['$' + k] = v; 449 | } 450 | return opts; 451 | }; 452 | 453 | Query.prototype.getURL = function() { 454 | var opts, query; 455 | opts = this.getOpts(); 456 | query = toQuerystring(opts.query); 457 | return ("https://" + this.consumer.dataSite + opts.path) + (query ? "?" + query : ""); 458 | }; 459 | 460 | Query.prototype.getRows = function() { 461 | var opts; 462 | opts = this.getOpts(); 463 | this.consumer.connection.networker(opts)(); 464 | return this.consumer.connection.emitter; 465 | }; 466 | 467 | Query.prototype._buildQueryComponents = function() { 468 | var query; 469 | query = {}; 470 | if (this._soql != null) { 471 | query.query = this._soql; 472 | } else { 473 | if (this._select.length > 0) { 474 | query.select = this._select.join(', '); 475 | } 476 | if (this._where.length > 0) { 477 | query.where = expr.and.apply(this, this._where); 478 | } 479 | if (this._group.length > 0) { 480 | query.group = this._group.join(', '); 481 | } 482 | if (this._having.length > 0) { 483 | if (!(this._group.length > 0)) { 484 | throw new Error('Having provided without group by!'); 485 | } 486 | query.having = expr.and.apply(this, this._having); 487 | } 488 | if (this._order.length > 0) { 489 | query.order = this._order.join(', '); 490 | } 491 | if (isNumber(this._offset)) { 492 | query.offset = this._offset; 493 | } 494 | if (isNumber(this._limit)) { 495 | query.limit = this._limit; 496 | } 497 | if (this._q) { 498 | query.q = this._q; 499 | } 500 | } 501 | return query; 502 | }; 503 | 504 | return Query; 505 | 506 | })(); 507 | 508 | Dataset = (function() { 509 | function Dataset(data, client) { 510 | this.data = data; 511 | this.client = client; 512 | } 513 | 514 | return Dataset; 515 | 516 | })(); 517 | 518 | extend(typeof exports !== "undefined" && exports !== null ? exports : this.soda, { 519 | Consumer: Consumer, 520 | Producer: Producer, 521 | expr: expr, 522 | _internal: { 523 | Connection: Connection, 524 | Query: Query, 525 | Operation: Operation, 526 | util: { 527 | toBase64: toBase64, 528 | handleLiteral: handleLiteral, 529 | handleOrder: handleOrder 530 | } 531 | } 532 | }); 533 | 534 | }).call(this,require("buffer").Buffer) 535 | },{"buffer":3,"eventemitter2":6,"superagent":9}],2:[function(require,module,exports){ 536 | var lookup = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; 537 | 538 | ;(function (exports) { 539 | 'use strict'; 540 | 541 | var Arr = (typeof Uint8Array !== 'undefined') 542 | ? Uint8Array 543 | : Array 544 | 545 | var PLUS = '+'.charCodeAt(0) 546 | var SLASH = '/'.charCodeAt(0) 547 | var NUMBER = '0'.charCodeAt(0) 548 | var LOWER = 'a'.charCodeAt(0) 549 | var UPPER = 'A'.charCodeAt(0) 550 | var PLUS_URL_SAFE = '-'.charCodeAt(0) 551 | var SLASH_URL_SAFE = '_'.charCodeAt(0) 552 | 553 | function decode (elt) { 554 | var code = elt.charCodeAt(0) 555 | if (code === PLUS || 556 | code === PLUS_URL_SAFE) 557 | return 62 // '+' 558 | if (code === SLASH || 559 | code === SLASH_URL_SAFE) 560 | return 63 // '/' 561 | if (code < NUMBER) 562 | return -1 //no match 563 | if (code < NUMBER + 10) 564 | return code - NUMBER + 26 + 26 565 | if (code < UPPER + 26) 566 | return code - UPPER 567 | if (code < LOWER + 26) 568 | return code - LOWER + 26 569 | } 570 | 571 | function b64ToByteArray (b64) { 572 | var i, j, l, tmp, placeHolders, arr 573 | 574 | if (b64.length % 4 > 0) { 575 | throw new Error('Invalid string. Length must be a multiple of 4') 576 | } 577 | 578 | // the number of equal signs (place holders) 579 | // if there are two placeholders, than the two characters before it 580 | // represent one byte 581 | // if there is only one, then the three characters before it represent 2 bytes 582 | // this is just a cheap hack to not do indexOf twice 583 | var len = b64.length 584 | placeHolders = '=' === b64.charAt(len - 2) ? 2 : '=' === b64.charAt(len - 1) ? 1 : 0 585 | 586 | // base64 is 4/3 + up to two characters of the original data 587 | arr = new Arr(b64.length * 3 / 4 - placeHolders) 588 | 589 | // if there are placeholders, only get up to the last complete 4 chars 590 | l = placeHolders > 0 ? b64.length - 4 : b64.length 591 | 592 | var L = 0 593 | 594 | function push (v) { 595 | arr[L++] = v 596 | } 597 | 598 | for (i = 0, j = 0; i < l; i += 4, j += 3) { 599 | tmp = (decode(b64.charAt(i)) << 18) | (decode(b64.charAt(i + 1)) << 12) | (decode(b64.charAt(i + 2)) << 6) | decode(b64.charAt(i + 3)) 600 | push((tmp & 0xFF0000) >> 16) 601 | push((tmp & 0xFF00) >> 8) 602 | push(tmp & 0xFF) 603 | } 604 | 605 | if (placeHolders === 2) { 606 | tmp = (decode(b64.charAt(i)) << 2) | (decode(b64.charAt(i + 1)) >> 4) 607 | push(tmp & 0xFF) 608 | } else if (placeHolders === 1) { 609 | tmp = (decode(b64.charAt(i)) << 10) | (decode(b64.charAt(i + 1)) << 4) | (decode(b64.charAt(i + 2)) >> 2) 610 | push((tmp >> 8) & 0xFF) 611 | push(tmp & 0xFF) 612 | } 613 | 614 | return arr 615 | } 616 | 617 | function uint8ToBase64 (uint8) { 618 | var i, 619 | extraBytes = uint8.length % 3, // if we have 1 byte left, pad 2 bytes 620 | output = "", 621 | temp, length 622 | 623 | function encode (num) { 624 | return lookup.charAt(num) 625 | } 626 | 627 | function tripletToBase64 (num) { 628 | return encode(num >> 18 & 0x3F) + encode(num >> 12 & 0x3F) + encode(num >> 6 & 0x3F) + encode(num & 0x3F) 629 | } 630 | 631 | // go through the array every three bytes, we'll deal with trailing stuff later 632 | for (i = 0, length = uint8.length - extraBytes; i < length; i += 3) { 633 | temp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2]) 634 | output += tripletToBase64(temp) 635 | } 636 | 637 | // pad the end with zeros, but make sure to not forget the extra bytes 638 | switch (extraBytes) { 639 | case 1: 640 | temp = uint8[uint8.length - 1] 641 | output += encode(temp >> 2) 642 | output += encode((temp << 4) & 0x3F) 643 | output += '==' 644 | break 645 | case 2: 646 | temp = (uint8[uint8.length - 2] << 8) + (uint8[uint8.length - 1]) 647 | output += encode(temp >> 10) 648 | output += encode((temp >> 4) & 0x3F) 649 | output += encode((temp << 2) & 0x3F) 650 | output += '=' 651 | break 652 | } 653 | 654 | return output 655 | } 656 | 657 | exports.toByteArray = b64ToByteArray 658 | exports.fromByteArray = uint8ToBase64 659 | }(typeof exports === 'undefined' ? (this.base64js = {}) : exports)) 660 | 661 | },{}],3:[function(require,module,exports){ 662 | (function (global){ 663 | /*! 664 | * The buffer module from node.js, for the browser. 665 | * 666 | * @author Feross Aboukhadijeh 667 | * @license MIT 668 | */ 669 | /* eslint-disable no-proto */ 670 | 671 | 'use strict' 672 | 673 | var base64 = require('base64-js') 674 | var ieee754 = require('ieee754') 675 | var isArray = require('isarray') 676 | 677 | exports.Buffer = Buffer 678 | exports.SlowBuffer = SlowBuffer 679 | exports.INSPECT_MAX_BYTES = 50 680 | Buffer.poolSize = 8192 // not used by this implementation 681 | 682 | var rootParent = {} 683 | 684 | /** 685 | * If `Buffer.TYPED_ARRAY_SUPPORT`: 686 | * === true Use Uint8Array implementation (fastest) 687 | * === false Use Object implementation (most compatible, even IE6) 688 | * 689 | * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+, 690 | * Opera 11.6+, iOS 4.2+. 691 | * 692 | * Due to various browser bugs, sometimes the Object implementation will be used even 693 | * when the browser supports typed arrays. 694 | * 695 | * Note: 696 | * 697 | * - Firefox 4-29 lacks support for adding new properties to `Uint8Array` instances, 698 | * See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438. 699 | * 700 | * - Safari 5-7 lacks support for changing the `Object.prototype.constructor` property 701 | * on objects. 702 | * 703 | * - Chrome 9-10 is missing the `TypedArray.prototype.subarray` function. 704 | * 705 | * - IE10 has a broken `TypedArray.prototype.subarray` function which returns arrays of 706 | * incorrect length in some situations. 707 | 708 | * We detect these buggy browsers and set `Buffer.TYPED_ARRAY_SUPPORT` to `false` so they 709 | * get the Object implementation, which is slower but behaves correctly. 710 | */ 711 | Buffer.TYPED_ARRAY_SUPPORT = global.TYPED_ARRAY_SUPPORT !== undefined 712 | ? global.TYPED_ARRAY_SUPPORT 713 | : typedArraySupport() 714 | 715 | function typedArraySupport () { 716 | function Bar () {} 717 | try { 718 | var arr = new Uint8Array(1) 719 | arr.foo = function () { return 42 } 720 | arr.constructor = Bar 721 | return arr.foo() === 42 && // typed array instances can be augmented 722 | arr.constructor === Bar && // constructor can be set 723 | typeof arr.subarray === 'function' && // chrome 9-10 lack `subarray` 724 | arr.subarray(1, 1).byteLength === 0 // ie10 has broken `subarray` 725 | } catch (e) { 726 | return false 727 | } 728 | } 729 | 730 | function kMaxLength () { 731 | return Buffer.TYPED_ARRAY_SUPPORT 732 | ? 0x7fffffff 733 | : 0x3fffffff 734 | } 735 | 736 | /** 737 | * Class: Buffer 738 | * ============= 739 | * 740 | * The Buffer constructor returns instances of `Uint8Array` that are augmented 741 | * with function properties for all the node `Buffer` API functions. We use 742 | * `Uint8Array` so that square bracket notation works as expected -- it returns 743 | * a single octet. 744 | * 745 | * By augmenting the instances, we can avoid modifying the `Uint8Array` 746 | * prototype. 747 | */ 748 | function Buffer (arg) { 749 | if (!(this instanceof Buffer)) { 750 | // Avoid going through an ArgumentsAdaptorTrampoline in the common case. 751 | if (arguments.length > 1) return new Buffer(arg, arguments[1]) 752 | return new Buffer(arg) 753 | } 754 | 755 | if (!Buffer.TYPED_ARRAY_SUPPORT) { 756 | this.length = 0 757 | this.parent = undefined 758 | } 759 | 760 | // Common case. 761 | if (typeof arg === 'number') { 762 | return fromNumber(this, arg) 763 | } 764 | 765 | // Slightly less common case. 766 | if (typeof arg === 'string') { 767 | return fromString(this, arg, arguments.length > 1 ? arguments[1] : 'utf8') 768 | } 769 | 770 | // Unusual. 771 | return fromObject(this, arg) 772 | } 773 | 774 | function fromNumber (that, length) { 775 | that = allocate(that, length < 0 ? 0 : checked(length) | 0) 776 | if (!Buffer.TYPED_ARRAY_SUPPORT) { 777 | for (var i = 0; i < length; i++) { 778 | that[i] = 0 779 | } 780 | } 781 | return that 782 | } 783 | 784 | function fromString (that, string, encoding) { 785 | if (typeof encoding !== 'string' || encoding === '') encoding = 'utf8' 786 | 787 | // Assumption: byteLength() return value is always < kMaxLength. 788 | var length = byteLength(string, encoding) | 0 789 | that = allocate(that, length) 790 | 791 | that.write(string, encoding) 792 | return that 793 | } 794 | 795 | function fromObject (that, object) { 796 | if (Buffer.isBuffer(object)) return fromBuffer(that, object) 797 | 798 | if (isArray(object)) return fromArray(that, object) 799 | 800 | if (object == null) { 801 | throw new TypeError('must start with number, buffer, array or string') 802 | } 803 | 804 | if (typeof ArrayBuffer !== 'undefined') { 805 | if (object.buffer instanceof ArrayBuffer) { 806 | return fromTypedArray(that, object) 807 | } 808 | if (object instanceof ArrayBuffer) { 809 | return fromArrayBuffer(that, object) 810 | } 811 | } 812 | 813 | if (object.length) return fromArrayLike(that, object) 814 | 815 | return fromJsonObject(that, object) 816 | } 817 | 818 | function fromBuffer (that, buffer) { 819 | var length = checked(buffer.length) | 0 820 | that = allocate(that, length) 821 | buffer.copy(that, 0, 0, length) 822 | return that 823 | } 824 | 825 | function fromArray (that, array) { 826 | var length = checked(array.length) | 0 827 | that = allocate(that, length) 828 | for (var i = 0; i < length; i += 1) { 829 | that[i] = array[i] & 255 830 | } 831 | return that 832 | } 833 | 834 | // Duplicate of fromArray() to keep fromArray() monomorphic. 835 | function fromTypedArray (that, array) { 836 | var length = checked(array.length) | 0 837 | that = allocate(that, length) 838 | // Truncating the elements is probably not what people expect from typed 839 | // arrays with BYTES_PER_ELEMENT > 1 but it's compatible with the behavior 840 | // of the old Buffer constructor. 841 | for (var i = 0; i < length; i += 1) { 842 | that[i] = array[i] & 255 843 | } 844 | return that 845 | } 846 | 847 | function fromArrayBuffer (that, array) { 848 | if (Buffer.TYPED_ARRAY_SUPPORT) { 849 | // Return an augmented `Uint8Array` instance, for best performance 850 | array.byteLength 851 | that = Buffer._augment(new Uint8Array(array)) 852 | } else { 853 | // Fallback: Return an object instance of the Buffer class 854 | that = fromTypedArray(that, new Uint8Array(array)) 855 | } 856 | return that 857 | } 858 | 859 | function fromArrayLike (that, array) { 860 | var length = checked(array.length) | 0 861 | that = allocate(that, length) 862 | for (var i = 0; i < length; i += 1) { 863 | that[i] = array[i] & 255 864 | } 865 | return that 866 | } 867 | 868 | // Deserialize { type: 'Buffer', data: [1,2,3,...] } into a Buffer object. 869 | // Returns a zero-length buffer for inputs that don't conform to the spec. 870 | function fromJsonObject (that, object) { 871 | var array 872 | var length = 0 873 | 874 | if (object.type === 'Buffer' && isArray(object.data)) { 875 | array = object.data 876 | length = checked(array.length) | 0 877 | } 878 | that = allocate(that, length) 879 | 880 | for (var i = 0; i < length; i += 1) { 881 | that[i] = array[i] & 255 882 | } 883 | return that 884 | } 885 | 886 | if (Buffer.TYPED_ARRAY_SUPPORT) { 887 | Buffer.prototype.__proto__ = Uint8Array.prototype 888 | Buffer.__proto__ = Uint8Array 889 | } else { 890 | // pre-set for values that may exist in the future 891 | Buffer.prototype.length = undefined 892 | Buffer.prototype.parent = undefined 893 | } 894 | 895 | function allocate (that, length) { 896 | if (Buffer.TYPED_ARRAY_SUPPORT) { 897 | // Return an augmented `Uint8Array` instance, for best performance 898 | that = Buffer._augment(new Uint8Array(length)) 899 | that.__proto__ = Buffer.prototype 900 | } else { 901 | // Fallback: Return an object instance of the Buffer class 902 | that.length = length 903 | that._isBuffer = true 904 | } 905 | 906 | var fromPool = length !== 0 && length <= Buffer.poolSize >>> 1 907 | if (fromPool) that.parent = rootParent 908 | 909 | return that 910 | } 911 | 912 | function checked (length) { 913 | // Note: cannot use `length < kMaxLength` here because that fails when 914 | // length is NaN (which is otherwise coerced to zero.) 915 | if (length >= kMaxLength()) { 916 | throw new RangeError('Attempt to allocate Buffer larger than maximum ' + 917 | 'size: 0x' + kMaxLength().toString(16) + ' bytes') 918 | } 919 | return length | 0 920 | } 921 | 922 | function SlowBuffer (subject, encoding) { 923 | if (!(this instanceof SlowBuffer)) return new SlowBuffer(subject, encoding) 924 | 925 | var buf = new Buffer(subject, encoding) 926 | delete buf.parent 927 | return buf 928 | } 929 | 930 | Buffer.isBuffer = function isBuffer (b) { 931 | return !!(b != null && b._isBuffer) 932 | } 933 | 934 | Buffer.compare = function compare (a, b) { 935 | if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) { 936 | throw new TypeError('Arguments must be Buffers') 937 | } 938 | 939 | if (a === b) return 0 940 | 941 | var x = a.length 942 | var y = b.length 943 | 944 | var i = 0 945 | var len = Math.min(x, y) 946 | while (i < len) { 947 | if (a[i] !== b[i]) break 948 | 949 | ++i 950 | } 951 | 952 | if (i !== len) { 953 | x = a[i] 954 | y = b[i] 955 | } 956 | 957 | if (x < y) return -1 958 | if (y < x) return 1 959 | return 0 960 | } 961 | 962 | Buffer.isEncoding = function isEncoding (encoding) { 963 | switch (String(encoding).toLowerCase()) { 964 | case 'hex': 965 | case 'utf8': 966 | case 'utf-8': 967 | case 'ascii': 968 | case 'binary': 969 | case 'base64': 970 | case 'raw': 971 | case 'ucs2': 972 | case 'ucs-2': 973 | case 'utf16le': 974 | case 'utf-16le': 975 | return true 976 | default: 977 | return false 978 | } 979 | } 980 | 981 | Buffer.concat = function concat (list, length) { 982 | if (!isArray(list)) throw new TypeError('list argument must be an Array of Buffers.') 983 | 984 | if (list.length === 0) { 985 | return new Buffer(0) 986 | } 987 | 988 | var i 989 | if (length === undefined) { 990 | length = 0 991 | for (i = 0; i < list.length; i++) { 992 | length += list[i].length 993 | } 994 | } 995 | 996 | var buf = new Buffer(length) 997 | var pos = 0 998 | for (i = 0; i < list.length; i++) { 999 | var item = list[i] 1000 | item.copy(buf, pos) 1001 | pos += item.length 1002 | } 1003 | return buf 1004 | } 1005 | 1006 | function byteLength (string, encoding) { 1007 | if (typeof string !== 'string') string = '' + string 1008 | 1009 | var len = string.length 1010 | if (len === 0) return 0 1011 | 1012 | // Use a for loop to avoid recursion 1013 | var loweredCase = false 1014 | for (;;) { 1015 | switch (encoding) { 1016 | case 'ascii': 1017 | case 'binary': 1018 | // Deprecated 1019 | case 'raw': 1020 | case 'raws': 1021 | return len 1022 | case 'utf8': 1023 | case 'utf-8': 1024 | return utf8ToBytes(string).length 1025 | case 'ucs2': 1026 | case 'ucs-2': 1027 | case 'utf16le': 1028 | case 'utf-16le': 1029 | return len * 2 1030 | case 'hex': 1031 | return len >>> 1 1032 | case 'base64': 1033 | return base64ToBytes(string).length 1034 | default: 1035 | if (loweredCase) return utf8ToBytes(string).length // assume utf8 1036 | encoding = ('' + encoding).toLowerCase() 1037 | loweredCase = true 1038 | } 1039 | } 1040 | } 1041 | Buffer.byteLength = byteLength 1042 | 1043 | function slowToString (encoding, start, end) { 1044 | var loweredCase = false 1045 | 1046 | start = start | 0 1047 | end = end === undefined || end === Infinity ? this.length : end | 0 1048 | 1049 | if (!encoding) encoding = 'utf8' 1050 | if (start < 0) start = 0 1051 | if (end > this.length) end = this.length 1052 | if (end <= start) return '' 1053 | 1054 | while (true) { 1055 | switch (encoding) { 1056 | case 'hex': 1057 | return hexSlice(this, start, end) 1058 | 1059 | case 'utf8': 1060 | case 'utf-8': 1061 | return utf8Slice(this, start, end) 1062 | 1063 | case 'ascii': 1064 | return asciiSlice(this, start, end) 1065 | 1066 | case 'binary': 1067 | return binarySlice(this, start, end) 1068 | 1069 | case 'base64': 1070 | return base64Slice(this, start, end) 1071 | 1072 | case 'ucs2': 1073 | case 'ucs-2': 1074 | case 'utf16le': 1075 | case 'utf-16le': 1076 | return utf16leSlice(this, start, end) 1077 | 1078 | default: 1079 | if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding) 1080 | encoding = (encoding + '').toLowerCase() 1081 | loweredCase = true 1082 | } 1083 | } 1084 | } 1085 | 1086 | Buffer.prototype.toString = function toString () { 1087 | var length = this.length | 0 1088 | if (length === 0) return '' 1089 | if (arguments.length === 0) return utf8Slice(this, 0, length) 1090 | return slowToString.apply(this, arguments) 1091 | } 1092 | 1093 | Buffer.prototype.equals = function equals (b) { 1094 | if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer') 1095 | if (this === b) return true 1096 | return Buffer.compare(this, b) === 0 1097 | } 1098 | 1099 | Buffer.prototype.inspect = function inspect () { 1100 | var str = '' 1101 | var max = exports.INSPECT_MAX_BYTES 1102 | if (this.length > 0) { 1103 | str = this.toString('hex', 0, max).match(/.{2}/g).join(' ') 1104 | if (this.length > max) str += ' ... ' 1105 | } 1106 | return '' 1107 | } 1108 | 1109 | Buffer.prototype.compare = function compare (b) { 1110 | if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer') 1111 | if (this === b) return 0 1112 | return Buffer.compare(this, b) 1113 | } 1114 | 1115 | Buffer.prototype.indexOf = function indexOf (val, byteOffset) { 1116 | if (byteOffset > 0x7fffffff) byteOffset = 0x7fffffff 1117 | else if (byteOffset < -0x80000000) byteOffset = -0x80000000 1118 | byteOffset >>= 0 1119 | 1120 | if (this.length === 0) return -1 1121 | if (byteOffset >= this.length) return -1 1122 | 1123 | // Negative offsets start from the end of the buffer 1124 | if (byteOffset < 0) byteOffset = Math.max(this.length + byteOffset, 0) 1125 | 1126 | if (typeof val === 'string') { 1127 | if (val.length === 0) return -1 // special case: looking for empty string always fails 1128 | return String.prototype.indexOf.call(this, val, byteOffset) 1129 | } 1130 | if (Buffer.isBuffer(val)) { 1131 | return arrayIndexOf(this, val, byteOffset) 1132 | } 1133 | if (typeof val === 'number') { 1134 | if (Buffer.TYPED_ARRAY_SUPPORT && Uint8Array.prototype.indexOf === 'function') { 1135 | return Uint8Array.prototype.indexOf.call(this, val, byteOffset) 1136 | } 1137 | return arrayIndexOf(this, [ val ], byteOffset) 1138 | } 1139 | 1140 | function arrayIndexOf (arr, val, byteOffset) { 1141 | var foundIndex = -1 1142 | for (var i = 0; byteOffset + i < arr.length; i++) { 1143 | if (arr[byteOffset + i] === val[foundIndex === -1 ? 0 : i - foundIndex]) { 1144 | if (foundIndex === -1) foundIndex = i 1145 | if (i - foundIndex + 1 === val.length) return byteOffset + foundIndex 1146 | } else { 1147 | foundIndex = -1 1148 | } 1149 | } 1150 | return -1 1151 | } 1152 | 1153 | throw new TypeError('val must be string, number or Buffer') 1154 | } 1155 | 1156 | // `get` is deprecated 1157 | Buffer.prototype.get = function get (offset) { 1158 | console.log('.get() is deprecated. Access using array indexes instead.') 1159 | return this.readUInt8(offset) 1160 | } 1161 | 1162 | // `set` is deprecated 1163 | Buffer.prototype.set = function set (v, offset) { 1164 | console.log('.set() is deprecated. Access using array indexes instead.') 1165 | return this.writeUInt8(v, offset) 1166 | } 1167 | 1168 | function hexWrite (buf, string, offset, length) { 1169 | offset = Number(offset) || 0 1170 | var remaining = buf.length - offset 1171 | if (!length) { 1172 | length = remaining 1173 | } else { 1174 | length = Number(length) 1175 | if (length > remaining) { 1176 | length = remaining 1177 | } 1178 | } 1179 | 1180 | // must be an even number of digits 1181 | var strLen = string.length 1182 | if (strLen % 2 !== 0) throw new Error('Invalid hex string') 1183 | 1184 | if (length > strLen / 2) { 1185 | length = strLen / 2 1186 | } 1187 | for (var i = 0; i < length; i++) { 1188 | var parsed = parseInt(string.substr(i * 2, 2), 16) 1189 | if (isNaN(parsed)) throw new Error('Invalid hex string') 1190 | buf[offset + i] = parsed 1191 | } 1192 | return i 1193 | } 1194 | 1195 | function utf8Write (buf, string, offset, length) { 1196 | return blitBuffer(utf8ToBytes(string, buf.length - offset), buf, offset, length) 1197 | } 1198 | 1199 | function asciiWrite (buf, string, offset, length) { 1200 | return blitBuffer(asciiToBytes(string), buf, offset, length) 1201 | } 1202 | 1203 | function binaryWrite (buf, string, offset, length) { 1204 | return asciiWrite(buf, string, offset, length) 1205 | } 1206 | 1207 | function base64Write (buf, string, offset, length) { 1208 | return blitBuffer(base64ToBytes(string), buf, offset, length) 1209 | } 1210 | 1211 | function ucs2Write (buf, string, offset, length) { 1212 | return blitBuffer(utf16leToBytes(string, buf.length - offset), buf, offset, length) 1213 | } 1214 | 1215 | Buffer.prototype.write = function write (string, offset, length, encoding) { 1216 | // Buffer#write(string) 1217 | if (offset === undefined) { 1218 | encoding = 'utf8' 1219 | length = this.length 1220 | offset = 0 1221 | // Buffer#write(string, encoding) 1222 | } else if (length === undefined && typeof offset === 'string') { 1223 | encoding = offset 1224 | length = this.length 1225 | offset = 0 1226 | // Buffer#write(string, offset[, length][, encoding]) 1227 | } else if (isFinite(offset)) { 1228 | offset = offset | 0 1229 | if (isFinite(length)) { 1230 | length = length | 0 1231 | if (encoding === undefined) encoding = 'utf8' 1232 | } else { 1233 | encoding = length 1234 | length = undefined 1235 | } 1236 | // legacy write(string, encoding, offset, length) - remove in v0.13 1237 | } else { 1238 | var swap = encoding 1239 | encoding = offset 1240 | offset = length | 0 1241 | length = swap 1242 | } 1243 | 1244 | var remaining = this.length - offset 1245 | if (length === undefined || length > remaining) length = remaining 1246 | 1247 | if ((string.length > 0 && (length < 0 || offset < 0)) || offset > this.length) { 1248 | throw new RangeError('attempt to write outside buffer bounds') 1249 | } 1250 | 1251 | if (!encoding) encoding = 'utf8' 1252 | 1253 | var loweredCase = false 1254 | for (;;) { 1255 | switch (encoding) { 1256 | case 'hex': 1257 | return hexWrite(this, string, offset, length) 1258 | 1259 | case 'utf8': 1260 | case 'utf-8': 1261 | return utf8Write(this, string, offset, length) 1262 | 1263 | case 'ascii': 1264 | return asciiWrite(this, string, offset, length) 1265 | 1266 | case 'binary': 1267 | return binaryWrite(this, string, offset, length) 1268 | 1269 | case 'base64': 1270 | // Warning: maxLength not taken into account in base64Write 1271 | return base64Write(this, string, offset, length) 1272 | 1273 | case 'ucs2': 1274 | case 'ucs-2': 1275 | case 'utf16le': 1276 | case 'utf-16le': 1277 | return ucs2Write(this, string, offset, length) 1278 | 1279 | default: 1280 | if (loweredCase) throw new TypeError('Unknown encoding: ' + encoding) 1281 | encoding = ('' + encoding).toLowerCase() 1282 | loweredCase = true 1283 | } 1284 | } 1285 | } 1286 | 1287 | Buffer.prototype.toJSON = function toJSON () { 1288 | return { 1289 | type: 'Buffer', 1290 | data: Array.prototype.slice.call(this._arr || this, 0) 1291 | } 1292 | } 1293 | 1294 | function base64Slice (buf, start, end) { 1295 | if (start === 0 && end === buf.length) { 1296 | return base64.fromByteArray(buf) 1297 | } else { 1298 | return base64.fromByteArray(buf.slice(start, end)) 1299 | } 1300 | } 1301 | 1302 | function utf8Slice (buf, start, end) { 1303 | end = Math.min(buf.length, end) 1304 | var res = [] 1305 | 1306 | var i = start 1307 | while (i < end) { 1308 | var firstByte = buf[i] 1309 | var codePoint = null 1310 | var bytesPerSequence = (firstByte > 0xEF) ? 4 1311 | : (firstByte > 0xDF) ? 3 1312 | : (firstByte > 0xBF) ? 2 1313 | : 1 1314 | 1315 | if (i + bytesPerSequence <= end) { 1316 | var secondByte, thirdByte, fourthByte, tempCodePoint 1317 | 1318 | switch (bytesPerSequence) { 1319 | case 1: 1320 | if (firstByte < 0x80) { 1321 | codePoint = firstByte 1322 | } 1323 | break 1324 | case 2: 1325 | secondByte = buf[i + 1] 1326 | if ((secondByte & 0xC0) === 0x80) { 1327 | tempCodePoint = (firstByte & 0x1F) << 0x6 | (secondByte & 0x3F) 1328 | if (tempCodePoint > 0x7F) { 1329 | codePoint = tempCodePoint 1330 | } 1331 | } 1332 | break 1333 | case 3: 1334 | secondByte = buf[i + 1] 1335 | thirdByte = buf[i + 2] 1336 | if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80) { 1337 | tempCodePoint = (firstByte & 0xF) << 0xC | (secondByte & 0x3F) << 0x6 | (thirdByte & 0x3F) 1338 | if (tempCodePoint > 0x7FF && (tempCodePoint < 0xD800 || tempCodePoint > 0xDFFF)) { 1339 | codePoint = tempCodePoint 1340 | } 1341 | } 1342 | break 1343 | case 4: 1344 | secondByte = buf[i + 1] 1345 | thirdByte = buf[i + 2] 1346 | fourthByte = buf[i + 3] 1347 | if ((secondByte & 0xC0) === 0x80 && (thirdByte & 0xC0) === 0x80 && (fourthByte & 0xC0) === 0x80) { 1348 | tempCodePoint = (firstByte & 0xF) << 0x12 | (secondByte & 0x3F) << 0xC | (thirdByte & 0x3F) << 0x6 | (fourthByte & 0x3F) 1349 | if (tempCodePoint > 0xFFFF && tempCodePoint < 0x110000) { 1350 | codePoint = tempCodePoint 1351 | } 1352 | } 1353 | } 1354 | } 1355 | 1356 | if (codePoint === null) { 1357 | // we did not generate a valid codePoint so insert a 1358 | // replacement char (U+FFFD) and advance only 1 byte 1359 | codePoint = 0xFFFD 1360 | bytesPerSequence = 1 1361 | } else if (codePoint > 0xFFFF) { 1362 | // encode to utf16 (surrogate pair dance) 1363 | codePoint -= 0x10000 1364 | res.push(codePoint >>> 10 & 0x3FF | 0xD800) 1365 | codePoint = 0xDC00 | codePoint & 0x3FF 1366 | } 1367 | 1368 | res.push(codePoint) 1369 | i += bytesPerSequence 1370 | } 1371 | 1372 | return decodeCodePointsArray(res) 1373 | } 1374 | 1375 | // Based on http://stackoverflow.com/a/22747272/680742, the browser with 1376 | // the lowest limit is Chrome, with 0x10000 args. 1377 | // We go 1 magnitude less, for safety 1378 | var MAX_ARGUMENTS_LENGTH = 0x1000 1379 | 1380 | function decodeCodePointsArray (codePoints) { 1381 | var len = codePoints.length 1382 | if (len <= MAX_ARGUMENTS_LENGTH) { 1383 | return String.fromCharCode.apply(String, codePoints) // avoid extra slice() 1384 | } 1385 | 1386 | // Decode in chunks to avoid "call stack size exceeded". 1387 | var res = '' 1388 | var i = 0 1389 | while (i < len) { 1390 | res += String.fromCharCode.apply( 1391 | String, 1392 | codePoints.slice(i, i += MAX_ARGUMENTS_LENGTH) 1393 | ) 1394 | } 1395 | return res 1396 | } 1397 | 1398 | function asciiSlice (buf, start, end) { 1399 | var ret = '' 1400 | end = Math.min(buf.length, end) 1401 | 1402 | for (var i = start; i < end; i++) { 1403 | ret += String.fromCharCode(buf[i] & 0x7F) 1404 | } 1405 | return ret 1406 | } 1407 | 1408 | function binarySlice (buf, start, end) { 1409 | var ret = '' 1410 | end = Math.min(buf.length, end) 1411 | 1412 | for (var i = start; i < end; i++) { 1413 | ret += String.fromCharCode(buf[i]) 1414 | } 1415 | return ret 1416 | } 1417 | 1418 | function hexSlice (buf, start, end) { 1419 | var len = buf.length 1420 | 1421 | if (!start || start < 0) start = 0 1422 | if (!end || end < 0 || end > len) end = len 1423 | 1424 | var out = '' 1425 | for (var i = start; i < end; i++) { 1426 | out += toHex(buf[i]) 1427 | } 1428 | return out 1429 | } 1430 | 1431 | function utf16leSlice (buf, start, end) { 1432 | var bytes = buf.slice(start, end) 1433 | var res = '' 1434 | for (var i = 0; i < bytes.length; i += 2) { 1435 | res += String.fromCharCode(bytes[i] + bytes[i + 1] * 256) 1436 | } 1437 | return res 1438 | } 1439 | 1440 | Buffer.prototype.slice = function slice (start, end) { 1441 | var len = this.length 1442 | start = ~~start 1443 | end = end === undefined ? len : ~~end 1444 | 1445 | if (start < 0) { 1446 | start += len 1447 | if (start < 0) start = 0 1448 | } else if (start > len) { 1449 | start = len 1450 | } 1451 | 1452 | if (end < 0) { 1453 | end += len 1454 | if (end < 0) end = 0 1455 | } else if (end > len) { 1456 | end = len 1457 | } 1458 | 1459 | if (end < start) end = start 1460 | 1461 | var newBuf 1462 | if (Buffer.TYPED_ARRAY_SUPPORT) { 1463 | newBuf = Buffer._augment(this.subarray(start, end)) 1464 | } else { 1465 | var sliceLen = end - start 1466 | newBuf = new Buffer(sliceLen, undefined) 1467 | for (var i = 0; i < sliceLen; i++) { 1468 | newBuf[i] = this[i + start] 1469 | } 1470 | } 1471 | 1472 | if (newBuf.length) newBuf.parent = this.parent || this 1473 | 1474 | return newBuf 1475 | } 1476 | 1477 | /* 1478 | * Need to make sure that buffer isn't trying to write out of bounds. 1479 | */ 1480 | function checkOffset (offset, ext, length) { 1481 | if ((offset % 1) !== 0 || offset < 0) throw new RangeError('offset is not uint') 1482 | if (offset + ext > length) throw new RangeError('Trying to access beyond buffer length') 1483 | } 1484 | 1485 | Buffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) { 1486 | offset = offset | 0 1487 | byteLength = byteLength | 0 1488 | if (!noAssert) checkOffset(offset, byteLength, this.length) 1489 | 1490 | var val = this[offset] 1491 | var mul = 1 1492 | var i = 0 1493 | while (++i < byteLength && (mul *= 0x100)) { 1494 | val += this[offset + i] * mul 1495 | } 1496 | 1497 | return val 1498 | } 1499 | 1500 | Buffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) { 1501 | offset = offset | 0 1502 | byteLength = byteLength | 0 1503 | if (!noAssert) { 1504 | checkOffset(offset, byteLength, this.length) 1505 | } 1506 | 1507 | var val = this[offset + --byteLength] 1508 | var mul = 1 1509 | while (byteLength > 0 && (mul *= 0x100)) { 1510 | val += this[offset + --byteLength] * mul 1511 | } 1512 | 1513 | return val 1514 | } 1515 | 1516 | Buffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) { 1517 | if (!noAssert) checkOffset(offset, 1, this.length) 1518 | return this[offset] 1519 | } 1520 | 1521 | Buffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) { 1522 | if (!noAssert) checkOffset(offset, 2, this.length) 1523 | return this[offset] | (this[offset + 1] << 8) 1524 | } 1525 | 1526 | Buffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) { 1527 | if (!noAssert) checkOffset(offset, 2, this.length) 1528 | return (this[offset] << 8) | this[offset + 1] 1529 | } 1530 | 1531 | Buffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) { 1532 | if (!noAssert) checkOffset(offset, 4, this.length) 1533 | 1534 | return ((this[offset]) | 1535 | (this[offset + 1] << 8) | 1536 | (this[offset + 2] << 16)) + 1537 | (this[offset + 3] * 0x1000000) 1538 | } 1539 | 1540 | Buffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) { 1541 | if (!noAssert) checkOffset(offset, 4, this.length) 1542 | 1543 | return (this[offset] * 0x1000000) + 1544 | ((this[offset + 1] << 16) | 1545 | (this[offset + 2] << 8) | 1546 | this[offset + 3]) 1547 | } 1548 | 1549 | Buffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) { 1550 | offset = offset | 0 1551 | byteLength = byteLength | 0 1552 | if (!noAssert) checkOffset(offset, byteLength, this.length) 1553 | 1554 | var val = this[offset] 1555 | var mul = 1 1556 | var i = 0 1557 | while (++i < byteLength && (mul *= 0x100)) { 1558 | val += this[offset + i] * mul 1559 | } 1560 | mul *= 0x80 1561 | 1562 | if (val >= mul) val -= Math.pow(2, 8 * byteLength) 1563 | 1564 | return val 1565 | } 1566 | 1567 | Buffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) { 1568 | offset = offset | 0 1569 | byteLength = byteLength | 0 1570 | if (!noAssert) checkOffset(offset, byteLength, this.length) 1571 | 1572 | var i = byteLength 1573 | var mul = 1 1574 | var val = this[offset + --i] 1575 | while (i > 0 && (mul *= 0x100)) { 1576 | val += this[offset + --i] * mul 1577 | } 1578 | mul *= 0x80 1579 | 1580 | if (val >= mul) val -= Math.pow(2, 8 * byteLength) 1581 | 1582 | return val 1583 | } 1584 | 1585 | Buffer.prototype.readInt8 = function readInt8 (offset, noAssert) { 1586 | if (!noAssert) checkOffset(offset, 1, this.length) 1587 | if (!(this[offset] & 0x80)) return (this[offset]) 1588 | return ((0xff - this[offset] + 1) * -1) 1589 | } 1590 | 1591 | Buffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) { 1592 | if (!noAssert) checkOffset(offset, 2, this.length) 1593 | var val = this[offset] | (this[offset + 1] << 8) 1594 | return (val & 0x8000) ? val | 0xFFFF0000 : val 1595 | } 1596 | 1597 | Buffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) { 1598 | if (!noAssert) checkOffset(offset, 2, this.length) 1599 | var val = this[offset + 1] | (this[offset] << 8) 1600 | return (val & 0x8000) ? val | 0xFFFF0000 : val 1601 | } 1602 | 1603 | Buffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) { 1604 | if (!noAssert) checkOffset(offset, 4, this.length) 1605 | 1606 | return (this[offset]) | 1607 | (this[offset + 1] << 8) | 1608 | (this[offset + 2] << 16) | 1609 | (this[offset + 3] << 24) 1610 | } 1611 | 1612 | Buffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) { 1613 | if (!noAssert) checkOffset(offset, 4, this.length) 1614 | 1615 | return (this[offset] << 24) | 1616 | (this[offset + 1] << 16) | 1617 | (this[offset + 2] << 8) | 1618 | (this[offset + 3]) 1619 | } 1620 | 1621 | Buffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) { 1622 | if (!noAssert) checkOffset(offset, 4, this.length) 1623 | return ieee754.read(this, offset, true, 23, 4) 1624 | } 1625 | 1626 | Buffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) { 1627 | if (!noAssert) checkOffset(offset, 4, this.length) 1628 | return ieee754.read(this, offset, false, 23, 4) 1629 | } 1630 | 1631 | Buffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) { 1632 | if (!noAssert) checkOffset(offset, 8, this.length) 1633 | return ieee754.read(this, offset, true, 52, 8) 1634 | } 1635 | 1636 | Buffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) { 1637 | if (!noAssert) checkOffset(offset, 8, this.length) 1638 | return ieee754.read(this, offset, false, 52, 8) 1639 | } 1640 | 1641 | function checkInt (buf, value, offset, ext, max, min) { 1642 | if (!Buffer.isBuffer(buf)) throw new TypeError('buffer must be a Buffer instance') 1643 | if (value > max || value < min) throw new RangeError('value is out of bounds') 1644 | if (offset + ext > buf.length) throw new RangeError('index out of range') 1645 | } 1646 | 1647 | Buffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) { 1648 | value = +value 1649 | offset = offset | 0 1650 | byteLength = byteLength | 0 1651 | if (!noAssert) checkInt(this, value, offset, byteLength, Math.pow(2, 8 * byteLength), 0) 1652 | 1653 | var mul = 1 1654 | var i = 0 1655 | this[offset] = value & 0xFF 1656 | while (++i < byteLength && (mul *= 0x100)) { 1657 | this[offset + i] = (value / mul) & 0xFF 1658 | } 1659 | 1660 | return offset + byteLength 1661 | } 1662 | 1663 | Buffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) { 1664 | value = +value 1665 | offset = offset | 0 1666 | byteLength = byteLength | 0 1667 | if (!noAssert) checkInt(this, value, offset, byteLength, Math.pow(2, 8 * byteLength), 0) 1668 | 1669 | var i = byteLength - 1 1670 | var mul = 1 1671 | this[offset + i] = value & 0xFF 1672 | while (--i >= 0 && (mul *= 0x100)) { 1673 | this[offset + i] = (value / mul) & 0xFF 1674 | } 1675 | 1676 | return offset + byteLength 1677 | } 1678 | 1679 | Buffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) { 1680 | value = +value 1681 | offset = offset | 0 1682 | if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0) 1683 | if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value) 1684 | this[offset] = (value & 0xff) 1685 | return offset + 1 1686 | } 1687 | 1688 | function objectWriteUInt16 (buf, value, offset, littleEndian) { 1689 | if (value < 0) value = 0xffff + value + 1 1690 | for (var i = 0, j = Math.min(buf.length - offset, 2); i < j; i++) { 1691 | buf[offset + i] = (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>> 1692 | (littleEndian ? i : 1 - i) * 8 1693 | } 1694 | } 1695 | 1696 | Buffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) { 1697 | value = +value 1698 | offset = offset | 0 1699 | if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0) 1700 | if (Buffer.TYPED_ARRAY_SUPPORT) { 1701 | this[offset] = (value & 0xff) 1702 | this[offset + 1] = (value >>> 8) 1703 | } else { 1704 | objectWriteUInt16(this, value, offset, true) 1705 | } 1706 | return offset + 2 1707 | } 1708 | 1709 | Buffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) { 1710 | value = +value 1711 | offset = offset | 0 1712 | if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0) 1713 | if (Buffer.TYPED_ARRAY_SUPPORT) { 1714 | this[offset] = (value >>> 8) 1715 | this[offset + 1] = (value & 0xff) 1716 | } else { 1717 | objectWriteUInt16(this, value, offset, false) 1718 | } 1719 | return offset + 2 1720 | } 1721 | 1722 | function objectWriteUInt32 (buf, value, offset, littleEndian) { 1723 | if (value < 0) value = 0xffffffff + value + 1 1724 | for (var i = 0, j = Math.min(buf.length - offset, 4); i < j; i++) { 1725 | buf[offset + i] = (value >>> (littleEndian ? i : 3 - i) * 8) & 0xff 1726 | } 1727 | } 1728 | 1729 | Buffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) { 1730 | value = +value 1731 | offset = offset | 0 1732 | if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0) 1733 | if (Buffer.TYPED_ARRAY_SUPPORT) { 1734 | this[offset + 3] = (value >>> 24) 1735 | this[offset + 2] = (value >>> 16) 1736 | this[offset + 1] = (value >>> 8) 1737 | this[offset] = (value & 0xff) 1738 | } else { 1739 | objectWriteUInt32(this, value, offset, true) 1740 | } 1741 | return offset + 4 1742 | } 1743 | 1744 | Buffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) { 1745 | value = +value 1746 | offset = offset | 0 1747 | if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0) 1748 | if (Buffer.TYPED_ARRAY_SUPPORT) { 1749 | this[offset] = (value >>> 24) 1750 | this[offset + 1] = (value >>> 16) 1751 | this[offset + 2] = (value >>> 8) 1752 | this[offset + 3] = (value & 0xff) 1753 | } else { 1754 | objectWriteUInt32(this, value, offset, false) 1755 | } 1756 | return offset + 4 1757 | } 1758 | 1759 | Buffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) { 1760 | value = +value 1761 | offset = offset | 0 1762 | if (!noAssert) { 1763 | var limit = Math.pow(2, 8 * byteLength - 1) 1764 | 1765 | checkInt(this, value, offset, byteLength, limit - 1, -limit) 1766 | } 1767 | 1768 | var i = 0 1769 | var mul = 1 1770 | var sub = value < 0 ? 1 : 0 1771 | this[offset] = value & 0xFF 1772 | while (++i < byteLength && (mul *= 0x100)) { 1773 | this[offset + i] = ((value / mul) >> 0) - sub & 0xFF 1774 | } 1775 | 1776 | return offset + byteLength 1777 | } 1778 | 1779 | Buffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) { 1780 | value = +value 1781 | offset = offset | 0 1782 | if (!noAssert) { 1783 | var limit = Math.pow(2, 8 * byteLength - 1) 1784 | 1785 | checkInt(this, value, offset, byteLength, limit - 1, -limit) 1786 | } 1787 | 1788 | var i = byteLength - 1 1789 | var mul = 1 1790 | var sub = value < 0 ? 1 : 0 1791 | this[offset + i] = value & 0xFF 1792 | while (--i >= 0 && (mul *= 0x100)) { 1793 | this[offset + i] = ((value / mul) >> 0) - sub & 0xFF 1794 | } 1795 | 1796 | return offset + byteLength 1797 | } 1798 | 1799 | Buffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) { 1800 | value = +value 1801 | offset = offset | 0 1802 | if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80) 1803 | if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value) 1804 | if (value < 0) value = 0xff + value + 1 1805 | this[offset] = (value & 0xff) 1806 | return offset + 1 1807 | } 1808 | 1809 | Buffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) { 1810 | value = +value 1811 | offset = offset | 0 1812 | if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000) 1813 | if (Buffer.TYPED_ARRAY_SUPPORT) { 1814 | this[offset] = (value & 0xff) 1815 | this[offset + 1] = (value >>> 8) 1816 | } else { 1817 | objectWriteUInt16(this, value, offset, true) 1818 | } 1819 | return offset + 2 1820 | } 1821 | 1822 | Buffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) { 1823 | value = +value 1824 | offset = offset | 0 1825 | if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000) 1826 | if (Buffer.TYPED_ARRAY_SUPPORT) { 1827 | this[offset] = (value >>> 8) 1828 | this[offset + 1] = (value & 0xff) 1829 | } else { 1830 | objectWriteUInt16(this, value, offset, false) 1831 | } 1832 | return offset + 2 1833 | } 1834 | 1835 | Buffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) { 1836 | value = +value 1837 | offset = offset | 0 1838 | if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000) 1839 | if (Buffer.TYPED_ARRAY_SUPPORT) { 1840 | this[offset] = (value & 0xff) 1841 | this[offset + 1] = (value >>> 8) 1842 | this[offset + 2] = (value >>> 16) 1843 | this[offset + 3] = (value >>> 24) 1844 | } else { 1845 | objectWriteUInt32(this, value, offset, true) 1846 | } 1847 | return offset + 4 1848 | } 1849 | 1850 | Buffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) { 1851 | value = +value 1852 | offset = offset | 0 1853 | if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000) 1854 | if (value < 0) value = 0xffffffff + value + 1 1855 | if (Buffer.TYPED_ARRAY_SUPPORT) { 1856 | this[offset] = (value >>> 24) 1857 | this[offset + 1] = (value >>> 16) 1858 | this[offset + 2] = (value >>> 8) 1859 | this[offset + 3] = (value & 0xff) 1860 | } else { 1861 | objectWriteUInt32(this, value, offset, false) 1862 | } 1863 | return offset + 4 1864 | } 1865 | 1866 | function checkIEEE754 (buf, value, offset, ext, max, min) { 1867 | if (value > max || value < min) throw new RangeError('value is out of bounds') 1868 | if (offset + ext > buf.length) throw new RangeError('index out of range') 1869 | if (offset < 0) throw new RangeError('index out of range') 1870 | } 1871 | 1872 | function writeFloat (buf, value, offset, littleEndian, noAssert) { 1873 | if (!noAssert) { 1874 | checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38) 1875 | } 1876 | ieee754.write(buf, value, offset, littleEndian, 23, 4) 1877 | return offset + 4 1878 | } 1879 | 1880 | Buffer.prototype.writeFloatLE = function writeFloatLE (value, offset, noAssert) { 1881 | return writeFloat(this, value, offset, true, noAssert) 1882 | } 1883 | 1884 | Buffer.prototype.writeFloatBE = function writeFloatBE (value, offset, noAssert) { 1885 | return writeFloat(this, value, offset, false, noAssert) 1886 | } 1887 | 1888 | function writeDouble (buf, value, offset, littleEndian, noAssert) { 1889 | if (!noAssert) { 1890 | checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308) 1891 | } 1892 | ieee754.write(buf, value, offset, littleEndian, 52, 8) 1893 | return offset + 8 1894 | } 1895 | 1896 | Buffer.prototype.writeDoubleLE = function writeDoubleLE (value, offset, noAssert) { 1897 | return writeDouble(this, value, offset, true, noAssert) 1898 | } 1899 | 1900 | Buffer.prototype.writeDoubleBE = function writeDoubleBE (value, offset, noAssert) { 1901 | return writeDouble(this, value, offset, false, noAssert) 1902 | } 1903 | 1904 | // copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length) 1905 | Buffer.prototype.copy = function copy (target, targetStart, start, end) { 1906 | if (!start) start = 0 1907 | if (!end && end !== 0) end = this.length 1908 | if (targetStart >= target.length) targetStart = target.length 1909 | if (!targetStart) targetStart = 0 1910 | if (end > 0 && end < start) end = start 1911 | 1912 | // Copy 0 bytes; we're done 1913 | if (end === start) return 0 1914 | if (target.length === 0 || this.length === 0) return 0 1915 | 1916 | // Fatal error conditions 1917 | if (targetStart < 0) { 1918 | throw new RangeError('targetStart out of bounds') 1919 | } 1920 | if (start < 0 || start >= this.length) throw new RangeError('sourceStart out of bounds') 1921 | if (end < 0) throw new RangeError('sourceEnd out of bounds') 1922 | 1923 | // Are we oob? 1924 | if (end > this.length) end = this.length 1925 | if (target.length - targetStart < end - start) { 1926 | end = target.length - targetStart + start 1927 | } 1928 | 1929 | var len = end - start 1930 | var i 1931 | 1932 | if (this === target && start < targetStart && targetStart < end) { 1933 | // descending copy from end 1934 | for (i = len - 1; i >= 0; i--) { 1935 | target[i + targetStart] = this[i + start] 1936 | } 1937 | } else if (len < 1000 || !Buffer.TYPED_ARRAY_SUPPORT) { 1938 | // ascending copy from start 1939 | for (i = 0; i < len; i++) { 1940 | target[i + targetStart] = this[i + start] 1941 | } 1942 | } else { 1943 | target._set(this.subarray(start, start + len), targetStart) 1944 | } 1945 | 1946 | return len 1947 | } 1948 | 1949 | // fill(value, start=0, end=buffer.length) 1950 | Buffer.prototype.fill = function fill (value, start, end) { 1951 | if (!value) value = 0 1952 | if (!start) start = 0 1953 | if (!end) end = this.length 1954 | 1955 | if (end < start) throw new RangeError('end < start') 1956 | 1957 | // Fill 0 bytes; we're done 1958 | if (end === start) return 1959 | if (this.length === 0) return 1960 | 1961 | if (start < 0 || start >= this.length) throw new RangeError('start out of bounds') 1962 | if (end < 0 || end > this.length) throw new RangeError('end out of bounds') 1963 | 1964 | var i 1965 | if (typeof value === 'number') { 1966 | for (i = start; i < end; i++) { 1967 | this[i] = value 1968 | } 1969 | } else { 1970 | var bytes = utf8ToBytes(value.toString()) 1971 | var len = bytes.length 1972 | for (i = start; i < end; i++) { 1973 | this[i] = bytes[i % len] 1974 | } 1975 | } 1976 | 1977 | return this 1978 | } 1979 | 1980 | /** 1981 | * Creates a new `ArrayBuffer` with the *copied* memory of the buffer instance. 1982 | * Added in Node 0.12. Only available in browsers that support ArrayBuffer. 1983 | */ 1984 | Buffer.prototype.toArrayBuffer = function toArrayBuffer () { 1985 | if (typeof Uint8Array !== 'undefined') { 1986 | if (Buffer.TYPED_ARRAY_SUPPORT) { 1987 | return (new Buffer(this)).buffer 1988 | } else { 1989 | var buf = new Uint8Array(this.length) 1990 | for (var i = 0, len = buf.length; i < len; i += 1) { 1991 | buf[i] = this[i] 1992 | } 1993 | return buf.buffer 1994 | } 1995 | } else { 1996 | throw new TypeError('Buffer.toArrayBuffer not supported in this browser') 1997 | } 1998 | } 1999 | 2000 | // HELPER FUNCTIONS 2001 | // ================ 2002 | 2003 | var BP = Buffer.prototype 2004 | 2005 | /** 2006 | * Augment a Uint8Array *instance* (not the Uint8Array class!) with Buffer methods 2007 | */ 2008 | Buffer._augment = function _augment (arr) { 2009 | arr.constructor = Buffer 2010 | arr._isBuffer = true 2011 | 2012 | // save reference to original Uint8Array set method before overwriting 2013 | arr._set = arr.set 2014 | 2015 | // deprecated 2016 | arr.get = BP.get 2017 | arr.set = BP.set 2018 | 2019 | arr.write = BP.write 2020 | arr.toString = BP.toString 2021 | arr.toLocaleString = BP.toString 2022 | arr.toJSON = BP.toJSON 2023 | arr.equals = BP.equals 2024 | arr.compare = BP.compare 2025 | arr.indexOf = BP.indexOf 2026 | arr.copy = BP.copy 2027 | arr.slice = BP.slice 2028 | arr.readUIntLE = BP.readUIntLE 2029 | arr.readUIntBE = BP.readUIntBE 2030 | arr.readUInt8 = BP.readUInt8 2031 | arr.readUInt16LE = BP.readUInt16LE 2032 | arr.readUInt16BE = BP.readUInt16BE 2033 | arr.readUInt32LE = BP.readUInt32LE 2034 | arr.readUInt32BE = BP.readUInt32BE 2035 | arr.readIntLE = BP.readIntLE 2036 | arr.readIntBE = BP.readIntBE 2037 | arr.readInt8 = BP.readInt8 2038 | arr.readInt16LE = BP.readInt16LE 2039 | arr.readInt16BE = BP.readInt16BE 2040 | arr.readInt32LE = BP.readInt32LE 2041 | arr.readInt32BE = BP.readInt32BE 2042 | arr.readFloatLE = BP.readFloatLE 2043 | arr.readFloatBE = BP.readFloatBE 2044 | arr.readDoubleLE = BP.readDoubleLE 2045 | arr.readDoubleBE = BP.readDoubleBE 2046 | arr.writeUInt8 = BP.writeUInt8 2047 | arr.writeUIntLE = BP.writeUIntLE 2048 | arr.writeUIntBE = BP.writeUIntBE 2049 | arr.writeUInt16LE = BP.writeUInt16LE 2050 | arr.writeUInt16BE = BP.writeUInt16BE 2051 | arr.writeUInt32LE = BP.writeUInt32LE 2052 | arr.writeUInt32BE = BP.writeUInt32BE 2053 | arr.writeIntLE = BP.writeIntLE 2054 | arr.writeIntBE = BP.writeIntBE 2055 | arr.writeInt8 = BP.writeInt8 2056 | arr.writeInt16LE = BP.writeInt16LE 2057 | arr.writeInt16BE = BP.writeInt16BE 2058 | arr.writeInt32LE = BP.writeInt32LE 2059 | arr.writeInt32BE = BP.writeInt32BE 2060 | arr.writeFloatLE = BP.writeFloatLE 2061 | arr.writeFloatBE = BP.writeFloatBE 2062 | arr.writeDoubleLE = BP.writeDoubleLE 2063 | arr.writeDoubleBE = BP.writeDoubleBE 2064 | arr.fill = BP.fill 2065 | arr.inspect = BP.inspect 2066 | arr.toArrayBuffer = BP.toArrayBuffer 2067 | 2068 | return arr 2069 | } 2070 | 2071 | var INVALID_BASE64_RE = /[^+\/0-9A-Za-z-_]/g 2072 | 2073 | function base64clean (str) { 2074 | // Node strips out invalid characters like \n and \t from the string, base64-js does not 2075 | str = stringtrim(str).replace(INVALID_BASE64_RE, '') 2076 | // Node converts strings with length < 2 to '' 2077 | if (str.length < 2) return '' 2078 | // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not 2079 | while (str.length % 4 !== 0) { 2080 | str = str + '=' 2081 | } 2082 | return str 2083 | } 2084 | 2085 | function stringtrim (str) { 2086 | if (str.trim) return str.trim() 2087 | return str.replace(/^\s+|\s+$/g, '') 2088 | } 2089 | 2090 | function toHex (n) { 2091 | if (n < 16) return '0' + n.toString(16) 2092 | return n.toString(16) 2093 | } 2094 | 2095 | function utf8ToBytes (string, units) { 2096 | units = units || Infinity 2097 | var codePoint 2098 | var length = string.length 2099 | var leadSurrogate = null 2100 | var bytes = [] 2101 | 2102 | for (var i = 0; i < length; i++) { 2103 | codePoint = string.charCodeAt(i) 2104 | 2105 | // is surrogate component 2106 | if (codePoint > 0xD7FF && codePoint < 0xE000) { 2107 | // last char was a lead 2108 | if (!leadSurrogate) { 2109 | // no lead yet 2110 | if (codePoint > 0xDBFF) { 2111 | // unexpected trail 2112 | if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) 2113 | continue 2114 | } else if (i + 1 === length) { 2115 | // unpaired lead 2116 | if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) 2117 | continue 2118 | } 2119 | 2120 | // valid lead 2121 | leadSurrogate = codePoint 2122 | 2123 | continue 2124 | } 2125 | 2126 | // 2 leads in a row 2127 | if (codePoint < 0xDC00) { 2128 | if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) 2129 | leadSurrogate = codePoint 2130 | continue 2131 | } 2132 | 2133 | // valid surrogate pair 2134 | codePoint = (leadSurrogate - 0xD800 << 10 | codePoint - 0xDC00) + 0x10000 2135 | } else if (leadSurrogate) { 2136 | // valid bmp char, but last char was a lead 2137 | if ((units -= 3) > -1) bytes.push(0xEF, 0xBF, 0xBD) 2138 | } 2139 | 2140 | leadSurrogate = null 2141 | 2142 | // encode utf8 2143 | if (codePoint < 0x80) { 2144 | if ((units -= 1) < 0) break 2145 | bytes.push(codePoint) 2146 | } else if (codePoint < 0x800) { 2147 | if ((units -= 2) < 0) break 2148 | bytes.push( 2149 | codePoint >> 0x6 | 0xC0, 2150 | codePoint & 0x3F | 0x80 2151 | ) 2152 | } else if (codePoint < 0x10000) { 2153 | if ((units -= 3) < 0) break 2154 | bytes.push( 2155 | codePoint >> 0xC | 0xE0, 2156 | codePoint >> 0x6 & 0x3F | 0x80, 2157 | codePoint & 0x3F | 0x80 2158 | ) 2159 | } else if (codePoint < 0x110000) { 2160 | if ((units -= 4) < 0) break 2161 | bytes.push( 2162 | codePoint >> 0x12 | 0xF0, 2163 | codePoint >> 0xC & 0x3F | 0x80, 2164 | codePoint >> 0x6 & 0x3F | 0x80, 2165 | codePoint & 0x3F | 0x80 2166 | ) 2167 | } else { 2168 | throw new Error('Invalid code point') 2169 | } 2170 | } 2171 | 2172 | return bytes 2173 | } 2174 | 2175 | function asciiToBytes (str) { 2176 | var byteArray = [] 2177 | for (var i = 0; i < str.length; i++) { 2178 | // Node's code seems to be doing this and not & 0x7F.. 2179 | byteArray.push(str.charCodeAt(i) & 0xFF) 2180 | } 2181 | return byteArray 2182 | } 2183 | 2184 | function utf16leToBytes (str, units) { 2185 | var c, hi, lo 2186 | var byteArray = [] 2187 | for (var i = 0; i < str.length; i++) { 2188 | if ((units -= 2) < 0) break 2189 | 2190 | c = str.charCodeAt(i) 2191 | hi = c >> 8 2192 | lo = c % 256 2193 | byteArray.push(lo) 2194 | byteArray.push(hi) 2195 | } 2196 | 2197 | return byteArray 2198 | } 2199 | 2200 | function base64ToBytes (str) { 2201 | return base64.toByteArray(base64clean(str)) 2202 | } 2203 | 2204 | function blitBuffer (src, dst, offset, length) { 2205 | for (var i = 0; i < length; i++) { 2206 | if ((i + offset >= dst.length) || (i >= src.length)) break 2207 | dst[i + offset] = src[i] 2208 | } 2209 | return i 2210 | } 2211 | 2212 | }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) 2213 | },{"base64-js":2,"ieee754":7,"isarray":4}],4:[function(require,module,exports){ 2214 | var toString = {}.toString; 2215 | 2216 | module.exports = Array.isArray || function (arr) { 2217 | return toString.call(arr) == '[object Array]'; 2218 | }; 2219 | 2220 | },{}],5:[function(require,module,exports){ 2221 | 2222 | /** 2223 | * Expose `Emitter`. 2224 | */ 2225 | 2226 | module.exports = Emitter; 2227 | 2228 | /** 2229 | * Initialize a new `Emitter`. 2230 | * 2231 | * @api public 2232 | */ 2233 | 2234 | function Emitter(obj) { 2235 | if (obj) return mixin(obj); 2236 | }; 2237 | 2238 | /** 2239 | * Mixin the emitter properties. 2240 | * 2241 | * @param {Object} obj 2242 | * @return {Object} 2243 | * @api private 2244 | */ 2245 | 2246 | function mixin(obj) { 2247 | for (var key in Emitter.prototype) { 2248 | obj[key] = Emitter.prototype[key]; 2249 | } 2250 | return obj; 2251 | } 2252 | 2253 | /** 2254 | * Listen on the given `event` with `fn`. 2255 | * 2256 | * @param {String} event 2257 | * @param {Function} fn 2258 | * @return {Emitter} 2259 | * @api public 2260 | */ 2261 | 2262 | Emitter.prototype.on = 2263 | Emitter.prototype.addEventListener = function(event, fn){ 2264 | this._callbacks = this._callbacks || {}; 2265 | (this._callbacks[event] = this._callbacks[event] || []) 2266 | .push(fn); 2267 | return this; 2268 | }; 2269 | 2270 | /** 2271 | * Adds an `event` listener that will be invoked a single 2272 | * time then automatically removed. 2273 | * 2274 | * @param {String} event 2275 | * @param {Function} fn 2276 | * @return {Emitter} 2277 | * @api public 2278 | */ 2279 | 2280 | Emitter.prototype.once = function(event, fn){ 2281 | var self = this; 2282 | this._callbacks = this._callbacks || {}; 2283 | 2284 | function on() { 2285 | self.off(event, on); 2286 | fn.apply(this, arguments); 2287 | } 2288 | 2289 | on.fn = fn; 2290 | this.on(event, on); 2291 | return this; 2292 | }; 2293 | 2294 | /** 2295 | * Remove the given callback for `event` or all 2296 | * registered callbacks. 2297 | * 2298 | * @param {String} event 2299 | * @param {Function} fn 2300 | * @return {Emitter} 2301 | * @api public 2302 | */ 2303 | 2304 | Emitter.prototype.off = 2305 | Emitter.prototype.removeListener = 2306 | Emitter.prototype.removeAllListeners = 2307 | Emitter.prototype.removeEventListener = function(event, fn){ 2308 | this._callbacks = this._callbacks || {}; 2309 | 2310 | // all 2311 | if (0 == arguments.length) { 2312 | this._callbacks = {}; 2313 | return this; 2314 | } 2315 | 2316 | // specific event 2317 | var callbacks = this._callbacks[event]; 2318 | if (!callbacks) return this; 2319 | 2320 | // remove all handlers 2321 | if (1 == arguments.length) { 2322 | delete this._callbacks[event]; 2323 | return this; 2324 | } 2325 | 2326 | // remove specific handler 2327 | var cb; 2328 | for (var i = 0; i < callbacks.length; i++) { 2329 | cb = callbacks[i]; 2330 | if (cb === fn || cb.fn === fn) { 2331 | callbacks.splice(i, 1); 2332 | break; 2333 | } 2334 | } 2335 | return this; 2336 | }; 2337 | 2338 | /** 2339 | * Emit `event` with the given args. 2340 | * 2341 | * @param {String} event 2342 | * @param {Mixed} ... 2343 | * @return {Emitter} 2344 | */ 2345 | 2346 | Emitter.prototype.emit = function(event){ 2347 | this._callbacks = this._callbacks || {}; 2348 | var args = [].slice.call(arguments, 1) 2349 | , callbacks = this._callbacks[event]; 2350 | 2351 | if (callbacks) { 2352 | callbacks = callbacks.slice(0); 2353 | for (var i = 0, len = callbacks.length; i < len; ++i) { 2354 | callbacks[i].apply(this, args); 2355 | } 2356 | } 2357 | 2358 | return this; 2359 | }; 2360 | 2361 | /** 2362 | * Return array of callbacks for `event`. 2363 | * 2364 | * @param {String} event 2365 | * @return {Array} 2366 | * @api public 2367 | */ 2368 | 2369 | Emitter.prototype.listeners = function(event){ 2370 | this._callbacks = this._callbacks || {}; 2371 | return this._callbacks[event] || []; 2372 | }; 2373 | 2374 | /** 2375 | * Check if this emitter has `event` handlers. 2376 | * 2377 | * @param {String} event 2378 | * @return {Boolean} 2379 | * @api public 2380 | */ 2381 | 2382 | Emitter.prototype.hasListeners = function(event){ 2383 | return !! this.listeners(event).length; 2384 | }; 2385 | 2386 | },{}],6:[function(require,module,exports){ 2387 | /*! 2388 | * EventEmitter2 2389 | * https://github.com/hij1nx/EventEmitter2 2390 | * 2391 | * Copyright (c) 2013 hij1nx 2392 | * Licensed under the MIT license. 2393 | */ 2394 | ;!function(undefined) { 2395 | 2396 | var isArray = Array.isArray ? Array.isArray : function _isArray(obj) { 2397 | return Object.prototype.toString.call(obj) === "[object Array]"; 2398 | }; 2399 | var defaultMaxListeners = 10; 2400 | 2401 | function init() { 2402 | this._events = {}; 2403 | if (this._conf) { 2404 | configure.call(this, this._conf); 2405 | } 2406 | } 2407 | 2408 | function configure(conf) { 2409 | if (conf) { 2410 | 2411 | this._conf = conf; 2412 | 2413 | conf.delimiter && (this.delimiter = conf.delimiter); 2414 | conf.maxListeners && (this._events.maxListeners = conf.maxListeners); 2415 | conf.wildcard && (this.wildcard = conf.wildcard); 2416 | conf.newListener && (this.newListener = conf.newListener); 2417 | 2418 | if (this.wildcard) { 2419 | this.listenerTree = {}; 2420 | } 2421 | } 2422 | } 2423 | 2424 | function EventEmitter(conf) { 2425 | this._events = {}; 2426 | this.newListener = false; 2427 | configure.call(this, conf); 2428 | } 2429 | 2430 | // 2431 | // Attention, function return type now is array, always ! 2432 | // It has zero elements if no any matches found and one or more 2433 | // elements (leafs) if there are matches 2434 | // 2435 | function searchListenerTree(handlers, type, tree, i) { 2436 | if (!tree) { 2437 | return []; 2438 | } 2439 | var listeners=[], leaf, len, branch, xTree, xxTree, isolatedBranch, endReached, 2440 | typeLength = type.length, currentType = type[i], nextType = type[i+1]; 2441 | if (i === typeLength && tree._listeners) { 2442 | // 2443 | // If at the end of the event(s) list and the tree has listeners 2444 | // invoke those listeners. 2445 | // 2446 | if (typeof tree._listeners === 'function') { 2447 | handlers && handlers.push(tree._listeners); 2448 | return [tree]; 2449 | } else { 2450 | for (leaf = 0, len = tree._listeners.length; leaf < len; leaf++) { 2451 | handlers && handlers.push(tree._listeners[leaf]); 2452 | } 2453 | return [tree]; 2454 | } 2455 | } 2456 | 2457 | if ((currentType === '*' || currentType === '**') || tree[currentType]) { 2458 | // 2459 | // If the event emitted is '*' at this part 2460 | // or there is a concrete match at this patch 2461 | // 2462 | if (currentType === '*') { 2463 | for (branch in tree) { 2464 | if (branch !== '_listeners' && tree.hasOwnProperty(branch)) { 2465 | listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i+1)); 2466 | } 2467 | } 2468 | return listeners; 2469 | } else if(currentType === '**') { 2470 | endReached = (i+1 === typeLength || (i+2 === typeLength && nextType === '*')); 2471 | if(endReached && tree._listeners) { 2472 | // The next element has a _listeners, add it to the handlers. 2473 | listeners = listeners.concat(searchListenerTree(handlers, type, tree, typeLength)); 2474 | } 2475 | 2476 | for (branch in tree) { 2477 | if (branch !== '_listeners' && tree.hasOwnProperty(branch)) { 2478 | if(branch === '*' || branch === '**') { 2479 | if(tree[branch]._listeners && !endReached) { 2480 | listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], typeLength)); 2481 | } 2482 | listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i)); 2483 | } else if(branch === nextType) { 2484 | listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i+2)); 2485 | } else { 2486 | // No match on this one, shift into the tree but not in the type array. 2487 | listeners = listeners.concat(searchListenerTree(handlers, type, tree[branch], i)); 2488 | } 2489 | } 2490 | } 2491 | return listeners; 2492 | } 2493 | 2494 | listeners = listeners.concat(searchListenerTree(handlers, type, tree[currentType], i+1)); 2495 | } 2496 | 2497 | xTree = tree['*']; 2498 | if (xTree) { 2499 | // 2500 | // If the listener tree will allow any match for this part, 2501 | // then recursively explore all branches of the tree 2502 | // 2503 | searchListenerTree(handlers, type, xTree, i+1); 2504 | } 2505 | 2506 | xxTree = tree['**']; 2507 | if(xxTree) { 2508 | if(i < typeLength) { 2509 | if(xxTree._listeners) { 2510 | // If we have a listener on a '**', it will catch all, so add its handler. 2511 | searchListenerTree(handlers, type, xxTree, typeLength); 2512 | } 2513 | 2514 | // Build arrays of matching next branches and others. 2515 | for(branch in xxTree) { 2516 | if(branch !== '_listeners' && xxTree.hasOwnProperty(branch)) { 2517 | if(branch === nextType) { 2518 | // We know the next element will match, so jump twice. 2519 | searchListenerTree(handlers, type, xxTree[branch], i+2); 2520 | } else if(branch === currentType) { 2521 | // Current node matches, move into the tree. 2522 | searchListenerTree(handlers, type, xxTree[branch], i+1); 2523 | } else { 2524 | isolatedBranch = {}; 2525 | isolatedBranch[branch] = xxTree[branch]; 2526 | searchListenerTree(handlers, type, { '**': isolatedBranch }, i+1); 2527 | } 2528 | } 2529 | } 2530 | } else if(xxTree._listeners) { 2531 | // We have reached the end and still on a '**' 2532 | searchListenerTree(handlers, type, xxTree, typeLength); 2533 | } else if(xxTree['*'] && xxTree['*']._listeners) { 2534 | searchListenerTree(handlers, type, xxTree['*'], typeLength); 2535 | } 2536 | } 2537 | 2538 | return listeners; 2539 | } 2540 | 2541 | function growListenerTree(type, listener) { 2542 | 2543 | type = typeof type === 'string' ? type.split(this.delimiter) : type.slice(); 2544 | 2545 | // 2546 | // Looks for two consecutive '**', if so, don't add the event at all. 2547 | // 2548 | for(var i = 0, len = type.length; i+1 < len; i++) { 2549 | if(type[i] === '**' && type[i+1] === '**') { 2550 | return; 2551 | } 2552 | } 2553 | 2554 | var tree = this.listenerTree; 2555 | var name = type.shift(); 2556 | 2557 | while (name) { 2558 | 2559 | if (!tree[name]) { 2560 | tree[name] = {}; 2561 | } 2562 | 2563 | tree = tree[name]; 2564 | 2565 | if (type.length === 0) { 2566 | 2567 | if (!tree._listeners) { 2568 | tree._listeners = listener; 2569 | } 2570 | else if(typeof tree._listeners === 'function') { 2571 | tree._listeners = [tree._listeners, listener]; 2572 | } 2573 | else if (isArray(tree._listeners)) { 2574 | 2575 | tree._listeners.push(listener); 2576 | 2577 | if (!tree._listeners.warned) { 2578 | 2579 | var m = defaultMaxListeners; 2580 | 2581 | if (typeof this._events.maxListeners !== 'undefined') { 2582 | m = this._events.maxListeners; 2583 | } 2584 | 2585 | if (m > 0 && tree._listeners.length > m) { 2586 | 2587 | tree._listeners.warned = true; 2588 | console.error('(node) warning: possible EventEmitter memory ' + 2589 | 'leak detected. %d listeners added. ' + 2590 | 'Use emitter.setMaxListeners() to increase limit.', 2591 | tree._listeners.length); 2592 | console.trace(); 2593 | } 2594 | } 2595 | } 2596 | return true; 2597 | } 2598 | name = type.shift(); 2599 | } 2600 | return true; 2601 | } 2602 | 2603 | // By default EventEmitters will print a warning if more than 2604 | // 10 listeners are added to it. This is a useful default which 2605 | // helps finding memory leaks. 2606 | // 2607 | // Obviously not all Emitters should be limited to 10. This function allows 2608 | // that to be increased. Set to zero for unlimited. 2609 | 2610 | EventEmitter.prototype.delimiter = '.'; 2611 | 2612 | EventEmitter.prototype.setMaxListeners = function(n) { 2613 | this._events || init.call(this); 2614 | this._events.maxListeners = n; 2615 | if (!this._conf) this._conf = {}; 2616 | this._conf.maxListeners = n; 2617 | }; 2618 | 2619 | EventEmitter.prototype.event = ''; 2620 | 2621 | EventEmitter.prototype.once = function(event, fn) { 2622 | this.many(event, 1, fn); 2623 | return this; 2624 | }; 2625 | 2626 | EventEmitter.prototype.many = function(event, ttl, fn) { 2627 | var self = this; 2628 | 2629 | if (typeof fn !== 'function') { 2630 | throw new Error('many only accepts instances of Function'); 2631 | } 2632 | 2633 | function listener() { 2634 | if (--ttl === 0) { 2635 | self.off(event, listener); 2636 | } 2637 | fn.apply(this, arguments); 2638 | } 2639 | 2640 | listener._origin = fn; 2641 | 2642 | this.on(event, listener); 2643 | 2644 | return self; 2645 | }; 2646 | 2647 | EventEmitter.prototype.emit = function() { 2648 | 2649 | this._events || init.call(this); 2650 | 2651 | var type = arguments[0]; 2652 | 2653 | if (type === 'newListener' && !this.newListener) { 2654 | if (!this._events.newListener) { return false; } 2655 | } 2656 | 2657 | // Loop through the *_all* functions and invoke them. 2658 | if (this._all) { 2659 | var l = arguments.length; 2660 | var args = new Array(l - 1); 2661 | for (var i = 1; i < l; i++) args[i - 1] = arguments[i]; 2662 | for (i = 0, l = this._all.length; i < l; i++) { 2663 | this.event = type; 2664 | this._all[i].apply(this, args); 2665 | } 2666 | } 2667 | 2668 | // If there is no 'error' event listener then throw. 2669 | if (type === 'error') { 2670 | 2671 | if (!this._all && 2672 | !this._events.error && 2673 | !(this.wildcard && this.listenerTree.error)) { 2674 | 2675 | if (arguments[1] instanceof Error) { 2676 | throw arguments[1]; // Unhandled 'error' event 2677 | } else { 2678 | throw new Error("Uncaught, unspecified 'error' event."); 2679 | } 2680 | return false; 2681 | } 2682 | } 2683 | 2684 | var handler; 2685 | 2686 | if(this.wildcard) { 2687 | handler = []; 2688 | var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice(); 2689 | searchListenerTree.call(this, handler, ns, this.listenerTree, 0); 2690 | } 2691 | else { 2692 | handler = this._events[type]; 2693 | } 2694 | 2695 | if (typeof handler === 'function') { 2696 | this.event = type; 2697 | if (arguments.length === 1) { 2698 | handler.call(this); 2699 | } 2700 | else if (arguments.length > 1) 2701 | switch (arguments.length) { 2702 | case 2: 2703 | handler.call(this, arguments[1]); 2704 | break; 2705 | case 3: 2706 | handler.call(this, arguments[1], arguments[2]); 2707 | break; 2708 | // slower 2709 | default: 2710 | var l = arguments.length; 2711 | var args = new Array(l - 1); 2712 | for (var i = 1; i < l; i++) args[i - 1] = arguments[i]; 2713 | handler.apply(this, args); 2714 | } 2715 | return true; 2716 | } 2717 | else if (handler) { 2718 | var l = arguments.length; 2719 | var args = new Array(l - 1); 2720 | for (var i = 1; i < l; i++) args[i - 1] = arguments[i]; 2721 | 2722 | var listeners = handler.slice(); 2723 | for (var i = 0, l = listeners.length; i < l; i++) { 2724 | this.event = type; 2725 | listeners[i].apply(this, args); 2726 | } 2727 | return (listeners.length > 0) || !!this._all; 2728 | } 2729 | else { 2730 | return !!this._all; 2731 | } 2732 | 2733 | }; 2734 | 2735 | EventEmitter.prototype.on = function(type, listener) { 2736 | 2737 | if (typeof type === 'function') { 2738 | this.onAny(type); 2739 | return this; 2740 | } 2741 | 2742 | if (typeof listener !== 'function') { 2743 | throw new Error('on only accepts instances of Function'); 2744 | } 2745 | this._events || init.call(this); 2746 | 2747 | // To avoid recursion in the case that type == "newListeners"! Before 2748 | // adding it to the listeners, first emit "newListeners". 2749 | this.emit('newListener', type, listener); 2750 | 2751 | if(this.wildcard) { 2752 | growListenerTree.call(this, type, listener); 2753 | return this; 2754 | } 2755 | 2756 | if (!this._events[type]) { 2757 | // Optimize the case of one listener. Don't need the extra array object. 2758 | this._events[type] = listener; 2759 | } 2760 | else if(typeof this._events[type] === 'function') { 2761 | // Adding the second element, need to change to array. 2762 | this._events[type] = [this._events[type], listener]; 2763 | } 2764 | else if (isArray(this._events[type])) { 2765 | // If we've already got an array, just append. 2766 | this._events[type].push(listener); 2767 | 2768 | // Check for listener leak 2769 | if (!this._events[type].warned) { 2770 | 2771 | var m = defaultMaxListeners; 2772 | 2773 | if (typeof this._events.maxListeners !== 'undefined') { 2774 | m = this._events.maxListeners; 2775 | } 2776 | 2777 | if (m > 0 && this._events[type].length > m) { 2778 | 2779 | this._events[type].warned = true; 2780 | console.error('(node) warning: possible EventEmitter memory ' + 2781 | 'leak detected. %d listeners added. ' + 2782 | 'Use emitter.setMaxListeners() to increase limit.', 2783 | this._events[type].length); 2784 | console.trace(); 2785 | } 2786 | } 2787 | } 2788 | return this; 2789 | }; 2790 | 2791 | EventEmitter.prototype.onAny = function(fn) { 2792 | 2793 | if (typeof fn !== 'function') { 2794 | throw new Error('onAny only accepts instances of Function'); 2795 | } 2796 | 2797 | if(!this._all) { 2798 | this._all = []; 2799 | } 2800 | 2801 | // Add the function to the event listener collection. 2802 | this._all.push(fn); 2803 | return this; 2804 | }; 2805 | 2806 | EventEmitter.prototype.addListener = EventEmitter.prototype.on; 2807 | 2808 | EventEmitter.prototype.off = function(type, listener) { 2809 | if (typeof listener !== 'function') { 2810 | throw new Error('removeListener only takes instances of Function'); 2811 | } 2812 | 2813 | var handlers,leafs=[]; 2814 | 2815 | if(this.wildcard) { 2816 | var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice(); 2817 | leafs = searchListenerTree.call(this, null, ns, this.listenerTree, 0); 2818 | } 2819 | else { 2820 | // does not use listeners(), so no side effect of creating _events[type] 2821 | if (!this._events[type]) return this; 2822 | handlers = this._events[type]; 2823 | leafs.push({_listeners:handlers}); 2824 | } 2825 | 2826 | for (var iLeaf=0; iLeaf 0) { 2881 | fns = this._all; 2882 | for(i = 0, l = fns.length; i < l; i++) { 2883 | if(fn === fns[i]) { 2884 | fns.splice(i, 1); 2885 | return this; 2886 | } 2887 | } 2888 | } else { 2889 | this._all = []; 2890 | } 2891 | return this; 2892 | }; 2893 | 2894 | EventEmitter.prototype.removeListener = EventEmitter.prototype.off; 2895 | 2896 | EventEmitter.prototype.removeAllListeners = function(type) { 2897 | if (arguments.length === 0) { 2898 | !this._events || init.call(this); 2899 | return this; 2900 | } 2901 | 2902 | if(this.wildcard) { 2903 | var ns = typeof type === 'string' ? type.split(this.delimiter) : type.slice(); 2904 | var leafs = searchListenerTree.call(this, null, ns, this.listenerTree, 0); 2905 | 2906 | for (var iLeaf=0; iLeaf> 1 2967 | var nBits = -7 2968 | var i = isLE ? (nBytes - 1) : 0 2969 | var d = isLE ? -1 : 1 2970 | var s = buffer[offset + i] 2971 | 2972 | i += d 2973 | 2974 | e = s & ((1 << (-nBits)) - 1) 2975 | s >>= (-nBits) 2976 | nBits += eLen 2977 | for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {} 2978 | 2979 | m = e & ((1 << (-nBits)) - 1) 2980 | e >>= (-nBits) 2981 | nBits += mLen 2982 | for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {} 2983 | 2984 | if (e === 0) { 2985 | e = 1 - eBias 2986 | } else if (e === eMax) { 2987 | return m ? NaN : ((s ? -1 : 1) * Infinity) 2988 | } else { 2989 | m = m + Math.pow(2, mLen) 2990 | e = e - eBias 2991 | } 2992 | return (s ? -1 : 1) * m * Math.pow(2, e - mLen) 2993 | } 2994 | 2995 | exports.write = function (buffer, value, offset, isLE, mLen, nBytes) { 2996 | var e, m, c 2997 | var eLen = nBytes * 8 - mLen - 1 2998 | var eMax = (1 << eLen) - 1 2999 | var eBias = eMax >> 1 3000 | var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0) 3001 | var i = isLE ? 0 : (nBytes - 1) 3002 | var d = isLE ? 1 : -1 3003 | var s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0 3004 | 3005 | value = Math.abs(value) 3006 | 3007 | if (isNaN(value) || value === Infinity) { 3008 | m = isNaN(value) ? 1 : 0 3009 | e = eMax 3010 | } else { 3011 | e = Math.floor(Math.log(value) / Math.LN2) 3012 | if (value * (c = Math.pow(2, -e)) < 1) { 3013 | e-- 3014 | c *= 2 3015 | } 3016 | if (e + eBias >= 1) { 3017 | value += rt / c 3018 | } else { 3019 | value += rt * Math.pow(2, 1 - eBias) 3020 | } 3021 | if (value * c >= 2) { 3022 | e++ 3023 | c /= 2 3024 | } 3025 | 3026 | if (e + eBias >= eMax) { 3027 | m = 0 3028 | e = eMax 3029 | } else if (e + eBias >= 1) { 3030 | m = (value * c - 1) * Math.pow(2, mLen) 3031 | e = e + eBias 3032 | } else { 3033 | m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen) 3034 | e = 0 3035 | } 3036 | } 3037 | 3038 | for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8) {} 3039 | 3040 | e = (e << mLen) | m 3041 | eLen += mLen 3042 | for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8) {} 3043 | 3044 | buffer[offset + i - d] |= s * 128 3045 | } 3046 | 3047 | },{}],8:[function(require,module,exports){ 3048 | 3049 | /** 3050 | * Reduce `arr` with `fn`. 3051 | * 3052 | * @param {Array} arr 3053 | * @param {Function} fn 3054 | * @param {Mixed} initial 3055 | * 3056 | * TODO: combatible error handling? 3057 | */ 3058 | 3059 | module.exports = function(arr, fn, initial){ 3060 | var idx = 0; 3061 | var len = arr.length; 3062 | var curr = arguments.length == 3 3063 | ? initial 3064 | : arr[idx++]; 3065 | 3066 | while (idx < len) { 3067 | curr = fn.call(null, curr, arr[idx], ++idx, arr); 3068 | } 3069 | 3070 | return curr; 3071 | }; 3072 | },{}],9:[function(require,module,exports){ 3073 | /** 3074 | * Module dependencies. 3075 | */ 3076 | 3077 | var Emitter = require('emitter'); 3078 | var reduce = require('reduce'); 3079 | 3080 | /** 3081 | * Root reference for iframes. 3082 | */ 3083 | 3084 | var root = 'undefined' == typeof window 3085 | ? this 3086 | : window; 3087 | 3088 | /** 3089 | * Noop. 3090 | */ 3091 | 3092 | function noop(){}; 3093 | 3094 | /** 3095 | * Check if `obj` is a host object, 3096 | * we don't want to serialize these :) 3097 | * 3098 | * TODO: future proof, move to compoent land 3099 | * 3100 | * @param {Object} obj 3101 | * @return {Boolean} 3102 | * @api private 3103 | */ 3104 | 3105 | function isHost(obj) { 3106 | var str = {}.toString.call(obj); 3107 | 3108 | switch (str) { 3109 | case '[object File]': 3110 | case '[object Blob]': 3111 | case '[object FormData]': 3112 | return true; 3113 | default: 3114 | return false; 3115 | } 3116 | } 3117 | 3118 | /** 3119 | * Determine XHR. 3120 | */ 3121 | 3122 | function getXHR() { 3123 | if (root.XMLHttpRequest 3124 | && ('file:' != root.location.protocol || !root.ActiveXObject)) { 3125 | return new XMLHttpRequest; 3126 | } else { 3127 | try { return new ActiveXObject('Microsoft.XMLHTTP'); } catch(e) {} 3128 | try { return new ActiveXObject('Msxml2.XMLHTTP.6.0'); } catch(e) {} 3129 | try { return new ActiveXObject('Msxml2.XMLHTTP.3.0'); } catch(e) {} 3130 | try { return new ActiveXObject('Msxml2.XMLHTTP'); } catch(e) {} 3131 | } 3132 | return false; 3133 | } 3134 | 3135 | /** 3136 | * Removes leading and trailing whitespace, added to support IE. 3137 | * 3138 | * @param {String} s 3139 | * @return {String} 3140 | * @api private 3141 | */ 3142 | 3143 | var trim = ''.trim 3144 | ? function(s) { return s.trim(); } 3145 | : function(s) { return s.replace(/(^\s*|\s*$)/g, ''); }; 3146 | 3147 | /** 3148 | * Check if `obj` is an object. 3149 | * 3150 | * @param {Object} obj 3151 | * @return {Boolean} 3152 | * @api private 3153 | */ 3154 | 3155 | function isObject(obj) { 3156 | return obj === Object(obj); 3157 | } 3158 | 3159 | /** 3160 | * Serialize the given `obj`. 3161 | * 3162 | * @param {Object} obj 3163 | * @return {String} 3164 | * @api private 3165 | */ 3166 | 3167 | function serialize(obj) { 3168 | if (!isObject(obj)) return obj; 3169 | var pairs = []; 3170 | for (var key in obj) { 3171 | if (null != obj[key]) { 3172 | pairs.push(encodeURIComponent(key) 3173 | + '=' + encodeURIComponent(obj[key])); 3174 | } 3175 | } 3176 | return pairs.join('&'); 3177 | } 3178 | 3179 | /** 3180 | * Expose serialization method. 3181 | */ 3182 | 3183 | request.serializeObject = serialize; 3184 | 3185 | /** 3186 | * Parse the given x-www-form-urlencoded `str`. 3187 | * 3188 | * @param {String} str 3189 | * @return {Object} 3190 | * @api private 3191 | */ 3192 | 3193 | function parseString(str) { 3194 | var obj = {}; 3195 | var pairs = str.split('&'); 3196 | var parts; 3197 | var pair; 3198 | 3199 | for (var i = 0, len = pairs.length; i < len; ++i) { 3200 | pair = pairs[i]; 3201 | parts = pair.split('='); 3202 | obj[decodeURIComponent(parts[0])] = decodeURIComponent(parts[1]); 3203 | } 3204 | 3205 | return obj; 3206 | } 3207 | 3208 | /** 3209 | * Expose parser. 3210 | */ 3211 | 3212 | request.parseString = parseString; 3213 | 3214 | /** 3215 | * Default MIME type map. 3216 | * 3217 | * superagent.types.xml = 'application/xml'; 3218 | * 3219 | */ 3220 | 3221 | request.types = { 3222 | html: 'text/html', 3223 | json: 'application/json', 3224 | xml: 'application/xml', 3225 | urlencoded: 'application/x-www-form-urlencoded', 3226 | 'form': 'application/x-www-form-urlencoded', 3227 | 'form-data': 'application/x-www-form-urlencoded' 3228 | }; 3229 | 3230 | /** 3231 | * Default serialization map. 3232 | * 3233 | * superagent.serialize['application/xml'] = function(obj){ 3234 | * return 'generated xml here'; 3235 | * }; 3236 | * 3237 | */ 3238 | 3239 | request.serialize = { 3240 | 'application/x-www-form-urlencoded': serialize, 3241 | 'application/json': JSON.stringify 3242 | }; 3243 | 3244 | /** 3245 | * Default parsers. 3246 | * 3247 | * superagent.parse['application/xml'] = function(str){ 3248 | * return { object parsed from str }; 3249 | * }; 3250 | * 3251 | */ 3252 | 3253 | request.parse = { 3254 | 'application/x-www-form-urlencoded': parseString, 3255 | 'application/json': JSON.parse 3256 | }; 3257 | 3258 | /** 3259 | * Parse the given header `str` into 3260 | * an object containing the mapped fields. 3261 | * 3262 | * @param {String} str 3263 | * @return {Object} 3264 | * @api private 3265 | */ 3266 | 3267 | function parseHeader(str) { 3268 | var lines = str.split(/\r?\n/); 3269 | var fields = {}; 3270 | var index; 3271 | var line; 3272 | var field; 3273 | var val; 3274 | 3275 | lines.pop(); // trailing CRLF 3276 | 3277 | for (var i = 0, len = lines.length; i < len; ++i) { 3278 | line = lines[i]; 3279 | index = line.indexOf(':'); 3280 | field = line.slice(0, index).toLowerCase(); 3281 | val = trim(line.slice(index + 1)); 3282 | fields[field] = val; 3283 | } 3284 | 3285 | return fields; 3286 | } 3287 | 3288 | /** 3289 | * Return the mime type for the given `str`. 3290 | * 3291 | * @param {String} str 3292 | * @return {String} 3293 | * @api private 3294 | */ 3295 | 3296 | function type(str){ 3297 | return str.split(/ *; */).shift(); 3298 | }; 3299 | 3300 | /** 3301 | * Return header field parameters. 3302 | * 3303 | * @param {String} str 3304 | * @return {Object} 3305 | * @api private 3306 | */ 3307 | 3308 | function params(str){ 3309 | return reduce(str.split(/ *; */), function(obj, str){ 3310 | var parts = str.split(/ *= */) 3311 | , key = parts.shift() 3312 | , val = parts.shift(); 3313 | 3314 | if (key && val) obj[key] = val; 3315 | return obj; 3316 | }, {}); 3317 | }; 3318 | 3319 | /** 3320 | * Initialize a new `Response` with the given `xhr`. 3321 | * 3322 | * - set flags (.ok, .error, etc) 3323 | * - parse header 3324 | * 3325 | * Examples: 3326 | * 3327 | * Aliasing `superagent` as `request` is nice: 3328 | * 3329 | * request = superagent; 3330 | * 3331 | * We can use the promise-like API, or pass callbacks: 3332 | * 3333 | * request.get('/').end(function(res){}); 3334 | * request.get('/', function(res){}); 3335 | * 3336 | * Sending data can be chained: 3337 | * 3338 | * request 3339 | * .post('/user') 3340 | * .send({ name: 'tj' }) 3341 | * .end(function(res){}); 3342 | * 3343 | * Or passed to `.send()`: 3344 | * 3345 | * request 3346 | * .post('/user') 3347 | * .send({ name: 'tj' }, function(res){}); 3348 | * 3349 | * Or passed to `.post()`: 3350 | * 3351 | * request 3352 | * .post('/user', { name: 'tj' }) 3353 | * .end(function(res){}); 3354 | * 3355 | * Or further reduced to a single call for simple cases: 3356 | * 3357 | * request 3358 | * .post('/user', { name: 'tj' }, function(res){}); 3359 | * 3360 | * @param {XMLHTTPRequest} xhr 3361 | * @param {Object} options 3362 | * @api private 3363 | */ 3364 | 3365 | function Response(req, options) { 3366 | options = options || {}; 3367 | this.req = req; 3368 | this.xhr = this.req.xhr; 3369 | this.text = this.req.method !='HEAD' 3370 | ? this.xhr.responseText 3371 | : null; 3372 | this.setStatusProperties(this.xhr.status); 3373 | this.header = this.headers = parseHeader(this.xhr.getAllResponseHeaders()); 3374 | // getAllResponseHeaders sometimes falsely returns "" for CORS requests, but 3375 | // getResponseHeader still works. so we get content-type even if getting 3376 | // other headers fails. 3377 | this.header['content-type'] = this.xhr.getResponseHeader('content-type'); 3378 | this.setHeaderProperties(this.header); 3379 | this.body = this.req.method != 'HEAD' 3380 | ? this.parseBody(this.text) 3381 | : null; 3382 | } 3383 | 3384 | /** 3385 | * Get case-insensitive `field` value. 3386 | * 3387 | * @param {String} field 3388 | * @return {String} 3389 | * @api public 3390 | */ 3391 | 3392 | Response.prototype.get = function(field){ 3393 | return this.header[field.toLowerCase()]; 3394 | }; 3395 | 3396 | /** 3397 | * Set header related properties: 3398 | * 3399 | * - `.type` the content type without params 3400 | * 3401 | * A response of "Content-Type: text/plain; charset=utf-8" 3402 | * will provide you with a `.type` of "text/plain". 3403 | * 3404 | * @param {Object} header 3405 | * @api private 3406 | */ 3407 | 3408 | Response.prototype.setHeaderProperties = function(header){ 3409 | // content-type 3410 | var ct = this.header['content-type'] || ''; 3411 | this.type = type(ct); 3412 | 3413 | // params 3414 | var obj = params(ct); 3415 | for (var key in obj) this[key] = obj[key]; 3416 | }; 3417 | 3418 | /** 3419 | * Parse the given body `str`. 3420 | * 3421 | * Used for auto-parsing of bodies. Parsers 3422 | * are defined on the `superagent.parse` object. 3423 | * 3424 | * @param {String} str 3425 | * @return {Mixed} 3426 | * @api private 3427 | */ 3428 | 3429 | Response.prototype.parseBody = function(str){ 3430 | var parse = request.parse[this.type]; 3431 | return parse && str && str.length 3432 | ? parse(str) 3433 | : null; 3434 | }; 3435 | 3436 | /** 3437 | * Set flags such as `.ok` based on `status`. 3438 | * 3439 | * For example a 2xx response will give you a `.ok` of __true__ 3440 | * whereas 5xx will be __false__ and `.error` will be __true__. The 3441 | * `.clientError` and `.serverError` are also available to be more 3442 | * specific, and `.statusType` is the class of error ranging from 1..5 3443 | * sometimes useful for mapping respond colors etc. 3444 | * 3445 | * "sugar" properties are also defined for common cases. Currently providing: 3446 | * 3447 | * - .noContent 3448 | * - .badRequest 3449 | * - .unauthorized 3450 | * - .notAcceptable 3451 | * - .notFound 3452 | * 3453 | * @param {Number} status 3454 | * @api private 3455 | */ 3456 | 3457 | Response.prototype.setStatusProperties = function(status){ 3458 | var type = status / 100 | 0; 3459 | 3460 | // status / class 3461 | this.status = status; 3462 | this.statusType = type; 3463 | 3464 | // basics 3465 | this.info = 1 == type; 3466 | this.ok = 2 == type; 3467 | this.clientError = 4 == type; 3468 | this.serverError = 5 == type; 3469 | this.error = (4 == type || 5 == type) 3470 | ? this.toError() 3471 | : false; 3472 | 3473 | // sugar 3474 | this.accepted = 202 == status; 3475 | this.noContent = 204 == status || 1223 == status; 3476 | this.badRequest = 400 == status; 3477 | this.unauthorized = 401 == status; 3478 | this.notAcceptable = 406 == status; 3479 | this.notFound = 404 == status; 3480 | this.forbidden = 403 == status; 3481 | }; 3482 | 3483 | /** 3484 | * Return an `Error` representative of this response. 3485 | * 3486 | * @return {Error} 3487 | * @api public 3488 | */ 3489 | 3490 | Response.prototype.toError = function(){ 3491 | var req = this.req; 3492 | var method = req.method; 3493 | var url = req.url; 3494 | 3495 | var msg = 'cannot ' + method + ' ' + url + ' (' + this.status + ')'; 3496 | var err = new Error(msg); 3497 | err.status = this.status; 3498 | err.method = method; 3499 | err.url = url; 3500 | 3501 | return err; 3502 | }; 3503 | 3504 | /** 3505 | * Expose `Response`. 3506 | */ 3507 | 3508 | request.Response = Response; 3509 | 3510 | /** 3511 | * Initialize a new `Request` with the given `method` and `url`. 3512 | * 3513 | * @param {String} method 3514 | * @param {String} url 3515 | * @api public 3516 | */ 3517 | 3518 | function Request(method, url) { 3519 | var self = this; 3520 | Emitter.call(this); 3521 | this._query = this._query || []; 3522 | this.method = method; 3523 | this.url = url; 3524 | this.header = {}; 3525 | this._header = {}; 3526 | this.on('end', function(){ 3527 | var err = null; 3528 | var res = null; 3529 | 3530 | try { 3531 | res = new Response(self); 3532 | } catch(e) { 3533 | err = new Error('Parser is unable to parse the response'); 3534 | err.parse = true; 3535 | err.original = e; 3536 | } 3537 | 3538 | self.callback(err, res); 3539 | }); 3540 | } 3541 | 3542 | /** 3543 | * Mixin `Emitter`. 3544 | */ 3545 | 3546 | Emitter(Request.prototype); 3547 | 3548 | /** 3549 | * Allow for extension 3550 | */ 3551 | 3552 | Request.prototype.use = function(fn) { 3553 | fn(this); 3554 | return this; 3555 | } 3556 | 3557 | /** 3558 | * Set timeout to `ms`. 3559 | * 3560 | * @param {Number} ms 3561 | * @return {Request} for chaining 3562 | * @api public 3563 | */ 3564 | 3565 | Request.prototype.timeout = function(ms){ 3566 | this._timeout = ms; 3567 | return this; 3568 | }; 3569 | 3570 | /** 3571 | * Clear previous timeout. 3572 | * 3573 | * @return {Request} for chaining 3574 | * @api public 3575 | */ 3576 | 3577 | Request.prototype.clearTimeout = function(){ 3578 | this._timeout = 0; 3579 | clearTimeout(this._timer); 3580 | return this; 3581 | }; 3582 | 3583 | /** 3584 | * Abort the request, and clear potential timeout. 3585 | * 3586 | * @return {Request} 3587 | * @api public 3588 | */ 3589 | 3590 | Request.prototype.abort = function(){ 3591 | if (this.aborted) return; 3592 | this.aborted = true; 3593 | this.xhr.abort(); 3594 | this.clearTimeout(); 3595 | this.emit('abort'); 3596 | return this; 3597 | }; 3598 | 3599 | /** 3600 | * Set header `field` to `val`, or multiple fields with one object. 3601 | * 3602 | * Examples: 3603 | * 3604 | * req.get('/') 3605 | * .set('Accept', 'application/json') 3606 | * .set('X-API-Key', 'foobar') 3607 | * .end(callback); 3608 | * 3609 | * req.get('/') 3610 | * .set({ Accept: 'application/json', 'X-API-Key': 'foobar' }) 3611 | * .end(callback); 3612 | * 3613 | * @param {String|Object} field 3614 | * @param {String} val 3615 | * @return {Request} for chaining 3616 | * @api public 3617 | */ 3618 | 3619 | Request.prototype.set = function(field, val){ 3620 | if (isObject(field)) { 3621 | for (var key in field) { 3622 | this.set(key, field[key]); 3623 | } 3624 | return this; 3625 | } 3626 | this._header[field.toLowerCase()] = val; 3627 | this.header[field] = val; 3628 | return this; 3629 | }; 3630 | 3631 | /** 3632 | * Remove header `field`. 3633 | * 3634 | * Example: 3635 | * 3636 | * req.get('/') 3637 | * .unset('User-Agent') 3638 | * .end(callback); 3639 | * 3640 | * @param {String} field 3641 | * @return {Request} for chaining 3642 | * @api public 3643 | */ 3644 | 3645 | Request.prototype.unset = function(field){ 3646 | delete this._header[field.toLowerCase()]; 3647 | delete this.header[field]; 3648 | return this; 3649 | }; 3650 | 3651 | /** 3652 | * Get case-insensitive header `field` value. 3653 | * 3654 | * @param {String} field 3655 | * @return {String} 3656 | * @api private 3657 | */ 3658 | 3659 | Request.prototype.getHeader = function(field){ 3660 | return this._header[field.toLowerCase()]; 3661 | }; 3662 | 3663 | /** 3664 | * Set Content-Type to `type`, mapping values from `request.types`. 3665 | * 3666 | * Examples: 3667 | * 3668 | * superagent.types.xml = 'application/xml'; 3669 | * 3670 | * request.post('/') 3671 | * .type('xml') 3672 | * .send(xmlstring) 3673 | * .end(callback); 3674 | * 3675 | * request.post('/') 3676 | * .type('application/xml') 3677 | * .send(xmlstring) 3678 | * .end(callback); 3679 | * 3680 | * @param {String} type 3681 | * @return {Request} for chaining 3682 | * @api public 3683 | */ 3684 | 3685 | Request.prototype.type = function(type){ 3686 | this.set('Content-Type', request.types[type] || type); 3687 | return this; 3688 | }; 3689 | 3690 | /** 3691 | * Set Accept to `type`, mapping values from `request.types`. 3692 | * 3693 | * Examples: 3694 | * 3695 | * superagent.types.json = 'application/json'; 3696 | * 3697 | * request.get('/agent') 3698 | * .accept('json') 3699 | * .end(callback); 3700 | * 3701 | * request.get('/agent') 3702 | * .accept('application/json') 3703 | * .end(callback); 3704 | * 3705 | * @param {String} accept 3706 | * @return {Request} for chaining 3707 | * @api public 3708 | */ 3709 | 3710 | Request.prototype.accept = function(type){ 3711 | this.set('Accept', request.types[type] || type); 3712 | return this; 3713 | }; 3714 | 3715 | /** 3716 | * Set Authorization field value with `user` and `pass`. 3717 | * 3718 | * @param {String} user 3719 | * @param {String} pass 3720 | * @return {Request} for chaining 3721 | * @api public 3722 | */ 3723 | 3724 | Request.prototype.auth = function(user, pass){ 3725 | var str = btoa(user + ':' + pass); 3726 | this.set('Authorization', 'Basic ' + str); 3727 | return this; 3728 | }; 3729 | 3730 | /** 3731 | * Add query-string `val`. 3732 | * 3733 | * Examples: 3734 | * 3735 | * request.get('/shoes') 3736 | * .query('size=10') 3737 | * .query({ color: 'blue' }) 3738 | * 3739 | * @param {Object|String} val 3740 | * @return {Request} for chaining 3741 | * @api public 3742 | */ 3743 | 3744 | Request.prototype.query = function(val){ 3745 | if ('string' != typeof val) val = serialize(val); 3746 | if (val) this._query.push(val); 3747 | return this; 3748 | }; 3749 | 3750 | /** 3751 | * Write the field `name` and `val` for "multipart/form-data" 3752 | * request bodies. 3753 | * 3754 | * ``` js 3755 | * request.post('/upload') 3756 | * .field('foo', 'bar') 3757 | * .end(callback); 3758 | * ``` 3759 | * 3760 | * @param {String} name 3761 | * @param {String|Blob|File} val 3762 | * @return {Request} for chaining 3763 | * @api public 3764 | */ 3765 | 3766 | Request.prototype.field = function(name, val){ 3767 | if (!this._formData) this._formData = new FormData(); 3768 | this._formData.append(name, val); 3769 | return this; 3770 | }; 3771 | 3772 | /** 3773 | * Queue the given `file` as an attachment to the specified `field`, 3774 | * with optional `filename`. 3775 | * 3776 | * ``` js 3777 | * request.post('/upload') 3778 | * .attach(new Blob(['hey!'], { type: "text/html"})) 3779 | * .end(callback); 3780 | * ``` 3781 | * 3782 | * @param {String} field 3783 | * @param {Blob|File} file 3784 | * @param {String} filename 3785 | * @return {Request} for chaining 3786 | * @api public 3787 | */ 3788 | 3789 | Request.prototype.attach = function(field, file, filename){ 3790 | if (!this._formData) this._formData = new FormData(); 3791 | this._formData.append(field, file, filename); 3792 | return this; 3793 | }; 3794 | 3795 | /** 3796 | * Send `data`, defaulting the `.type()` to "json" when 3797 | * an object is given. 3798 | * 3799 | * Examples: 3800 | * 3801 | * // querystring 3802 | * request.get('/search') 3803 | * .end(callback) 3804 | * 3805 | * // multiple data "writes" 3806 | * request.get('/search') 3807 | * .send({ search: 'query' }) 3808 | * .send({ range: '1..5' }) 3809 | * .send({ order: 'desc' }) 3810 | * .end(callback) 3811 | * 3812 | * // manual json 3813 | * request.post('/user') 3814 | * .type('json') 3815 | * .send('{"name":"tj"}) 3816 | * .end(callback) 3817 | * 3818 | * // auto json 3819 | * request.post('/user') 3820 | * .send({ name: 'tj' }) 3821 | * .end(callback) 3822 | * 3823 | * // manual x-www-form-urlencoded 3824 | * request.post('/user') 3825 | * .type('form') 3826 | * .send('name=tj') 3827 | * .end(callback) 3828 | * 3829 | * // auto x-www-form-urlencoded 3830 | * request.post('/user') 3831 | * .type('form') 3832 | * .send({ name: 'tj' }) 3833 | * .end(callback) 3834 | * 3835 | * // defaults to x-www-form-urlencoded 3836 | * request.post('/user') 3837 | * .send('name=tobi') 3838 | * .send('species=ferret') 3839 | * .end(callback) 3840 | * 3841 | * @param {String|Object} data 3842 | * @return {Request} for chaining 3843 | * @api public 3844 | */ 3845 | 3846 | Request.prototype.send = function(data){ 3847 | var obj = isObject(data); 3848 | var type = this.getHeader('Content-Type'); 3849 | 3850 | // merge 3851 | if (obj && isObject(this._data)) { 3852 | for (var key in data) { 3853 | this._data[key] = data[key]; 3854 | } 3855 | } else if ('string' == typeof data) { 3856 | if (!type) this.type('form'); 3857 | type = this.getHeader('Content-Type'); 3858 | if ('application/x-www-form-urlencoded' == type) { 3859 | this._data = this._data 3860 | ? this._data + '&' + data 3861 | : data; 3862 | } else { 3863 | this._data = (this._data || '') + data; 3864 | } 3865 | } else { 3866 | this._data = data; 3867 | } 3868 | 3869 | if (!obj) return this; 3870 | if (!type) this.type('json'); 3871 | return this; 3872 | }; 3873 | 3874 | /** 3875 | * Invoke the callback with `err` and `res` 3876 | * and handle arity check. 3877 | * 3878 | * @param {Error} err 3879 | * @param {Response} res 3880 | * @api private 3881 | */ 3882 | 3883 | Request.prototype.callback = function(err, res){ 3884 | var fn = this._callback; 3885 | this.clearTimeout(); 3886 | if (2 == fn.length) return fn(err, res); 3887 | if (err) return this.emit('error', err); 3888 | fn(res); 3889 | }; 3890 | 3891 | /** 3892 | * Invoke callback with x-domain error. 3893 | * 3894 | * @api private 3895 | */ 3896 | 3897 | Request.prototype.crossDomainError = function(){ 3898 | var err = new Error('Origin is not allowed by Access-Control-Allow-Origin'); 3899 | err.crossDomain = true; 3900 | this.callback(err); 3901 | }; 3902 | 3903 | /** 3904 | * Invoke callback with timeout error. 3905 | * 3906 | * @api private 3907 | */ 3908 | 3909 | Request.prototype.timeoutError = function(){ 3910 | var timeout = this._timeout; 3911 | var err = new Error('timeout of ' + timeout + 'ms exceeded'); 3912 | err.timeout = timeout; 3913 | this.callback(err); 3914 | }; 3915 | 3916 | /** 3917 | * Enable transmission of cookies with x-domain requests. 3918 | * 3919 | * Note that for this to work the origin must not be 3920 | * using "Access-Control-Allow-Origin" with a wildcard, 3921 | * and also must set "Access-Control-Allow-Credentials" 3922 | * to "true". 3923 | * 3924 | * @api public 3925 | */ 3926 | 3927 | Request.prototype.withCredentials = function(){ 3928 | this._withCredentials = true; 3929 | return this; 3930 | }; 3931 | 3932 | /** 3933 | * Initiate request, invoking callback `fn(res)` 3934 | * with an instanceof `Response`. 3935 | * 3936 | * @param {Function} fn 3937 | * @return {Request} for chaining 3938 | * @api public 3939 | */ 3940 | 3941 | Request.prototype.end = function(fn){ 3942 | var self = this; 3943 | var xhr = this.xhr = getXHR(); 3944 | var query = this._query.join('&'); 3945 | var timeout = this._timeout; 3946 | var data = this._formData || this._data; 3947 | 3948 | // store callback 3949 | this._callback = fn || noop; 3950 | 3951 | // state change 3952 | xhr.onreadystatechange = function(){ 3953 | if (4 != xhr.readyState) return; 3954 | if (0 == xhr.status) { 3955 | if (self.aborted) return self.timeoutError(); 3956 | return self.crossDomainError(); 3957 | } 3958 | self.emit('end'); 3959 | }; 3960 | 3961 | // progress 3962 | if (xhr.upload) { 3963 | xhr.upload.onprogress = function(e){ 3964 | e.percent = e.loaded / e.total * 100; 3965 | self.emit('progress', e); 3966 | }; 3967 | } 3968 | 3969 | // timeout 3970 | if (timeout && !this._timer) { 3971 | this._timer = setTimeout(function(){ 3972 | self.abort(); 3973 | }, timeout); 3974 | } 3975 | 3976 | // querystring 3977 | if (query) { 3978 | query = request.serializeObject(query); 3979 | this.url += ~this.url.indexOf('?') 3980 | ? '&' + query 3981 | : '?' + query; 3982 | } 3983 | 3984 | // initiate request 3985 | xhr.open(this.method, this.url, true); 3986 | 3987 | // CORS 3988 | if (this._withCredentials) xhr.withCredentials = true; 3989 | 3990 | // body 3991 | if ('GET' != this.method && 'HEAD' != this.method && 'string' != typeof data && !isHost(data)) { 3992 | // serialize stuff 3993 | var serialize = request.serialize[this.getHeader('Content-Type')]; 3994 | if (serialize) data = serialize(data); 3995 | } 3996 | 3997 | // set header fields 3998 | for (var field in this.header) { 3999 | if (null == this.header[field]) continue; 4000 | xhr.setRequestHeader(field, this.header[field]); 4001 | } 4002 | 4003 | // send stuff 4004 | this.emit('request', this); 4005 | xhr.send(data); 4006 | return this; 4007 | }; 4008 | 4009 | /** 4010 | * Expose `Request`. 4011 | */ 4012 | 4013 | request.Request = Request; 4014 | 4015 | /** 4016 | * Issue a request: 4017 | * 4018 | * Examples: 4019 | * 4020 | * request('GET', '/users').end(callback) 4021 | * request('/users').end(callback) 4022 | * request('/users', callback) 4023 | * 4024 | * @param {String} method 4025 | * @param {String|Function} url or callback 4026 | * @return {Request} 4027 | * @api public 4028 | */ 4029 | 4030 | function request(method, url) { 4031 | // callback 4032 | if ('function' == typeof url) { 4033 | return new Request('GET', method).end(url); 4034 | } 4035 | 4036 | // url first 4037 | if (1 == arguments.length) { 4038 | return new Request('GET', method); 4039 | } 4040 | 4041 | return new Request(method, url); 4042 | } 4043 | 4044 | /** 4045 | * GET `url` with optional callback `fn(res)`. 4046 | * 4047 | * @param {String} url 4048 | * @param {Mixed|Function} data or fn 4049 | * @param {Function} fn 4050 | * @return {Request} 4051 | * @api public 4052 | */ 4053 | 4054 | request.get = function(url, data, fn){ 4055 | var req = request('GET', url); 4056 | if ('function' == typeof data) fn = data, data = null; 4057 | if (data) req.query(data); 4058 | if (fn) req.end(fn); 4059 | return req; 4060 | }; 4061 | 4062 | /** 4063 | * HEAD `url` with optional callback `fn(res)`. 4064 | * 4065 | * @param {String} url 4066 | * @param {Mixed|Function} data or fn 4067 | * @param {Function} fn 4068 | * @return {Request} 4069 | * @api public 4070 | */ 4071 | 4072 | request.head = function(url, data, fn){ 4073 | var req = request('HEAD', url); 4074 | if ('function' == typeof data) fn = data, data = null; 4075 | if (data) req.send(data); 4076 | if (fn) req.end(fn); 4077 | return req; 4078 | }; 4079 | 4080 | /** 4081 | * DELETE `url` with optional callback `fn(res)`. 4082 | * 4083 | * @param {String} url 4084 | * @param {Function} fn 4085 | * @return {Request} 4086 | * @api public 4087 | */ 4088 | 4089 | request.del = function(url, fn){ 4090 | var req = request('DELETE', url); 4091 | if (fn) req.end(fn); 4092 | return req; 4093 | }; 4094 | 4095 | /** 4096 | * PATCH `url` with optional `data` and callback `fn(res)`. 4097 | * 4098 | * @param {String} url 4099 | * @param {Mixed} data 4100 | * @param {Function} fn 4101 | * @return {Request} 4102 | * @api public 4103 | */ 4104 | 4105 | request.patch = function(url, data, fn){ 4106 | var req = request('PATCH', url); 4107 | if ('function' == typeof data) fn = data, data = null; 4108 | if (data) req.send(data); 4109 | if (fn) req.end(fn); 4110 | return req; 4111 | }; 4112 | 4113 | /** 4114 | * POST `url` with optional `data` and callback `fn(res)`. 4115 | * 4116 | * @param {String} url 4117 | * @param {Mixed} data 4118 | * @param {Function} fn 4119 | * @return {Request} 4120 | * @api public 4121 | */ 4122 | 4123 | request.post = function(url, data, fn){ 4124 | var req = request('POST', url); 4125 | if ('function' == typeof data) fn = data, data = null; 4126 | if (data) req.send(data); 4127 | if (fn) req.end(fn); 4128 | return req; 4129 | }; 4130 | 4131 | /** 4132 | * PUT `url` with optional `data` and callback `fn(res)`. 4133 | * 4134 | * @param {String} url 4135 | * @param {Mixed|Function} data or fn 4136 | * @param {Function} fn 4137 | * @return {Request} 4138 | * @api public 4139 | */ 4140 | 4141 | request.put = function(url, data, fn){ 4142 | var req = request('PUT', url); 4143 | if ('function' == typeof data) fn = data, data = null; 4144 | if (data) req.send(data); 4145 | if (fn) req.end(fn); 4146 | return req; 4147 | }; 4148 | 4149 | /** 4150 | * Expose `request`. 4151 | */ 4152 | 4153 | module.exports = request; 4154 | 4155 | },{"emitter":5,"reduce":8}]},{},[1])(1) 4156 | }); --------------------------------------------------------------------------------