|
!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.TubeMaps=e()}}(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<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ |
|
(function (__dirname){ |
|
module.exports = { |
|
"london": { |
|
csv: { |
|
connections: __dirname + '/london.connections.csv', |
|
lines: __dirname + '/london.lines.csv', |
|
stations: __dirname + '/london.stations.csv' |
|
}, |
|
json: __dirname + '/london.json' |
|
} |
|
}; |
|
|
|
}).call(this,"/datasets") |
|
},{}],2:[function(require,module,exports){ |
|
var async = require('async'); |
|
var fs = require('fs'); |
|
var path = require('path'); |
|
var JSONStream = require('JSONStream'); |
|
var __ = require('highland'); |
|
var datasets = require('./datasets'); |
|
|
|
exports.TubeMap = TubeMap; |
|
exports.Maps = Maps; |
|
|
|
function Station(opts) { |
|
this.id = opts.id; |
|
this.conns = opts.conns || []; |
|
this.name = opts.name || "Unknown"; |
|
this.display_name = opts.display_name || "Unknown"; |
|
this.rail = opts.rail ? parseInt(opts.rail, 10) : null; |
|
this.total_lines = opts.total_lines ? parseInt(opts.total_lines, 10) : 1; |
|
this.latitude = +parseFloat(opts.latitude); |
|
this.longitude = +parseFloat(opts.longitude); |
|
} |
|
|
|
function TubeMap(opts) { |
|
opts = opts || {}; |
|
this.stationsById = {}; |
|
this.stationsByName = {}; |
|
this.linesById = {}; |
|
this.linesByName = {}; |
|
this.stations = opts.stations || []; |
|
this.connections = opts.connections || []; |
|
this.lines = opts.lines || []; |
|
|
|
this.make(); |
|
} |
|
|
|
TubeMap.prototype.makeStation = function(s) { |
|
s = new Station(s); |
|
this.stationsById[s.id] = s; |
|
this.stationsByName[s.name] = s; |
|
}; |
|
|
|
TubeMap.prototype.getAdjacent = function (root, line) { |
|
var conns = root.conns; |
|
if (line) { |
|
conns = conns.filter(function (c) { |
|
return c.line == line; |
|
}); |
|
} |
|
return conns.map(function(c) { |
|
c.station1.line = c.line; |
|
c.station2.line = c.line; |
|
return c.station1.id !== root.id ? c.station1 : c.station2; |
|
}); |
|
}; |
|
|
|
TubeMap.prototype.constructPath = function (dict, path, start, destination){ |
|
if (path[path.length-1] && path[path.length-1].station2 == start) { |
|
return path; |
|
} |
|
path.push({station1: destination, station2: dict[destination.id]}); |
|
return this.constructPath(dict, path, start, dict[destination.id]); |
|
}; |
|
|
|
TubeMap.prototype.path = function(start, destination, line){ |
|
var Q = [destination]; |
|
var V = {}; |
|
var family = {}; |
|
family[destination.id] = null; |
|
|
|
while (Q.length > 0) { |
|
var currentStation = Q.shift(); |
|
if (currentStation.id in V) { |
|
continue; |
|
} |
|
var conns = this.getAdjacent(currentStation, line); |
|
conns.forEach(function(child) { |
|
if (!(child.id in V)){ |
|
Q.push(child); |
|
} |
|
|
|
if (!(child.id in family)){ |
|
family[child.id] = currentStation; |
|
} |
|
}); |
|
V[currentStation.id] = currentStation; |
|
if (currentStation.id === start.id) { |
|
var path = this.constructPath(family, [], destination, start); |
|
|
|
if (line) { |
|
path = path.map(function(d) { |
|
d.line = line; |
|
return d; |
|
}); |
|
} |
|
return path; |
|
} |
|
} |
|
return false; |
|
}; |
|
|
|
TubeMap.prototype.line = function(id) { |
|
return this.connections.filter(function(d) { |
|
return d.line == id; |
|
}); |
|
}; |
|
|
|
TubeMap.prototype.makeConnection = function(c) { |
|
c.station1 = this.stationsById[c.station1]; |
|
c.station2 = this.stationsById[c.station2]; |
|
c.time = parseInt(c.time, 10); |
|
|
|
c.station1.conns.push(c); |
|
c.station2.conns.push(c); |
|
}; |
|
|
|
TubeMap.prototype.makeLine = function(r) { |
|
this.linesById[r.line] = r; |
|
this.linesByName[r.name] = r; |
|
}; |
|
|
|
TubeMap.prototype.getLine = function(id) { |
|
return this.linesById[id]; |
|
}; |
|
|
|
TubeMap.prototype.getLineByName = function(name) { |
|
return this.linesByName[name]; |
|
} |
|
|
|
TubeMap.prototype.getStation = function(id) { |
|
return this.stationsById[id]; |
|
}; |
|
|
|
TubeMap.prototype.getStationByName = function(display_name) { |
|
return this.stationsByName[display_name]; |
|
}; |
|
|
|
TubeMap.prototype.make = function() { |
|
this.stations.forEach(this.makeStation.bind(this)); |
|
this.connections.forEach(this.makeConnection.bind(this)); |
|
this.lines.forEach(this.makeLine.bind(this)); |
|
}; |
|
|
|
function Maps (city, cb) { |
|
var dataset = require(datasets[city].json); |
|
cb(null, new TubeMap(dataset)); |
|
}; |
|
|
|
},{"./datasets":1,"JSONStream":3,"async":6,"fs":8,"highland":7,"path":15}],3:[function(require,module,exports){ |
|
(function (process,Buffer){ |
|
|
|
|
|
var Parser = require('jsonparse') |
|
, through = require('through') |
|
|
|
/* |
|
|
|
the value of this.stack that creationix's jsonparse has is weird. |
|
|
|
it makes this code ugly, but his problem is way harder that mine, |
|
so i'll forgive him. |
|
|
|
*/ |
|
|
|
exports.parse = function (path, map) { |
|
|
|
var parser = new Parser() |
|
var stream = through(function (chunk) { |
|
if('string' === typeof chunk) |
|
chunk = new Buffer(chunk) |
|
parser.write(chunk) |
|
}, |
|
function (data) { |
|
if(data) |
|
stream.write(data) |
|
stream.queue(null) |
|
}) |
|
|
|
if('string' === typeof path) |
|
path = path.split('.').map(function (e) { |
|
if (e === '*') |
|
return true |
|
else if (e === '') // '..'.split('.') returns an empty string |
|
return {recurse: true} |
|
else |
|
return e |
|
}) |
|
|
|
|
|
var count = 0, _key |
|
if(!path || !path.length) |
|
path = null |
|
|
|
parser.onValue = function (value) { |
|
if (!this.root) |
|
stream.root = value |
|
|
|
if(! path) return |
|
|
|
var i = 0 // iterates on path |
|
var j = 0 // iterates on stack |
|
while (i < path.length) { |
|
var key = path[i] |
|
var c |
|
j++ |
|
|
|
if (key && !key.recurse) { |
|
c = (j === this.stack.length) ? this : this.stack[j] |
|
if (!c) return |
|
if (! check(key, c.key)) return |
|
i++ |
|
} else { |
|
i++ |
|
var nextKey = path[i] |
|
if (! nextKey) return |
|
while (true) { |
|
c = (j === this.stack.length) ? this : this.stack[j] |
|
if (!c) return |
|
if (check(nextKey, c.key)) { i++; break} |
|
j++ |
|
} |
|
} |
|
} |
|
if (j !== this.stack.length) return |
|
|
|
count ++ |
|
var actualPath = this.stack.slice(1).map(function(element) { return element.key }).concat([this.key]) |
|
var data = this.value[this.key] |
|
if(null != data) |
|
if(null != (data = map ? map(data, actualPath) : data)) |
|
stream.queue(data) |
|
delete this.value[this.key] |
|
} |
|
parser._onToken = parser.onToken; |
|
|
|
parser.onToken = function (token, value) { |
|
parser._onToken(token, value); |
|
if (this.stack.length === 0) { |
|
if (stream.root) { |
|
if(!path) |
|
stream.queue(stream.root) |
|
stream.emit('root', stream.root, count) |
|
count = 0; |
|
stream.root = null; |
|
} |
|
} |
|
} |
|
|
|
parser.onError = function (err) { |
|
stream.emit('error', err) |
|
} |
|
|
|
|
|
return stream |
|
} |
|
|
|
function check (x, y) { |
|
if ('string' === typeof x) |
|
return y == x |
|
else if (x && 'function' === typeof x.exec) |
|
return x.exec(y) |
|
else if ('boolean' === typeof x) |
|
return x |
|
else if ('function' === typeof x) |
|
return x(y) |
|
return false |
|
} |
|
|
|
exports.stringify = function (op, sep, cl, indent) { |
|
indent = indent || 0 |
|
if (op === false){ |
|
op = '' |
|
sep = '\n' |
|
cl = '' |
|
} else if (op == null) { |
|
|
|
op = '[\n' |
|
sep = '\n,\n' |
|
cl = '\n]\n' |
|
|
|
} |
|
|
|
//else, what ever you like |
|
|
|
var stream |
|
, first = true |
|
, anyData = false |
|
stream = through(function (data) { |
|
anyData = true |
|
var json = JSON.stringify(data, null, indent) |
|
if(first) { first = false ; stream.queue(op + json)} |
|
else stream.queue(sep + json) |
|
}, |
|
function (data) { |
|
if(!anyData) |
|
stream.queue(op) |
|
stream.queue(cl) |
|
stream.queue(null) |
|
}) |
|
|
|
return stream |
|
} |
|
|
|
exports.stringifyObject = function (op, sep, cl, indent) { |
|
indent = indent || 0 |
|
if (op === false){ |
|
op = '' |
|
sep = '\n' |
|
cl = '' |
|
} else if (op == null) { |
|
|
|
op = '{\n' |
|
sep = '\n,\n' |
|
cl = '\n}\n' |
|
|
|
} |
|
|
|
//else, what ever you like |
|
|
|
var first = true |
|
, anyData = false |
|
stream = through(function (data) { |
|
anyData = true |
|
var json = JSON.stringify(data[0]) + ':' + JSON.stringify(data[1], null, indent) |
|
if(first) { first = false ; this.queue(op + json)} |
|
else this.queue(sep + json) |
|
}, |
|
function (data) { |
|
if(!anyData) this.queue(op) |
|
this.queue(cl) |
|
|
|
this.queue(null) |
|
}) |
|
|
|
return stream |
|
} |
|
|
|
if(!module.parent && process.title !== 'browser') { |
|
process.stdin |
|
.pipe(exports.parse(process.argv[2])) |
|
.pipe(exports.stringify('[', ',\n', ']\n', 2)) |
|
.pipe(process.stdout) |
|
} |
|
|
|
}).call(this,require('_process'),require("buffer").Buffer) |
|
},{"_process":16,"buffer":9,"jsonparse":4,"through":5}],4:[function(require,module,exports){ |
|
(function (Buffer){ |
|
/*global Buffer*/ |
|
// Named constants with unique integer values |
|
var C = {}; |
|
// Tokens |
|
var LEFT_BRACE = C.LEFT_BRACE = 0x1; |
|
var RIGHT_BRACE = C.RIGHT_BRACE = 0x2; |
|
var LEFT_BRACKET = C.LEFT_BRACKET = 0x3; |
|
var RIGHT_BRACKET = C.RIGHT_BRACKET = 0x4; |
|
var COLON = C.COLON = 0x5; |
|
var COMMA = C.COMMA = 0x6; |
|
var TRUE = C.TRUE = 0x7; |
|
var FALSE = C.FALSE = 0x8; |
|
var NULL = C.NULL = 0x9; |
|
var STRING = C.STRING = 0xa; |
|
var NUMBER = C.NUMBER = 0xb; |
|
// Tokenizer States |
|
var START = C.START = 0x11; |
|
var TRUE1 = C.TRUE1 = 0x21; |
|
var TRUE2 = C.TRUE2 = 0x22; |
|
var TRUE3 = C.TRUE3 = 0x23; |
|
var FALSE1 = C.FALSE1 = 0x31; |
|
var FALSE2 = C.FALSE2 = 0x32; |
|
var FALSE3 = C.FALSE3 = 0x33; |
|
var FALSE4 = C.FALSE4 = 0x34; |
|
var NULL1 = C.NULL1 = 0x41; |
|
var NULL2 = C.NULL3 = 0x42; |
|
var NULL3 = C.NULL2 = 0x43; |
|
var NUMBER1 = C.NUMBER1 = 0x51; |
|
var NUMBER2 = C.NUMBER2 = 0x52; |
|
var NUMBER3 = C.NUMBER3 = 0x53; |
|
var NUMBER4 = C.NUMBER4 = 0x54; |
|
var NUMBER5 = C.NUMBER5 = 0x55; |
|
var NUMBER6 = C.NUMBER6 = 0x56; |
|
var NUMBER7 = C.NUMBER7 = 0x57; |
|
var NUMBER8 = C.NUMBER8 = 0x58; |
|
var STRING1 = C.STRING1 = 0x61; |
|
var STRING2 = C.STRING2 = 0x62; |
|
var STRING3 = C.STRING3 = 0x63; |
|
var STRING4 = C.STRING4 = 0x64; |
|
var STRING5 = C.STRING5 = 0x65; |
|
var STRING6 = C.STRING6 = 0x66; |
|
// Parser States |
|
var VALUE = C.VALUE = 0x71; |
|
var KEY = C.KEY = 0x72; |
|
// Parser Modes |
|
var OBJECT = C.OBJECT = 0x81; |
|
var ARRAY = C.ARRAY = 0x82; |
|
|
|
// Slow code to string converter (only used when throwing syntax errors) |
|
function toknam(code) { |
|
var keys = Object.keys(C); |
|
for (var i = 0, l = keys.length; i < l; i++) { |
|
var key = keys[i]; |
|
if (C[key] === code) { return key; } |
|
} |
|
return code && ("0x" + code.toString(16)); |
|
} |
|
|
|
|
|
function Parser() { |
|
this.tState = START; |
|
this.value = undefined; |
|
|
|
this.string = undefined; // string data |
|
this.unicode = undefined; // unicode escapes |
|
|
|
// For number parsing |
|
this.negative = undefined; |
|
this.magnatude = undefined; |
|
this.position = undefined; |
|
this.exponent = undefined; |
|
this.negativeExponent = undefined; |
|
|
|
this.key = undefined; |
|
this.mode = undefined; |
|
this.stack = []; |
|
this.state = VALUE; |
|
this.bytes_remaining = 0; // number of bytes remaining in multi byte utf8 char to read after split boundary |
|
this.bytes_in_sequence = 0; // bytes in multi byte utf8 char to read |
|
this.temp_buffs = { "2": new Buffer(2), "3": new Buffer(3), "4": new Buffer(4) }; // for rebuilding chars split before boundary is reached |
|
} |
|
var proto = Parser.prototype; |
|
proto.charError = function (buffer, i) { |
|
this.onError(new Error("Unexpected " + JSON.stringify(String.fromCharCode(buffer[i])) + " at position " + i + " in state " + toknam(this.tState))); |
|
}; |
|
proto.onError = function (err) { throw err; }; |
|
proto.write = function (buffer) { |
|
if (typeof buffer === "string") buffer = new Buffer(buffer); |
|
//process.stdout.write("Input: "); |
|
//console.dir(buffer.toString()); |
|
var n; |
|
for (var i = 0, l = buffer.length; i < l; i++) { |
|
if (this.tState === START){ |
|
n = buffer[i]; |
|
if(n === 0x7b){ this.onToken(LEFT_BRACE, "{"); // { |
|
}else if(n === 0x7d){ this.onToken(RIGHT_BRACE, "}"); // } |
|
}else if(n === 0x5b){ this.onToken(LEFT_BRACKET, "["); // [ |
|
}else if(n === 0x5d){ this.onToken(RIGHT_BRACKET, "]"); // ] |
|
}else if(n === 0x3a){ this.onToken(COLON, ":"); // : |
|
}else if(n === 0x2c){ this.onToken(COMMA, ","); // , |
|
}else if(n === 0x74){ this.tState = TRUE1; // t |
|
}else if(n === 0x66){ this.tState = FALSE1; // f |
|
}else if(n === 0x6e){ this.tState = NULL1; // n |
|
}else if(n === 0x22){ this.string = ""; this.tState = STRING1; // " |
|
}else if(n === 0x2d){ this.negative = true; this.tState = NUMBER1; // - |
|
}else if(n === 0x30){ this.magnatude = 0; this.tState = NUMBER2; // 0 |
|
}else{ |
|
if (n > 0x30 && n < 0x40) { // 1-9 |
|
this.magnatude = n - 0x30; this.tState = NUMBER3; |
|
} else if (n === 0x20 || n === 0x09 || n === 0x0a || n === 0x0d) { |
|
// whitespace |
|
} else { this.charError(buffer, i); } |
|
} |
|
}else if (this.tState === STRING1){ // After open quote |
|
n = buffer[i]; // get current byte from buffer |
|
// check for carry over of a multi byte char split between data chunks |
|
// & fill temp buffer it with start of this data chunk up to the boundary limit set in the last iteration |
|
if (this.bytes_remaining > 0) { |
|
for (var j = 0; j < this.bytes_remaining; j++) { |
|
this.temp_buffs[this.bytes_in_sequence][this.bytes_in_sequence - this.bytes_remaining + j] = buffer[j]; |
|
} |
|
this.string += this.temp_buffs[this.bytes_in_sequence].toString(); |
|
this.bytes_in_sequence = this.bytes_remaining = 0; |
|
i = i + j - 1; |
|
} else if (this.bytes_remaining === 0 && n >= 128) { // else if no remainder bytes carried over, parse multi byte (>=128) chars one at a time |
|
if ((n >= 194) && (n <= 223)) this.bytes_in_sequence = 2; |
|
if ((n >= 224) && (n <= 239)) this.bytes_in_sequence = 3; |
|
if ((n >= 240) && (n <= 244)) this.bytes_in_sequence = 4; |
|
if ((this.bytes_in_sequence + i) > buffer.length) { // if bytes needed to complete char fall outside buffer length, we have a boundary split |
|
for (var k = 0; k <= (buffer.length - 1 - i); k++) { |
|
this.temp_buffs[this.bytes_in_sequence][k] = buffer[i + k]; // fill temp buffer of correct size with bytes available in this chunk |
|
} |
|
this.bytes_remaining = (i + this.bytes_in_sequence) - buffer.length; |
|
i = buffer.length - 1; |
|
} else { |
|
this.string += buffer.slice(i, (i + this.bytes_in_sequence)).toString(); |
|
i = i + this.bytes_in_sequence - 1; |
|
} |
|
} else if (n === 0x22) { this.tState = START; this.onToken(STRING, this.string); this.string = undefined; } |
|
else if (n === 0x5c) { this.tState = STRING2; } |
|
else if (n >= 0x20) { this.string += String.fromCharCode(n); } |
|
else { this.charError(buffer, i); } |
|
}else if (this.tState === STRING2){ // After backslash |
|
n = buffer[i]; |
|
if(n === 0x22){ this.string += "\""; this.tState = STRING1; |
|
}else if(n === 0x5c){ this.string += "\\"; this.tState = STRING1; |
|
}else if(n === 0x2f){ this.string += "\/"; this.tState = STRING1; |
|
}else if(n === 0x62){ this.string += "\b"; this.tState = STRING1; |
|
}else if(n === 0x66){ this.string += "\f"; this.tState = STRING1; |
|
}else if(n === 0x6e){ this.string += "\n"; this.tState = STRING1; |
|
}else if(n === 0x72){ this.string += "\r"; this.tState = STRING1; |
|
}else if(n === 0x74){ this.string += "\t"; this.tState = STRING1; |
|
}else if(n === 0x75){ this.unicode = ""; this.tState = STRING3; |
|
}else{ |
|
this.charError(buffer, i); |
|
} |
|
}else if (this.tState === STRING3 || this.tState === STRING4 || this.tState === STRING5 || this.tState === STRING6){ // unicode hex codes |
|
n = buffer[i]; |
|
// 0-9 A-F a-f |
|
if ((n >= 0x30 && n < 0x40) || (n > 0x40 && n <= 0x46) || (n > 0x60 && n <= 0x66)) { |
|
this.unicode += String.fromCharCode(n); |
|
if (this.tState++ === STRING6) { |
|
this.string += String.fromCharCode(parseInt(this.unicode, 16)); |
|
this.unicode = undefined; |
|
this.tState = STRING1; |
|
} |
|
} else { |
|
this.charError(buffer, i); |
|
} |
|
}else if (this.tState === NUMBER1){ // after minus |
|
n = buffer[i]; |
|
if (n === 0x30) { this.magnatude = 0; this.tState = NUMBER2; } |
|
else if (n > 0x30 && n < 0x40) { this.magnatude = n - 0x30; this.tState = NUMBER3; } |
|
else { this.charError(buffer, i); } |
|
}else if (this.tState === NUMBER2){ // * After initial zero |
|
n = buffer[i]; |
|
if(n === 0x2e){ // . |
|
this.position = 0.1; this.tState = NUMBER4; |
|
}else if(n === 0x65 || n === 0x45){ // e/E |
|
this.exponent = 0; this.tState = NUMBER6; |
|
}else{ |
|
this.tState = START; |
|
this.onToken(NUMBER, 0); |
|
this.magnatude = undefined; |
|
this.negative = undefined; |
|
i--; |
|
} |
|
}else if (this.tState === NUMBER3){ // * After digit (before period) |
|
n = buffer[i]; |
|
if(n === 0x2e){ // . |
|
this.position = 0.1; this.tState = NUMBER4; |
|
}else if(n === 0x65 || n === 0x45){ // e/E |
|
this.exponent = 0; this.tState = NUMBER6; |
|
}else{ |
|
if (n >= 0x30 && n < 0x40) { this.magnatude = this.magnatude * 10 + n - 0x30; } |
|
else { |
|
this.tState = START; |
|
if (this.negative) { |
|
this.magnatude = -this.magnatude; |
|
this.negative = undefined; |
|
} |
|
this.onToken(NUMBER, this.magnatude); |
|
this.magnatude = undefined; |
|
i--; |
|
} |
|
} |
|
}else if (this.tState === NUMBER4){ // After period |
|
n = buffer[i]; |
|
if (n >= 0x30 && n < 0x40) { // 0-9 |
|
this.magnatude += this.position * (n - 0x30); |
|
this.position /= 10; |
|
this.tState = NUMBER5; |
|
} else { this.charError(buffer, i); } |
|
}else if (this.tState === NUMBER5){ // * After digit (after period) |
|
n = buffer[i]; |
|
if (n >= 0x30 && n < 0x40) { // 0-9 |
|
this.magnatude += this.position * (n - 0x30); |
|
this.position /= 10; |
|
} |
|
else if (n === 0x65 || n === 0x45) { this.exponent = 0; this.tState = NUMBER6; } // E/e |
|
else { |
|
this.tState = START; |
|
if (this.negative) { |
|
this.magnatude = -this.magnatude; |
|
this.negative = undefined; |
|
} |
|
this.onToken(NUMBER, this.negative ? -this.magnatude : this.magnatude); |
|
this.magnatude = undefined; |
|
this.position = undefined; |
|
i--; |
|
} |
|
}else if (this.tState === NUMBER6){ // After E |
|
n = buffer[i]; |
|
if (n === 0x2b || n === 0x2d) { // +/- |
|
if (n === 0x2d) { this.negativeExponent = true; } |
|
this.tState = NUMBER7; |
|
} |
|
else if (n >= 0x30 && n < 0x40) { |
|
this.exponent = this.exponent * 10 + (n - 0x30); |
|
this.tState = NUMBER8; |
|
} |
|
else { this.charError(buffer, i); } |
|
}else if (this.tState === NUMBER7){ // After +/- |
|
n = buffer[i]; |
|
if (n >= 0x30 && n < 0x40) { // 0-9 |
|
this.exponent = this.exponent * 10 + (n - 0x30); |
|
this.tState = NUMBER8; |
|
} |
|
else { this.charError(buffer, i); } |
|
}else if (this.tState === NUMBER8){ // * After digit (after +/-) |
|
n = buffer[i]; |
|
if (n >= 0x30 && n < 0x40) { // 0-9 |
|
this.exponent = this.exponent * 10 + (n - 0x30); |
|
} |
|
else { |
|
if (this.negativeExponent) { |
|
this.exponent = -this.exponent; |
|
this.negativeExponent = undefined; |
|
} |
|
this.magnatude *= Math.pow(10, this.exponent); |
|
this.exponent = undefined; |
|
if (this.negative) { |
|
this.magnatude = -this.magnatude; |
|
this.negative = undefined; |
|
} |
|
this.tState = START; |
|
this.onToken(NUMBER, this.magnatude); |
|
this.magnatude = undefined; |
|
i--; |
|
} |
|
}else if (this.tState === TRUE1){ // r |
|
if (buffer[i] === 0x72) { this.tState = TRUE2; } |
|
else { this.charError(buffer, i); } |
|
}else if (this.tState === TRUE2){ // u |
|
if (buffer[i] === 0x75) { this.tState = TRUE3; } |
|
else { this.charError(buffer, i); } |
|
}else if (this.tState === TRUE3){ // e |
|
if (buffer[i] === 0x65) { this.tState = START; this.onToken(TRUE, true); } |
|
else { this.charError(buffer, i); } |
|
}else if (this.tState === FALSE1){ // a |
|
if (buffer[i] === 0x61) { this.tState = FALSE2; } |
|
else { this.charError(buffer, i); } |
|
}else if (this.tState === FALSE2){ // l |
|
if (buffer[i] === 0x6c) { this.tState = FALSE3; } |
|
else { this.charError(buffer, i); } |
|
}else if (this.tState === FALSE3){ // s |
|
if (buffer[i] === 0x73) { this.tState = FALSE4; } |
|
else { this.charError(buffer, i); } |
|
}else if (this.tState === FALSE4){ // e |
|
if (buffer[i] === 0x65) { this.tState = START; this.onToken(FALSE, false); } |
|
else { this.charError(buffer, i); } |
|
}else if (this.tState === NULL1){ // u |
|
if (buffer[i] === 0x75) { this.tState = NULL2; } |
|
else { this.charError(buffer, i); } |
|
}else if (this.tState === NULL2){ // l |
|
if (buffer[i] === 0x6c) { this.tState = NULL3; } |
|
else { this.charError(buffer, i); } |
|
}else if (this.tState === NULL3){ // l |
|
if (buffer[i] === 0x6c) { this.tState = START; this.onToken(NULL, null); } |
|
else { this.charError(buffer, i); } |
|
} |
|
} |
|
}; |
|
proto.onToken = function (token, value) { |
|
// Override this to get events |
|
}; |
|
|
|
proto.parseError = function (token, value) { |
|
this.onError(new Error("Unexpected " + toknam(token) + (value ? ("(" + JSON.stringify(value) + ")") : "") + " in state " + toknam(this.state))); |
|
}; |
|
proto.onError = function (err) { throw err; }; |
|
proto.push = function () { |
|
this.stack.push({value: this.value, key: this.key, mode: this.mode}); |
|
}; |
|
proto.pop = function () { |
|
var value = this.value; |
|
var parent = this.stack.pop(); |
|
this.value = parent.value; |
|
this.key = parent.key; |
|
this.mode = parent.mode; |
|
this.emit(value); |
|
if (!this.mode) { this.state = VALUE; } |
|
}; |
|
proto.emit = function (value) { |
|
if (this.mode) { this.state = COMMA; } |
|
this.onValue(value); |
|
}; |
|
proto.onValue = function (value) { |
|
// Override me |
|
}; |
|
proto.onToken = function (token, value) { |
|
//console.log("OnToken: state=%s token=%s %s", toknam(this.state), toknam(token), value?JSON.stringify(value):""); |
|
if(this.state === VALUE){ |
|
if(token === STRING || token === NUMBER || token === TRUE || token === FALSE || token === NULL){ |
|
if (this.value) { |
|
this.value[this.key] = value; |
|
} |
|
this.emit(value); |
|
}else if(token === LEFT_BRACE){ |
|
this.push(); |
|
if (this.value) { |
|
this.value = this.value[this.key] = {}; |
|
} else { |
|
this.value = {}; |
|
} |
|
this.key = undefined; |
|
this.state = KEY; |
|
this.mode = OBJECT; |
|
}else if(token === LEFT_BRACKET){ |
|
this.push(); |
|
if (this.value) { |
|
this.value = this.value[this.key] = []; |
|
} else { |
|
this.value = []; |
|
} |
|
this.key = 0; |
|
this.mode = ARRAY; |
|
this.state = VALUE; |
|
}else if(token === RIGHT_BRACE){ |
|
if (this.mode === OBJECT) { |
|
this.pop(); |
|
} else { |
|
this.parseError(token, value); |
|
} |
|
}else if(token === RIGHT_BRACKET){ |
|
if (this.mode === ARRAY) { |
|
this.pop(); |
|
} else { |
|
this.parseError(token, value); |
|
} |
|
}else{ |
|
this.parseError(token, value); |
|
} |
|
}else if(this.state === KEY){ |
|
if (token === STRING) { |
|
this.key = value; |
|
this.state = COLON; |
|
} else if (token === RIGHT_BRACE) { |
|
this.pop(); |
|
} else { |
|
this.parseError(token, value); |
|
} |
|
}else if(this.state === COLON){ |
|
if (token === COLON) { this.state = VALUE; } |
|
else { this.parseError(token, value); } |
|
}else if(this.state === COMMA){ |
|
if (token === COMMA) { |
|
if (this.mode === ARRAY) { this.key++; this.state = VALUE; } |
|
else if (this.mode === OBJECT) { this.state = KEY; } |
|
|
|
} else if (token === RIGHT_BRACKET && this.mode === ARRAY || token === RIGHT_BRACE && this.mode === OBJECT) { |
|
this.pop(); |
|
} else { |
|
this.parseError(token, value); |
|
} |
|
}else{ |
|
this.parseError(token, value); |
|
} |
|
}; |
|
|
|
module.exports = Parser; |
|
|
|
}).call(this,require("buffer").Buffer) |
|
},{"buffer":9}],5:[function(require,module,exports){ |
|
(function (process){ |
|
var Stream = require('stream') |
|
|
|
// through |
|
// |
|
// a stream that does nothing but re-emit the input. |
|
// useful for aggregating a series of changing but not ending streams into one stream) |
|
|
|
exports = module.exports = through |
|
through.through = through |
|
|
|
//create a readable writable stream. |
|
|
|
function through (write, end, opts) { |
|
write = write || function (data) { this.queue(data) } |
|
end = end || function () { this.queue(null) } |
|
|
|
var ended = false, destroyed = false, buffer = [], _ended = false |
|
var stream = new Stream() |
|
stream.readable = stream.writable = true |
|
stream.paused = false |
|
|
|
// stream.autoPause = !(opts && opts.autoPause === false) |
|
stream.autoDestroy = !(opts && opts.autoDestroy === false) |
|
|
|
stream.write = function (data) { |
|
write.call(this, data) |
|
return !stream.paused |
|
} |
|
|
|
function drain() { |
|
while(buffer.length && !stream.paused) { |
|
var data = buffer.shift() |
|
if(null === data) |
|
return stream.emit('end') |
|
else |
|
stream.emit('data', data) |
|
} |
|
} |
|
|
|
stream.queue = stream.push = function (data) { |
|
// console.error(ended) |
|
if(_ended) return stream |
|
if(data == null) _ended = true |
|
buffer.push(data) |
|
drain() |
|
return stream |
|
} |
|
|
|
//this will be registered as the first 'end' listener |
|
//must call destroy next tick, to make sure we're after any |
|
//stream piped from here. |
|
//this is only a problem if end is not emitted synchronously. |
|
//a nicer way to do this is to make sure this is the last listener for 'end' |
|
|
|
stream.on('end', function () { |
|
stream.readable = false |
|
if(!stream.writable && stream.autoDestroy) |
|
process.nextTick(function () { |
|
stream.destroy() |
|
}) |
|
}) |
|
|
|
function _end () { |
|
stream.writable = false |
|
end.call(stream) |
|
if(!stream.readable && stream.autoDestroy) |
|
stream.destroy() |
|
} |
|
|
|
stream.end = function (data) { |
|
if(ended) return |
|
ended = true |
|
if(arguments.length) stream.write(data) |
|
_end() // will emit or queue |
|
return stream |
|
} |
|
|
|
stream.destroy = function () { |
|
if(destroyed) return |
|
destroyed = true |
|
ended = true |
|
buffer.length = 0 |
|
stream.writable = stream.readable = false |
|
stream.emit('close') |
|
return stream |
|
} |
|
|
|
stream.pause = function () { |
|
if(stream.paused) return |
|
stream.paused = true |
|
return stream |
|
} |
|
|
|
stream.resume = function () { |
|
if(stream.paused) { |
|
stream.paused = false |
|
stream.emit('resume') |
|
} |
|
drain() |
|
//may have become paused again, |
|
//as drain emits 'data'. |
|
if(!stream.paused) |
|
stream.emit('drain') |
|
return stream |
|
} |
|
return stream |
|
} |
|
|
|
|
|
}).call(this,require('_process')) |
|
},{"_process":16,"stream":29}],6:[function(require,module,exports){ |
|
(function (process){ |
|
/*! |
|
* async |
|
* https://github.com/caolan/async |
|
* |
|
* Copyright 2010-2014 Caolan McMahon |
|
* Released under the MIT license |
|
*/ |
|
/*jshint onevar: false, indent:4 */ |
|
/*global setImmediate: false, setTimeout: false, console: false */ |
|
(function () { |
|
|
|
var async = {}; |
|
|
|
// global on the server, window in the browser |
|
var root, previous_async; |
|
|
|
root = this; |
|
if (root != null) { |
|
previous_async = root.async; |
|
} |
|
|
|
async.noConflict = function () { |
|
root.async = previous_async; |
|
return async; |
|
}; |
|
|
|
function only_once(fn) { |
|
var called = false; |
|
return function() { |
|
if (called) throw new Error("Callback was already called."); |
|
called = true; |
|
fn.apply(root, arguments); |
|
} |
|
} |
|
|
|
//// cross-browser compatiblity functions //// |
|
|
|
var _toString = Object.prototype.toString; |
|
|
|
var _isArray = Array.isArray || function (obj) { |
|
return _toString.call(obj) === '[object Array]'; |
|
}; |
|
|
|
var _each = function (arr, iterator) { |
|
if (arr.forEach) { |
|
return arr.forEach(iterator); |
|
} |
|
for (var i = 0; i < arr.length; i += 1) { |
|
iterator(arr[i], i, arr); |
|
} |
|
}; |
|
|
|
var _map = function (arr, iterator) { |
|
if (arr.map) { |
|
return arr.map(iterator); |
|
} |
|
var results = []; |
|
_each(arr, function (x, i, a) { |
|
results.push(iterator(x, i, a)); |
|
}); |
|
return results; |
|
}; |
|
|
|
var _reduce = function (arr, iterator, memo) { |
|
if (arr.reduce) { |
|
return arr.reduce(iterator, memo); |
|
} |
|
_each(arr, function (x, i, a) { |
|
memo = iterator(memo, x, i, a); |
|
}); |
|
return memo; |
|
}; |
|
|
|
var _keys = function (obj) { |
|
if (Object.keys) { |
|
return Object.keys(obj); |
|
} |
|
var keys = []; |
|
for (var k in obj) { |
|
if (obj.hasOwnProperty(k)) { |
|
keys.push(k); |
|
} |
|
} |
|
return keys; |
|
}; |
|
|
|
//// exported async module functions //// |
|
|
|
//// nextTick implementation with browser-compatible fallback //// |
|
if (typeof process === 'undefined' || !(process.nextTick)) { |
|
if (typeof setImmediate === 'function') { |
|
async.nextTick = function (fn) { |
|
// not a direct alias for IE10 compatibility |
|
setImmediate(fn); |
|
}; |
|
async.setImmediate = async.nextTick; |
|
} |
|
else { |
|
async.nextTick = function (fn) { |
|
setTimeout(fn, 0); |
|
}; |
|
async.setImmediate = async.nextTick; |
|
} |
|
} |
|
else { |
|
async.nextTick = process.nextTick; |
|
if (typeof setImmediate !== 'undefined') { |
|
async.setImmediate = function (fn) { |
|
// not a direct alias for IE10 compatibility |
|
setImmediate(fn); |
|
}; |
|
} |
|
else { |
|
async.setImmediate = async.nextTick; |
|
} |
|
} |
|
|
|
async.each = function (arr, iterator, callback) { |
|
callback = callback || function () {}; |
|
if (!arr.length) { |
|
return callback(); |
|
} |
|
var completed = 0; |
|
_each(arr, function (x) { |
|
iterator(x, only_once(done) ); |
|
}); |
|
function done(err) { |
|
if (err) { |
|
callback(err); |
|
callback = function () {}; |
|
} |
|
else { |
|
completed += 1; |
|
if (completed >= arr.length) { |
|
callback(); |
|
} |
|
} |
|
} |
|
}; |
|
async.forEach = async.each; |
|
|
|
async.eachSeries = function (arr, iterator, callback) { |
|
callback = callback || function () {}; |
|
if (!arr.length) { |
|
return callback(); |
|
} |
|
var completed = 0; |
|
var iterate = function () { |
|
iterator(arr[completed], function (err) { |
|
if (err) { |
|
callback(err); |
|
callback = function () {}; |
|
} |
|
else { |
|
completed += 1; |
|
if (completed >= arr.length) { |
|
callback(); |
|
} |
|
else { |
|
iterate(); |
|
} |
|
} |
|
}); |
|
}; |
|
iterate(); |
|
}; |
|
async.forEachSeries = async.eachSeries; |
|
|
|
async.eachLimit = function (arr, limit, iterator, callback) { |
|
var fn = _eachLimit(limit); |
|
fn.apply(null, [arr, iterator, callback]); |
|
}; |
|
async.forEachLimit = async.eachLimit; |
|
|
|
var _eachLimit = function (limit) { |
|
|
|
return function (arr, iterator, callback) { |
|
callback = callback || function () {}; |
|
if (!arr.length || limit <= 0) { |
|
return callback(); |
|
} |
|
var completed = 0; |
|
var started = 0; |
|
var running = 0; |
|
|
|
(function replenish () { |
|
if (completed >= arr.length) { |
|
return callback(); |
|
} |
|
|
|
while (running < limit && started < arr.length) { |
|
started += 1; |
|
running += 1; |
|
iterator(arr[started - 1], function (err) { |
|
if (err) { |
|
callback(err); |
|
callback = function () {}; |
|
} |
|
else { |
|
completed += 1; |
|
running -= 1; |
|
if (completed >= arr.length) { |
|
callback(); |
|
} |
|
else { |
|
replenish(); |
|
} |
|
} |
|
}); |
|
} |
|
})(); |
|
}; |
|
}; |
|
|
|
|
|
var doParallel = function (fn) { |
|
return function () { |
|
var args = Array.prototype.slice.call(arguments); |
|
return fn.apply(null, [async.each].concat(args)); |
|
}; |
|
}; |
|
var doParallelLimit = function(limit, fn) { |
|
return function () { |
|
var args = Array.prototype.slice.call(arguments); |
|
return fn.apply(null, [_eachLimit(limit)].concat(args)); |
|
}; |
|
}; |
|
var doSeries = function (fn) { |
|
return function () { |
|
var args = Array.prototype.slice.call(arguments); |
|
return fn.apply(null, [async.eachSeries].concat(args)); |
|
}; |
|
}; |
|
|
|
|
|
var _asyncMap = function (eachfn, arr, iterator, callback) { |
|
arr = _map(arr, function (x, i) { |
|
return {index: i, value: x}; |
|
}); |
|
if (!callback) { |
|
eachfn(arr, function (x, callback) { |
|
iterator(x.value, function (err) { |
|
callback(err); |
|
}); |
|
}); |
|
} else { |
|
var results = []; |
|
eachfn(arr, function (x, callback) { |
|
iterator(x.value, function (err, v) { |
|
results[x.index] = v; |
|
callback(err); |
|
}); |
|
}, function (err) { |
|
callback(err, results); |
|
}); |
|
} |
|
}; |
|
async.map = doParallel(_asyncMap); |
|
async.mapSeries = doSeries(_asyncMap); |
|
async.mapLimit = function (arr, limit, iterator, callback) { |
|
return _mapLimit(limit)(arr, iterator, callback); |
|
}; |
|
|
|
var _mapLimit = function(limit) { |
|
return doParallelLimit(limit, _asyncMap); |
|
}; |
|
|
|
// reduce only has a series version, as doing reduce in parallel won't |
|
// work in many situations. |
|
async.reduce = function (arr, memo, iterator, callback) { |
|
async.eachSeries(arr, function (x, callback) { |
|
iterator(memo, x, function (err, v) { |
|
memo = v; |
|
callback(err); |
|
}); |
|
}, function (err) { |
|
callback(err, memo); |
|
}); |
|
}; |
|
// inject alias |
|
async.inject = async.reduce; |
|
// foldl alias |
|
async.foldl = async.reduce; |
|
|
|
async.reduceRight = function (arr, memo, iterator, callback) { |
|
var reversed = _map(arr, function (x) { |
|
return x; |
|
}).reverse(); |
|
async.reduce(reversed, memo, iterator, callback); |
|
}; |
|
// foldr alias |
|
async.foldr = async.reduceRight; |
|
|
|
var _filter = function (eachfn, arr, iterator, callback) { |
|
var results = []; |
|
arr = _map(arr, function (x, i) { |
|
return {index: i, value: x}; |
|
}); |
|
eachfn(arr, function (x, callback) { |
|
iterator(x.value, function (v) { |
|
if (v) { |
|
results.push(x); |
|
} |
|
callback(); |
|
}); |
|
}, function (err) { |
|
callback(_map(results.sort(function (a, b) { |
|
return a.index - b.index; |
|
}), function (x) { |
|
return x.value; |
|
})); |
|
}); |
|
}; |
|
async.filter = doParallel(_filter); |
|
async.filterSeries = doSeries(_filter); |
|
// select alias |
|
async.select = async.filter; |
|
async.selectSeries = async.filterSeries; |
|
|
|
var _reject = function (eachfn, arr, iterator, callback) { |
|
var results = []; |
|
arr = _map(arr, function (x, i) { |
|
return {index: i, value: x}; |
|
}); |
|
eachfn(arr, function (x, callback) { |
|
iterator(x.value, function (v) { |
|
if (!v) { |
|
results.push(x); |
|
} |
|
callback(); |
|
}); |
|
}, function (err) { |
|
callback(_map(results.sort(function (a, b) { |
|
return a.index - b.index; |
|
}), function (x) { |
|
return x.value; |
|
})); |
|
}); |
|
}; |
|
async.reject = doParallel(_reject); |
|
async.rejectSeries = doSeries(_reject); |
|
|
|
var _detect = function (eachfn, arr, iterator, main_callback) { |
|
eachfn(arr, function (x, callback) { |
|
iterator(x, function (result) { |
|
if (result) { |
|
main_callback(x); |
|
main_callback = function () {}; |
|
} |
|
else { |
|
callback(); |
|
} |
|
}); |
|
}, function (err) { |
|
main_callback(); |
|
}); |
|
}; |
|
async.detect = doParallel(_detect); |
|
async.detectSeries = doSeries(_detect); |
|
|
|
async.some = function (arr, iterator, main_callback) { |
|
async.each(arr, function (x, callback) { |
|
iterator(x, function (v) { |
|
if (v) { |
|
main_callback(true); |
|
main_callback = function () {}; |
|
} |
|
callback(); |
|
}); |
|
}, function (err) { |
|
main_callback(false); |
|
}); |
|
}; |
|
// any alias |
|
async.any = async.some; |
|
|
|
async.every = function (arr, iterator, main_callback) { |
|
async.each(arr, function (x, callback) { |
|
iterator(x, function (v) { |
|
if (!v) { |
|
main_callback(false); |
|
main_callback = function () {}; |
|
} |
|
callback(); |
|
}); |
|
}, function (err) { |
|
main_callback(true); |
|
}); |
|
}; |
|
// all alias |
|
async.all = async.every; |
|
|
|
async.sortBy = function (arr, iterator, callback) { |
|
async.map(arr, function (x, callback) { |
|
iterator(x, function (err, criteria) { |
|
if (err) { |
|
callback(err); |
|
} |
|
else { |
|
callback(null, {value: x, criteria: criteria}); |
|
} |
|
}); |
|
}, function (err, results) { |
|
if (err) { |
|
return callback(err); |
|
} |
|
else { |
|
var fn = function (left, right) { |
|
var a = left.criteria, b = right.criteria; |
|
return a < b ? -1 : a > b ? 1 : 0; |
|
}; |
|
callback(null, _map(results.sort(fn), function (x) { |
|
return x.value; |
|
})); |
|
} |
|
}); |
|
}; |
|
|
|
async.auto = function (tasks, callback) { |
|
callback = callback || function () {}; |
|
var keys = _keys(tasks); |
|
var remainingTasks = keys.length |
|
if (!remainingTasks) { |
|
return callback(); |
|
} |
|
|
|
var results = {}; |
|
|
|
var listeners = []; |
|
var addListener = function (fn) { |
|
listeners.unshift(fn); |
|
}; |
|
var removeListener = function (fn) { |
|
for (var i = 0; i < listeners.length; i += 1) { |
|
if (listeners[i] === fn) { |
|
listeners.splice(i, 1); |
|
return; |
|
} |
|
} |
|
}; |
|
var taskComplete = function () { |
|
remainingTasks-- |
|
_each(listeners.slice(0), function (fn) { |
|
fn(); |
|
}); |
|
}; |
|
|
|
addListener(function () { |
|
if (!remainingTasks) { |
|
var theCallback = callback; |
|
// prevent final callback from calling itself if it errors |
|
callback = function () {}; |
|
|
|
theCallback(null, results); |
|
} |
|
}); |
|
|
|
_each(keys, function (k) { |
|
var task = _isArray(tasks[k]) ? tasks[k]: [tasks[k]]; |
|
var taskCallback = function (err) { |
|
var args = Array.prototype.slice.call(arguments, 1); |
|
if (args.length <= 1) { |
|
args = args[0]; |
|
} |
|
if (err) { |
|
var safeResults = {}; |
|
_each(_keys(results), function(rkey) { |
|
safeResults[rkey] = results[rkey]; |
|
}); |
|
safeResults[k] = args; |
|
callback(err, safeResults); |
|
// stop subsequent errors hitting callback multiple times |
|
callback = function () {}; |
|
} |
|
else { |
|
results[k] = args; |
|
async.setImmediate(taskComplete); |
|
} |
|
}; |
|
var requires = task.slice(0, Math.abs(task.length - 1)) || []; |
|
var ready = function () { |
|
return _reduce(requires, function (a, x) { |
|
return (a && results.hasOwnProperty(x)); |
|
}, true) && !results.hasOwnProperty(k); |
|
}; |
|
if (ready()) { |
|
task[task.length - 1](taskCallback, results); |
|
} |
|
else { |
|
var listener = function () { |
|
if (ready()) { |
|
removeListener(listener); |
|
task[task.length - 1](taskCallback, results); |
|
} |
|
}; |
|
addListener(listener); |
|
} |
|
}); |
|
}; |
|
|
|
async.retry = function(times, task, callback) { |
|
var DEFAULT_TIMES = 5; |
|
var attempts = []; |
|
// Use defaults if times not passed |
|
if (typeof times === 'function') { |
|
callback = task; |
|
task = times; |
|
times = DEFAULT_TIMES; |
|
} |
|
// Make sure times is a number |
|
times = parseInt(times, 10) || DEFAULT_TIMES; |
|
var wrappedTask = function(wrappedCallback, wrappedResults) { |
|
var retryAttempt = function(task, finalAttempt) { |
|
return function(seriesCallback) { |
|
task(function(err, result){ |
|
seriesCallback(!err || finalAttempt, {err: err, result: result}); |
|
}, wrappedResults); |
|
}; |
|
}; |
|
while (times) { |
|
attempts.push(retryAttempt(task, !(times-=1))); |
|
} |
|
async.series(attempts, function(done, data){ |
|
data = data[data.length - 1]; |
|
(wrappedCallback || callback)(data.err, data.result); |
|
}); |
|
} |
|
// If a callback is passed, run this as a controll flow |
|
return callback ? wrappedTask() : wrappedTask |
|
}; |
|
|
|
async.waterfall = function (tasks, callback) { |
|
callback = callback || function () {}; |
|
if (!_isArray(tasks)) { |
|
var err = new Error('First argument to waterfall must be an array of functions'); |
|
return callback(err); |
|
} |
|
if (!tasks.length) { |
|
return callback(); |
|
} |
|
var wrapIterator = function (iterator) { |
|
return function (err) { |
|
if (err) { |
|
callback.apply(null, arguments); |
|
callback = function () {}; |
|
} |
|
else { |
|
var args = Array.prototype.slice.call(arguments, 1); |
|
var next = iterator.next(); |
|
if (next) { |
|
args.push(wrapIterator(next)); |
|
} |
|
else { |
|
args.push(callback); |
|
} |
|
async.setImmediate(function () { |
|
iterator.apply(null, args); |
|
}); |
|
} |
|
}; |
|
}; |
|
wrapIterator(async.iterator(tasks))(); |
|
}; |
|
|
|
var _parallel = function(eachfn, tasks, callback) { |
|
callback = callback || function () {}; |
|
if (_isArray(tasks)) { |
|
eachfn.map(tasks, function (fn, callback) { |
|
if (fn) { |
|
fn(function (err) { |
|
var args = Array.prototype.slice.call(arguments, 1); |
|
if (args.length <= 1) { |
|
args = args[0]; |
|
} |
|
callback.call(null, err, args); |
|
}); |
|
} |
|
}, callback); |
|
} |
|
else { |
|
var results = {}; |
|
eachfn.each(_keys(tasks), function (k, callback) { |
|
tasks[k](function (err) { |
|
var args = Array.prototype.slice.call(arguments, 1); |
|
if (args.length <= 1) { |
|
args = args[0]; |
|
} |
|
results[k] = args; |
|
callback(err); |
|
}); |
|
}, function (err) { |
|
callback(err, results); |
|
}); |
|
} |
|
}; |
|
|
|
async.parallel = function (tasks, callback) { |
|
_parallel({ map: async.map, each: async.each }, tasks, callback); |
|
}; |
|
|
|
async.parallelLimit = function(tasks, limit, callback) { |
|
_parallel({ map: _mapLimit(limit), each: _eachLimit(limit) }, tasks, callback); |
|
}; |
|
|
|
async.series = function (tasks, callback) { |
|
callback = callback || function () {}; |
|
if (_isArray(tasks)) { |
|
async.mapSeries(tasks, function (fn, callback) { |
|
if (fn) { |
|
fn(function (err) { |
|
var args = Array.prototype.slice.call(arguments, 1); |
|
if (args.length <= 1) { |
|
args = args[0]; |
|
} |
|
callback.call(null, err, args); |
|
}); |
|
} |
|
}, callback); |
|
} |
|
else { |
|
var results = {}; |
|
async.eachSeries(_keys(tasks), function (k, callback) { |
|
tasks[k](function (err) { |
|
var args = Array.prototype.slice.call(arguments, 1); |
|
if (args.length <= 1) { |
|
args = args[0]; |
|
} |
|
results[k] = args; |
|
callback(err); |
|
}); |
|
}, function (err) { |
|
callback(err, results); |
|
}); |
|
} |
|
}; |
|
|
|
async.iterator = function (tasks) { |
|
var makeCallback = function (index) { |
|
var fn = function () { |
|
if (tasks.length) { |
|
tasks[index].apply(null, arguments); |
|
} |
|
return fn.next(); |
|
}; |
|
fn.next = function () { |
|
return (index < tasks.length - 1) ? makeCallback(index + 1): null; |
|
}; |
|
return fn; |
|
}; |
|
return makeCallback(0); |
|
}; |
|
|
|
async.apply = function (fn) { |
|
var args = Array.prototype.slice.call(arguments, 1); |
|
return function () { |
|
return fn.apply( |
|
null, args.concat(Array.prototype.slice.call(arguments)) |
|
); |
|
}; |
|
}; |
|
|
|
var _concat = function (eachfn, arr, fn, callback) { |
|
var r = []; |
|
eachfn(arr, function (x, cb) { |
|
fn(x, function (err, y) { |
|
r = r.concat(y || []); |
|
cb(err); |
|
}); |
|
}, function (err) { |
|
callback(err, r); |
|
}); |
|
}; |
|
async.concat = doParallel(_concat); |
|
async.concatSeries = doSeries(_concat); |
|
|
|
async.whilst = function (test, iterator, callback) { |
|
if (test()) { |
|
iterator(function (err) { |
|
if (err) { |
|
return callback(err); |
|
} |
|
async.whilst(test, iterator, callback); |
|
}); |
|
} |
|
else { |
|
callback(); |
|
} |
|
}; |
|
|
|
async.doWhilst = function (iterator, test, callback) { |
|
iterator(function (err) { |
|
if (err) { |
|
return callback(err); |
|
} |
|
var args = Array.prototype.slice.call(arguments, 1); |
|
if (test.apply(null, args)) { |
|
async.doWhilst(iterator, test, callback); |
|
} |
|
else { |
|
callback(); |
|
} |
|
}); |
|
}; |
|
|
|
async.until = function (test, iterator, callback) { |
|
if (!test()) { |
|
iterator(function (err) { |
|
if (err) { |
|
return callback(err); |
|
} |
|
async.until(test, iterator, callback); |
|
}); |
|
} |
|
else { |
|
callback(); |
|
} |
|
}; |
|
|
|
async.doUntil = function (iterator, test, callback) { |
|
iterator(function (err) { |
|
if (err) { |
|
return callback(err); |
|
} |
|
var args = Array.prototype.slice.call(arguments, 1); |
|
if (!test.apply(null, args)) { |
|
async.doUntil(iterator, test, callback); |
|
} |
|
else { |
|
callback(); |
|
} |
|
}); |
|
}; |
|
|
|
async.queue = function (worker, concurrency) { |
|
if (concurrency === undefined) { |
|
concurrency = 1; |
|
} |
|
function _insert(q, data, pos, callback) { |
|
if (!q.started){ |
|
q.started = true; |
|
} |
|
if (!_isArray(data)) { |
|
data = [data]; |
|
} |
|
if(data.length == 0) { |
|
// call drain immediately if there are no tasks |
|
return async.setImmediate(function() { |
|
if (q.drain) { |
|
q.drain(); |
|
} |
|
}); |
|
} |
|
_each(data, function(task) { |
|
var item = { |
|
data: task, |
|
callback: typeof callback === 'function' ? callback : null |
|
}; |
|
|
|
if (pos) { |
|
q.tasks.unshift(item); |
|
} else { |
|
q.tasks.push(item); |
|
} |
|
|
|
if (q.saturated && q.tasks.length === q.concurrency) { |
|
q.saturated(); |
|
} |
|
async.setImmediate(q.process); |
|
}); |
|
} |
|
|
|
var workers = 0; |
|
var q = { |
|
tasks: [], |
|
concurrency: concurrency, |
|
saturated: null, |
|
empty: null, |
|
drain: null, |
|
started: false, |
|
paused: false, |
|
push: function (data, callback) { |
|
_insert(q, data, false, callback); |
|
}, |
|
kill: function () { |
|
q.drain = null; |
|
q.tasks = []; |
|
}, |
|
unshift: function (data, callback) { |
|
_insert(q, data, true, callback); |
|
}, |
|
process: function () { |
|
if (!q.paused && workers < q.concurrency && q.tasks.length) { |
|
var task = q.tasks.shift(); |
|
if (q.empty && q.tasks.length === 0) { |
|
q.empty(); |
|
} |
|
workers += 1; |
|
var next = function () { |
|
workers -= 1; |
|
if (task.callback) { |
|
task.callback.apply(task, arguments); |
|
} |
|
if (q.drain && q.tasks.length + workers === 0) { |
|
q.drain(); |
|
} |
|
q.process(); |
|
}; |
|
var cb = only_once(next); |
|
worker(task.data, cb); |
|
} |
|
}, |
|
length: function () { |
|
return q.tasks.length; |
|
}, |
|
running: function () { |
|
return workers; |
|
}, |
|
idle: function() { |
|
return q.tasks.length + workers === 0; |
|
}, |
|
pause: function () { |
|
if (q.paused === true) { return; } |
|
q.paused = true; |
|
q.process(); |
|
}, |
|
resume: function () { |
|
if (q.paused === false) { return; } |
|
q.paused = false; |
|
q.process(); |
|
} |
|
}; |
|
return q; |
|
}; |
|
|
|
async.priorityQueue = function (worker, concurrency) { |
|
|
|
function _compareTasks(a, b){ |
|
return a.priority - b.priority; |
|
}; |
|
|
|
function _binarySearch(sequence, item, compare) { |
|
var beg = -1, |
|
end = sequence.length - 1; |
|
while (beg < end) { |
|
var mid = beg + ((end - beg + 1) >>> 1); |
|
if (compare(item, sequence[mid]) >= 0) { |
|
beg = mid; |
|
} else { |
|
end = mid - 1; |
|
} |
|
} |
|
return beg; |
|
} |
|
|
|
function _insert(q, data, priority, callback) { |
|
if (!q.started){ |
|
q.started = true; |
|
} |
|
if (!_isArray(data)) { |
|
data = [data]; |
|
} |
|
if(data.length == 0) { |
|
// call drain immediately if there are no tasks |
|
return async.setImmediate(function() { |
|
if (q.drain) { |
|
q.drain(); |
|
} |
|
}); |
|
} |
|
_each(data, function(task) { |
|
var item = { |
|
data: task, |
|
priority: priority, |
|
callback: typeof callback === 'function' ? callback : null |
|
}; |
|
|
|
q.tasks.splice(_binarySearch(q.tasks, item, _compareTasks) + 1, 0, item); |
|
|
|
if (q.saturated && q.tasks.length === q.concurrency) { |
|
q.saturated(); |
|
} |
|
async.setImmediate(q.process); |
|
}); |
|
} |
|
|
|
// Start with a normal queue |
|
var q = async.queue(worker, concurrency); |
|
|
|
// Override push to accept second parameter representing priority |
|
q.push = function (data, priority, callback) { |
|
_insert(q, data, priority, callback); |
|
}; |
|
|
|
// Remove unshift function |
|
delete q.unshift; |
|
|
|
return q; |
|
}; |
|
|
|
async.cargo = function (worker, payload) { |
|
var working = false, |
|
tasks = []; |
|
|
|
var cargo = { |
|
tasks: tasks, |
|
payload: payload, |
|
saturated: null, |
|
empty: null, |
|
drain: null, |
|
drained: true, |
|
push: function (data, callback) { |
|
if (!_isArray(data)) { |
|
data = [data]; |
|
} |
|
_each(data, function(task) { |
|
tasks.push({ |
|
data: task, |
|
callback: typeof callback === 'function' ? callback : null |
|
}); |
|
cargo.drained = false; |
|
if (cargo.saturated && tasks.length === payload) { |
|
cargo.saturated(); |
|
} |
|
}); |
|
async.setImmediate(cargo.process); |
|
}, |
|
process: function process() { |
|
if (working) return; |
|
if (tasks.length === 0) { |
|
if(cargo.drain && !cargo.drained) cargo.drain(); |
|
cargo.drained = true; |
|
return; |
|
} |
|
|
|
var ts = typeof payload === 'number' |
|
? tasks.splice(0, payload) |
|
: tasks.splice(0, tasks.length); |
|
|
|
var ds = _map(ts, function (task) { |
|
return task.data; |
|
}); |
|
|
|
if(cargo.empty) cargo.empty(); |
|
working = true; |
|
worker(ds, function () { |
|
working = false; |
|
|
|
var args = arguments; |
|
_each(ts, function (data) { |
|
if (data.callback) { |
|
data.callback.apply(null, args); |
|
} |
|
}); |
|
|
|
process(); |
|
}); |
|
}, |
|
length: function () { |
|
return tasks.length; |
|
}, |
|
running: function () { |
|
return working; |
|
} |
|
}; |
|
return cargo; |
|
}; |
|
|
|
var _console_fn = function (name) { |
|
return function (fn) { |
|
var args = Array.prototype.slice.call(arguments, 1); |
|
fn.apply(null, args.concat([function (err) { |
|
var args = Array.prototype.slice.call(arguments, 1); |
|
if (typeof console !== 'undefined') { |
|
if (err) { |
|
if (console.error) { |
|
console.error(err); |
|
} |
|
} |
|
else if (console[name]) { |
|
_each(args, function (x) { |
|
console[name](x); |
|
}); |
|
} |
|
} |
|
}])); |
|
}; |
|
}; |
|
async.log = _console_fn('log'); |
|
async.dir = _console_fn('dir'); |
|
/*async.info = _console_fn('info'); |
|
async.warn = _console_fn('warn'); |
|
async.error = _console_fn('error');*/ |
|
|
|
async.memoize = function (fn, hasher) { |
|
var memo = {}; |
|
var queues = {}; |
|
hasher = hasher || function (x) { |
|
return x; |
|
}; |
|
var memoized = function () { |
|
var args = Array.prototype.slice.call(arguments); |
|
var callback = args.pop(); |
|
var key = hasher.apply(null, args); |
|
if (key in memo) { |
|
async.nextTick(function () { |
|
callback.apply(null, memo[key]); |
|
}); |
|
} |
|
else if (key in queues) { |
|
queues[key].push(callback); |
|
} |
|
else { |
|
queues[key] = [callback]; |
|
fn.apply(null, args.concat([function () { |
|
memo[key] = arguments; |
|
var q = queues[key]; |
|
delete queues[key]; |
|
for (var i = 0, l = q.length; i < l; i++) { |
|
q[i].apply(null, arguments); |
|
} |
|
}])); |
|
} |
|
}; |
|
memoized.memo = memo; |
|
memoized.unmemoized = fn; |
|
return memoized; |
|
}; |
|
|
|
async.unmemoize = function (fn) { |
|
return function () { |
|
return (fn.unmemoized || fn).apply(null, arguments); |
|
}; |
|
}; |
|
|
|
async.times = function (count, iterator, callback) { |
|
var counter = []; |
|
for (var i = 0; i < count; i++) { |
|
counter.push(i); |
|
} |
|
return async.map(counter, iterator, callback); |
|
}; |
|
|
|
async.timesSeries = function (count, iterator, callback) { |
|
var counter = []; |
|
for (var i = 0; i < count; i++) { |
|
counter.push(i); |
|
} |
|
return async.mapSeries(counter, iterator, callback); |
|
}; |
|
|
|
async.seq = function (/* functions... */) { |
|
var fns = arguments; |
|
return function () { |
|
var that = this; |
|
var args = Array.prototype.slice.call(arguments); |
|
var callback = args.pop(); |
|
async.reduce(fns, args, function (newargs, fn, cb) { |
|
fn.apply(that, newargs.concat([function () { |
|
var err = arguments[0]; |
|
var nextargs = Array.prototype.slice.call(arguments, 1); |
|
cb(err, nextargs); |
|
}])) |
|
}, |
|
function (err, results) { |
|
callback.apply(that, [err].concat(results)); |
|
}); |
|
}; |
|
}; |
|
|
|
async.compose = function (/* functions... */) { |
|
return async.seq.apply(null, Array.prototype.reverse.call(arguments)); |
|
}; |
|
|
|
var _applyEach = function (eachfn, fns /*args...*/) { |
|
var go = function () { |
|
var that = this; |
|
var args = Array.prototype.slice.call(arguments); |
|
var callback = args.pop(); |
|
return eachfn(fns, function (fn, cb) { |
|
fn.apply(that, args.concat([cb])); |
|
}, |
|
callback); |
|
}; |
|
if (arguments.length > 2) { |
|
var args = Array.prototype.slice.call(arguments, 2); |
|
return go.apply(this, args); |
|
} |
|
else { |
|
return go; |
|
} |
|
}; |
|
async.applyEach = doParallel(_applyEach); |
|
async.applyEachSeries = doSeries(_applyEach); |
|
|
|
async.forever = function (fn, callback) { |
|
function next(err) { |
|
if (err) { |
|
if (callback) { |
|
return callback(err); |
|
} |
|
throw err; |
|
} |
|
fn(next); |
|
} |
|
next(); |
|
}; |
|
|
|
// Node.js |
|
if (typeof module !== 'undefined' && module.exports) { |
|
module.exports = async; |
|
} |
|
// AMD / RequireJS |
|
else if (typeof define !== 'undefined' && define.amd) { |
|
define([], function () { |
|
return async; |
|
}); |
|
} |
|
// included directly via <script> tag |
|
else { |
|
root.async = async; |
|
} |
|
|
|
}()); |
|
|
|
}).call(this,require('_process')) |
|
},{"_process":16}],7:[function(require,module,exports){ |
|
(function (process,global){ |
|
/** |
|
* Highland: the high-level streams library |
|
* |
|
* Highland may be freely distributed under the Apache 2.0 license. |
|
* http://github.com/caolan/highland |
|
* Copyright (c) Caolan McMahon |
|
* |
|
*/ |
|
|
|
|
|
var inherits = require('util').inherits; |
|
var EventEmitter = require('events').EventEmitter; |
|
var Decoder = require('string_decoder').StringDecoder; |
|
|
|
/** |
|
* The Stream constructor, accepts an array of values or a generator function |
|
* as an optional argument. This is typically the entry point to the Highland |
|
* APIs, providing a convenient way of chaining calls together. |
|
* |
|
* **Arrays -** Streams created from Arrays will emit each value of the Array |
|
* and then emit a [nil](#nil) value to signal the end of the Stream. |
|
* |
|
* **Generators -** These are functions which provide values for the Stream. |
|
* They are lazy and can be infinite, they can also be asynchronous (for |
|
* example, making a HTTP request). You emit values on the Stream by calling |
|
* `push(err, val)`, much like a standard Node.js callback. Once it has been |
|
* called, the generator function will not be called again unless you call |
|
* `next()`. This call to `next()` will signal you've finished processing the |
|
* current data and allow for the generator function to be called again. If the |
|
* Stream is still being consumed the generator function will then be called |
|
* again. |
|
* |
|
* You can also redirect a generator Stream by passing a new source Stream |
|
* to read from to next. For example: `next(other_stream)` - then any subsequent |
|
* calls will be made to the new source. |
|
* |
|
* **Node Readable Stream -** Pass in a Node Readable Stream object to wrap |
|
* it with the Highland API. Reading from the resulting Highland Stream will |
|
* begin piping the data from the Node Stream to the Highland Stream. |
|
* |
|
* **EventEmitter / jQuery Elements -** Pass in both an event name and an |
|
* event emitter as the two arguments to the constructor and the first |
|
* argument emitted to the event handler will be written to the new Stream. |
|
* |
|
* You can also pass as an optional third parameter a function, an array of strings |
|
* or a number. In this case the event handler will try to wrap the arguments emitted |
|
* to it and write this object to the new stream. |
|
* |
|
* **Promise -** Accepts an ES6 / jQuery style promise and returns a |
|
* Highland Stream which will emit a single value (or an error). |
|
* |
|
* @id _(source) |
|
* @section Stream Objects |
|
* @name _(source) |
|
* @param {Array | Function | Readable Stream | Promise} source - (optional) source to take values from from |
|
* @api public |
|
* |
|
* // from an Array |
|
* _([1, 2, 3, 4]); |
|
* |
|
* // using a generator function |
|
* _(function (push, next) { |
|
* push(null, 1); |
|
* push(err); |
|
* next(); |
|
* }); |
|
* |
|
* // a stream with no source, can pipe node streams through it etc. |
|
* var through = _(); |
|
* |
|
* // wrapping a Node Readable Stream so you can easily manipulate it |
|
* _(readable).filter(hasSomething).pipe(writeable); |
|
* |
|
* // creating a stream from events |
|
* _('click', btn).each(handleEvent); |
|
* |
|
* // creating a stream from events with mapping |
|
* _('request', httpServer, ['req', 'res']).each(handleEvent); |
|
* |
|
* // from a Promise object |
|
* var foo = _($.getJSON('/api/foo')); |
|
*/ |
|
|
|
exports = module.exports = function (/*optional*/xs, /*optional*/ee, /*optional*/ mappingHint) { |
|
return new Stream(xs, ee, mappingHint); |
|
}; |
|
|
|
var _ = exports; |
|
|
|
|
|
// Save bytes in the minified (but not gzipped) version: |
|
var ArrayProto = Array.prototype, |
|
ObjProto = Object.prototype; |
|
|
|
// Create quick reference variables for speed access to core prototypes. |
|
var slice = ArrayProto.slice, |
|
toString = ObjProto.toString; |
|
|
|
|
|
_.isFunction = function (x) { |
|
return typeof x === 'function'; |
|
}; |
|
|
|
_.isObject = function (x) { |
|
return typeof x === 'object' && x !== null; |
|
}; |
|
|
|
_.isString = function (x) { |
|
return typeof x === 'string'; |
|
}; |
|
|
|
_.isArray = Array.isArray || function (x) { |
|
return toString.call(x) === '[object Array]'; |
|
}; |
|
|
|
// setImmediate implementation with browser and older node fallbacks |
|
if (typeof setImmediate === 'undefined') { |
|
if (typeof process === 'undefined' || !(process.nextTick)) { |
|
_.setImmediate = function (fn) { |
|
setTimeout(fn, 0); |
|
}; |
|
} |
|
else { |
|
// use nextTick on old node versions |
|
_.setImmediate = process.nextTick; |
|
} |
|
} |
|
// check no process.stdout to detect browserify |
|
else if (typeof process === 'undefined' || !(process.stdout)) { |
|
// modern browser - but not a direct alias for IE10 compatibility |
|
_.setImmediate = function (fn) { |
|
setImmediate(fn); |
|
}; |
|
} |
|
else { |
|
_.setImmediate = setImmediate; |
|
} |
|
|
|
|
|
/** |
|
* The end of stream marker. This is sent along the data channel of a Stream |
|
* to tell consumers that the Stream has ended. See the example map code for |
|
* an example of detecting the end of a Stream. |
|
* |
|
* Note: `nil` is setup as a global where possible. This makes it convenient |
|
* to access, but more importantly lets Streams from different Highland |
|
* instances work together and detect end-of-stream properly. This is mostly |
|
* useful for NPM where you may have many different Highland versions installed. |
|
* |
|
* @id nil |
|
* @section Utils |
|
* @name _.nil |
|
* @api public |
|
* |
|
* var map = function (iter, source) { |
|
* return source.consume(function (err, val, push, next) { |
|
* if (err) { |
|
* push(err); |
|
* next(); |
|
* } |
|
* else if (val === _.nil) { |
|
* push(null, val); |
|
* } |
|
* else { |
|
* push(null, iter(val)); |
|
* next(); |
|
* } |
|
* }); |
|
* }; |
|
*/ |
|
|
|
// set up a global nil object in cases where you have multiple Highland |
|
// instances installed (often via npm) |
|
var _global = this; |
|
if (typeof global !== 'undefined') { |
|
_global = global; |
|
} |
|
else if (typeof window !== 'undefined') { |
|
_global = window; |
|
} |
|
if (!_global.nil) { |
|
_global.nil = {}; |
|
} |
|
var nil = _.nil = _global.nil; |
|
|
|
/** |
|
* Transforms a function with specific arity (all arguments must be |
|
* defined) in a way that it can be called as a chain of functions until |
|
* the arguments list is saturated. |
|
* |
|
* This function is not itself curryable. |
|
* |
|
* @id curry |
|
* @name curry(fn, [*arguments]) |
|
* @section Functions |
|
* @param {Function} fn - the function to curry |
|
* @param args.. - any number of arguments to pre-apply to the function |
|
* @returns Function |
|
* @api public |
|
* |
|
* fn = curry(function (a, b, c) { |
|
* return a + b + c; |
|
* }); |
|
* |
|
* fn(1)(2)(3) == fn(1, 2, 3) |
|
* fn(1, 2)(3) == fn(1, 2, 3) |
|
* fn(1)(2, 3) == fn(1, 2, 3) |
|
*/ |
|
|
|
_.curry = function (fn /* args... */) { |
|
var args = slice.call(arguments); |
|
return _.ncurry.apply(this, [fn.length].concat(args)); |
|
}; |
|
|
|
/** |
|
* Same as `curry` but with a specific number of arguments. This can be |
|
* useful when functions do not explicitly define all its parameters. |
|
* |
|
* This function is not itself curryable. |
|
* |
|
* @id ncurry |
|
* @name ncurry(n, fn, [args...]) |
|
* @section Functions |
|
* @param {Number} n - the number of arguments to wait for before apply fn |
|
* @param {Function} fn - the function to curry |
|
* @param args... - any number of arguments to pre-apply to the function |
|
* @returns Function |
|
* @api public |
|
* |
|
* fn = ncurry(3, function () { |
|
* return Array.prototype.join.call(arguments, '.'); |
|
* }); |
|
* |
|
* fn(1, 2, 3) == '1.2.3'; |
|
* fn(1, 2)(3) == '1.2.3'; |
|
* fn(1)(2)(3) == '1.2.3'; |
|
*/ |
|
|
|
_.ncurry = function (n, fn /* args... */) { |
|
var largs = slice.call(arguments, 2); |
|
if (largs.length >= n) { |
|
return fn.apply(this, largs.slice(0, n)); |
|
} |
|
return function () { |
|
var args = largs.concat(slice.call(arguments)); |
|
if (args.length < n) { |
|
return _.ncurry.apply(this, [n, fn].concat(args)); |
|
} |
|
return fn.apply(this, args.slice(0, n)); |
|
}; |
|
}; |
|
|
|
/** |
|
* Partially applies the function (regardless of whether it has had curry |
|
* called on it). This will always postpone execution until at least the next |
|
* call of the partially applied function. |
|
* |
|
* @id partial |
|
* @name partial(fn, args...) |
|
* @section Functions |
|
* @param {Function} fn - function to partial apply |
|
* @param args... - the arguments to apply to the function |
|
* @api public |
|
* |
|
* var addAll = function () { |
|
* var args = Array.prototype.slice.call(arguments); |
|
* return foldl1(add, args); |
|
* }; |
|
* var f = partial(addAll, 1, 2); |
|
* f(3, 4) == 10 |
|
*/ |
|
|
|
_.partial = function (f /* args... */) { |
|
var args = slice.call(arguments, 1); |
|
return function () { |
|
return f.apply(this, args.concat(slice.call(arguments))); |
|
}; |
|
}; |
|
|
|
/** |
|
* Evaluates the function `fn` with the argument positions swapped. Only |
|
* works with functions that accept two arguments. |
|
* |
|
* @id flip |
|
* @name flip(fn, [x, y]) |
|
* @section Functions |
|
* @param {Function} f - function to flip argument application for |
|
* @param x - parameter to apply to the right hand side of f |
|
* @param y - parameter to apply to the left hand side of f |
|
* @api public |
|
* |
|
* div(2, 4) == 0.5 |
|
* flip(div, 2, 4) == 2 |
|
* flip(div)(2, 4) == 2 |
|
*/ |
|
|
|
_.flip = _.curry(function (fn, x, y) { return fn(y, x); }); |
|
|
|
/** |
|
* Creates a composite function, which is the application of function1 to |
|
* the results of function2. You can pass an arbitrary number of arguments |
|
* and have them composed. This means you can't partially apply the compose |
|
* function itself. |
|
* |
|
* @id compose |
|
* @name compose(fn1, fn2, ...) |
|
* @section Functions |
|
* @api public |
|
* |
|
* var add1 = add(1); |
|
* var mul3 = mul(3); |
|
* |
|
* var add1mul3 = compose(mul3, add1); |
|
* add1mul3(2) == 9 |
|
*/ |
|
|
|
_.compose = function (/*functions...*/) { |
|
var fns = slice.call(arguments).reverse(); |
|
return _.seq.apply(null, fns); |
|
}; |
|
|
|
/** |
|
* The reversed version of compose. Where arguments are in the order of |
|
* application. |
|
* |
|
* @id seq |
|
* @name seq(fn1, fn2, ...) |
|
* @section Functions |
|
* @api public |
|
* |
|
* var add1 = add(1); |
|
* var mul3 = mul(3); |
|
* |
|
* var add1mul3 = seq(add1, mul3); |
|
* add1mul3(2) == 9 |
|
*/ |
|
|
|
_.seq = function () { |
|
var fns = slice.call(arguments); |
|
return function () { |
|
if (!fns.length) { |
|
return; |
|
} |
|
var r = fns[0].apply(this, arguments); |
|
for (var i = 1; i < fns.length; i++) { |
|
r = fns[i].call(this, r); |
|
} |
|
return r; |
|
}; |
|
}; |
|
|
|
/** |
|
* Actual Stream constructor wrapped the the main exported function |
|
*/ |
|
|
|
function Stream(/*optional*/xs, /*optional*/ee, /*optional*/mappingHint) { |
|
if (xs && _.isStream(xs)) { |
|
// already a Stream |
|
return xs; |
|
} |
|
|
|
EventEmitter.call(this); |
|
var self = this; |
|
|
|
// used to detect Highland Streams using isStream(x), this |
|
// will work even in cases where npm has installed multiple |
|
// versions, unlike an instanceof check |
|
self.__HighlandStream__ = true; |
|
|
|
self.id = ('' + Math.random()).substr(2, 6); |
|
this.paused = true; |
|
this._incoming = []; |
|
this._outgoing = []; |
|
this._consumers = []; |
|
this._observers = []; |
|
this._destructors = []; |
|
this._send_events = false; |
|
this._delegate = null; |
|
this.source = null; |
|
|
|
// Old-style node Stream.pipe() checks for this |
|
this.writable = true; |
|
|
|
self.on('newListener', function (ev) { |
|
if (ev === 'data') { |
|
self._send_events = true; |
|
_.setImmediate(self.resume.bind(self)); |
|
} |
|
else if (ev === 'end') { |
|
// this property avoids us checking the length of the |
|
// listners subscribed to each event on each _send() call |
|
self._send_events = true; |
|
} |
|
}); |
|
|
|
// TODO: write test to cover this removeListener code |
|
self.on('removeListener', function (ev) { |
|
if (ev === 'end' || ev === 'data') { |
|
var end_listeners = self.listeners('end').length; |
|
var data_listeners = self.listeners('data').length; |
|
if (end_listeners + data_listeners === 0) { |
|
// stop emitting events |
|
self._send_events = false; |
|
} |
|
} |
|
}); |
|
|
|
if (xs === undefined) { |
|
// nothing else to do |
|
} |
|
else if (_.isArray(xs)) { |
|
self._incoming = xs.concat([nil]); |
|
} |
|
else if (typeof xs === 'function') { |
|
this._generator = xs; |
|
this._generator_push = function (err, x) { |
|
self.write(err ? new StreamError(err): x); |
|
}; |
|
this._generator_next = function (s) { |
|
if (s) { |
|
// we MUST pause to get the redirect object into the _incoming |
|
// buffer otherwise it would be passed directly to _send(), |
|
// which does not handle StreamRedirect objects! |
|
var _paused = self.paused; |
|
if (!_paused) { |
|
self.pause(); |
|
} |
|
self.write(new StreamRedirect(s)); |
|
if (!_paused) { |
|
self.resume(); |
|
} |
|
} |
|
else { |
|
self._generator_running = false; |
|
} |
|
if (!self.paused) { |
|
self.resume(); |
|
} |
|
}; |
|
} |
|
else if (_.isObject(xs)) { |
|
if (_.isFunction(xs.then)) { |
|
// probably a promise |
|
return _(function (push) { |
|
xs.then(function (value) { |
|
push(null, value); |
|
return push(null, nil); |
|
}, |
|
function (err) { |
|
push(err); |
|
return push(null, nil); |
|
}); |
|
}); |
|
} |
|
else { |
|
// write any errors into the stream |
|
xs.on('error', function (err) { |
|
self.write(new StreamError(err)); |
|
}); |
|
// assume it's a pipeable stream as a source |
|
xs.pipe(self); |
|
} |
|
} |
|
else if (typeof xs === 'string') { |
|
var mappingHintType = (typeof mappingHint); |
|
var mapper; |
|
|
|
if (mappingHintType === 'function') { |
|
mapper = mappingHint; |
|
} else if (mappingHintType === 'number') { |
|
mapper = function () { |
|
return slice.call(arguments, 0, mappingHint); |
|
}; |
|
} else if (_.isArray(mappingHint)) { |
|
mapper = function () { |
|
var args = arguments; |
|
return mappingHint.reduce(function (ctx, hint, idx) { |
|
ctx[hint] = args[idx]; |
|
return ctx; |
|
}, {}); |
|
}; |
|
} else { |
|
mapper = function (x) { return x; }; |
|
} |
|
|
|
ee.on(xs, function () { |
|
var ctx = mapper.apply(this, arguments); |
|
self.write(ctx); |
|
}); |
|
} |
|
else { |
|
throw new Error( |
|
'Unexpected argument type to Stream(): ' + (typeof xs) |
|
); |
|
} |
|
} |
|
inherits(Stream, EventEmitter); |
|
|
|
/** |
|
* adds a top-level _.foo(mystream) style export for Stream methods |
|
*/ |
|
|
|
function exposeMethod(name) { |
|
var f = Stream.prototype[name]; |
|
var n = f.length; |
|
_[name] = _.ncurry(n + 1, function () { |
|
var args = Array.prototype.slice.call(arguments); |
|
var s = _(args.pop()); |
|
return f.apply(s, args); |
|
}); |
|
} |
|
|
|
/** |
|
* Used as an Error marker when writing to a Stream's incoming buffer |
|
*/ |
|
|
|
function StreamError(err) { |
|
this.__HighlandStreamError__ = true; |
|
this.error = err; |
|
} |
|
|
|
/** |
|
* Used as a Redirect marker when writing to a Stream's incoming buffer |
|
*/ |
|
|
|
function StreamRedirect(to) { |
|
this.__HighlandStreamRedirect__ = true; |
|
this.to = to; |
|
} |
|
|
|
/** |
|
* Returns true if `x` is a Highland Stream. |
|
* |
|
* @id isStream |
|
* @section Utils |
|
* @name _.isStream(x) |
|
* @param x - the object to test |
|
* @api public |
|
* |
|
* _.isStream('foo') // => false |
|
* _.isStream(_([1,2,3])) // => true |
|
*/ |
|
|
|
_.isStream = function (x) { |
|
return _.isObject(x) && x.__HighlandStream__; |
|
}; |
|
|
|
_._isStreamError = function (x) { |
|
return _.isObject(x) && x.__HighlandStreamError__; |
|
}; |
|
|
|
_._isStreamRedirect = function (x) { |
|
return _.isObject(x) && x.__HighlandStreamRedirect__; |
|
}; |
|
|
|
/** |
|
* Sends errors / data to consumers, observers and event handlers |
|
*/ |
|
|
|
Stream.prototype._send = function (err, x) { |
|
//console.log(['_send', this.id, err, x]); |
|
if (x === nil) { |
|
this.ended = true; |
|
} |
|
if (this._consumers.length) { |
|
for (var i = 0, len = this._consumers.length; i < len; i++) { |
|
var c = this._consumers[i]; |
|
if (err) { |
|
c.write(new StreamError(err)); |
|
} |
|
else { |
|
c.write(x); |
|
} |
|
} |
|
} |
|
if (this._observers.length) { |
|
for (var j = 0, len2 = this._observers.length; j < len2; j++) { |
|
this._observers[j].write(x); |
|
} |
|
} |
|
if (this._send_events) { |
|
if (x === nil) { |
|
this.emit('end'); |
|
} |
|
else { |
|
this.emit('data', x); |
|
} |
|
} |
|
}; |
|
|
|
/** |
|
* Pauses the stream. All Highland Streams start in the paused state. |
|
* |
|
* @id pause |
|
* @section Stream Objects |
|
* @name Stream.pause() |
|
* @api public |
|
* |
|
* var xs = _(generator); |
|
* xs.pause(); |
|
*/ |
|
|
|
Stream.prototype.pause = function () { |
|
//console.log(['pause', this.id]); |
|
this.paused = true; |
|
if (this.source) { |
|
this.source._checkBackPressure(); |
|
} |
|
}; |
|
|
|
/** |
|
* When there is a change in downstream consumers, it will often ask |
|
* the parent Stream to re-check it's state and pause/resume accordingly. |
|
*/ |
|
|
|
Stream.prototype._checkBackPressure = function () { |
|
if (!this._consumers.length) { |
|
return this.pause(); |
|
} |
|
for (var i = 0, len = this._consumers.length; i < len; i++) { |
|
if (this._consumers[i].paused) { |
|
return this.pause(); |
|
} |
|
} |
|
return this.resume(); |
|
}; |
|
|
|
/** |
|
* Starts pull values out of the incoming buffer and sending them downstream, |
|
* this will exit early if this causes a downstream consumer to pause. |
|
*/ |
|
|
|
Stream.prototype._readFromBuffer = function () { |
|
//console.log(['_readFromBuffer', this.id, this.paused, this._incoming]); |
|
var len = this._incoming.length; |
|
var i = 0; |
|
while (i < len && !this.paused) { |
|
var x = this._incoming[i]; |
|
if (_._isStreamError(x)) { |
|
this._send(x.error); |
|
} |
|
else if (_._isStreamRedirect(x)) { |
|
this._redirect(x.to); |
|
} |
|
else { |
|
this._send(null, x); |
|
} |
|
i++; |
|
} |
|
// remove processed data from _incoming buffer |
|
this._incoming.splice(0, i); |
|
}; |
|
|
|
/** |
|
* Starts pull values out of the incoming buffer and sending them downstream, |
|
* this will exit early if this causes a downstream consumer to pause. |
|
*/ |
|
|
|
Stream.prototype._sendOutgoing = function () { |
|
//console.log(['_sendOutgoing', this.id, this.paused, this._outgoing]); |
|
var len = this._outgoing.length; |
|
var i = 0; |
|
while (i < len && !this.paused) { |
|
var x = this._outgoing[i]; |
|
if (_._isStreamError(x)) { |
|
Stream.prototype._send.call(this, x.error); |
|
} |
|
else if (_._isStreamRedirect(x)) { |
|
this._redirect(x.to); |
|
} |
|
else { |
|
Stream.prototype._send.call(this, null, x); |
|
} |
|
i++; |
|
} |
|
// remove processed data from _outgoing buffer |
|
this._outgoing.splice(0, i); |
|
}; |
|
|
|
/** |
|
* Resumes a paused Stream. This will either read from the Stream's incoming |
|
* buffer or request more data from an upstream source. |
|
* |
|
* @id resume |
|
* @section Stream Objects |
|
* @name Stream.resume() |
|
* @api public |
|
* |
|
* var xs = _(generator); |
|
* xs.resume(); |
|
*/ |
|
|
|
Stream.prototype.resume = function () { |
|
//console.log(['resume', this.id]); |
|
if (this._resume_running) { |
|
//console.log(['resume already processing _incoming buffer, ignore resume call']); |
|
// already processing _incoming buffer, ignore resume call |
|
this._repeat_resume = true; |
|
return; |
|
} |
|
this._resume_running = true; |
|
do { |
|
// use a repeat flag to avoid recursing resume() calls |
|
this._repeat_resume = false; |
|
this.paused = false; |
|
|
|
// send values from outgoing buffer first |
|
this._sendOutgoing(); |
|
|
|
// send values from incoming buffer before reading from source |
|
this._readFromBuffer(); |
|
|
|
// we may have paused while reading from buffer |
|
if (!this.paused) { |
|
// ask parent for more data |
|
if (this.source) { |
|
//console.log(['ask parent for more data']); |
|
this.source._checkBackPressure(); |
|
} |
|
// run _generator to fill up _incoming buffer |
|
else if (this._generator) { |
|
//console.log(['run generator to fill up _incoming buffer']); |
|
this._runGenerator(); |
|
} |
|
else { |
|
// perhaps a node stream is being piped in |
|
this.emit('drain'); |
|
} |
|
} |
|
} while (this._repeat_resume); |
|
this._resume_running = false; |
|
}; |
|
|
|
/** |
|
* Ends a Stream. This is the same as sending a [nil](#nil) value as data. |
|
* You shouldn't need to call this directly, rather it will be called by |
|
* any [Node Readable Streams](http://nodejs.org/api/stream.html#stream_class_stream_readable) |
|
* you pipe in. |
|
* |
|
* @id end |
|
* @section Stream Objects |
|
* @name Stream.end() |
|
* @api public |
|
* |
|
* mystream.end(); |
|
*/ |
|
|
|
Stream.prototype.end = function () { |
|
this.write(nil); |
|
}; |
|
|
|
/** |
|
* Pipes a Highland Stream to a [Node Writable Stream](http://nodejs.org/api/stream.html#stream_class_stream_writable) |
|
* (Highland Streams are also Node Writable Streams). This will pull all the |
|
* data from the source Highland Stream and write it to the destination, |
|
* automatically managing flow so that the destination is not overwhelmed |
|
* by a fast source. |
|
* |
|
* This function returns the destination so you can chain together pipe calls. |
|
* |
|
* @id pipe |
|
* @section Consumption |
|
* @name Stream.pipe(dest) |
|
* @param {Writable Stream} dest - the destination to write all data to |
|
* @api public |
|
* |
|
* var source = _(generator); |
|
* var dest = fs.createWriteStream('myfile.txt') |
|
* source.pipe(dest); |
|
* |
|
* // chained call |
|
* source.pipe(through).pipe(dest); |
|
*/ |
|
|
|
Stream.prototype.pipe = function (dest) { |
|
var self = this; |
|
|
|
// stdout and stderr are special case writables that cannot be closed |
|
var canClose = dest !== process.stdout && dest !== process.stderr; |
|
|
|
var s = self.consume(function (err, x, push, next) { |
|
if (err) { |
|
self.emit('error', err); |
|
return; |
|
} |
|
if (x === nil) { |
|
if (canClose) { |
|
dest.end(); |
|
} |
|
} |
|
else if (dest.write(x) !== false) { |
|
next(); |
|
} |
|
}); |
|
|
|
dest.on('drain', onConsumerDrain); |
|
|
|
// Since we don't keep a reference to piped-to streams, |
|
// save a callback that will unbind the event handler. |
|
this._destructors.push(function () { |
|
dest.removeListener('drain', onConsumerDrain); |
|
}); |
|
|
|
s.resume(); |
|
return dest; |
|
|
|
function onConsumerDrain() { |
|
s.resume(); |
|
} |
|
}; |
|
|
|
/** |
|
* Destroys a stream by unlinking it from any consumers and sources. This will |
|
* stop all consumers from receiving events from this stream and removes this |
|
* stream as a consumer of any source stream. |
|
* |
|
* This function calls end() on the stream and unlinks it from any piped-to streams. |
|
* |
|
* @id destroy |
|
* @section Stream Objects |
|
* @name Stream.destroy() |
|
* @api public |
|
*/ |
|
|
|
Stream.prototype.destroy = function () { |
|
var self = this; |
|
this.end(); |
|
_(this._consumers).each(function (consumer) { |
|
self._removeConsumer(consumer); |
|
}); |
|
if (this.source) { |
|
this.source._removeConsumer(this); |
|
} |
|
_(this._destructors).each(function (destructor) { |
|
destructor(); |
|
}); |
|
}; |
|
|
|
/** |
|
* Runs the generator function for this Stream. If the generator is already |
|
* running (it has been called and not called next() yet) then this function |
|
* will do nothing. |
|
*/ |
|
|
|
Stream.prototype._runGenerator = function () { |
|
//console.log(['_runGenerator', this.id]); |
|
// if _generator already running, exit |
|
if (this._generator_running) { |
|
return; |
|
} |
|
this._generator_running = true; |
|
this._generator(this._generator_push, this._generator_next); |
|
}; |
|
|
|
/** |
|
* Performs the redirect from one Stream to another. In order for the |
|
* redirect to happen at the appropriate time, it is put on the incoming |
|
* buffer as a StreamRedirect object, and this function is called |
|
* once it is read from the buffer. |
|
*/ |
|
|
|
Stream.prototype._redirect = function (to) { |
|
//console.log(['_redirect', this.id, '=>', to.id]); |
|
// coerce to Stream |
|
to = _(to); |
|
|
|
while (to._delegate) { |
|
to = to._delegate; |
|
} |
|
|
|
to._consumers = this._consumers.map(function (c) { |
|
c.source = to; |
|
return c; |
|
}); |
|
|
|
// TODO: copy _observers |
|
this._consumers = []; |
|
//[this.consume = function () { |
|
// return to.consume.apply(to, arguments); |
|
//}; |
|
//this._removeConsumer = function () { |
|
// return to._removeConsumer.apply(to, arguments); |
|
//}; |
|
|
|
// this will cause a memory leak as long as the root object is around |
|
to._delegate_source = this._delegate_source || this; |
|
to._delegate_source._delegate = to; |
|
|
|
if (this.paused) { |
|
to.pause(); |
|
} |
|
else { |
|
this.pause(); |
|
to._checkBackPressure(); |
|
} |
|
}; |
|
|
|
/** |
|
* Adds a new consumer Stream, which will accept data and provide backpressure |
|
* to this Stream. Adding more than one consumer will cause an exception to be |
|
* thrown as the backpressure strategy must be explicitly chosen by the |
|
* developer (through calling fork or observe). |
|
*/ |
|
|
|
Stream.prototype._addConsumer = function (s) { |
|
if (this._consumers.length) { |
|
throw new Error( |
|
'Stream already being consumed, you must either fork() or observe()' |
|
); |
|
} |
|
s.source = this; |
|
this._consumers.push(s); |
|
this._checkBackPressure(); |
|
}; |
|
|
|
/** |
|
* Removes a consumer from this Stream. |
|
*/ |
|
|
|
Stream.prototype._removeConsumer = function (s) { |
|
var src = this; |
|
while (src._delegate) { |
|
src = src._delegate; |
|
} |
|
src._consumers = src._consumers.filter(function (c) { |
|
return c !== s; |
|
}); |
|
if (s.source === src) { |
|
s.source = null; |
|
} |
|
src._checkBackPressure(); |
|
}; |
|
|
|
/** |
|
* Consumes values from a Stream (once resumed) and returns a new Stream for |
|
* you to optionally push values onto using the provided push / next functions. |
|
* |
|
* This function forms the basis of many higher-level Stream operations. |
|
* It will not cause a paused stream to immediately resume, but behaves more |
|
* like a 'through' stream, handling values as they are read. |
|
* |
|
* @id consume |
|
* @section Transforms |
|
* @name Stream.consume(f) |
|
* @param {Function} f - the function to handle errors and values |
|
* @api public |
|
* |
|
* var filter = function (f, source) { |
|
* return source.consume(function (err, x, push, next) { |
|
* if (err) { |
|
* // pass errors along the stream and consume next value |
|
* push(err); |
|
* next(); |
|
* } |
|
* else if (x === _.nil) { |
|
* // pass nil (end event) along the stream |
|
* push(null, x); |
|
* } |
|
* else { |
|
* // pass on the value only if the value passes the predicate |
|
* if (f(x)) { |
|
* push(null, x); |
|
* } |
|
* next(); |
|
* } |
|
* }); |
|
* }; |
|
*/ |
|
|
|
Stream.prototype.consume = function (f) { |
|
var self = this; |
|
while (self._delegate) { |
|
self = self._delegate; |
|
} |
|
var s = new Stream(); |
|
var _send = s._send; |
|
var push = function (err, x) { |
|
//console.log(['push', err, x, s.paused]); |
|
if (x === nil) { |
|
// ended, remove consumer from source |
|
self._removeConsumer(s); |
|
} |
|
if (s.paused) { |
|
if (err) { |
|
s._outgoing.push(new StreamError(err)); |
|
} |
|
else { |
|
s._outgoing.push(x); |
|
} |
|
} |
|
else { |
|
_send.call(s, err, x); |
|
} |
|
}; |
|
var async; |
|
var next_called; |
|
var next = function (s2) { |
|
//console.log(['next', async]); |
|
if (s2) { |
|
// we MUST pause to get the redirect object into the _incoming |
|
// buffer otherwise it would be passed directly to _send(), |
|
// which does not handle StreamRedirect objects! |
|
var _paused = s.paused; |
|
if (!_paused) { |
|
s.pause(); |
|
} |
|
s.write(new StreamRedirect(s2)); |
|
if (!_paused) { |
|
s.resume(); |
|
} |
|
} |
|
else if (async) { |
|
s.resume(); |
|
} |
|
else { |
|
next_called = true; |
|
} |
|
}; |
|
s._send = function (err, x) { |
|
async = false; |
|
next_called = false; |
|
f(err, x, push, next); |
|
async = true; |
|
if (!next_called) { |
|
s.pause(); |
|
} |
|
}; |
|
self._addConsumer(s); |
|
return s; |
|
}; |
|
exposeMethod('consume'); |
|
|
|
/** |
|
* Consumes a single item from the Stream. Unlike consume, this function will |
|
* not provide a new stream for you to push values onto, and it will unsubscribe |
|
* as soon as it has a single error, value or nil from the source. |
|
* |
|
* You probably won't need to use this directly, but it is used internally by |
|
* some functions in the Highland library. |
|
* |
|
* @id pull |
|
* @section Consumption |
|
* @name Stream.pull(f) |
|
* @param {Function} f - the function to handle data |
|
* @api public |
|
* |
|
* xs.pull(function (err, x) { |
|
* // do something |
|
* }); |
|
*/ |
|
|
|
Stream.prototype.pull = function (f) { |
|
var s = this.consume(function (err, x) { |
|
s.source._removeConsumer(s); |
|
f(err, x); |
|
}); |
|
s.id = 'pull:' + s.id; |
|
s.resume(); |
|
}; |
|
|
|
/** |
|
* Writes a value to the Stream. If the Stream is paused it will go into the |
|
* Stream's incoming buffer, otherwise it will be immediately processed and |
|
* sent to the Stream's consumers (if any). Returns false if the Stream is |
|
* paused, true otherwise. This lets Node's pipe method handle back-pressure. |
|
* |
|
* You shouldn't need to call this yourself, but it may be called by Node |
|
* functions which treat Highland Streams as a [Node Writable Stream](http://nodejs.org/api/stream.html#stream_class_stream_writable). |
|
* |
|
* @id write |
|
* @section Stream Objects |
|
* @name Stream.write(x) |
|
* @param x - the value to write to the Stream |
|
* @api public |
|
* |
|
* var xs = _(); |
|
* xs.write(1); |
|
* xs.write(2); |
|
* xs.end(); |
|
* |
|
* xs.toArray(function (ys) { |
|
* // ys will be [1, 2] |
|
* }); |
|
*/ |
|
|
|
Stream.prototype.write = function (x) { |
|
if (this.paused) { |
|
this._incoming.push(x); |
|
} |
|
else { |
|
if (_._isStreamError(x)) { |
|
this._send(x.error); |
|
} |
|
else { |
|
this._send(null, x); |
|
} |
|
} |
|
return !this.paused; |
|
}; |
|
|
|
/** |
|
* Forks a stream, allowing you to add additional consumers with shared |
|
* back-pressure. A stream forked to multiple consumers will only pull values |
|
* from it's source as fast as the slowest consumer can handle them. |
|
* |
|
* @id fork |
|
* @section Higher-order Streams |
|
* @name Stream.fork() |
|
* @api public |
|
* |
|
* var xs = _([1, 2, 3, 4]); |
|
* var ys = xs.fork(); |
|
* var zs = xs.fork(); |
|
* |
|
* // no values will be pulled from xs until zs also resume |
|
* ys.resume(); |
|
* |
|
* // now both ys and zs will get values from xs |
|
* zs.resume(); |
|
*/ |
|
|
|
Stream.prototype.fork = function () { |
|
var s = new Stream(); |
|
s.id = 'fork:' + s.id; |
|
s.source = this; |
|
this._consumers.push(s); |
|
this._checkBackPressure(); |
|
return s; |
|
}; |
|
|
|
/** |
|
* Observes a stream, allowing you to handle values as they are emitted, without |
|
* adding back-pressure or causing data to be pulled from the source. This can |
|
* be useful when you are performing two related queries on a stream where one |
|
* would block the other. Just be aware that a slow observer could fill up it's |
|
* buffer and cause memory issues. Where possible, you should use [fork](#fork). |
|
* |
|
* @id observe |
|
* @section Higher-order Streams |
|
* @name Stream.observe() |
|
* @api public |
|
* |
|
* var xs = _([1, 2, 3, 4]); |
|
* var ys = xs.fork(); |
|
* var zs = xs.observe(); |
|
* |
|
* // now both zs and ys will receive data as fast as ys can handle it |
|
* ys.resume(); |
|
*/ |
|
|
|
Stream.prototype.observe = function () { |
|
var s = new Stream(); |
|
s.id = 'observe:' + s.id; |
|
s.source = this; |
|
this._observers.push(s); |
|
return s; |
|
}; |
|
|
|
/** |
|
* Extracts errors from a Stream and applies them to an error handler |
|
* function. Returns a new Stream with the errors removed (unless the error |
|
* handler chooses to rethrow them using `push`). Errors can also be |
|
* transformed and put back onto the Stream as values. |
|
* |
|
* @id errors |
|
* @section Transforms |
|
* @name Stream.errors(f) |
|
* @param {Function} f - the function to pass all errors to |
|
* @api public |
|
* |
|
* getDocument.errors(function (err, push) { |
|
* if (err.statusCode === 404) { |
|
* // not found, return empty doc |
|
* push(null, {}); |
|
* } |
|
* else { |
|
* // otherwise, re-throw the error |
|
* push(err); |
|
* } |
|
* }); |
|
*/ |
|
|
|
Stream.prototype.errors = function (f) { |
|
return this.consume(function (err, x, push, next) { |
|
if (err) { |
|
f(err, push); |
|
next(); |
|
} |
|
else if (x === nil) { |
|
push(null, nil); |
|
} |
|
else { |
|
push(null, x); |
|
next(); |
|
} |
|
}); |
|
}; |
|
exposeMethod('errors'); |
|
|
|
/** |
|
* Like the [errors](#errors) method, but emits a Stream end marker after |
|
* an Error is encountered. |
|
* |
|
* @id stopOnError |
|
* @section Transforms |
|
* @name Stream.stopOnError(f) |
|
* @param {Function} f - the function to handle an error |
|
* @api public |
|
* |
|
* brokenStream.stopOnError(function (err) { |
|
* //console.error('Something broke: ' + err); |
|
* }); |
|
*/ |
|
|
|
Stream.prototype.stopOnError = function (f) { |
|
return this.consume(function (err, x, push, next) { |
|
if (err) { |
|
f(err, push); |
|
push(null, nil); |
|
} |
|
else if (x === nil) { |
|
push(null, nil); |
|
} |
|
else { |
|
push(null, x); |
|
next(); |
|
} |
|
}); |
|
}; |
|
exposeMethod('stopOnError'); |
|
|
|
/** |
|
* Iterates over every value from the Stream, calling the iterator function |
|
* on each of them. This function causes a **thunk**. |
|
* |
|
* If an error from the Stream reaches the `each` call, it will emit an |
|
* error event (which will cause it to throw if unhandled). |
|
* |
|
* @id each |
|
* @section Consumption |
|
* @name Stream.each(f) |
|
* @param {Function} f - the iterator function |
|
* @api public |
|
* |
|
* _([1, 2, 3, 4]).each(function (x) { |
|
* // will be called 4 times with x being 1, 2, 3 and 4 |
|
* }); |
|
*/ |
|
|
|
Stream.prototype.each = function (f) { |
|
var self = this; |
|
return this.consume(function (err, x, push, next) { |
|
if (err) { |
|
self.emit('error', err); |
|
} |
|
else if (x !== nil) { |
|
f(x); |
|
next(); |
|
} |
|
}).resume(); |
|
}; |
|
exposeMethod('each'); |
|
|
|
/** |
|
* Applies results from a Stream as arguments to a function |
|
* |
|
* @id apply |
|
* @section Consumption |
|
* @name Stream.apply(f) |
|
* @param {Function} f - the function to apply arguments to |
|
* @api public |
|
* |
|
* _([1, 2, 3]).apply(function (a, b, c) { |
|
* // a === 1 |
|
* // b === 2 |
|
* // c === 3 |
|
* }); |
|
*/ |
|
|
|
Stream.prototype.apply = function (f) { |
|
return this.toArray(function (args) { |
|
f.apply(null, args); |
|
}); |
|
}; |
|
exposeMethod('apply'); |
|
|
|
/** |
|
* Collects all values from a Stream into an Array and calls a function with |
|
* once with the result. This function causes a **thunk**. |
|
* |
|
* If an error from the Stream reaches the `toArray` call, it will emit an |
|
* error event (which will cause it to throw if unhandled). |
|
* |
|
* @id toArray |
|
* @section Consumption |
|
* @name Stream.toArray(f) |
|
* @param {Function} f - the callback to provide the completed Array to |
|
* @api public |
|
* |
|
* _([1, 2, 3, 4]).toArray(function (x) { |
|
* // parameter x will be [1,2,3,4] |
|
* }); |
|
*/ |
|
|
|
Stream.prototype.toArray = function (f) { |
|
var self = this; |
|
return this.collect().pull(function (err, x) { |
|
if (err) { |
|
self.emit('error', err); |
|
} |
|
else { |
|
f(x); |
|
} |
|
}); |
|
}; |
|
|
|
/** |
|
* Creates a new Stream of transformed values by applying a function to each |
|
* value from the source. The transformation function can be replaced with |
|
* a non-function value for convenience, and it will emit that value |
|
* for every data event on the source Stream. |
|
* |
|
* @id map |
|
* @section Transforms |
|
* @name Stream.map(f) |
|
* @param f - the transformation function or value to map to |
|
* @api public |
|
* |
|
* var doubled = _([1, 2, 3, 4]).map(function (x) { |
|
* return x * 2; |
|
* }); |
|
* |
|
* _([1, 2, 3]).map('hi') // => 'hi', 'hi', 'hi' |
|
*/ |
|
|
|
Stream.prototype.map = function (f) { |
|
if (!_.isFunction(f)) { |
|
var val = f; |
|
f = function () { |
|
return val; |
|
}; |
|
} |
|
return this.consume(function (err, x, push, next) { |
|
if (err) { |
|
push(err); |
|
next(); |
|
} |
|
else if (x === nil) { |
|
push(err, x); |
|
} |
|
else { |
|
var fnVal, fnErr; |
|
try { |
|
fnVal = f(x); |
|
} catch (e) { |
|
fnErr = e; |
|
} |
|
push(fnErr, fnVal); |
|
next(); |
|
} |
|
}); |
|
}; |
|
exposeMethod('map'); |
|
|
|
/** |
|
* Creates a new Stream which applies a function to each value from the source |
|
* and re-emits the source value. Useful when you want to mutate the value or |
|
* perform side effects |
|
* |
|
* @id doto |
|
* @section Transforms |
|
* @name Stream.doto(f) |
|
* @param f - the function to apply |
|
* @api public |
|
* |
|
* var appended = _([[1], [2], [3], [4]]).doto(function (x) { |
|
* x.push(1); |
|
* }); |
|
* |
|
* _([1, 2, 3]).doto(console.log) |
|
* // 1 |
|
* // 2 |
|
* // 3 |
|
* // => 1, 2, 3 |
|
*/ |
|
|
|
Stream.prototype.doto = function (f) { |
|
return this.map(function (x) { |
|
f(x); |
|
return x; |
|
}); |
|
}; |
|
exposeMethod('doto'); |
|
|
|
/** |
|
* Limits number of values through the stream to a maximum of number of values |
|
* per window. Errors are not limited but allowed to pass through as soon as |
|
* they are read from the source. |
|
* |
|
* @id ratelimit |
|
* @section Transforms |
|
* @name Stream.ratelimit(num, ms) |
|
* @param {Number} num - the number of operations to perform per window |
|
* @param {Number} ms - the window of time to limit the operations in (in ms) |
|
* @api public |
|
* |
|
* _([1, 2, 3, 4, 5]).ratelimit(2, 100); |
|
* |
|
* // after 0ms => 1, 2 |
|
* // after 100ms => 1, 2, 3, 4 |
|
* // after 200ms => 1, 2, 3, 4, 5 |
|
*/ |
|
|
|
Stream.prototype.ratelimit = function (num, ms) { |
|
if (num < 1) { |
|
throw new Error('Invalid number of operations per ms: ' + num); |
|
} |
|
var sent = 0; |
|
return this.consume(function (err, x, push, next) { |
|
if (err) { |
|
push(err); |
|
next(); |
|
} |
|
else if (x === nil) { |
|
push(null, nil); |
|
} |
|
else { |
|
if (sent < num) { |
|
sent++; |
|
push(null, x); |
|
next(); |
|
} |
|
else { |
|
setTimeout(function () { |
|
sent = 1; |
|
push(null, x); |
|
next(); |
|
}, ms); |
|
} |
|
} |
|
}); |
|
}; |
|
exposeMethod('ratelimit'); |
|
|
|
/** |
|
* Creates a new Stream of values by applying each item in a Stream to an |
|
* iterator function which must return a (possibly empty) Stream. Each item on |
|
* these result Streams are then emitted on a single output Stream. |
|
* |
|
* @id flatMap |
|
* @section Higher-order Streams |
|
* @name Stream.flatMap(f) |
|
* @param {Function} f - the iterator function |
|
* @api public |
|
* |
|
* filenames.flatMap(readFile) |
|
*/ |
|
|
|
Stream.prototype.flatMap = function (f) { |
|
return this.map(f).sequence(); |
|
}; |
|
exposeMethod('flatMap'); |
|
|
|
/** |
|
* Retrieves values associated with a given property from all elements in |
|
* the collection. |
|
* |
|
* @id pluck |
|
* @section Transforms |
|
* @name Stream.pluck(property) |
|
* @param {String} prop - the property to which values should be associated |
|
* @api public |
|
* |
|
* var docs = [ |
|
* {type: 'blogpost', title: 'foo'}, |
|
* {type: 'blogpost', title: 'bar'}, |
|
* {type: 'comment', title: 'baz'} |
|
* ]; |
|
* |
|
* _(docs).pluck('title').toArray(function (xs) { |
|
* // xs is now ['foo', 'bar', 'baz'] |
|
* }); |
|
*/ |
|
|
|
Stream.prototype.pluck = function (prop) { |
|
return this.consume(function (err, x, push, next) { |
|
if (err) { |
|
push(err); |
|
next(); |
|
} |
|
else if (x === nil) { |
|
push(err, x); |
|
} |
|
else if (_.isObject(x)) { |
|
push(null, x[prop]); |
|
next(); |
|
} |
|
else { |
|
push(new Error( |
|
'Expected Object, got ' + (typeof x) |
|
)); |
|
next(); |
|
} |
|
}); |
|
}; |
|
exposeMethod('pluck'); |
|
|
|
/** |
|
* Creates a new Stream including only the values which pass a truth test. |
|
* |
|
* @id filter |
|
* @section Transforms |
|
* @name Stream.filter(f) |
|
* @param f - the truth test function |
|
* @api public |
|
* |
|
* var evens = _([1, 2, 3, 4]).filter(function (x) { |
|
* return x % 2 === 0; |
|
* }); |
|
*/ |
|
|
|
Stream.prototype.filter = function (f) { |
|
return this.consume(function (err, x, push, next) { |
|
if (err) { |
|
push(err); |
|
next(); |
|
} |
|
else if (x === nil) { |
|
push(err, x); |
|
} |
|
else { |
|
var fnVal, fnErr; |
|
try { |
|
fnVal = f(x); |
|
} catch (e) { |
|
fnErr = e; |
|
} |
|
|
|
if (fnErr) { |
|
push(fnErr); |
|
} else if (fnVal) { |
|
push(null, x); |
|
} |
|
next(); |
|
} |
|
}); |
|
}; |
|
exposeMethod('filter'); |
|
|
|
/** |
|
* Filters using a predicate which returns a Stream. If you need to check |
|
* against an asynchronous data source when filtering a Stream, this can |
|
* be convenient. The Stream returned from the filter function should have |
|
* a Boolean as it's first value (all other values on the Stream will be |
|
* disregarded). |
|
* |
|
* @id flatFilter |
|
* @section Higher-order Streams |
|
* @name Stream.flatFilter(f) |
|
* @param {Function} f - the truth test function which returns a Stream |
|
* @api public |
|
* |
|
* var checkExists = _.wrapCallback(fs.exists); |
|
* filenames.flatFilter(checkExists) |
|
*/ |
|
|
|
Stream.prototype.flatFilter = function (f) { |
|
return this.flatMap(function (x) { |
|
return f(x).take(1).otherwise(errorStream()) |
|
.flatMap(function (bool) { |
|
return _(bool ? [x] : []); |
|
}); |
|
}); |
|
|
|
function errorStream() { |
|
return _(function (push) { |
|
push(new Error('Stream returned by function was empty.')); |
|
push(null, _.nil); |
|
}); |
|
} |
|
}; |
|
exposeMethod('flatFilter'); |
|
|
|
/** |
|
* The inverse of [filter](#filter). |
|
* |
|
* @id reject |
|
* @section Transforms |
|
* @name Stream.reject(f) |
|
* @param {Function} f - the truth test function |
|
* @api public |
|
* |
|
* var odds = _([1, 2, 3, 4]).reject(function (x) { |
|
* return x % 2 === 0; |
|
* }); |
|
*/ |
|
|
|
Stream.prototype.reject = function (f) { |
|
return this.filter(_.compose(_.not, f)); |
|
}; |
|
exposeMethod('reject'); |
|
|
|
/** |
|
* A convenient form of filter, which returns the first object from a |
|
* Stream that passes the provided truth test |
|
* |
|
* @id find |
|
* @section Transforms |
|
* @name Stream.find(f) |
|
* @param {Function} f - the truth test function which returns a Stream |
|
* @api public |
|
* |
|
* var docs = [ |
|
* {type: 'blogpost', title: 'foo'}, |
|
* {type: 'blogpost', title: 'bar'}, |
|
* {type: 'comment', title: 'foo'} |
|
* ]; |
|
* |
|
* var f = function (x) { |
|
* return x.type == 'blogpost'; |
|
* }; |
|
* |
|
* _(docs).find(f); |
|
* // => {type: 'blogpost', title: 'foo'} |
|
* |
|
* // example with partial application |
|
* var firstBlogpost = _.find(f); |
|
* |
|
* firstBlogpost(docs) |
|
* // => {type: 'blogpost', title: 'foo'} |
|
*/ |
|
|
|
Stream.prototype.find = function (f) { |
|
return this.filter(f).take(1); |
|
}; |
|
exposeMethod('find'); |
|
|
|
/** |
|
* A convenient form of where, which returns the first object from a |
|
* Stream that matches a set of property values. findWhere is to where as find is to filter. |
|
* |
|
* @id findWhere |
|
* @section Transforms |
|
* @name Stream.findWhere(props) |
|
* @param {Object} props - the properties to match against |
|
* @api public |
|
* |
|
* var docs = [ |
|
* {type: 'blogpost', title: 'foo'}, |
|
* {type: 'blogpost', title: 'bar'}, |
|
* {type: 'comment', title: 'foo'} |
|
* ]; |
|
* |
|
* _(docs).findWhere({type: 'blogpost'}) |
|
* // => {type: 'blogpost', title: 'foo'} |
|
* |
|
* // example with partial application |
|
* var firstBlogpost = _.findWhere({type: 'blogpost'}); |
|
* |
|
* firstBlogpost(docs) |
|
* // => {type: 'blogpost', title: 'foo'} |
|
*/ |
|
|
|
Stream.prototype.findWhere = function (props) { |
|
return this.where(props).take(1); |
|
}; |
|
exposeMethod('findWhere'); |
|
|
|
|
|
/** |
|
* A convenient form of reduce, which groups items based on a function or property name |
|
* |
|
* @id group |
|
* @section Transforms |
|
* @name Stream.group(f) |
|
* @param {Function|String} f - the function or property name on which to group, |
|
* toString() is called on the result of a function. |
|
* @api public |
|
* |
|
* var docs = [ |
|
* {type: 'blogpost', title: 'foo'}, |
|
* {type: 'blogpost', title: 'bar'}, |
|
* {type: 'comment', title: 'foo'} |
|
* ]; |
|
* |
|
* var f = function (x) { |
|
* return x.type; |
|
* }; |
|
* |
|
* _(docs).group(f); OR _(docs).group('type'); |
|
* // => { |
|
* // => 'blogpost': [{type: 'blogpost', title: 'foo'}, {type: 'blogpost', title: 'bar'}] |
|
* // => 'comment': [{type: 'comment', title: 'foo'}] |
|
* // => } |
|
* |
|
*/ |
|
|
|
Stream.prototype.group = function (f) { |
|
var lambda = _.isString(f) ? _.get(f) : f; |
|
return this.reduce({}, function (m, o) { |
|
var key = lambda(o); |
|
if (!m.hasOwnProperty(key)) { m[key] = []; } |
|
m[key].push(o); |
|
return m; |
|
}.bind(this)); |
|
}; |
|
exposeMethod('group'); |
|
|
|
/** |
|
* Filters a Stream to drop all non-truthy values. |
|
* |
|
* @id compact |
|
* @section Transforms |
|
* @name Stream.compact() |
|
* @api public |
|
* |
|
* var compacted = _([0, 1, false, 3, null, undefined, 6]).compact(); |
|
* // => 1, 3, 6 |
|
*/ |
|
|
|
Stream.prototype.compact = function () { |
|
return this.filter(function (x) { |
|
return x; |
|
}); |
|
}; |
|
exposeMethod('compact'); |
|
|
|
/** |
|
* A convenient form of filter, which returns all objects from a Stream |
|
* which match a set of property values. |
|
* |
|
* @id where |
|
* @section Transforms |
|
* @name Stream.where(props) |
|
* @param {Object} props - the properties to match against |
|
* @api public |
|
* |
|
* var docs = [ |
|
* {type: 'blogpost', title: 'foo'}, |
|
* {type: 'blogpost', title: 'bar'}, |
|
* {type: 'comment', title: 'foo'} |
|
* ]; |
|
* |
|
* _(docs).where({title: 'foo'}) |
|
* // => {type: 'blogpost', title: 'foo'} |
|
* // => {type: 'comment', title: 'foo'} |
|
* |
|
* // example with partial application |
|
* var getBlogposts = _.where({type: 'blogpost'}); |
|
* |
|
* getBlogposts(docs) |
|
* // => {type: 'blogpost', title: 'foo'} |
|
* // => {type: 'blogpost', title: 'bar'} |
|
*/ |
|
|
|
Stream.prototype.where = function (props) { |
|
return this.filter(function (x) { |
|
for (var k in props) { |
|
if (x[k] !== props[k]) { |
|
return false; |
|
} |
|
} |
|
return true; |
|
}); |
|
}; |
|
exposeMethod('where'); |
|
|
|
/** |
|
* Takes two Streams and returns a Stream of corresponding pairs. |
|
* |
|
* @id zip |
|
* @section Higher-order Streams |
|
* @name Stream.zip(ys) |
|
* @param {Array | Stream} ys - the other stream to combine values with |
|
* @api public |
|
* |
|
* _(['a', 'b', 'c']).zip([1, 2, 3]) // => ['a', 1], ['b', 2], ['c', 3] |
|
*/ |
|
|
|
Stream.prototype.zip = function (ys) { |
|
ys = _(ys); |
|
var xs = this; |
|
var returned = 0; |
|
var z = []; |
|
function nextValue(index, max, src, push, next) { |
|
src.pull(function (err, x) { |
|
if (err) { |
|
push(err); |
|
nextValue(index, max, src, push, next); |
|
} |
|
else if (x === _.nil) { |
|
push(null, nil); |
|
} |
|
else { |
|
returned++; |
|
z[index] = x; |
|
if (returned === max) { |
|
push(null, z); |
|
next(); |
|
} |
|
} |
|
}); |
|
} |
|
return _(function (push, next) { |
|
returned = 0; |
|
z = []; |
|
nextValue(0, 2, xs, push, next); |
|
nextValue(1, 2, ys, push, next); |
|
}); |
|
}; |
|
exposeMethod('zip'); |
|
|
|
/** |
|
* Takes one Stream and batches incoming data into arrays of given length |
|
* |
|
* @id batch |
|
* @section Transforms |
|
* @name Stream.batch(n) |
|
* @param {Number} n - length of the array to batch |
|
* @api public |
|
* |
|
* _([1, 2, 3, 4, 5]).batch(2) // => [1, 2], [3, 4], [5] |
|
*/ |
|
|
|
Stream.prototype.batch = function (n) { |
|
var batched = []; |
|
|
|
return this.consume(function (err, x, push, next) { |
|
if (err) { |
|
push(err); |
|
next(); |
|
} else if (x === nil) { |
|
if (batched.length > 0) { |
|
push(null, batched); |
|
} |
|
|
|
push(null, nil); |
|
} else { |
|
batched.push(x); |
|
|
|
if (batched.length === n) { |
|
push(null, batched); |
|
batched = []; |
|
} |
|
|
|
next(); |
|
} |
|
}); |
|
}; |
|
exposeMethod('batch'); |
|
|
|
/** |
|
* Creates a new Stream with the separator interspersed between the elements of the source. |
|
* |
|
* intersperse is effectively the inverse of [splitBy](#splitBy). |
|
* |
|
* @id intersperse |
|
* @section Transforms |
|
* @name Stream.intersperse(sep) |
|
* @param sep - the value to intersperse between the source elements |
|
* @api public |
|
* |
|
* _(['ba', 'a', 'a']).intersperse('n') // => ba, n, a, n, a |
|
* _(['mississippi']).splitBy('ss').intersperse('ss') // => mi, ss, i, ss, ippi |
|
* _(['foo']).intersperse('bar') // => foo |
|
*/ |
|
|
|
Stream.prototype.intersperse = function (separator) { |
|
var started = false; |
|
return this.consume(function (err, x, push, next) { |
|
if (err) { |
|
push(err); |
|
next(); |
|
} else if (x === nil) { |
|
push(null, nil); |
|
} else { |
|
if (started) { |
|
push(null, separator); |
|
} else { |
|
started = true; |
|
} |
|
push(null, x); |
|
next(); |
|
} |
|
}); |
|
}; |
|
exposeMethod('intersperse'); |
|
|
|
/** |
|
* Splits the source Stream by a separator and emits the pieces in between, much like splitting a string. |
|
* |
|
* splitBy is effectively the inverse of [intersperse](#intersperse). |
|
* |
|
* @id splitBy |
|
* @section Transforms |
|
* @name Stream.splitBy(sep) |
|
* @param sep - the separator to split on |
|
* @api public |
|
* |
|
* _(['mis', 'si', 's', 'sippi']).splitBy('ss') // => mi, i, ippi |
|
* _(['ba', 'a', 'a']).intersperse('n').splitBy('n') // => ba, a, a |
|
* _(['foo']).splitBy('bar') // => foo |
|
*/ |
|
|
|
Stream.prototype.splitBy = function (sep) { |
|
var decoder = new Decoder(); |
|
var buffer = ''; |
|
|
|
function drain(x, push) { |
|
buffer = buffer + decoder.write(x); |
|
var pieces = buffer.split(sep); |
|
buffer = pieces.pop(); |
|
|
|
pieces.forEach(function (piece) { |
|
push(null, piece); |
|
}); |
|
} |
|
|
|
return this.consume(function (err, x, push, next) { |
|
if (err) { |
|
push(err); |
|
next(); |
|
} else if (x === nil) { |
|
drain(decoder.end(), push); |
|
if (buffer) push(null, buffer); |
|
push(null, nil); |
|
} else { |
|
drain(x, push); |
|
next(); |
|
} |
|
}); |
|
}; |
|
exposeMethod('splitBy'); |
|
|
|
/** |
|
* [splitBy](#splitBy) over newlines. |
|
* |
|
* @id split |
|
* @section Transforms |
|
* @name Stream.split() |
|
* @api public |
|
* |
|
* _(['a\n', 'b\nc\n', 'd', '\ne']).split() // => a, b, c, d, e |
|
* _(['a\r\nb\nc']]).split() // => a, b, c |
|
*/ |
|
|
|
Stream.prototype.split = function () { |
|
return this.splitBy(/\r?\n/); |
|
}; |
|
exposeMethod('split'); |
|
|
|
/** |
|
* Creates a new Stream with the first `n` values from the source. |
|
* |
|
* @id take |
|
* @section Transforms |
|
* @name Stream.take(n) |
|
* @param {Number} n - integer representing number of values to read from source |
|
* @api public |
|
* |
|
* _([1, 2, 3, 4]).take(2) // => 1, 2 |
|
*/ |
|
|
|
Stream.prototype.take = function (n) { |
|
if (n === 0) { |
|
return _([]); |
|
} |
|
var s = this.consume(function (err, x, push, next) { |
|
//console.log(['take', err, x, n]); |
|
if (err) { |
|
push(err); |
|
if (n > 0) { |
|
next(); |
|
} |
|
else { |
|
push(null, nil); |
|
} |
|
} |
|
else if (x === nil) { |
|
push(null, nil); |
|
} |
|
else { |
|
n--; |
|
push(null, x); |
|
if (n > 0) { |
|
next(); |
|
} |
|
else { |
|
push(null, nil); |
|
} |
|
} |
|
}); |
|
s.id = 'take:' + s.id; |
|
return s; |
|
}; |
|
exposeMethod('take'); |
|
|
|
/** |
|
* Creates a new Stream with only the first value from the source. |
|
* |
|
* @id head |
|
* @section Transforms |
|
* @name Stream.head() |
|
* @api public |
|
* |
|
* _([1, 2, 3, 4]).head() // => 1 |
|
*/ |
|
|
|
Stream.prototype.head = function () { |
|
return this.take(1); |
|
}; |
|
exposeMethod('head'); |
|
|
|
/** |
|
* Drops all values from the Stream apart from the last one (if any). |
|
* |
|
* @id last |
|
* @section Transforms |
|
* @name Stream.last() |
|
* @api public |
|
* |
|
* _([1, 2, 3, 4]).last() // => 4 |
|
*/ |
|
|
|
Stream.prototype.last = function () { |
|
var nothing = {}; |
|
var prev = nothing; |
|
return this.consume(function (err, x, push, next) { |
|
if (err) { |
|
push(err); |
|
next(); |
|
} |
|
else if (x === nil) { |
|
if (prev !== nothing) { |
|
push(null, prev); |
|
} |
|
push(null, nil); |
|
} |
|
else { |
|
prev = x; |
|
next(); |
|
} |
|
}); |
|
}; |
|
exposeMethod('last'); |
|
|
|
/** |
|
* Passes the current Stream to a function, returning the result. Can also |
|
* be used to pipe the current Stream through another Stream. It will always |
|
* return a Highland Stream (instead of the piped to target directly as in |
|
* Node.js). |
|
* |
|
* @id through |
|
* @section Higher-order Streams |
|
* @name Stream.through(target) |
|
* @api public |
|
* |
|
* function oddDoubler(s) { |
|
* return s.filter(function (x) { |
|
* return x % 2; // odd numbers only |
|
* }) |
|
* .map(function (x) { |
|
* return x * 2; |
|
* }); |
|
* } |
|
* |
|
* _([1, 2, 3, 4]).through(oddDoubler).toArray(function (xs) { |
|
* // xs will be [2, 6] |
|
* }); |
|
* |
|
* // Can also be used with Node Through Streams |
|
* _(filenames).through(jsonParser).map(function (obj) { |
|
* // ... |
|
* }); |
|
*/ |
|
|
|
Stream.prototype.through = function (target) { |
|
if (_.isFunction(target)) { |
|
return target(this); |
|
} |
|
else { |
|
var output = _(); |
|
target.pause(); |
|
this.pipe(target).pipe(output); |
|
return output; |
|
} |
|
}; |
|
exposeMethod('through'); |
|
|
|
/** |
|
* Creates a 'Through Stream', which passes data through a pipeline |
|
* of functions or other through Streams. This is particularly useful |
|
* when combined with partial application of Highland functions to expose a |
|
* Node-compatible Through Stream. |
|
* |
|
* This is not a method on a Stream, and it only exposed at the top-level |
|
* as `_.pipeline`. It takes an arbitrary number of arguments. |
|
* |
|
* @id pipeline |
|
* @section Higher-order Streams |
|
* @name _.pipeline(...) |
|
* @api public |
|
* |
|
* var through = _.pipeline( |
|
* _.map(parseJSON), |
|
* _.filter(isBlogpost), |
|
* _.reduce(collectCategories) |
|
* _.through(otherPipeline) |
|
* ); |
|
* |
|
* readStream.pipe(through).pipe(outStream); |
|
* |
|
* // Alternatively, you can use pipeline to manipulate a stream in |
|
* // the chained method call style: |
|
* |
|
* var through2 = _.pipeline(function (s) { |
|
* return s.map(parseJSON).filter(isBlogpost); // etc. |
|
* }); |
|
*/ |
|
|
|
_.pipeline = function (/*through...*/) { |
|
if (!arguments.length) { |
|
return _(); |
|
} |
|
var start = arguments[0], rest; |
|
if (!_.isStream(start) && !_.isFunction(start.resume)) { |
|
// not a Highland stream or Node stream, start with empty stream |
|
start = _(); |
|
rest = slice.call(arguments); |
|
} |
|
else { |
|
// got a stream as first argument, co-erce to Highland stream |
|
start = _(start); |
|
rest = slice.call(arguments, 1); |
|
} |
|
var end = rest.reduce(function (src, dest) { |
|
return src.through(dest); |
|
}, start); |
|
var wrapper = _(function (push, next) { |
|
end.pull(function (err, x) { |
|
if (err) { |
|
wrapper._send(err); |
|
next(); |
|
} |
|
else if (x === nil) { |
|
wrapper._send(null, nil); |
|
} |
|
else { |
|
wrapper._send(null, x); |
|
next(); |
|
} |
|
}); |
|
}); |
|
wrapper.write = function (x) { |
|
start.write(x); |
|
}; |
|
return wrapper; |
|
}; |
|
|
|
/** |
|
* Reads values from a Stream of Streams, emitting them on a Single output |
|
* Stream. This can be thought of as a flatten, just one level deep. Often |
|
* used for resolving asynchronous actions such as a HTTP request or reading |
|
* a file. |
|
* |
|
* @id sequence |
|
* @section Higher-order Streams |
|
* @name Stream.sequence() |
|
* @api public |
|
* |
|
* var nums = _([ |
|
* _([1, 2, 3]), |
|
* _([4, 5, 6]) |
|
* ]); |
|
* |
|
* nums.sequence() // => 1, 2, 3, 4, 5, 6 |
|
* |
|
* // using sequence to read from files in series |
|
* filenames.map(readFile).sequence() |
|
*/ |
|
|
|
Stream.prototype.sequence = function () { |
|
var original = this; |
|
var curr = this; |
|
return _(function (push, next) { |
|
curr.pull(function (err, x) { |
|
if (err) { |
|
push(err); |
|
return next(); |
|
} |
|
else if (_.isArray(x)) { |
|
if (onOriginalStream()) { |
|
// just send all values from array directly |
|
x.forEach(function (y) { |
|
push(null, y); |
|
}); |
|
} else { |
|
push(null, x); |
|
} |
|
return next(); |
|
} |
|
else if (_.isStream(x)) { |
|
if (onOriginalStream()) { |
|
// switch to reading new stream |
|
curr = x; |
|
return next(); |
|
} |
|
else { |
|
// sequence only goes 1 level deep |
|
push(null, x); |
|
return next(); |
|
} |
|
} |
|
else if (x === nil) { |
|
if (onOriginalStream()) { |
|
push(null, nil); |
|
} |
|
else { |
|
// resume reading from original |
|
curr = original; |
|
return next(); |
|
} |
|
} |
|
else { |
|
if (onOriginalStream()) { |
|
// we shouldn't be getting non-stream (or array) |
|
// values from the top-level stream |
|
push(new Error( |
|
'Expected Stream, got ' + (typeof x) |
|
)); |
|
return next(); |
|
} |
|
else { |
|
push(null, x); |
|
return next(); |
|
} |
|
} |
|
}); |
|
}); |
|
|
|
function onOriginalStream() { |
|
return curr === original; |
|
} |
|
}; |
|
exposeMethod('sequence'); |
|
|
|
/** |
|
* An alias for the [sequence](#sequence) method. |
|
* |
|
* @id series |
|
* @section Higher-order Streams |
|
* @name Stream.series() |
|
* @api public |
|
* |
|
* filenames.map(readFile).series() |
|
*/ |
|
|
|
Stream.prototype.series = Stream.prototype.sequence; |
|
_.series = _.sequence; |
|
|
|
/** |
|
* Recursively reads values from a Stream which may contain nested Streams |
|
* or Arrays. As values or errors are encountered, they are emitted on a |
|
* single output Stream. |
|
* |
|
* @id flatten |
|
* @section Higher-order Streams |
|
* @name Stream.flatten() |
|
* @api public |
|
* |
|
* _([1, [2, 3], [[4]]]).flatten(); // => 1, 2, 3, 4 |
|
* |
|
* var nums = _( |
|
* _([1, 2, 3]), |
|
* _([4, _([5, 6]) ]) |
|
* ); |
|
* |
|
* nums.flatten(); // => 1, 2, 3, 4, 5, 6 |
|
*/ |
|
|
|
Stream.prototype.flatten = function () { |
|
var curr = this; |
|
var stack = []; |
|
return _(function (push, next) { |
|
curr.pull(function (err, x) { |
|
if (err) { |
|
push(err); |
|
return next(); |
|
} |
|
if (_.isArray(x)) { |
|
x = _(x); |
|
} |
|
if (_.isStream(x)) { |
|
stack.push(curr); |
|
curr = x; |
|
next(); |
|
} |
|
else if (x === nil) { |
|
if (stack.length) { |
|
curr = stack.pop(); |
|
next(); |
|
} |
|
else { |
|
push(null, nil); |
|
} |
|
} |
|
else { |
|
push(null, x); |
|
next(); |
|
} |
|
}); |
|
}); |
|
}; |
|
exposeMethod('flatten'); |
|
|
|
/** |
|
* Takes a Stream of Streams and reads from them in parallel, buffering |
|
* the results until they can be returned to the consumer in their original |
|
* order. |
|
* |
|
* @id parallel |
|
* @section Higher-order Streams |
|
* @name Stream.parallel(n) |
|
* @param {Number} n - the maximum number of concurrent reads/buffers |
|
* @api public |
|
* |
|
* var readFile = _.wrapCallback(fs.readFile); |
|
* var filenames = _(['foo.txt', 'bar.txt', 'baz.txt']); |
|
* |
|
* // read from up to 10 files at once |
|
* filenames.map(readFile).parallel(10); |
|
*/ |
|
|
|
Stream.prototype.parallel = function (n) { |
|
var source = this; |
|
var running = []; |
|
var ended = false; |
|
var reading_source = false; |
|
|
|
return _(function (push, next) { |
|
if (running.length && running[0].buffer.length) { |
|
// send buffered data |
|
var buf = running[0].buffer; |
|
for (var i = 0; i < buf.length; i++) { |
|
if (buf[i][1] === nil) { |
|
// this stream has ended |
|
running.shift(); |
|
return next(); |
|
} |
|
else { |
|
// send the buffered output |
|
push.apply(null, buf[i]); |
|
} |
|
} |
|
// still waiting for more data before we can shift |
|
// the running array... |
|
} |
|
else if (running.length < n && !ended && !reading_source) { |
|
// get another stream if not already waiting for one |
|
reading_source = true; |
|
source.pull(function (err, x) { |
|
reading_source = false; |
|
if (err) { |
|
push(err); |
|
} |
|
else if (x === nil) { |
|
ended = true; |
|
} |
|
else { |
|
// got a new source, add it to the running array |
|
var run = {stream: x, buffer: []}; |
|
running.push(run); |
|
x.consume(function (err, y, _push, _next) { |
|
if (running[0] === run) { |
|
// current output stream |
|
if (y === nil) { |
|
// remove self from running and check |
|
// to see if we need to read from source again |
|
running.shift(); |
|
next(); |
|
} |
|
else { |
|
// push directly onto parallel output stream |
|
push(err, y); |
|
} |
|
} |
|
else { |
|
// we're reading ahead, buffer the output |
|
run.buffer.push([err, y]); |
|
} |
|
if (y !== nil) { |
|
// keep reading until we hit nil |
|
_next(); |
|
} |
|
}).resume(); |
|
} |
|
// check if we need to get any more streams |
|
return next(); |
|
}); |
|
} |
|
else if (!running.length && ended) { |
|
// nothing more to do |
|
push(null, nil); |
|
} |
|
else { |
|
// wait for more data to arrive from running streams |
|
} |
|
}); |
|
}; |
|
exposeMethod('parallel'); |
|
|
|
/** |
|
* Switches source to an alternate Stream if the current Stream is empty. |
|
* |
|
* @id otherwise |
|
* @section Higher-order Streams |
|
* @name Stream.otherwise(ys) |
|
* @param {Stream} ys - alternate stream to use if this stream is empty |
|
* @api public |
|
* |
|
* _([1,2,3]).otherwise(['foo']) // => 1, 2, 3 |
|
* _([]).otherwise(['foo']) // => 'foo' |
|
* |
|
* _.otherwise(_(['foo']), _([1,2,3])) // => 1, 2, 3 |
|
* _.otherwise(_(['foo']), _([])) // => 'foo' |
|
*/ |
|
|
|
Stream.prototype.otherwise = function (ys) { |
|
var xs = this; |
|
return xs.consume(function (err, x, push, next) { |
|
if (err) { |
|
// got an error, just keep going |
|
push(err); |
|
next(); |
|
} else if (x === nil) { |
|
// hit the end without redirecting to xs, use alternative |
|
next(ys); |
|
} |
|
else { |
|
// got a value, push it, then redirect to xs |
|
push(null, x); |
|
next(xs); |
|
} |
|
}); |
|
}; |
|
exposeMethod('otherwise'); |
|
|
|
/** |
|
* Adds a value to the end of a Stream. |
|
* |
|
* @id append |
|
* @section Transforms |
|
* @name Stream.append(y) |
|
* @param y - the value to append to the Stream |
|
* @api public |
|
* |
|
* _([1, 2, 3]).append(4) // => 1, 2, 3, 4 |
|
*/ |
|
|
|
Stream.prototype.append = function (y) { |
|
return this.consume(function (err, x, push, next) { |
|
if (x === nil) { |
|
push(null, y); |
|
push(null, _.nil); |
|
} |
|
else { |
|
push(err, x); |
|
next(); |
|
} |
|
}); |
|
}; |
|
exposeMethod('append'); |
|
|
|
/** |
|
* Boils down a Stream to a single value. The memo is the initial state |
|
* of the reduction, and each successive step of it should be returned by |
|
* the iterator function. The iterator is passed two arguments: |
|
* the memo and the next value. |
|
* |
|
* If the iterator throws an error, the reduction stops and the resulting |
|
* stream will emit that error instead of a value. |
|
* |
|
* @id reduce |
|
* @section Transforms |
|
* @name Stream.reduce(memo, iterator) |
|
* @param memo - the initial state of the reduction |
|
* @param {Function} iterator - the function which reduces the values |
|
* @api public |
|
* |
|
* var add = function (a, b) { |
|
* return a + b; |
|
* }; |
|
* |
|
* _([1, 2, 3, 4]).reduce(0, add) // => 10 |
|
*/ |
|
|
|
Stream.prototype.reduce = function (z, f) { |
|
// This can't be implemented with scan(), because we don't know if the |
|
// errors that we see from the scan were thrown by the iterator or just |
|
// passed through from the source stream. |
|
return this.consume(function (err, x, push, next) { |
|
if (x === nil) { |
|
push(null, z); |
|
push(null, _.nil); |
|
} |
|
else if (err) { |
|
push(err); |
|
next(); |
|
} |
|
else { |
|
try { |
|
z = f(z, x); |
|
} catch (e) { |
|
push(e); |
|
push(null, _.nil); |
|
return; |
|
} |
|
|
|
next(); |
|
} |
|
}); |
|
}; |
|
exposeMethod('reduce'); |
|
|
|
/** |
|
* Same as [reduce](#reduce), but uses the first element as the initial |
|
* state instead of passing in a `memo` value. |
|
* |
|
* @id reduce1 |
|
* @section Transforms |
|
* @name Stream.reduce1(iterator) |
|
* @param {Function} iterator - the function which reduces the values |
|
* @api public |
|
* |
|
* _([1, 2, 3, 4]).reduce1(add) // => 10 |
|
*/ |
|
|
|
Stream.prototype.reduce1 = function (f) { |
|
var self = this; |
|
return _(function (push, next) { |
|
self.pull(function (err, x) { |
|
if (err) { |
|
push(err); |
|
next(); |
|
} else if (x === nil) { |
|
push(null, nil); |
|
} |
|
else { |
|
next(self.reduce(x, f)); |
|
} |
|
}); |
|
}); |
|
}; |
|
exposeMethod('reduce1'); |
|
|
|
/** |
|
* Groups all values into an Array and passes down the stream as a single |
|
* data event. This is a bit like doing [toArray](#toArray), but instead |
|
* of accepting a callback and causing a *thunk*, it passes the value on. |
|
* |
|
* @id collect |
|
* @section Transforms |
|
* @name Stream.collect() |
|
* @api public |
|
* |
|
* _(['foo', 'bar']).collect().toArray(function (xs) { |
|
* // xs will be [['foo', 'bar']] |
|
* }); |
|
*/ |
|
|
|
Stream.prototype.collect = function () { |
|
var xs = []; |
|
return this.consume(function (err, x, push, next) { |
|
if (err) { |
|
push(err); |
|
next(); |
|
} |
|
else if (x === nil) { |
|
push(null, xs); |
|
push(null, nil); |
|
} |
|
else { |
|
xs.push(x); |
|
next(); |
|
} |
|
}); |
|
}; |
|
exposeMethod('collect'); |
|
|
|
/** |
|
* Like [reduce](#reduce), but emits each intermediate value of the |
|
* reduction as it is calculated. |
|
* |
|
* If the iterator throws an error, the scan will stop and the stream will |
|
* emit that error. Any intermediate values that were produced before the |
|
* error will still be emitted. |
|
* |
|
* @id scan |
|
* @section Transforms |
|
* @name Stream.scan(memo, iterator) |
|
* @param memo - the initial state of the reduction |
|
* @param {Function} iterator - the function which reduces the values |
|
* @api public |
|
* |
|
* _([1, 2, 3, 4]).scan(0, add) // => 0, 1, 3, 6, 10 |
|
*/ |
|
|
|
Stream.prototype.scan = function (z, f) { |
|
var self = this; |
|
return _([z]).concat( |
|
self.consume(function (err, x, push, next) { |
|
if (x === nil) { |
|
push(null, _.nil); |
|
} |
|
else if (err) { |
|
push(err); |
|
next(); |
|
} |
|
else { |
|
try { |
|
z = f(z, x); |
|
} catch (e) { |
|
push(e); |
|
push(null, _.nil); |
|
return; |
|
} |
|
|
|
push(null, z); |
|
next(); |
|
} |
|
}) |
|
); |
|
}; |
|
exposeMethod('scan'); |
|
|
|
/** |
|
* Same as [scan](#scan), but uses the first element as the initial |
|
* state instead of passing in a `memo` value. |
|
* |
|
* @id scan1 |
|
* @section Transforms |
|
* @name Stream.scan1(iterator) |
|
* @param {Function} iterator - the function which reduces the values |
|
* @api public |
|
* |
|
* _([1, 2, 3, 4]).scan1(add) // => 1, 3, 6, 10 |
|
*/ |
|
|
|
Stream.prototype.scan1 = function (f) { |
|
var self = this; |
|
return _(function (push, next) { |
|
self.pull(function (err, x) { |
|
if (err) { |
|
push(err); |
|
next(); |
|
} else if (x === nil) { |
|
push(null, nil); |
|
} |
|
else { |
|
next(self.scan(x, f)); |
|
} |
|
}); |
|
}); |
|
}; |
|
exposeMethod('scan1'); |
|
|
|
/** |
|
* Concatenates a Stream to the end of this Stream. |
|
* |
|
* Be aware that in the top-level export, the args may be in the reverse |
|
* order to what you'd expect `_([a], [b]) => b, a`, as this follows the |
|
* convention of other top-level exported functions which do `x` to `y`. |
|
* |
|
* @id concat |
|
* @section Higher-order Streams |
|
* @name Stream.concat(ys) |
|
* @params {Stream | Array} ys - the values to concatenate onto this Stream |
|
* @api public |
|
* |
|
* _([1, 2]).concat([3, 4]) // => 1, 2, 3, 4 |
|
* _.concat([3, 4], [1, 2]) // => 1, 2, 3, 4 |
|
*/ |
|
|
|
Stream.prototype.concat = function (ys) { |
|
ys = _(ys); |
|
return this.consume(function (err, x, push, next) { |
|
if (x === nil) { |
|
next(ys); |
|
} |
|
else { |
|
push(err, x); |
|
next(); |
|
} |
|
}); |
|
}; |
|
exposeMethod('concat'); |
|
|
|
/** |
|
* Takes a Stream of Streams and merges their values and errors into a |
|
* single new Stream. The merged stream ends when all source streams have |
|
* ended. |
|
* |
|
* Note that no guarantee is made with respect to the order in which |
|
* values for each stream end up in the merged stream. Values in the |
|
* merged stream will, however, respect the order they were emitted from |
|
* their respective streams. |
|
* |
|
* @id merge |
|
* @section Higher-order Streams |
|
* @name Stream.merge() |
|
* @api public |
|
* |
|
* var txt = _(['foo.txt', 'bar.txt']).map(readFile) |
|
* var md = _(['baz.md']).map(readFile) |
|
* |
|
* _([txt, md]).merge(); |
|
* // => contents of foo.txt, bar.txt and baz.txt in the order they were read |
|
*/ |
|
|
|
Stream.prototype.merge = function () { |
|
var self = this; |
|
var resuming = false; |
|
var go_next = false; |
|
var srcs; |
|
return _(function (push, next) { |
|
var safeNext = function () { |
|
if (!resuming) { |
|
next(); |
|
} |
|
else { |
|
go_next = true; |
|
} |
|
}; |
|
if (!srcs) { |
|
self.errors(push).toArray(function (xs) { |
|
srcs = xs; |
|
srcs.forEach(function (src) { |
|
src.on('end', function () { |
|
srcs = srcs.filter(function (s) { |
|
return s !== src; |
|
}); |
|
safeNext(); |
|
}); |
|
src.on('data', function (x) { |
|
src.pause(); |
|
push(null, x); |
|
safeNext(); |
|
}); |
|
src.on('error', function (err) { |
|
push(err); |
|
safeNext(); |
|
}); |
|
}); |
|
next(); |
|
}); |
|
} |
|
else if (srcs.length === 0) { |
|
push(null, nil); |
|
} |
|
else { |
|
go_next = false; |
|
resuming = true; |
|
srcs.forEach(function (src) { |
|
src.resume(); |
|
}); |
|
resuming = false; |
|
if (go_next) { |
|
next(); |
|
} |
|
} |
|
}); |
|
}; |
|
exposeMethod('merge'); |
|
|
|
/** |
|
* Calls a named method on each object from the Stream - returning |
|
* a new stream with the result of those calls. |
|
* |
|
* @id invoke |
|
* @section Transforms |
|
* @name Stream.invoke(method, args) |
|
* @param {String} method - the method name to call |
|
* @param {Array} args - the arguments to call the method with |
|
* @api public |
|
* |
|
* _(['foo', 'bar']).invoke('toUpperCase', []) // => FOO, BAR |
|
* |
|
* filenames.map(readFile).sequence().invoke('toString', ['utf8']); |
|
*/ |
|
|
|
Stream.prototype.invoke = function (method, args) { |
|
return this.map(function (x) { |
|
return x[method].apply(x, args); |
|
}); |
|
}; |
|
exposeMethod('invoke'); |
|
|
|
/** |
|
* Ensures that only one data event is push downstream (or into the buffer) |
|
* every `ms` milliseconds, any other values are dropped. |
|
* |
|
* @id throttle |
|
* @section Transforms |
|
* @name Stream.throttle(ms) |
|
* @param {Number} ms - the minimum milliseconds between each value |
|
* @api public |
|
* |
|
* _('mousemove', document).throttle(1000); |
|
*/ |
|
|
|
Stream.prototype.throttle = function (ms) { |
|
var s = new Stream(); |
|
var last = 0 - ms; |
|
var _write = s.write; |
|
s.write = function (x) { |
|
var now = new Date().getTime(); |
|
if (_._isStreamError(x) || x === nil) { |
|
return _write.apply(this, arguments); |
|
} |
|
else if (now - ms >= last) { |
|
last = now; |
|
return _write.apply(this, arguments); |
|
} |
|
}; |
|
this._addConsumer(s); |
|
return s; |
|
}; |
|
exposeMethod('throttle'); |
|
|
|
/** |
|
* Holds off pushing data events downstream until there has been no more |
|
* data for `ms` milliseconds. Sends the last value that occurred before |
|
* the delay, discarding all other values. |
|
* |
|
* @id debounce |
|
* @section Transforms |
|
* @name Stream.debounce(ms) |
|
* @param {Number} ms - the milliseconds to wait before sending data |
|
* @api public |
|
* |
|
* // sends last keyup event after user has stopped typing for 1 second |
|
* $('keyup', textbox).debounce(1000); |
|
*/ |
|
|
|
Stream.prototype.debounce = function (ms) { |
|
var s = new Stream(); |
|
var t = null; |
|
var nothing = {}; |
|
var last = nothing; |
|
var _write = s.write; |
|
s.write = function (x) { |
|
if (_._isStreamError(x)) { |
|
// let errors through regardless |
|
return _write.apply(this, arguments); |
|
} |
|
else if (x === nil) { |
|
if (t) { |
|
clearTimeout(t); |
|
} |
|
if (last !== nothing) { |
|
_write.call(s, last); |
|
} |
|
return _write.apply(this, arguments); |
|
} |
|
else { |
|
last = x; |
|
if (t) { |
|
clearTimeout(t); |
|
} |
|
t = setTimeout(function () { |
|
_write.call(s, last); |
|
}, ms); |
|
return !this.paused; |
|
} |
|
}; |
|
this._addConsumer(s); |
|
return s; |
|
}; |
|
exposeMethod('debounce'); |
|
|
|
/** |
|
* Creates a new Stream, which when read from, only returns the last |
|
* seen value from the source. The source stream does not experience |
|
* back-pressure. Useful if you're using a Stream to model a changing |
|
* property which you need to query periodically. |
|
* |
|
* @id latest |
|
* @section Transforms |
|
* @name Stream.latest() |
|
* @api public |
|
* |
|
* // slowThing will always get the last known mouse position |
|
* // when it asks for more data from the mousePosition stream |
|
* mousePosition.latest().map(slowThing) |
|
*/ |
|
|
|
Stream.prototype.latest = function () { |
|
var s = new Stream(); |
|
var _write = s.write; |
|
s.pause = function () { |
|
this.paused = true; |
|
// do not force parent to checkBackpressure |
|
}; |
|
s.write = function (x) { |
|
if (_._isStreamError(x)) { |
|
// pass errors straight through |
|
_write.call(this, x); |
|
} |
|
else if (x === nil) { |
|
_write.call(this, x); |
|
} |
|
else { |
|
if (this.paused) { |
|
this._incoming = this._incoming.filter(function (x) { |
|
// remove any existing values from buffer |
|
return _._isStreamError(x) || x === nil; |
|
}); |
|
this._incoming.push(x); |
|
} |
|
else { |
|
_write.call(this, x); |
|
} |
|
} |
|
// never push back |
|
return true; |
|
}; |
|
this._addConsumer(s); |
|
s.resume(); |
|
return s; |
|
}; |
|
exposeMethod('latest'); |
|
|
|
/** |
|
* Returns values from an Object as a Stream. Reads properties |
|
* lazily, so if you don't read from all keys on an object, not |
|
* all properties will be read from (may have an effect where getters |
|
* are used). |
|
* |
|
* @id values |
|
* @section Objects |
|
* @name _.values(obj) |
|
* @param {Object} obj - the object to return values from |
|
* @api public |
|
* |
|
* _.values({foo: 1, bar: 2, baz: 3}) // => 1, 2, 3 |
|
*/ |
|
|
|
_.values = function (obj) { |
|
return _.keys(obj).map(function (k) { |
|
return obj[k]; |
|
}); |
|
}; |
|
|
|
/** |
|
* Returns keys from an Object as a Stream. |
|
* |
|
* @id keys |
|
* @section Objects |
|
* @name _.keys(obj) |
|
* @param {Object} obj - the object to return keys from |
|
* @api public |
|
* |
|
* _.keys({foo: 1, bar: 2, baz: 3}) // => 'foo', 'bar', 'baz' |
|
*/ |
|
|
|
_.keys = function (obj) { |
|
var keys = []; |
|
for (var k in obj) { |
|
if (obj.hasOwnProperty(k)) { |
|
keys.push(k); |
|
} |
|
} |
|
return _(keys); |
|
}; |
|
|
|
/** |
|
* Returns key/value pairs for an Object as a Stream. Reads properties |
|
* lazily, so if you don't read from all keys on an object, not |
|
* all properties will be read from (may have an effect where getters |
|
* are used). |
|
* |
|
* @id pairs |
|
* @section Objects |
|
* @name _.pairs(obj) |
|
* @param {Object} obj - the object to return key/value pairs from |
|
* @api public |
|
* |
|
* _.pairs({foo: 1, bar: 2}) // => ['foo', 1], ['bar', 2] |
|
*/ |
|
|
|
_.pairs = function (obj) { |
|
return _.keys(obj).map(function (k) { |
|
return [k, obj[k]]; |
|
}); |
|
}; |
|
|
|
/** |
|
* Extends one object with the properties of another. **Note:** The |
|
* arguments are in the reverse order of other libraries such as |
|
* underscore. This is so it follows the convention of other functions in |
|
* this library and so you can more meaningfully partially apply it. |
|
* |
|
* @id extend |
|
* @section Objects |
|
* @name _.extend(a, b) |
|
* @param {Object} a - the properties to extend b with |
|
* @param {Object} b - the original object to extend |
|
* @api public |
|
* |
|
* _.extend({name: 'bar'}, {name: 'foo', price: 20}) |
|
* // => {name: 'bar', price: 20} |
|
* |
|
* // example of partial application |
|
* var publish = _.extend({published: true}); |
|
* |
|
* publish({title: 'test post'}) |
|
* // => {title: 'test post', published: true} |
|
*/ |
|
|
|
_.extend = _.curry(function (extensions, target) { |
|
for (var k in extensions) { |
|
if (extensions.hasOwnProperty(k)) { |
|
target[k] = extensions[k]; |
|
} |
|
} |
|
return target; |
|
}); |
|
|
|
/** |
|
* Returns a property from an object. |
|
* |
|
* @id get |
|
* @section Objects |
|
* @name _.get(prop, obj) |
|
* @param {String} prop - the property to return |
|
* @param {Object} obj - the object to read properties from |
|
* @api public |
|
* |
|
* var obj = {foo: 'bar', baz: 123}; |
|
* _.get('foo', obj) // => 'bar' |
|
* |
|
* // making use of partial application |
|
* var posts = [ |
|
* {title: 'one'}, |
|
* {title: 'two'}, |
|
* {title: 'three'} |
|
* ]; |
|
* |
|
* _(posts).map(_.get('title')) // => 'one', 'two', 'three' |
|
*/ |
|
|
|
_.get = _.curry(function (prop, obj) { |
|
return obj[prop]; |
|
}); |
|
|
|
/** |
|
* Updates a property on an object, returning the updated object. |
|
* |
|
* @id set |
|
* @section Objects |
|
* @name _.set(prop, value, obj) |
|
* @param {String} prop - the property to return |
|
* @param value - the value to set the property to |
|
* @param {Object} obj - the object to set properties on |
|
* @api public |
|
* |
|
* var obj = {foo: 'bar', baz: 123}; |
|
* _.set('foo', 'wheeee', obj) // => {foo: 'wheeee', baz: 123} |
|
* |
|
* // making use of partial application |
|
* var publish = _.set('published', true); |
|
* |
|
* publish({title: 'example'}) // => {title: 'example', published: true} |
|
*/ |
|
|
|
_.set = _.curry(function (prop, val, obj) { |
|
obj[prop] = val; |
|
return obj; |
|
}); |
|
|
|
/** |
|
* Logs values to the console, a simple wrapper around `console.log` that |
|
* it suitable for passing to other functions by reference without having to |
|
* call `bind`. |
|
* |
|
* @id log |
|
* @section Utils |
|
* @name _.log(args..) |
|
* @api public |
|
* |
|
* _.log('Hello, world!'); |
|
* |
|
* _([1, 2, 3, 4]).each(_.log); |
|
*/ |
|
|
|
_.log = function () { |
|
console.log.apply(console, arguments); |
|
}; |
|
|
|
/** |
|
* Wraps a node-style async function which accepts a callback, transforming |
|
* it to a function which accepts the same arguments minus the callback and |
|
* returns a Highland Stream instead. Only the first argument to the |
|
* callback (or an error) will be pushed onto the Stream. |
|
* |
|
* @id wrapCallback |
|
* @section Utils |
|
* @name _.wrapCallback(f) |
|
* @param {Function} f - the node-style function to wrap |
|
* @api public |
|
* |
|
* var fs = require('fs'); |
|
* |
|
* var readFile = _.wrapCallback(fs.readFile); |
|
* |
|
* readFile('example.txt').apply(function (data) { |
|
* // data is now the contents of example.txt |
|
* }); |
|
*/ |
|
|
|
_.wrapCallback = function (f) { |
|
return function () { |
|
var args = slice.call(arguments); |
|
return _(function (push) { |
|
var cb = function (err, x) { |
|
if (err) { |
|
push(err); |
|
} |
|
else { |
|
push(null, x); |
|
} |
|
push(null, nil); |
|
}; |
|
f.apply(null, args.concat([cb])); |
|
}); |
|
}; |
|
}; |
|
|
|
/** |
|
* Add two values. Can be partially applied. |
|
* |
|
* @id add |
|
* @section Operators |
|
* @name _.add(a, b) |
|
* @api public |
|
* |
|
* add(1, 2) === 3 |
|
* add(1)(5) === 6 |
|
*/ |
|
|
|
_.add = _.curry(function (a, b) { |
|
return a + b; |
|
}); |
|
|
|
/** |
|
* Perform logical negation on a value. If `x` is truthy then returns false, |
|
* otherwise returns true. |
|
* |
|
* @id not |
|
* @section Operators |
|
* @name _.not(x) |
|
* @param x - the value to negate |
|
* @api public |
|
* |
|
* _.not(true) // => false |
|
* _.not(false) // => true |
|
*/ |
|
|
|
_.not = function (x) { |
|
return !x; |
|
}; |
|
|
|
}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) |
|
},{"_process":16,"events":12,"string_decoder":30,"util":32}],8:[function(require,module,exports){ |
|
|
|
},{}],9:[function(require,module,exports){ |
|
/*! |
|
* The buffer module from node.js, for the browser. |
|
* |
|
* @author Feross Aboukhadijeh <feross@feross.org> <http://feross.org> |
|
* @license MIT |
|
*/ |
|
|
|
var base64 = require('base64-js') |
|
var ieee754 = require('ieee754') |
|
|
|
exports.Buffer = Buffer |
|
exports.SlowBuffer = Buffer |
|
exports.INSPECT_MAX_BYTES = 50 |
|
Buffer.poolSize = 8192 |
|
|
|
/** |
|
* If `TYPED_ARRAY_SUPPORT`: |
|
* === true Use Uint8Array implementation (fastest) |
|
* === false Use Object implementation (most compatible, even IE6) |
|
* |
|
* Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+, |
|
* Opera 11.6+, iOS 4.2+. |
|
* |
|
* Note: |
|
* |
|
* - Implementation must support adding new properties to `Uint8Array` instances. |
|
* Firefox 4-29 lacked support, fixed in Firefox 30+. |
|
* See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438. |
|
* |
|
* - Chrome 9-10 is missing the `TypedArray.prototype.subarray` function. |
|
* |
|
* - IE10 has a broken `TypedArray.prototype.subarray` function which returns arrays of |
|
* incorrect length in some situations. |
|
* |
|
* We detect these buggy browsers and set `TYPED_ARRAY_SUPPORT` to `false` so they will |
|
* get the Object implementation, which is slower but will work correctly. |
|
*/ |
|
var TYPED_ARRAY_SUPPORT = (function () { |
|
try { |
|
var buf = new ArrayBuffer(0) |
|
var arr = new Uint8Array(buf) |
|
arr.foo = function () { return 42 } |
|
return 42 === arr.foo() && // typed array instances can be augmented |
|
typeof arr.subarray === 'function' && // chrome 9-10 lack `subarray` |
|
new Uint8Array(1).subarray(1, 1).byteLength === 0 // ie10 has broken `subarray` |
|
} catch (e) { |
|
return false |
|
} |
|
})() |
|
|
|
/** |
|
* Class: Buffer |
|
* ============= |
|
* |
|
* The Buffer constructor returns instances of `Uint8Array` that are augmented |
|
* with function properties for all the node `Buffer` API functions. We use |
|
* `Uint8Array` so that square bracket notation works as expected -- it returns |
|
* a single octet. |
|
* |
|
* By augmenting the instances, we can avoid modifying the `Uint8Array` |
|
* prototype. |
|
*/ |
|
function Buffer (subject, encoding, noZero) { |
|
if (!(this instanceof Buffer)) |
|
return new Buffer(subject, encoding, noZero) |
|
|
|
var type = typeof subject |
|
|
|
// Find the length |
|
var length |
|
if (type === 'number') |
|
length = subject > 0 ? subject >>> 0 : 0 |
|
else if (type === 'string') { |
|
if (encoding === 'base64') |
|
subject = base64clean(subject) |
|
length = Buffer.byteLength(subject, encoding) |
|
} else if (type === 'object' && subject !== null) { // assume object is array-like |
|
if (subject.type === 'Buffer' && isArray(subject.data)) |
|
subject = subject.data |
|
length = +subject.length > 0 ? Math.floor(+subject.length) : 0 |
|
} else |
|
throw new Error('First argument needs to be a number, array or string.') |
|
|
|
var buf |
|
if (TYPED_ARRAY_SUPPORT) { |
|
// Preferred: Return an augmented `Uint8Array` instance for best performance |
|
buf = Buffer._augment(new Uint8Array(length)) |
|
} else { |
|
// Fallback: Return THIS instance of Buffer (created by `new`) |
|
buf = this |
|
buf.length = length |
|
buf._isBuffer = true |
|
} |
|
|
|
var i |
|
if (TYPED_ARRAY_SUPPORT && typeof subject.byteLength === 'number') { |
|
// Speed optimization -- use set if we're copying from a typed array |
|
buf._set(subject) |
|
} else if (isArrayish(subject)) { |
|
// Treat array-ish objects as a byte array |
|
if (Buffer.isBuffer(subject)) { |
|
for (i = 0; i < length; i++) |
|
buf[i] = subject.readUInt8(i) |
|
} else { |
|
for (i = 0; i < length; i++) |
|
buf[i] = ((subject[i] % 256) + 256) % 256 |
|
} |
|
} else if (type === 'string') { |
|
buf.write(subject, 0, encoding) |
|
} else if (type === 'number' && !TYPED_ARRAY_SUPPORT && !noZero) { |
|
for (i = 0; i < length; i++) { |
|
buf[i] = 0 |
|
} |
|
} |
|
|
|
return buf |
|
} |
|
|
|
// STATIC METHODS |
|
// ============== |
|
|
|
Buffer.isEncoding = function (encoding) { |
|
switch (String(encoding).toLowerCase()) { |
|
case 'hex': |
|
case 'utf8': |
|
case 'utf-8': |
|
case 'ascii': |
|
case 'binary': |
|
case 'base64': |
|
case 'raw': |
|
case 'ucs2': |
|
case 'ucs-2': |
|
case 'utf16le': |
|
case 'utf-16le': |
|
return true |
|
default: |
|
return false |
|
} |
|
} |
|
|
|
Buffer.isBuffer = function (b) { |
|
return !!(b != null && b._isBuffer) |
|
} |
|
|
|
Buffer.byteLength = function (str, encoding) { |
|
var ret |
|
str = str.toString() |
|
switch (encoding || 'utf8') { |
|
case 'hex': |
|
ret = str.length / 2 |
|
break |
|
case 'utf8': |
|
case 'utf-8': |
|
ret = utf8ToBytes(str).length |
|
break |
|
case 'ascii': |
|
case 'binary': |
|
case 'raw': |
|
ret = str.length |
|
break |
|
case 'base64': |
|
ret = base64ToBytes(str).length |
|
break |
|
case 'ucs2': |
|
case 'ucs-2': |
|
case 'utf16le': |
|
case 'utf-16le': |
|
ret = str.length * 2 |
|
break |
|
default: |
|
throw new Error('Unknown encoding') |
|
} |
|
return ret |
|
} |
|
|
|
Buffer.concat = function (list, totalLength) { |
|
assert(isArray(list), 'Usage: Buffer.concat(list[, length])') |
|
|
|
if (list.length === 0) { |
|
return new Buffer(0) |
|
} else if (list.length === 1) { |
|
return list[0] |
|
} |
|
|
|
var i |
|
if (totalLength === undefined) { |
|
totalLength = 0 |
|
for (i = 0; i < list.length; i++) { |
|
totalLength += list[i].length |
|
} |
|
} |
|
|
|
var buf = new Buffer(totalLength) |
|
var pos = 0 |
|
for (i = 0; i < list.length; i++) { |
|
var item = list[i] |
|
item.copy(buf, pos) |
|
pos += item.length |
|
} |
|
return buf |
|
} |
|
|
|
Buffer.compare = function (a, b) { |
|
assert(Buffer.isBuffer(a) && Buffer.isBuffer(b), 'Arguments must be Buffers') |
|
var x = a.length |
|
var y = b.length |
|
for (var i = 0, len = Math.min(x, y); i < len && a[i] === b[i]; i++) {} |
|
if (i !== len) { |
|
x = a[i] |
|
y = b[i] |
|
} |
|
if (x < y) { |
|
return -1 |
|
} |
|
if (y < x) { |
|
return 1 |
|
} |
|
return 0 |
|
} |
|
|
|
// BUFFER INSTANCE METHODS |
|
// ======================= |
|
|
|
function hexWrite (buf, string, offset, length) { |
|
offset = Number(offset) || 0 |
|
var remaining = buf.length - offset |
|
if (!length) { |
|
length = remaining |
|
} else { |
|
length = Number(length) |
|
if (length > remaining) { |
|
length = remaining |
|
} |
|
} |
|
|
|
// must be an even number of digits |
|
var strLen = string.length |
|
assert(strLen % 2 === 0, 'Invalid hex string') |
|
|
|
if (length > strLen / 2) { |
|
length = strLen / 2 |
|
} |
|
for (var i = 0; i < length; i++) { |
|
var byte = parseInt(string.substr(i * 2, 2), 16) |
|
assert(!isNaN(byte), 'Invalid hex string') |
|
buf[offset + i] = byte |
|
} |
|
return i |
|
} |
|
|
|
function utf8Write (buf, string, offset, length) { |
|
var charsWritten = blitBuffer(utf8ToBytes(string), buf, offset, length) |
|
return charsWritten |
|
} |
|
|
|
function asciiWrite (buf, string, offset, length) { |
|
var charsWritten = blitBuffer(asciiToBytes(string), buf, offset, length) |
|
return charsWritten |
|
} |
|
|
|
function binaryWrite (buf, string, offset, length) { |
|
return asciiWrite(buf, string, offset, length) |
|
} |
|
|
|
function base64Write (buf, string, offset, length) { |
|
var charsWritten = blitBuffer(base64ToBytes(string), buf, offset, length) |
|
return charsWritten |
|
} |
|
|
|
function utf16leWrite (buf, string, offset, length) { |
|
var charsWritten = blitBuffer(utf16leToBytes(string), buf, offset, length) |
|
return charsWritten |
|
} |
|
|
|
Buffer.prototype.write = function (string, offset, length, encoding) { |
|
// Support both (string, offset, length, encoding) |
|
// and the legacy (string, encoding, offset, length) |
|
if (isFinite(offset)) { |
|
if (!isFinite(length)) { |
|
encoding = length |
|
length = undefined |
|
} |
|
} else { // legacy |
|
var swap = encoding |
|
encoding = offset |
|
offset = length |
|
length = swap |
|
} |
|
|
|
offset = Number(offset) || 0 |
|
var remaining = this.length - offset |
|
if (!length) { |
|
length = remaining |
|
} else { |
|
length = Number(length) |
|
if (length > remaining) { |
|
length = remaining |
|
} |
|
} |
|
encoding = String(encoding || 'utf8').toLowerCase() |
|
|
|
var ret |
|
switch (encoding) { |
|
case 'hex': |
|
ret = hexWrite(this, string, offset, length) |
|
break |
|
case 'utf8': |
|
case 'utf-8': |
|
ret = utf8Write(this, string, offset, length) |
|
break |
|
case 'ascii': |
|
ret = asciiWrite(this, string, offset, length) |
|
break |
|
case 'binary': |
|
ret = binaryWrite(this, string, offset, length) |
|
break |
|
case 'base64': |
|
ret = base64Write(this, string, offset, length) |
|
break |
|
case 'ucs2': |
|
case 'ucs-2': |
|
case 'utf16le': |
|
case 'utf-16le': |
|
ret = utf16leWrite(this, string, offset, length) |
|
break |
|
default: |
|
throw new Error('Unknown encoding') |
|
} |
|
return ret |
|
} |
|
|
|
Buffer.prototype.toString = function (encoding, start, end) { |
|
var self = this |
|
|
|
encoding = String(encoding || 'utf8').toLowerCase() |
|
start = Number(start) || 0 |
|
end = (end === undefined) ? self.length : Number(end) |
|
|
|
// Fastpath empty strings |
|
if (end === start) |
|
return '' |
|
|
|
var ret |
|
switch (encoding) { |
|
case 'hex': |
|
ret = hexSlice(self, start, end) |
|
break |
|
case 'utf8': |
|
case 'utf-8': |
|
ret = utf8Slice(self, start, end) |
|
break |
|
case 'ascii': |
|
ret = asciiSlice(self, start, end) |
|
break |
|
case 'binary': |
|
ret = binarySlice(self, start, end) |
|
break |
|
case 'base64': |
|
ret = base64Slice(self, start, end) |
|
break |
|
case 'ucs2': |
|
case 'ucs-2': |
|
case 'utf16le': |
|
case 'utf-16le': |
|
ret = utf16leSlice(self, start, end) |
|
break |
|
default: |
|
throw new Error('Unknown encoding') |
|
} |
|
return ret |
|
} |
|
|
|
Buffer.prototype.toJSON = function () { |
|
return { |
|
type: 'Buffer', |
|
data: Array.prototype.slice.call(this._arr || this, 0) |
|
} |
|
} |
|
|
|
Buffer.prototype.equals = function (b) { |
|
assert(Buffer.isBuffer(b), 'Argument must be a Buffer') |
|
return Buffer.compare(this, b) === 0 |
|
} |
|
|
|
Buffer.prototype.compare = function (b) { |
|
assert(Buffer.isBuffer(b), 'Argument must be a Buffer') |
|
return Buffer.compare(this, b) |
|
} |
|
|
|
// copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length) |
|
Buffer.prototype.copy = function (target, target_start, start, end) { |
|
var source = this |
|
|
|
if (!start) start = 0 |
|
if (!end && end !== 0) end = this.length |
|
if (!target_start) target_start = 0 |
|
|
|
// Copy 0 bytes; we're done |
|
if (end === start) return |
|
if (target.length === 0 || source.length === 0) return |
|
|
|
// Fatal error conditions |
|
assert(end >= start, 'sourceEnd < sourceStart') |
|
assert(target_start >= 0 && target_start < target.length, |
|
'targetStart out of bounds') |
|
assert(start >= 0 && start < source.length, 'sourceStart out of bounds') |
|
assert(end >= 0 && end <= source.length, 'sourceEnd out of bounds') |
|
|
|
// Are we oob? |
|
if (end > this.length) |
|
end = this.length |
|
if (target.length - target_start < end - start) |
|
end = target.length - target_start + start |
|
|
|
var len = end - start |
|
|
|
if (len < 100 || !TYPED_ARRAY_SUPPORT) { |
|
for (var i = 0; i < len; i++) { |
|
target[i + target_start] = this[i + start] |
|
} |
|
} else { |
|
target._set(this.subarray(start, start + len), target_start) |
|
} |
|
} |
|
|
|
function base64Slice (buf, start, end) { |
|
if (start === 0 && end === buf.length) { |
|
return base64.fromByteArray(buf) |
|
} else { |
|
return base64.fromByteArray(buf.slice(start, end)) |
|
} |
|
} |
|
|
|
function utf8Slice (buf, start, end) { |
|
var res = '' |
|
var tmp = '' |
|
end = Math.min(buf.length, end) |
|
|
|
for (var i = start; i < end; i++) { |
|
if (buf[i] <= 0x7F) { |
|
res += decodeUtf8Char(tmp) + String.fromCharCode(buf[i]) |
|
tmp = '' |
|
} else { |
|
tmp += '%' + buf[i].toString(16) |
|
} |
|
} |
|
|
|
return res + decodeUtf8Char(tmp) |
|
} |
|
|
|
function asciiSlice (buf, start, end) { |
|
var ret = '' |
|
end = Math.min(buf.length, end) |
|
|
|
for (var i = start; i < end; i++) { |
|
ret += String.fromCharCode(buf[i]) |
|
} |
|
return ret |
|
} |
|
|
|
function binarySlice (buf, start, end) { |
|
return asciiSlice(buf, start, end) |
|
} |
|
|
|
function hexSlice (buf, start, end) { |
|
var len = buf.length |
|
|
|
if (!start || start < 0) start = 0 |
|
if (!end || end < 0 || end > len) end = len |
|
|
|
var out = '' |
|
for (var i = start; i < end; i++) { |
|
out += toHex(buf[i]) |
|
} |
|
return out |
|
} |
|
|
|
function utf16leSlice (buf, start, end) { |
|
var bytes = buf.slice(start, end) |
|
var res = '' |
|
for (var i = 0; i < bytes.length; i += 2) { |
|
res += String.fromCharCode(bytes[i] + bytes[i + 1] * 256) |
|
} |
|
return res |
|
} |
|
|
|
Buffer.prototype.slice = function (start, end) { |
|
var len = this.length |
|
start = ~~start |
|
end = end === undefined ? len : ~~end |
|
|
|
if (start < 0) { |
|
start += len; |
|
if (start < 0) |
|
start = 0 |
|
} else if (start > len) { |
|
start = len |
|
} |
|
|
|
if (end < 0) { |
|
end += len |
|
if (end < 0) |
|
end = 0 |
|
} else if (end > len) { |
|
end = len |
|
} |
|
|
|
if (end < start) |
|
end = start |
|
|
|
if (TYPED_ARRAY_SUPPORT) { |
|
return Buffer._augment(this.subarray(start, end)) |
|
} else { |
|
var sliceLen = end - start |
|
var newBuf = new Buffer(sliceLen, undefined, true) |
|
for (var i = 0; i < sliceLen; i++) { |
|
newBuf[i] = this[i + start] |
|
} |
|
return newBuf |
|
} |
|
} |
|
|
|
// `get` will be removed in Node 0.13+ |
|
Buffer.prototype.get = function (offset) { |
|
console.log('.get() is deprecated. Access using array indexes instead.') |
|
return this.readUInt8(offset) |
|
} |
|
|
|
// `set` will be removed in Node 0.13+ |
|
Buffer.prototype.set = function (v, offset) { |
|
console.log('.set() is deprecated. Access using array indexes instead.') |
|
return this.writeUInt8(v, offset) |
|
} |
|
|
|
Buffer.prototype.readUInt8 = function (offset, noAssert) { |
|
if (!noAssert) { |
|
assert(offset !== undefined && offset !== null, 'missing offset') |
|
assert(offset < this.length, 'Trying to read beyond buffer length') |
|
} |
|
|
|
if (offset >= this.length) |
|
return |
|
|
|
return this[offset] |
|
} |
|
|
|
function readUInt16 (buf, offset, littleEndian, noAssert) { |
|
if (!noAssert) { |
|
assert(typeof littleEndian === 'boolean', 'missing or invalid endian') |
|
assert(offset !== undefined && offset !== null, 'missing offset') |
|
assert(offset + 1 < buf.length, 'Trying to read beyond buffer length') |
|
} |
|
|
|
var len = buf.length |
|
if (offset >= len) |
|
return |
|
|
|
var val |
|
if (littleEndian) { |
|
val = buf[offset] |
|
if (offset + 1 < len) |
|
val |= buf[offset + 1] << 8 |
|
} else { |
|
val = buf[offset] << 8 |
|
if (offset + 1 < len) |
|
val |= buf[offset + 1] |
|
} |
|
return val |
|
} |
|
|
|
Buffer.prototype.readUInt16LE = function (offset, noAssert) { |
|
return readUInt16(this, offset, true, noAssert) |
|
} |
|
|
|
Buffer.prototype.readUInt16BE = function (offset, noAssert) { |
|
return readUInt16(this, offset, false, noAssert) |
|
} |
|
|
|
function readUInt32 (buf, offset, littleEndian, noAssert) { |
|
if (!noAssert) { |
|
assert(typeof littleEndian === 'boolean', 'missing or invalid endian') |
|
assert(offset !== undefined && offset !== null, 'missing offset') |
|
assert(offset + 3 < buf.length, 'Trying to read beyond buffer length') |
|
} |
|
|
|
var len = buf.length |
|
if (offset >= len) |
|
return |
|
|
|
var val |
|
if (littleEndian) { |
|
if (offset + 2 < len) |
|
val = buf[offset + 2] << 16 |
|
if (offset + 1 < len) |
|
val |= buf[offset + 1] << 8 |
|
val |= buf[offset] |
|
if (offset + 3 < len) |
|
val = val + (buf[offset + 3] << 24 >>> 0) |
|
} else { |
|
if (offset + 1 < len) |
|
val = buf[offset + 1] << 16 |
|
if (offset + 2 < len) |
|
val |= buf[offset + 2] << 8 |
|
if (offset + 3 < len) |
|
val |= buf[offset + 3] |
|
val = val + (buf[offset] << 24 >>> 0) |
|
} |
|
return val |
|
} |
|
|
|
Buffer.prototype.readUInt32LE = function (offset, noAssert) { |
|
return readUInt32(this, offset, true, noAssert) |
|
} |
|
|
|
Buffer.prototype.readUInt32BE = function (offset, noAssert) { |
|
return readUInt32(this, offset, false, noAssert) |
|
} |
|
|
|
Buffer.prototype.readInt8 = function (offset, noAssert) { |
|
if (!noAssert) { |
|
assert(offset !== undefined && offset !== null, |
|
'missing offset') |
|
assert(offset < this.length, 'Trying to read beyond buffer length') |
|
} |
|
|
|
if (offset >= this.length) |
|
return |
|
|
|
var neg = this[offset] & 0x80 |
|
if (neg) |
|
return (0xff - this[offset] + 1) * -1 |
|
else |
|
return this[offset] |
|
} |
|
|
|
function readInt16 (buf, offset, littleEndian, noAssert) { |
|
if (!noAssert) { |
|
assert(typeof littleEndian === 'boolean', 'missing or invalid endian') |
|
assert(offset !== undefined && offset !== null, 'missing offset') |
|
assert(offset + 1 < buf.length, 'Trying to read beyond buffer length') |
|
} |
|
|
|
var len = buf.length |
|
if (offset >= len) |
|
return |
|
|
|
var val = readUInt16(buf, offset, littleEndian, true) |
|
var neg = val & 0x8000 |
|
if (neg) |
|
return (0xffff - val + 1) * -1 |
|
else |
|
return val |
|
} |
|
|
|
Buffer.prototype.readInt16LE = function (offset, noAssert) { |
|
return readInt16(this, offset, true, noAssert) |
|
} |
|
|
|
Buffer.prototype.readInt16BE = function (offset, noAssert) { |
|
return readInt16(this, offset, false, noAssert) |
|
} |
|
|
|
function readInt32 (buf, offset, littleEndian, noAssert) { |
|
if (!noAssert) { |
|
assert(typeof littleEndian === 'boolean', 'missing or invalid endian') |
|
assert(offset !== undefined && offset !== null, 'missing offset') |
|
assert(offset + 3 < buf.length, 'Trying to read beyond buffer length') |
|
} |
|
|
|
var len = buf.length |
|
if (offset >= len) |
|
return |
|
|
|
var val = readUInt32(buf, offset, littleEndian, true) |
|
var neg = val & 0x80000000 |
|
if (neg) |
|
return (0xffffffff - val + 1) * -1 |
|
else |
|
return val |
|
} |
|
|
|
Buffer.prototype.readInt32LE = function (offset, noAssert) { |
|
return readInt32(this, offset, true, noAssert) |
|
} |
|
|
|
Buffer.prototype.readInt32BE = function (offset, noAssert) { |
|
return readInt32(this, offset, false, noAssert) |
|
} |
|
|
|
function readFloat (buf, offset, littleEndian, noAssert) { |
|
if (!noAssert) { |
|
assert(typeof littleEndian === 'boolean', 'missing or invalid endian') |
|
assert(offset + 3 < buf.length, 'Trying to read beyond buffer length') |
|
} |
|
|
|
return ieee754.read(buf, offset, littleEndian, 23, 4) |
|
} |
|
|
|
Buffer.prototype.readFloatLE = function (offset, noAssert) { |
|
return readFloat(this, offset, true, noAssert) |
|
} |
|
|
|
Buffer.prototype.readFloatBE = function (offset, noAssert) { |
|
return readFloat(this, offset, false, noAssert) |
|
} |
|
|
|
function readDouble (buf, offset, littleEndian, noAssert) { |
|
if (!noAssert) { |
|
assert(typeof littleEndian === 'boolean', 'missing or invalid endian') |
|
assert(offset + 7 < buf.length, 'Trying to read beyond buffer length') |
|
} |
|
|
|
return ieee754.read(buf, offset, littleEndian, 52, 8) |
|
} |
|
|
|
Buffer.prototype.readDoubleLE = function (offset, noAssert) { |
|
return readDouble(this, offset, true, noAssert) |
|
} |
|
|
|
Buffer.prototype.readDoubleBE = function (offset, noAssert) { |
|
return readDouble(this, offset, false, noAssert) |
|
} |
|
|
|
Buffer.prototype.writeUInt8 = function (value, offset, noAssert) { |
|
if (!noAssert) { |
|
assert(value !== undefined && value !== null, 'missing value') |
|
assert(offset !== undefined && offset !== null, 'missing offset') |
|
assert(offset < this.length, 'trying to write beyond buffer length') |
|
verifuint(value, 0xff) |
|
} |
|
|
|
if (offset >= this.length) return |
|
|
|
this[offset] = value |
|
return offset + 1 |
|
} |
|
|
|
function writeUInt16 (buf, value, offset, littleEndian, noAssert) { |
|
if (!noAssert) { |
|
assert(value !== undefined && value !== null, 'missing value') |
|
assert(typeof littleEndian === 'boolean', 'missing or invalid endian') |
|
assert(offset !== undefined && offset !== null, 'missing offset') |
|
assert(offset + 1 < buf.length, 'trying to write beyond buffer length') |
|
verifuint(value, 0xffff) |
|
} |
|
|
|
var len = buf.length |
|
if (offset >= len) |
|
return |
|
|
|
for (var i = 0, j = Math.min(len - offset, 2); i < j; i++) { |
|
buf[offset + i] = |
|
(value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>> |
|
(littleEndian ? i : 1 - i) * 8 |
|
} |
|
return offset + 2 |
|
} |
|
|
|
Buffer.prototype.writeUInt16LE = function (value, offset, noAssert) { |
|
return writeUInt16(this, value, offset, true, noAssert) |
|
} |
|
|
|
Buffer.prototype.writeUInt16BE = function (value, offset, noAssert) { |
|
return writeUInt16(this, value, offset, false, noAssert) |
|
} |
|
|
|
function writeUInt32 (buf, value, offset, littleEndian, noAssert) { |
|
if (!noAssert) { |
|
assert(value !== undefined && value !== null, 'missing value') |
|
assert(typeof littleEndian === 'boolean', 'missing or invalid endian') |
|
assert(offset !== undefined && offset !== null, 'missing offset') |
|
assert(offset + 3 < buf.length, 'trying to write beyond buffer length') |
|
verifuint(value, 0xffffffff) |
|
} |
|
|
|
var len = buf.length |
|
if (offset >= len) |
|
return |
|
|
|
for (var i = 0, j = Math.min(len - offset, 4); i < j; i++) { |
|
buf[offset + i] = |
|
(value >>> (littleEndian ? i : 3 - i) * 8) & 0xff |
|
} |
|
return offset + 4 |
|
} |
|
|
|
Buffer.prototype.writeUInt32LE = function (value, offset, noAssert) { |
|
return writeUInt32(this, value, offset, true, noAssert) |
|
} |
|
|
|
Buffer.prototype.writeUInt32BE = function (value, offset, noAssert) { |
|
return writeUInt32(this, value, offset, false, noAssert) |
|
} |
|
|
|
Buffer.prototype.writeInt8 = function (value, offset, noAssert) { |
|
if (!noAssert) { |
|
assert(value !== undefined && value !== null, 'missing value') |
|
assert(offset !== undefined && offset !== null, 'missing offset') |
|
assert(offset < this.length, 'Trying to write beyond buffer length') |
|
verifsint(value, 0x7f, -0x80) |
|
} |
|
|
|
if (offset >= this.length) |
|
return |
|
|
|
if (value >= 0) |
|
this.writeUInt8(value, offset, noAssert) |
|
else |
|
this.writeUInt8(0xff + value + 1, offset, noAssert) |
|
return offset + 1 |
|
} |
|
|
|
function writeInt16 (buf, value, offset, littleEndian, noAssert) { |
|
if (!noAssert) { |
|
assert(value !== undefined && value !== null, 'missing value') |
|
assert(typeof littleEndian === 'boolean', 'missing or invalid endian') |
|
assert(offset !== undefined && offset !== null, 'missing offset') |
|
assert(offset + 1 < buf.length, 'Trying to write beyond buffer length') |
|
verifsint(value, 0x7fff, -0x8000) |
|
} |
|
|
|
var len = buf.length |
|
if (offset >= len) |
|
return |
|
|
|
if (value >= 0) |
|
writeUInt16(buf, value, offset, littleEndian, noAssert) |
|
else |
|
writeUInt16(buf, 0xffff + value + 1, offset, littleEndian, noAssert) |
|
return offset + 2 |
|
} |
|
|
|
Buffer.prototype.writeInt16LE = function (value, offset, noAssert) { |
|
return writeInt16(this, value, offset, true, noAssert) |
|
} |
|
|
|
Buffer.prototype.writeInt16BE = function (value, offset, noAssert) { |
|
return writeInt16(this, value, offset, false, noAssert) |
|
} |
|
|
|
function writeInt32 (buf, value, offset, littleEndian, noAssert) { |
|
if (!noAssert) { |
|
assert(value !== undefined && value !== null, 'missing value') |
|
assert(typeof littleEndian === 'boolean', 'missing or invalid endian') |
|
assert(offset !== undefined && offset !== null, 'missing offset') |
|
assert(offset + 3 < buf.length, 'Trying to write beyond buffer length') |
|
verifsint(value, 0x7fffffff, -0x80000000) |
|
} |
|
|
|
var len = buf.length |
|
if (offset >= len) |
|
return |
|
|
|
if (value >= 0) |
|
writeUInt32(buf, value, offset, littleEndian, noAssert) |
|
else |
|
writeUInt32(buf, 0xffffffff + value + 1, offset, littleEndian, noAssert) |
|
return offset + 4 |
|
} |
|
|
|
Buffer.prototype.writeInt32LE = function (value, offset, noAssert) { |
|
return writeInt32(this, value, offset, true, noAssert) |
|
} |
|
|
|
Buffer.prototype.writeInt32BE = function (value, offset, noAssert) { |
|
return writeInt32(this, value, offset, false, noAssert) |
|
} |
|
|
|
function writeFloat (buf, value, offset, littleEndian, noAssert) { |
|
if (!noAssert) { |
|
assert(value !== undefined && value !== null, 'missing value') |
|
assert(typeof littleEndian === 'boolean', 'missing or invalid endian') |
|
assert(offset !== undefined && offset !== null, 'missing offset') |
|
assert(offset + 3 < buf.length, 'Trying to write beyond buffer length') |
|
verifIEEE754(value, 3.4028234663852886e+38, -3.4028234663852886e+38) |
|
} |
|
|
|
var len = buf.length |
|
if (offset >= len) |
|
return |
|
|
|
ieee754.write(buf, value, offset, littleEndian, 23, 4) |
|
return offset + 4 |
|
} |
|
|
|
Buffer.prototype.writeFloatLE = function (value, offset, noAssert) { |
|
return writeFloat(this, value, offset, true, noAssert) |
|
} |
|
|
|
Buffer.prototype.writeFloatBE = function (value, offset, noAssert) { |
|
return writeFloat(this, value, offset, false, noAssert) |
|
} |
|
|
|
function writeDouble (buf, value, offset, littleEndian, noAssert) { |
|
if (!noAssert) { |
|
assert(value !== undefined && value !== null, 'missing value') |
|
assert(typeof littleEndian === 'boolean', 'missing or invalid endian') |
|
assert(offset !== undefined && offset !== null, 'missing offset') |
|
assert(offset + 7 < buf.length, |
|
'Trying to write beyond buffer length') |
|
verifIEEE754(value, 1.7976931348623157E+308, -1.7976931348623157E+308) |
|
} |
|
|
|
var len = buf.length |
|
if (offset >= len) |
|
return |
|
|
|
ieee754.write(buf, value, offset, littleEndian, 52, 8) |
|
return offset + 8 |
|
} |
|
|
|
Buffer.prototype.writeDoubleLE = function (value, offset, noAssert) { |
|
return writeDouble(this, value, offset, true, noAssert) |
|
} |
|
|
|
Buffer.prototype.writeDoubleBE = function (value, offset, noAssert) { |
|
return writeDouble(this, value, offset, false, noAssert) |
|
} |
|
|
|
// fill(value, start=0, end=buffer.length) |
|
Buffer.prototype.fill = function (value, start, end) { |
|
if (!value) value = 0 |
|
if (!start) start = 0 |
|
if (!end) end = this.length |
|
|
|
assert(end >= start, 'end < start') |
|
|
|
// Fill 0 bytes; we're done |
|
if (end === start) return |
|
if (this.length === 0) return |
|
|
|
assert(start >= 0 && start < this.length, 'start out of bounds') |
|
assert(end >= 0 && end <= this.length, 'end out of bounds') |
|
|
|
var i |
|
if (typeof value === 'number') { |
|
for (i = start; i < end; i++) { |
|
this[i] = value |
|
} |
|
} else { |
|
var bytes = utf8ToBytes(value.toString()) |
|
var len = bytes.length |
|
for (i = start; i < end; i++) { |
|
this[i] = bytes[i % len] |
|
} |
|
} |
|
|
|
return this |
|
} |
|
|
|
Buffer.prototype.inspect = function () { |
|
var out = [] |
|
var len = this.length |
|
for (var i = 0; i < len; i++) { |
|
out[i] = toHex(this[i]) |
|
if (i === exports.INSPECT_MAX_BYTES) { |
|
out[i + 1] = '...' |
|
break |
|
} |
|
} |
|
return '<Buffer ' + out.join(' ') + '>' |
|
} |
|
|
|
/** |
|
* Creates a new `ArrayBuffer` with the *copied* memory of the buffer instance. |
|
* Added in Node 0.12. Only available in browsers that support ArrayBuffer. |
|
*/ |
|
Buffer.prototype.toArrayBuffer = function () { |
|
if (typeof Uint8Array !== 'undefined') { |
|
if (TYPED_ARRAY_SUPPORT) { |
|
return (new Buffer(this)).buffer |
|
} else { |
|
var buf = new Uint8Array(this.length) |
|
for (var i = 0, len = buf.length; i < len; i += 1) { |
|
buf[i] = this[i] |
|
} |
|
return buf.buffer |
|
} |
|
} else { |
|
throw new Error('Buffer.toArrayBuffer not supported in this browser') |
|
} |
|
} |
|
|
|
// HELPER FUNCTIONS |
|
// ================ |
|
|
|
var BP = Buffer.prototype |
|
|
|
/** |
|
* Augment a Uint8Array *instance* (not the Uint8Array class!) with Buffer methods |
|
*/ |
|
Buffer._augment = function (arr) { |
|
arr._isBuffer = true |
|
|
|
// save reference to original Uint8Array get/set methods before overwriting |
|
arr._get = arr.get |
|
arr._set = arr.set |
|
|
|
// deprecated, will be removed in node 0.13+ |
|
arr.get = BP.get |
|
arr.set = BP.set |
|
|
|
arr.write = BP.write |
|
arr.toString = BP.toString |
|
arr.toLocaleString = BP.toString |
|
arr.toJSON = BP.toJSON |
|
arr.equals = BP.equals |
|
arr.compare = BP.compare |
|
arr.copy = BP.copy |
|
arr.slice = BP.slice |
|
arr.readUInt8 = BP.readUInt8 |
|
arr.readUInt16LE = BP.readUInt16LE |
|
arr.readUInt16BE = BP.readUInt16BE |
|
arr.readUInt32LE = BP.readUInt32LE |
|
arr.readUInt32BE = BP.readUInt32BE |
|
arr.readInt8 = BP.readInt8 |
|
arr.readInt16LE = BP.readInt16LE |
|
arr.readInt16BE = BP.readInt16BE |
|
arr.readInt32LE = BP.readInt32LE |
|
arr.readInt32BE = BP.readInt32BE |
|
arr.readFloatLE = BP.readFloatLE |
|
arr.readFloatBE = BP.readFloatBE |
|
arr.readDoubleLE = BP.readDoubleLE |
|
arr.readDoubleBE = BP.readDoubleBE |
|
arr.writeUInt8 = BP.writeUInt8 |
|
arr.writeUInt16LE = BP.writeUInt16LE |
|
arr.writeUInt16BE = BP.writeUInt16BE |
|
arr.writeUInt32LE = BP.writeUInt32LE |
|
arr.writeUInt32BE = BP.writeUInt32BE |
|
arr.writeInt8 = BP.writeInt8 |
|
arr.writeInt16LE = BP.writeInt16LE |
|
arr.writeInt16BE = BP.writeInt16BE |
|
arr.writeInt32LE = BP.writeInt32LE |
|
arr.writeInt32BE = BP.writeInt32BE |
|
arr.writeFloatLE = BP.writeFloatLE |
|
arr.writeFloatBE = BP.writeFloatBE |
|
arr.writeDoubleLE = BP.writeDoubleLE |
|
arr.writeDoubleBE = BP.writeDoubleBE |
|
arr.fill = BP.fill |
|
arr.inspect = BP.inspect |
|
arr.toArrayBuffer = BP.toArrayBuffer |
|
|
|
return arr |
|
} |
|
|
|
var INVALID_BASE64_RE = /[^+\/0-9A-z]/g |
|
|
|
function base64clean (str) { |
|
// Node strips out invalid characters like \n and \t from the string, base64-js does not |
|
str = stringtrim(str).replace(INVALID_BASE64_RE, '') |
|
// Node allows for non-padded base64 strings (missing trailing ===), base64-js does not |
|
while (str.length % 4 !== 0) { |
|
str = str + '=' |
|
} |
|
return str |
|
} |
|
|
|
function stringtrim (str) { |
|
if (str.trim) return str.trim() |
|
return str.replace(/^\s+|\s+$/g, '') |
|
} |
|
|
|
function isArray (subject) { |
|
return (Array.isArray || function (subject) { |
|
return Object.prototype.toString.call(subject) === '[object Array]' |
|
})(subject) |
|
} |
|
|
|
function isArrayish (subject) { |
|
return isArray(subject) || Buffer.isBuffer(subject) || |
|
subject && typeof subject === 'object' && |
|
typeof subject.length === 'number' |
|
} |
|
|
|
function toHex (n) { |
|
if (n < 16) return '0' + n.toString(16) |
|
return n.toString(16) |
|
} |
|
|
|
function utf8ToBytes (str) { |
|
var byteArray = [] |
|
for (var i = 0; i < str.length; i++) { |
|
var b = str.charCodeAt(i) |
|
if (b <= 0x7F) { |
|
byteArray.push(b) |
|
} else { |
|
var start = i |
|
if (b >= 0xD800 && b <= 0xDFFF) i++ |
|
var h = encodeURIComponent(str.slice(start, i+1)).substr(1).split('%') |
|
for (var j = 0; j < h.length; j++) { |
|
byteArray.push(parseInt(h[j], 16)) |
|
} |
|
} |
|
} |
|
return byteArray |
|
} |
|
|
|
function asciiToBytes (str) { |
|
var byteArray = [] |
|
for (var i = 0; i < str.length; i++) { |
|
// Node's code seems to be doing this and not & 0x7F.. |
|
byteArray.push(str.charCodeAt(i) & 0xFF) |
|
} |
|
return byteArray |
|
} |
|
|
|
function utf16leToBytes (str) { |
|
var c, hi, lo |
|
var byteArray = [] |
|
for (var i = 0; i < str.length; i++) { |
|
c = str.charCodeAt(i) |
|
hi = c >> 8 |
|
lo = c % 256 |
|
byteArray.push(lo) |
|
byteArray.push(hi) |
|
} |
|
|
|
return byteArray |
|
} |
|
|
|
function base64ToBytes (str) { |
|
return base64.toByteArray(str) |
|
} |
|
|
|
function blitBuffer (src, dst, offset, length) { |
|
for (var i = 0; i < length; i++) { |
|
if ((i + offset >= dst.length) || (i >= src.length)) |
|
break |
|
dst[i + offset] = src[i] |
|
} |
|
return i |
|
} |
|
|
|
function decodeUtf8Char (str) { |
|
try { |
|
return decodeURIComponent(str) |
|
} catch (err) { |
|
return String.fromCharCode(0xFFFD) // UTF 8 invalid char |
|
} |
|
} |
|
|
|
/* |
|
* We have to make sure that the value is a valid integer. This means that it |
|
* is non-negative. It has no fractional component and that it does not |
|
* exceed the maximum allowed value. |
|
*/ |
|
function verifuint (value, max) { |
|
assert(typeof value === 'number', 'cannot write a non-number as a number') |
|
assert(value >= 0, 'specified a negative value for writing an unsigned value') |
|
assert(value <= max, 'value is larger than maximum value for type') |
|
assert(Math.floor(value) === value, 'value has a fractional component') |
|
} |
|
|
|
function verifsint (value, max, min) { |
|
assert(typeof value === 'number', 'cannot write a non-number as a number') |
|
assert(value <= max, 'value larger than maximum allowed value') |
|
assert(value >= min, 'value smaller than minimum allowed value') |
|
assert(Math.floor(value) === value, 'value has a fractional component') |
|
} |
|
|
|
function verifIEEE754 (value, max, min) { |
|
assert(typeof value === 'number', 'cannot write a non-number as a number') |
|
assert(value <= max, 'value larger than maximum allowed value') |
|
assert(value >= min, 'value smaller than minimum allowed value') |
|
} |
|
|
|
function assert (test, message) { |
|
if (!test) throw new Error(message || 'Failed assertion') |
|
} |
|
|
|
},{"base64-js":10,"ieee754":11}],10:[function(require,module,exports){ |
|
var lookup = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; |
|
|
|
;(function (exports) { |
|
'use strict'; |
|
|
|
var Arr = (typeof Uint8Array !== 'undefined') |
|
? Uint8Array |
|
: Array |
|
|
|
var PLUS = '+'.charCodeAt(0) |
|
var SLASH = '/'.charCodeAt(0) |
|
var NUMBER = '0'.charCodeAt(0) |
|
var LOWER = 'a'.charCodeAt(0) |
|
var UPPER = 'A'.charCodeAt(0) |
|
|
|
function decode (elt) { |
|
var code = elt.charCodeAt(0) |
|
if (code === PLUS) |
|
return 62 // '+' |
|
if (code === SLASH) |
|
return 63 // '/' |
|
if (code < NUMBER) |
|
return -1 //no match |
|
if (code < NUMBER + 10) |
|
return code - NUMBER + 26 + 26 |
|
if (code < UPPER + 26) |
|
return code - UPPER |
|
if (code < LOWER + 26) |
|
return code - LOWER + 26 |
|
} |
|
|
|
function b64ToByteArray (b64) { |
|
var i, j, l, tmp, placeHolders, arr |
|
|
|
if (b64.length % 4 > 0) { |
|
throw new Error('Invalid string. Length must be a multiple of 4') |
|
} |
|
|
|
// the number of equal signs (place holders) |
|
// if there are two placeholders, than the two characters before it |
|
// represent one byte |
|
// if there is only one, then the three characters before it represent 2 bytes |
|
// this is just a cheap hack to not do indexOf twice |
|
var len = b64.length |
|
placeHolders = '=' === b64.charAt(len - 2) ? 2 : '=' === b64.charAt(len - 1) ? 1 : 0 |
|
|
|
// base64 is 4/3 + up to two characters of the original data |
|
arr = new Arr(b64.length * 3 / 4 - placeHolders) |
|
|
|
// if there are placeholders, only get up to the last complete 4 chars |
|
l = placeHolders > 0 ? b64.length - 4 : b64.length |
|
|
|
var L = 0 |
|
|
|
function push (v) { |
|
arr[L++] = v |
|
} |
|
|
|
for (i = 0, j = 0; i < l; i += 4, j += 3) { |
|
tmp = (decode(b64.charAt(i)) << 18) | (decode(b64.charAt(i + 1)) << 12) | (decode(b64.charAt(i + 2)) << 6) | decode(b64.charAt(i + 3)) |
|
push((tmp & 0xFF0000) >> 16) |
|
push((tmp & 0xFF00) >> 8) |
|
push(tmp & 0xFF) |
|
} |
|
|
|
if (placeHolders === 2) { |
|
tmp = (decode(b64.charAt(i)) << 2) | (decode(b64.charAt(i + 1)) >> 4) |
|
push(tmp & 0xFF) |
|
} else if (placeHolders === 1) { |
|
tmp = (decode(b64.charAt(i)) << 10) | (decode(b64.charAt(i + 1)) << 4) | (decode(b64.charAt(i + 2)) >> 2) |
|
push((tmp >> 8) & 0xFF) |
|
push(tmp & 0xFF) |
|
} |
|
|
|
return arr |
|
} |
|
|
|
function uint8ToBase64 (uint8) { |
|
var i, |
|
extraBytes = uint8.length % 3, // if we have 1 byte left, pad 2 bytes |
|
output = "", |
|
temp, length |
|
|
|
function encode (num) { |
|
return lookup.charAt(num) |
|
} |
|
|
|
function tripletToBase64 (num) { |
|
return encode(num >> 18 & 0x3F) + encode(num >> 12 & 0x3F) + encode(num >> 6 & 0x3F) + encode(num & 0x3F) |
|
} |
|
|
|
// go through the array every three bytes, we'll deal with trailing stuff later |
|
for (i = 0, length = uint8.length - extraBytes; i < length; i += 3) { |
|
temp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2]) |
|
output += tripletToBase64(temp) |
|
} |
|
|
|
// pad the end with zeros, but make sure to not forget the extra bytes |
|
switch (extraBytes) { |
|
case 1: |
|
temp = uint8[uint8.length - 1] |
|
output += encode(temp >> 2) |
|
output += encode((temp << 4) & 0x3F) |
|
output += '==' |
|
break |
|
case 2: |
|
temp = (uint8[uint8.length - 2] << 8) + (uint8[uint8.length - 1]) |
|
output += encode(temp >> 10) |
|
output += encode((temp >> 4) & 0x3F) |
|
output += encode((temp << 2) & 0x3F) |
|
output += '=' |
|
break |
|
} |
|
|
|
return output |
|
} |
|
|
|
exports.toByteArray = b64ToByteArray |
|
exports.fromByteArray = uint8ToBase64 |
|
}(typeof exports === 'undefined' ? (this.base64js = {}) : exports)) |
|
|
|
},{}],11:[function(require,module,exports){ |
|
exports.read = function(buffer, offset, isLE, mLen, nBytes) { |
|
var e, m, |
|
eLen = nBytes * 8 - mLen - 1, |
|
eMax = (1 << eLen) - 1, |
|
eBias = eMax >> 1, |
|
nBits = -7, |
|
i = isLE ? (nBytes - 1) : 0, |
|
d = isLE ? -1 : 1, |
|
s = buffer[offset + i]; |
|
|
|
i += d; |
|
|
|
e = s & ((1 << (-nBits)) - 1); |
|
s >>= (-nBits); |
|
nBits += eLen; |
|
for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8); |
|
|
|
m = e & ((1 << (-nBits)) - 1); |
|
e >>= (-nBits); |
|
nBits += mLen; |
|
for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8); |
|
|
|
if (e === 0) { |
|
e = 1 - eBias; |
|
} else if (e === eMax) { |
|
return m ? NaN : ((s ? -1 : 1) * Infinity); |
|
} else { |
|
m = m + Math.pow(2, mLen); |
|
e = e - eBias; |
|
} |
|
return (s ? -1 : 1) * m * Math.pow(2, e - mLen); |
|
}; |
|
|
|
exports.write = function(buffer, value, offset, isLE, mLen, nBytes) { |
|
var e, m, c, |
|
eLen = nBytes * 8 - mLen - 1, |
|
eMax = (1 << eLen) - 1, |
|
eBias = eMax >> 1, |
|
rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0), |
|
i = isLE ? 0 : (nBytes - 1), |
|
d = isLE ? 1 : -1, |
|
s = value < 0 || (value === 0 && 1 / value < 0) ? 1 : 0; |
|
|
|
value = Math.abs(value); |
|
|
|
if (isNaN(value) || value === Infinity) { |
|
m = isNaN(value) ? 1 : 0; |
|
e = eMax; |
|
} else { |
|
e = Math.floor(Math.log(value) / Math.LN2); |
|
if (value * (c = Math.pow(2, -e)) < 1) { |
|
e--; |
|
c *= 2; |
|
} |
|
if (e + eBias >= 1) { |
|
value += rt / c; |
|
} else { |
|
value += rt * Math.pow(2, 1 - eBias); |
|
} |
|
if (value * c >= 2) { |
|
e++; |
|
c /= 2; |
|
} |
|
|
|
if (e + eBias >= eMax) { |
|
m = 0; |
|
e = eMax; |
|
} else if (e + eBias >= 1) { |
|
m = (value * c - 1) * Math.pow(2, mLen); |
|
e = e + eBias; |
|
} else { |
|
m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen); |
|
e = 0; |
|
} |
|
} |
|
|
|
for (; mLen >= 8; buffer[offset + i] = m & 0xff, i += d, m /= 256, mLen -= 8); |
|
|
|
e = (e << mLen) | m; |
|
eLen += mLen; |
|
for (; eLen > 0; buffer[offset + i] = e & 0xff, i += d, e /= 256, eLen -= 8); |
|
|
|
buffer[offset + i - d] |= s * 128; |
|
}; |
|
|
|
},{}],12:[function(require,module,exports){ |
|
// Copyright Joyent, Inc. and other Node contributors. |
|
// |
|
// Permission is hereby granted, free of charge, to any person obtaining a |
|
// copy of this software and associated documentation files (the |
|
// "Software"), to deal in the Software without restriction, including |
|
// without limitation the rights to use, copy, modify, merge, publish, |
|
// distribute, sublicense, and/or sell copies of the Software, and to permit |
|
// persons to whom the Software is furnished to do so, subject to the |
|
// following conditions: |
|
// |
|
// The above copyright notice and this permission notice shall be included |
|
// in all copies or substantial portions of the Software. |
|
// |
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
|
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN |
|
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, |
|
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE |
|
// USE OR OTHER DEALINGS IN THE SOFTWARE. |
|
|
|
function EventEmitter() { |
|
this._events = this._events || {}; |
|
this._maxListeners = this._maxListeners || undefined; |
|
} |
|
module.exports = EventEmitter; |
|
|
|
// Backwards-compat with node 0.10.x |
|
EventEmitter.EventEmitter = EventEmitter; |
|
|
|
EventEmitter.prototype._events = undefined; |
|
EventEmitter.prototype._maxListeners = undefined; |
|
|
|
// By default EventEmitters will print a warning if more than 10 listeners are |
|
// added to it. This is a useful default which helps finding memory leaks. |
|
EventEmitter.defaultMaxListeners = 10; |
|
|
|
// Obviously not all Emitters should be limited to 10. This function allows |
|
// that to be increased. Set to zero for unlimited. |
|
EventEmitter.prototype.setMaxListeners = function(n) { |
|
if (!isNumber(n) || n < 0 || isNaN(n)) |
|
throw TypeError('n must be a positive number'); |
|
this._maxListeners = n; |
|
return this; |
|
}; |
|
|
|
EventEmitter.prototype.emit = function(type) { |
|
var er, handler, len, args, i, listeners; |
|
|
|
if (!this._events) |
|
this._events = {}; |
|
|
|
// If there is no 'error' event listener then throw. |
|
if (type === 'error') { |
|
if (!this._events.error || |
|
(isObject(this._events.error) && !this._events.error.length)) { |
|
er = arguments[1]; |
|
if (er instanceof Error) { |
|
throw er; // Unhandled 'error' event |
|
} else { |
|
throw TypeError('Uncaught, unspecified "error" event.'); |
|
} |
|
return false; |
|
} |
|
} |
|
|
|
handler = this._events[type]; |
|
|
|
if (isUndefined(handler)) |
|
return false; |
|
|
|
if (isFunction(handler)) { |
|
switch (arguments.length) { |
|
// fast cases |
|
case 1: |
|
handler.call(this); |
|
break; |
|
case 2: |
|
handler.call(this, arguments[1]); |
|
break; |
|
case 3: |
|
handler.call(this, arguments[1], arguments[2]); |
|
break; |
|
// slower |
|
default: |
|
len = arguments.length; |
|
args = new Array(len - 1); |
|
for (i = 1; i < len; i++) |
|
args[i - 1] = arguments[i]; |
|
handler.apply(this, args); |
|
} |
|
} else if (isObject(handler)) { |
|
len = arguments.length; |
|
args = new Array(len - 1); |
|
for (i = 1; i < len; i++) |
|
args[i - 1] = arguments[i]; |
|
|
|
listeners = handler.slice(); |
|
len = listeners.length; |
|
for (i = 0; i < len; i++) |
|
listeners[i].apply(this, args); |
|
} |
|
|
|
return true; |
|
}; |
|
|
|
EventEmitter.prototype.addListener = function(type, listener) { |
|
var m; |
|
|
|
if (!isFunction(listener)) |
|
throw TypeError('listener must be a function'); |
|
|
|
if (!this._events) |
|
this._events = {}; |
|
|
|
// To avoid recursion in the case that type === "newListener"! Before |
|
// adding it to the listeners, first emit "newListener". |
|
if (this._events.newListener) |
|
this.emit('newListener', type, |
|
isFunction(listener.listener) ? |
|
listener.listener : listener); |
|
|
|
if (!this._events[type]) |
|
// Optimize the case of one listener. Don't need the extra array object. |
|
this._events[type] = listener; |
|
else if (isObject(this._events[type])) |
|
// If we've already got an array, just append. |
|
this._events[type].push(listener); |
|
else |
|
// Adding the second element, need to change to array. |
|
this._events[type] = [this._events[type], listener]; |
|
|
|
// Check for listener leak |
|
if (isObject(this._events[type]) && !this._events[type].warned) { |
|
var m; |
|
if (!isUndefined(this._maxListeners)) { |
|
m = this._maxListeners; |
|
} else { |
|
m = EventEmitter.defaultMaxListeners; |
|
} |
|
|
|
if (m && m > 0 && this._events[type].length > m) { |
|
this._events[type].warned = true; |
|
console.error('(node) warning: possible EventEmitter memory ' + |
|
'leak detected. %d listeners added. ' + |
|
'Use emitter.setMaxListeners() to increase limit.', |
|
this._events[type].length); |
|
if (typeof console.trace === 'function') { |
|
// not supported in IE 10 |
|
console.trace(); |
|
} |
|
} |
|
} |
|
|
|
return this; |
|
}; |
|
|
|
EventEmitter.prototype.on = EventEmitter.prototype.addListener; |
|
|
|
EventEmitter.prototype.once = function(type, listener) { |
|
if (!isFunction(listener)) |
|
throw TypeError('listener must be a function'); |
|
|
|
var fired = false; |
|
|
|
function g() { |
|
this.removeListener(type, g); |
|
|
|
if (!fired) { |
|
fired = true; |
|
listener.apply(this, arguments); |
|
} |
|
} |
|
|
|
g.listener = listener; |
|
this.on(type, g); |
|
|
|
return this; |
|
}; |
|
|
|
// emits a 'removeListener' event iff the listener was removed |
|
EventEmitter.prototype.removeListener = function(type, listener) { |
|
var list, position, length, i; |
|
|
|
if (!isFunction(listener)) |
|
throw TypeError('listener must be a function'); |
|
|
|
if (!this._events || !this._events[type]) |
|
return this; |
|
|
|
list = this._events[type]; |
|
length = list.length; |
|
position = -1; |
|
|
|
if (list === listener || |
|
(isFunction(list.listener) && list.listener === listener)) { |
|
delete this._events[type]; |
|
if (this._events.removeListener) |
|
this.emit('removeListener', type, listener); |
|
|
|
} else if (isObject(list)) { |
|
for (i = length; i-- > 0;) { |
|
if (list[i] === listener || |
|
(list[i].listener && list[i].listener === listener)) { |
|
position = i; |
|
break; |
|
} |
|
} |
|
|
|
if (position < 0) |
|
return this; |
|
|
|
if (list.length === 1) { |
|
list.length = 0; |
|
delete this._events[type]; |
|
} else { |
|
list.splice(position, 1); |
|
} |
|
|
|
if (this._events.removeListener) |
|
this.emit('removeListener', type, listener); |
|
} |
|
|
|
return this; |
|
}; |
|
|
|
EventEmitter.prototype.removeAllListeners = function(type) { |
|
var key, listeners; |
|
|
|
if (!this._events) |
|
return this; |
|
|
|
// not listening for removeListener, no need to emit |
|
if (!this._events.removeListener) { |
|
if (arguments.length === 0) |
|
this._events = {}; |
|
else if (this._events[type]) |
|
delete this._events[type]; |
|
return this; |
|
} |
|
|
|
// emit removeListener for all listeners on all events |
|
if (arguments.length === 0) { |
|
for (key in this._events) { |
|
if (key === 'removeListener') continue; |
|
this.removeAllListeners(key); |
|
} |
|
this.removeAllListeners('removeListener'); |
|
this._events = {}; |
|
return this; |
|
} |
|
|
|
listeners = this._events[type]; |
|
|
|
if (isFunction(listeners)) { |
|
this.removeListener(type, listeners); |
|
} else { |
|
// LIFO order |
|
while (listeners.length) |
|
this.removeListener(type, listeners[listeners.length - 1]); |
|
} |
|
delete this._events[type]; |
|
|
|
return this; |
|
}; |
|
|
|
EventEmitter.prototype.listeners = function(type) { |
|
var ret; |
|
if (!this._events || !this._events[type]) |
|
ret = []; |
|
else if (isFunction(this._events[type])) |
|
ret = [this._events[type]]; |
|
else |
|
ret = this._events[type].slice(); |
|
return ret; |
|
}; |
|
|
|
EventEmitter.listenerCount = function(emitter, type) { |
|
var ret; |
|
if (!emitter._events || !emitter._events[type]) |
|
ret = 0; |
|
else if (isFunction(emitter._events[type])) |
|
ret = 1; |
|
else |
|
ret = emitter._events[type].length; |
|
return ret; |
|
}; |
|
|
|
function isFunction(arg) { |
|
return typeof arg === 'function'; |
|
} |
|
|
|
function isNumber(arg) { |
|
return typeof arg === 'number'; |
|
} |
|
|
|
function isObject(arg) { |
|
return typeof arg === 'object' && arg !== null; |
|
} |
|
|
|
function isUndefined(arg) { |
|
return arg === void 0; |
|
} |
|
|
|
},{}],13:[function(require,module,exports){ |
|
if (typeof Object.create === 'function') { |
|
// implementation from standard node.js 'util' module |
|
module.exports = function inherits(ctor, superCtor) { |
|
ctor.super_ = superCtor |
|
ctor.prototype = Object.create(superCtor.prototype, { |
|
constructor: { |
|
value: ctor, |
|
enumerable: false, |
|
writable: true, |
|
configurable: true |
|
} |
|
}); |
|
}; |
|
} else { |
|
// old school shim for old browsers |
|
module.exports = function inherits(ctor, superCtor) { |
|
ctor.super_ = superCtor |
|
var TempCtor = function () {} |
|
TempCtor.prototype = superCtor.prototype |
|
ctor.prototype = new TempCtor() |
|
ctor.prototype.constructor = ctor |
|
} |
|
} |
|
|
|
},{}],14:[function(require,module,exports){ |
|
module.exports = Array.isArray || function (arr) { |
|
return Object.prototype.toString.call(arr) == '[object Array]'; |
|
}; |
|
|
|
},{}],15:[function(require,module,exports){ |
|
(function (process){ |
|
// Copyright Joyent, Inc. and other Node contributors. |
|
// |
|
// Permission is hereby granted, free of charge, to any person obtaining a |
|
// copy of this software and associated documentation files (the |
|
// "Software"), to deal in the Software without restriction, including |
|
// without limitation the rights to use, copy, modify, merge, publish, |
|
// distribute, sublicense, and/or sell copies of the Software, and to permit |
|
// persons to whom the Software is furnished to do so, subject to the |
|
// following conditions: |
|
// |
|
// The above copyright notice and this permission notice shall be included |
|
// in all copies or substantial portions of the Software. |
|
// |
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
|
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN |
|
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, |
|
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE |
|
// USE OR OTHER DEALINGS IN THE SOFTWARE. |
|
|
|
// resolves . and .. elements in a path array with directory names there |
|
// must be no slashes, empty elements, or device names (c:\) in the array |
|
// (so also no leading and trailing slashes - it does not distinguish |
|
// relative and absolute paths) |
|
function normalizeArray(parts, allowAboveRoot) { |
|
// if the path tries to go above the root, `up` ends up > 0 |
|
var up = 0; |
|
for (var i = parts.length - 1; i >= 0; i--) { |
|
var last = parts[i]; |
|
if (last === '.') { |
|
parts.splice(i, 1); |
|
} else if (last === '..') { |
|
parts.splice(i, 1); |
|
up++; |
|
} else if (up) { |
|
parts.splice(i, 1); |
|
up--; |
|
} |
|
} |
|
|
|
// if the path is allowed to go above the root, restore leading ..s |
|
if (allowAboveRoot) { |
|
for (; up--; up) { |
|
parts.unshift('..'); |
|
} |
|
} |
|
|
|
return parts; |
|
} |
|
|
|
// Split a filename into [root, dir, basename, ext], unix version |
|
// 'root' is just a slash, or nothing. |
|
var splitPathRe = |
|
/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/; |
|
var splitPath = function(filename) { |
|
return splitPathRe.exec(filename).slice(1); |
|
}; |
|
|
|
// path.resolve([from ...], to) |
|
// posix version |
|
exports.resolve = function() { |
|
var resolvedPath = '', |
|
resolvedAbsolute = false; |
|
|
|
for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) { |
|
var path = (i >= 0) ? arguments[i] : process.cwd(); |
|
|
|
// Skip empty and invalid entries |
|
if (typeof path !== 'string') { |
|
throw new TypeError('Arguments to path.resolve must be strings'); |
|
} else if (!path) { |
|
continue; |
|
} |
|
|
|
resolvedPath = path + '/' + resolvedPath; |
|
resolvedAbsolute = path.charAt(0) === '/'; |
|
} |
|
|
|
// At this point the path should be resolved to a full absolute path, but |
|
// handle relative paths to be safe (might happen when process.cwd() fails) |
|
|
|
// Normalize the path |
|
resolvedPath = normalizeArray(filter(resolvedPath.split('/'), function(p) { |
|
return !!p; |
|
}), !resolvedAbsolute).join('/'); |
|
|
|
return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.'; |
|
}; |
|
|
|
// path.normalize(path) |
|
// posix version |
|
exports.normalize = function(path) { |
|
var isAbsolute = exports.isAbsolute(path), |
|
trailingSlash = substr(path, -1) === '/'; |
|
|
|
// Normalize the path |
|
path = normalizeArray(filter(path.split('/'), function(p) { |
|
return !!p; |
|
}), !isAbsolute).join('/'); |
|
|
|
if (!path && !isAbsolute) { |
|
path = '.'; |
|
} |
|
if (path && trailingSlash) { |
|
path += '/'; |
|
} |
|
|
|
return (isAbsolute ? '/' : '') + path; |
|
}; |
|
|
|
// posix version |
|
exports.isAbsolute = function(path) { |
|
return path.charAt(0) === '/'; |
|
}; |
|
|
|
// posix version |
|
exports.join = function() { |
|
var paths = Array.prototype.slice.call(arguments, 0); |
|
return exports.normalize(filter(paths, function(p, index) { |
|
if (typeof p !== 'string') { |
|
throw new TypeError('Arguments to path.join must be strings'); |
|
} |
|
return p; |
|
}).join('/')); |
|
}; |
|
|
|
|
|
// path.relative(from, to) |
|
// posix version |
|
exports.relative = function(from, to) { |
|
from = exports.resolve(from).substr(1); |
|
to = exports.resolve(to).substr(1); |
|
|
|
function trim(arr) { |
|
var start = 0; |
|
for (; start < arr.length; start++) { |
|
if (arr[start] !== '') break; |
|
} |
|
|
|
var end = arr.length - 1; |
|
for (; end >= 0; end--) { |
|
if (arr[end] !== '') break; |
|
} |
|
|
|
if (start > end) return []; |
|
return arr.slice(start, end - start + 1); |
|
} |
|
|
|
var fromParts = trim(from.split('/')); |
|
var toParts = trim(to.split('/')); |
|
|
|
var length = Math.min(fromParts.length, toParts.length); |
|
var samePartsLength = length; |
|
for (var i = 0; i < length; i++) { |
|
if (fromParts[i] !== toParts[i]) { |
|
samePartsLength = i; |
|
break; |
|
} |
|
} |
|
|
|
var outputParts = []; |
|
for (var i = samePartsLength; i < fromParts.length; i++) { |
|
outputParts.push('..'); |
|
} |
|
|
|
outputParts = outputParts.concat(toParts.slice(samePartsLength)); |
|
|
|
return outputParts.join('/'); |
|
}; |
|
|
|
exports.sep = '/'; |
|
exports.delimiter = ':'; |
|
|
|
exports.dirname = function(path) { |
|
var result = splitPath(path), |
|
root = result[0], |
|
dir = result[1]; |
|
|
|
if (!root && !dir) { |
|
// No dirname whatsoever |
|
return '.'; |
|
} |
|
|
|
if (dir) { |
|
// It has a dirname, strip trailing slash |
|
dir = dir.substr(0, dir.length - 1); |
|
} |
|
|
|
return root + dir; |
|
}; |
|
|
|
|
|
exports.basename = function(path, ext) { |
|
var f = splitPath(path)[2]; |
|
// TODO: make this comparison case-insensitive on windows? |
|
if (ext && f.substr(-1 * ext.length) === ext) { |
|
f = f.substr(0, f.length - ext.length); |
|
} |
|
return f; |
|
}; |
|
|
|
|
|
exports.extname = function(path) { |
|
return splitPath(path)[3]; |
|
}; |
|
|
|
function filter (xs, f) { |
|
if (xs.filter) return xs.filter(f); |
|
var res = []; |
|
for (var i = 0; i < xs.length; i++) { |
|
if (f(xs[i], i, xs)) res.push(xs[i]); |
|
} |
|
return res; |
|
} |
|
|
|
// String.prototype.substr - negative index don't work in IE8 |
|
var substr = 'ab'.substr(-1) === 'b' |
|
? function (str, start, len) { return str.substr(start, len) } |
|
: function (str, start, len) { |
|
if (start < 0) start = str.length + start; |
|
return str.substr(start, len); |
|
} |
|
; |
|
|
|
}).call(this,require('_process')) |
|
},{"_process":16}],16:[function(require,module,exports){ |
|
// shim for using process in browser |
|
|
|
var process = module.exports = {}; |
|
|
|
process.nextTick = (function () { |
|
var canSetImmediate = typeof window !== 'undefined' |
|
&& window.setImmediate; |
|
var canPost = typeof window !== 'undefined' |
|
&& window.postMessage && window.addEventListener |
|
; |
|
|
|
if (canSetImmediate) { |
|
return function (f) { return window.setImmediate(f) }; |
|
} |
|
|
|
if (canPost) { |
|
var queue = []; |
|
window.addEventListener('message', function (ev) { |
|
var source = ev.source; |
|
if ((source === window || source === null) && ev.data === 'process-tick') { |
|
ev.stopPropagation(); |
|
if (queue.length > 0) { |
|
var fn = queue.shift(); |
|
fn(); |
|
} |
|
} |
|
}, true); |
|
|
|
return function nextTick(fn) { |
|
queue.push(fn); |
|
window.postMessage('process-tick', '*'); |
|
}; |
|
} |
|
|
|
return function nextTick(fn) { |
|
setTimeout(fn, 0); |
|
}; |
|
})(); |
|
|
|
process.title = 'browser'; |
|
process.browser = true; |
|
process.env = {}; |
|
process.argv = []; |
|
|
|
function noop() {} |
|
|
|
process.on = noop; |
|
process.addListener = noop; |
|
process.once = noop; |
|
process.off = noop; |
|
process.removeListener = noop; |
|
process.removeAllListeners = noop; |
|
process.emit = noop; |
|
|
|
process.binding = function (name) { |
|
throw new Error('process.binding is not supported'); |
|
} |
|
|
|
// TODO(shtylman) |
|
process.cwd = function () { return '/' }; |
|
process.chdir = function (dir) { |
|
throw new Error('process.chdir is not supported'); |
|
}; |
|
|
|
},{}],17:[function(require,module,exports){ |
|
module.exports = require("./lib/_stream_duplex.js") |
|
|
|
},{"./lib/_stream_duplex.js":18}],18:[function(require,module,exports){ |
|
(function (process){ |
|
// Copyright Joyent, Inc. and other Node contributors. |
|
// |
|
// Permission is hereby granted, free of charge, to any person obtaining a |
|
// copy of this software and associated documentation files (the |
|
// "Software"), to deal in the Software without restriction, including |
|
// without limitation the rights to use, copy, modify, merge, publish, |
|
// distribute, sublicense, and/or sell copies of the Software, and to permit |
|
// persons to whom the Software is furnished to do so, subject to the |
|
// following conditions: |
|
// |
|
// The above copyright notice and this permission notice shall be included |
|
// in all copies or substantial portions of the Software. |
|
// |
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
|
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN |
|
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, |
|
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE |
|
// USE OR OTHER DEALINGS IN THE SOFTWARE. |
|
|
|
// a duplex stream is just a stream that is both readable and writable. |
|
// Since JS doesn't have multiple prototypal inheritance, this class |
|
// prototypally inherits from Readable, and then parasitically from |
|
// Writable. |
|
|
|
module.exports = Duplex; |
|
|
|
/*<replacement>*/ |
|
var objectKeys = Object.keys || function (obj) { |
|
var keys = []; |
|
for (var key in obj) keys.push(key); |
|
return keys; |
|
} |
|
/*</replacement>*/ |
|
|
|
|
|
/*<replacement>*/ |
|
var util = require('core-util-is'); |
|
util.inherits = require('inherits'); |
|
/*</replacement>*/ |
|
|
|
var Readable = require('./_stream_readable'); |
|
var Writable = require('./_stream_writable'); |
|
|
|
util.inherits(Duplex, Readable); |
|
|
|
forEach(objectKeys(Writable.prototype), function(method) { |
|
if (!Duplex.prototype[method]) |
|
Duplex.prototype[method] = Writable.prototype[method]; |
|
}); |
|
|
|
function Duplex(options) { |
|
if (!(this instanceof Duplex)) |
|
return new Duplex(options); |
|
|
|
Readable.call(this, options); |
|
Writable.call(this, options); |
|
|
|
if (options && options.readable === false) |
|
this.readable = false; |
|
|
|
if (options && options.writable === false) |
|
this.writable = false; |
|
|
|
this.allowHalfOpen = true; |
|
if (options && options.allowHalfOpen === false) |
|
this.allowHalfOpen = false; |
|
|
|
this.once('end', onend); |
|
} |
|
|
|
// the no-half-open enforcer |
|
function onend() { |
|
// if we allow half-open state, or if the writable side ended, |
|
// then we're ok. |
|
if (this.allowHalfOpen || this._writableState.ended) |
|
return; |
|
|
|
// no more data can be written. |
|
// But allow more writes to happen in this tick. |
|
process.nextTick(this.end.bind(this)); |
|
} |
|
|
|
function forEach (xs, f) { |
|
for (var i = 0, l = xs.length; i < l; i++) { |
|
f(xs[i], i); |
|
} |
|
} |
|
|
|
}).call(this,require('_process')) |
|
},{"./_stream_readable":20,"./_stream_writable":22,"_process":16,"core-util-is":23,"inherits":13}],19:[function(require,module,exports){ |
|
// Copyright Joyent, Inc. and other Node contributors. |
|
// |
|
// Permission is hereby granted, free of charge, to any person obtaining a |
|
// copy of this software and associated documentation files (the |
|
// "Software"), to deal in the Software without restriction, including |
|
// without limitation the rights to use, copy, modify, merge, publish, |
|
// distribute, sublicense, and/or sell copies of the Software, and to permit |
|
// persons to whom the Software is furnished to do so, subject to the |
|
// following conditions: |
|
// |
|
// The above copyright notice and this permission notice shall be included |
|
// in all copies or substantial portions of the Software. |
|
// |
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
|
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN |
|
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, |
|
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE |
|
// USE OR OTHER DEALINGS IN THE SOFTWARE. |
|
|
|
// a passthrough stream. |
|
// basically just the most minimal sort of Transform stream. |
|
// Every written chunk gets output as-is. |
|
|
|
module.exports = PassThrough; |
|
|
|
var Transform = require('./_stream_transform'); |
|
|
|
/*<replacement>*/ |
|
var util = require('core-util-is'); |
|
util.inherits = require('inherits'); |
|
/*</replacement>*/ |
|
|
|
util.inherits(PassThrough, Transform); |
|
|
|
function PassThrough(options) { |
|
if (!(this instanceof PassThrough)) |
|
return new PassThrough(options); |
|
|
|
Transform.call(this, options); |
|
} |
|
|
|
PassThrough.prototype._transform = function(chunk, encoding, cb) { |
|
cb(null, chunk); |
|
}; |
|
|
|
},{"./_stream_transform":21,"core-util-is":23,"inherits":13}],20:[function(require,module,exports){ |
|
(function (process){ |
|
// Copyright Joyent, Inc. and other Node contributors. |
|
// |
|
// Permission is hereby granted, free of charge, to any person obtaining a |
|
// copy of this software and associated documentation files (the |
|
// "Software"), to deal in the Software without restriction, including |
|
// without limitation the rights to use, copy, modify, merge, publish, |
|
// distribute, sublicense, and/or sell copies of the Software, and to permit |
|
// persons to whom the Software is furnished to do so, subject to the |
|
// following conditions: |
|
// |
|
// The above copyright notice and this permission notice shall be included |
|
// in all copies or substantial portions of the Software. |
|
// |
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
|
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN |
|
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, |
|
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE |
|
// USE OR OTHER DEALINGS IN THE SOFTWARE. |
|
|
|
module.exports = Readable; |
|
|
|
/*<replacement>*/ |
|
var isArray = require('isarray'); |
|
/*</replacement>*/ |
|
|
|
|
|
/*<replacement>*/ |
|
var Buffer = require('buffer').Buffer; |
|
/*</replacement>*/ |
|
|
|
Readable.ReadableState = ReadableState; |
|
|
|
var EE = require('events').EventEmitter; |
|
|
|
/*<replacement>*/ |
|
if (!EE.listenerCount) EE.listenerCount = function(emitter, type) { |
|
return emitter.listeners(type).length; |
|
}; |
|
/*</replacement>*/ |
|
|
|
var Stream = require('stream'); |
|
|
|
/*<replacement>*/ |
|
var util = require('core-util-is'); |
|
util.inherits = require('inherits'); |
|
/*</replacement>*/ |
|
|
|
var StringDecoder; |
|
|
|
util.inherits(Readable, Stream); |
|
|
|
function ReadableState(options, stream) { |
|
options = options || {}; |
|
|
|
// the point at which it stops calling _read() to fill the buffer |
|
// Note: 0 is a valid value, means "don't call _read preemptively ever" |
|
var hwm = options.highWaterMark; |
|
this.highWaterMark = (hwm || hwm === 0) ? hwm : 16 * 1024; |
|
|
|
// cast to ints. |
|
this.highWaterMark = ~~this.highWaterMark; |
|
|
|
this.buffer = []; |
|
this.length = 0; |
|
this.pipes = null; |
|
this.pipesCount = 0; |
|
this.flowing = false; |
|
this.ended = false; |
|
this.endEmitted = false; |
|
this.reading = false; |
|
|
|
// In streams that never have any data, and do push(null) right away, |
|
// the consumer can miss the 'end' event if they do some I/O before |
|
// consuming the stream. So, we don't emit('end') until some reading |
|
// happens. |
|
this.calledRead = false; |
|
|
|
// a flag to be able to tell if the onwrite cb is called immediately, |
|
// or on a later tick. We set this to true at first, becuase any |
|
// actions that shouldn't happen until "later" should generally also |
|
// not happen before the first write call. |
|
this.sync = true; |
|
|
|
// whenever we return null, then we set a flag to say |
|
// that we're awaiting a 'readable' event emission. |
|
this.needReadable = false; |
|
this.emittedReadable = false; |
|
this.readableListening = false; |
|
|
|
|
|
// object stream flag. Used to make read(n) ignore n and to |
|
// make all the buffer merging and length checks go away |
|
this.objectMode = !!options.objectMode; |
|
|
|
// Crypto is kind of old and crusty. Historically, its default string |
|
// encoding is 'binary' so we have to make this configurable. |
|
// Everything else in the universe uses 'utf8', though. |
|
this.defaultEncoding = options.defaultEncoding || 'utf8'; |
|
|
|
// when piping, we only care about 'readable' events that happen |
|
// after read()ing all the bytes and not getting any pushback. |
|
this.ranOut = false; |
|
|
|
// the number of writers that are awaiting a drain event in .pipe()s |
|
this.awaitDrain = 0; |
|
|
|
// if true, a maybeReadMore has been scheduled |
|
this.readingMore = false; |
|
|
|
this.decoder = null; |
|
this.encoding = null; |
|
if (options.encoding) { |
|
if (!StringDecoder) |
|
StringDecoder = require('string_decoder/').StringDecoder; |
|
this.decoder = new StringDecoder(options.encoding); |
|
this.encoding = options.encoding; |
|
} |
|
} |
|
|
|
function Readable(options) { |
|
if (!(this instanceof Readable)) |
|
return new Readable(options); |
|
|
|
this._readableState = new ReadableState(options, this); |
|
|
|
// legacy |
|
this.readable = true; |
|
|
|
Stream.call(this); |
|
} |
|
|
|
// Manually shove something into the read() buffer. |
|
// This returns true if the highWaterMark has not been hit yet, |
|
// similar to how Writable.write() returns true if you should |
|
// write() some more. |
|
Readable.prototype.push = function(chunk, encoding) { |
|
var state = this._readableState; |
|
|
|
if (typeof chunk === 'string' && !state.objectMode) { |
|
encoding = encoding || state.defaultEncoding; |
|
if (encoding !== state.encoding) { |
|
chunk = new Buffer(chunk, encoding); |
|
encoding = ''; |
|
} |
|
} |
|
|
|
return readableAddChunk(this, state, chunk, encoding, false); |
|
}; |
|
|
|
// Unshift should *always* be something directly out of read() |
|
Readable.prototype.unshift = function(chunk) { |
|
var state = this._readableState; |
|
return readableAddChunk(this, state, chunk, '', true); |
|
}; |
|
|
|
function readableAddChunk(stream, state, chunk, encoding, addToFront) { |
|
var er = chunkInvalid(state, chunk); |
|
if (er) { |
|
stream.emit('error', er); |
|
} else if (chunk === null || chunk === undefined) { |
|
state.reading = false; |
|
if (!state.ended) |
|
onEofChunk(stream, state); |
|
} else if (state.objectMode || chunk && chunk.length > 0) { |
|
if (state.ended && !addToFront) { |
|
var e = new Error('stream.push() after EOF'); |
|
stream.emit('error', e); |
|
} else if (state.endEmitted && addToFront) { |
|
var e = new Error('stream.unshift() after end event'); |
|
stream.emit('error', e); |
|
} else { |
|
if (state.decoder && !addToFront && !encoding) |
|
chunk = state.decoder.write(chunk); |
|
|
|
// update the buffer info. |
|
state.length += state.objectMode ? 1 : chunk.length; |
|
if (addToFront) { |
|
state.buffer.unshift(chunk); |
|
} else { |
|
state.reading = false; |
|
state.buffer.push(chunk); |
|
} |
|
|
|
if (state.needReadable) |
|
emitReadable(stream); |
|
|
|
maybeReadMore(stream, state); |
|
} |
|
} else if (!addToFront) { |
|
state.reading = false; |
|
} |
|
|
|
return needMoreData(state); |
|
} |
|
|
|
|
|
|
|
// if it's past the high water mark, we can push in some more. |
|
// Also, if we have no data yet, we can stand some |
|
// more bytes. This is to work around cases where hwm=0, |
|
// such as the repl. Also, if the push() triggered a |
|
// readable event, and the user called read(largeNumber) such that |
|
// needReadable was set, then we ought to push more, so that another |
|
// 'readable' event will be triggered. |
|
function needMoreData(state) { |
|
return !state.ended && |
|
(state.needReadable || |
|
state.length < state.highWaterMark || |
|
state.length === 0); |
|
} |
|
|
|
// backwards compatibility. |
|
Readable.prototype.setEncoding = function(enc) { |
|
if (!StringDecoder) |
|
StringDecoder = require('string_decoder/').StringDecoder; |
|
this._readableState.decoder = new StringDecoder(enc); |
|
this._readableState.encoding = enc; |
|
}; |
|
|
|
// Don't raise the hwm > 128MB |
|
var MAX_HWM = 0x800000; |
|
function roundUpToNextPowerOf2(n) { |
|
if (n >= MAX_HWM) { |
|
n = MAX_HWM; |
|
} else { |
|
// Get the next highest power of 2 |
|
n--; |
|
for (var p = 1; p < 32; p <<= 1) n |= n >> p; |
|
n++; |
|
} |
|
return n; |
|
} |
|
|
|
function howMuchToRead(n, state) { |
|
if (state.length === 0 && state.ended) |
|
return 0; |
|
|
|
if (state.objectMode) |
|
return n === 0 ? 0 : 1; |
|
|
|
if (isNaN(n) || n === null) { |
|
// only flow one buffer at a time |
|
if (state.flowing && state.buffer.length) |
|
return state.buffer[0].length; |
|
else |
|
return state.length; |
|
} |
|
|
|
if (n <= 0) |
|
return 0; |
|
|
|
// If we're asking for more than the target buffer level, |
|
// then raise the water mark. Bump up to the next highest |
|
// power of 2, to prevent increasing it excessively in tiny |
|
// amounts. |
|
if (n > state.highWaterMark) |
|
state.highWaterMark = roundUpToNextPowerOf2(n); |
|
|
|
// don't have that much. return null, unless we've ended. |
|
if (n > state.length) { |
|
if (!state.ended) { |
|
state.needReadable = true; |
|
return 0; |
|
} else |
|
return state.length; |
|
} |
|
|
|
return n; |
|
} |
|
|
|
// you can override either this method, or the async _read(n) below. |
|
Readable.prototype.read = function(n) { |
|
var state = this._readableState; |
|
state.calledRead = true; |
|
var nOrig = n; |
|
|
|
if (typeof n !== 'number' || n > 0) |
|
state.emittedReadable = false; |
|
|
|
// if we're doing read(0) to trigger a readable event, but we |
|
// already have a bunch of data in the buffer, then just trigger |
|
// the 'readable' event and move on. |
|
if (n === 0 && |
|
state.needReadable && |
|
(state.length >= state.highWaterMark || state.ended)) { |
|
emitReadable(this); |
|
return null; |
|
} |
|
|
|
n = howMuchToRead(n, state); |
|
|
|
// if we've ended, and we're now clear, then finish it up. |
|
if (n === 0 && state.ended) { |
|
if (state.length === 0) |
|
endReadable(this); |
|
return null; |
|
} |
|
|
|
// All the actual chunk generation logic needs to be |
|
// *below* the call to _read. The reason is that in certain |
|
// synthetic stream cases, such as passthrough streams, _read |
|
// may be a completely synchronous operation which may change |
|
// the state of the read buffer, providing enough data when |
|
// before there was *not* enough. |
|
// |
|
// So, the steps are: |
|
// 1. Figure out what the state of things will be after we do |
|
// a read from the buffer. |
|
// |
|
// 2. If that resulting state will trigger a _read, then call _read. |
|
// Note that this may be asynchronous, or synchronous. Yes, it is |
|
// deeply ugly to write APIs this way, but that still doesn't mean |
|
// that the Readable class should behave improperly, as streams are |
|
// designed to be sync/async agnostic. |
|
// Take note if the _read call is sync or async (ie, if the read call |
|
// has returned yet), so that we know whether or not it's safe to emit |
|
// 'readable' etc. |
|
// |
|
// 3. Actually pull the requested chunks out of the buffer and return. |
|
|
|
// if we need a readable event, then we need to do some reading. |
|
var doRead = state.needReadable; |
|
|
|
// if we currently have less than the highWaterMark, then also read some |
|
if (state.length - n <= state.highWaterMark) |
|
doRead = true; |
|
|
|
// however, if we've ended, then there's no point, and if we're already |
|
// reading, then it's unnecessary. |
|
if (state.ended || state.reading) |
|
doRead = false; |
|
|
|
if (doRead) { |
|
state.reading = true; |
|
state.sync = true; |
|
// if the length is currently zero, then we *need* a readable event. |
|
if (state.length === 0) |
|
state.needReadable = true; |
|
// call internal read method |
|
this._read(state.highWaterMark); |
|
state.sync = false; |
|
} |
|
|
|
// If _read called its callback synchronously, then `reading` |
|
// will be false, and we need to re-evaluate how much data we |
|
// can return to the user. |
|
if (doRead && !state.reading) |
|
n = howMuchToRead(nOrig, state); |
|
|
|
var ret; |
|
if (n > 0) |
|
ret = fromList(n, state); |
|
else |
|
ret = null; |
|
|
|
if (ret === null) { |
|
state.needReadable = true; |
|
n = 0; |
|
} |
|
|
|
state.length -= n; |
|
|
|
// If we have nothing in the buffer, then we want to know |
|
// as soon as we *do* get something into the buffer. |
|
if (state.length === 0 && !state.ended) |
|
state.needReadable = true; |
|
|
|
// If we happened to read() exactly the remaining amount in the |
|
// buffer, and the EOF has been seen at this point, then make sure |
|
// that we emit 'end' on the very next tick. |
|
if (state.ended && !state.endEmitted && state.length === 0) |
|
endReadable(this); |
|
|
|
return ret; |
|
}; |
|
|
|
function chunkInvalid(state, chunk) { |
|
var er = null; |
|
if (!Buffer.isBuffer(chunk) && |
|
'string' !== typeof chunk && |
|
chunk !== null && |
|
chunk !== undefined && |
|
!state.objectMode && |
|
!er) { |
|
er = new TypeError('Invalid non-string/buffer chunk'); |
|
} |
|
return er; |
|
} |
|
|
|
|
|
function onEofChunk(stream, state) { |
|
if (state.decoder && !state.ended) { |
|
var chunk = state.decoder.end(); |
|
if (chunk && chunk.length) { |
|
state.buffer.push(chunk); |
|
state.length += state.objectMode ? 1 : chunk.length; |
|
} |
|
} |
|
state.ended = true; |
|
|
|
// if we've ended and we have some data left, then emit |
|
// 'readable' now to make sure it gets picked up. |
|
if (state.length > 0) |
|
emitReadable(stream); |
|
else |
|
endReadable(stream); |
|
} |
|
|
|
// Don't emit readable right away in sync mode, because this can trigger |
|
// another read() call => stack overflow. This way, it might trigger |
|
// a nextTick recursion warning, but that's not so bad. |
|
function emitReadable(stream) { |
|
var state = stream._readableState; |
|
state.needReadable = false; |
|
if (state.emittedReadable) |
|
return; |
|
|
|
state.emittedReadable = true; |
|
if (state.sync) |
|
process.nextTick(function() { |
|
emitReadable_(stream); |
|
}); |
|
else |
|
emitReadable_(stream); |
|
} |
|
|
|
function emitReadable_(stream) { |
|
stream.emit('readable'); |
|
} |
|
|
|
|
|
// at this point, the user has presumably seen the 'readable' event, |
|
// and called read() to consume some data. that may have triggered |
|
// in turn another _read(n) call, in which case reading = true if |
|
// it's in progress. |
|
// However, if we're not ended, or reading, and the length < hwm, |
|
// then go ahead and try to read some more preemptively. |
|
function maybeReadMore(stream, state) { |
|
if (!state.readingMore) { |
|
state.readingMore = true; |
|
process.nextTick(function() { |
|
maybeReadMore_(stream, state); |
|
}); |
|
} |
|
} |
|
|
|
function maybeReadMore_(stream, state) { |
|
var len = state.length; |
|
while (!state.reading && !state.flowing && !state.ended && |
|
state.length < state.highWaterMark) { |
|
stream.read(0); |
|
if (len === state.length) |
|
// didn't get any data, stop spinning. |
|
break; |
|
else |
|
len = state.length; |
|
} |
|
state.readingMore = false; |
|
} |
|
|
|
// abstract method. to be overridden in specific implementation classes. |
|
// call cb(er, data) where data is <= n in length. |
|
// for virtual (non-string, non-buffer) streams, "length" is somewhat |
|
// arbitrary, and perhaps not very meaningful. |
|
Readable.prototype._read = function(n) { |
|
this.emit('error', new Error('not implemented')); |
|
}; |
|
|
|
Readable.prototype.pipe = function(dest, pipeOpts) { |
|
var src = this; |
|
var state = this._readableState; |
|
|
|
switch (state.pipesCount) { |
|
case 0: |
|
state.pipes = dest; |
|
break; |
|
case 1: |
|
state.pipes = [state.pipes, dest]; |
|
break; |
|
default: |
|
state.pipes.push(dest); |
|
break; |
|
} |
|
state.pipesCount += 1; |
|
|
|
var doEnd = (!pipeOpts || pipeOpts.end !== false) && |
|
dest !== process.stdout && |
|
dest !== process.stderr; |
|
|
|
var endFn = doEnd ? onend : cleanup; |
|
if (state.endEmitted) |
|
process.nextTick(endFn); |
|
else |
|
src.once('end', endFn); |
|
|
|
dest.on('unpipe', onunpipe); |
|
function onunpipe(readable) { |
|
if (readable !== src) return; |
|
cleanup(); |
|
} |
|
|
|
function onend() { |
|
dest.end(); |
|
} |
|
|
|
// when the dest drains, it reduces the awaitDrain counter |
|
// on the source. This would be more elegant with a .once() |
|
// handler in flow(), but adding and removing repeatedly is |
|
// too slow. |
|
var ondrain = pipeOnDrain(src); |
|
dest.on('drain', ondrain); |
|
|
|
function cleanup() { |
|
// cleanup event handlers once the pipe is broken |
|
dest.removeListener('close', onclose); |
|
dest.removeListener('finish', onfinish); |
|
dest.removeListener('drain', ondrain); |
|
dest.removeListener('error', onerror); |
|
dest.removeListener('unpipe', onunpipe); |
|
src.removeListener('end', onend); |
|
src.removeListener('end', cleanup); |
|
|
|
// if the reader is waiting for a drain event from this |
|
// specific writer, then it would cause it to never start |
|
// flowing again. |
|
// So, if this is awaiting a drain, then we just call it now. |
|
// If we don't know, then assume that we are waiting for one. |
|
if (!dest._writableState || dest._writableState.needDrain) |
|
ondrain(); |
|
} |
|
|
|
// if the dest has an error, then stop piping into it. |
|
// however, don't suppress the throwing behavior for this. |
|
function onerror(er) { |
|
unpipe(); |
|
dest.removeListener('error', onerror); |
|
if (EE.listenerCount(dest, 'error') === 0) |
|
dest.emit('error', er); |
|
} |
|
// This is a brutally ugly hack to make sure that our error handler |
|
// is attached before any userland ones. NEVER DO THIS. |
|
if (!dest._events || !dest._events.error) |
|
dest.on('error', onerror); |
|
else if (isArray(dest._events.error)) |
|
dest._events.error.unshift(onerror); |
|
else |
|
dest._events.error = [onerror, dest._events.error]; |
|
|
|
|
|
|
|
// Both close and finish should trigger unpipe, but only once. |
|
function onclose() { |
|
dest.removeListener('finish', onfinish); |
|
unpipe(); |
|
} |
|
dest.once('close', onclose); |
|
function onfinish() { |
|
dest.removeListener('close', onclose); |
|
unpipe(); |
|
} |
|
dest.once('finish', onfinish); |
|
|
|
function unpipe() { |
|
src.unpipe(dest); |
|
} |
|
|
|
// tell the dest that it's being piped to |
|
dest.emit('pipe', src); |
|
|
|
// start the flow if it hasn't been started already. |
|
if (!state.flowing) { |
|
// the handler that waits for readable events after all |
|
// the data gets sucked out in flow. |
|
// This would be easier to follow with a .once() handler |
|
// in flow(), but that is too slow. |
|
this.on('readable', pipeOnReadable); |
|
|
|
state.flowing = true; |
|
process.nextTick(function() { |
|
flow(src); |
|
}); |
|
} |
|
|
|
return dest; |
|
}; |
|
|
|
function pipeOnDrain(src) { |
|
return function() { |
|
var dest = this; |
|
var state = src._readableState; |
|
state.awaitDrain--; |
|
if (state.awaitDrain === 0) |
|
flow(src); |
|
}; |
|
} |
|
|
|
function flow(src) { |
|
var state = src._readableState; |
|
var chunk; |
|
state.awaitDrain = 0; |
|
|
|
function write(dest, i, list) { |
|
var written = dest.write(chunk); |
|
if (false === written) { |
|
state.awaitDrain++; |
|
} |
|
} |
|
|
|
while (state.pipesCount && null !== (chunk = src.read())) { |
|
|
|
if (state.pipesCount === 1) |
|
write(state.pipes, 0, null); |
|
else |
|
forEach(state.pipes, write); |
|
|
|
src.emit('data', chunk); |
|
|
|
// if anyone needs a drain, then we have to wait for that. |
|
if (state.awaitDrain > 0) |
|
return; |
|
} |
|
|
|
// if every destination was unpiped, either before entering this |
|
// function, or in the while loop, then stop flowing. |
|
// |
|
// NB: This is a pretty rare edge case. |
|
if (state.pipesCount === 0) { |
|
state.flowing = false; |
|
|
|
// if there were data event listeners added, then switch to old mode. |
|
if (EE.listenerCount(src, 'data') > 0) |
|
emitDataEvents(src); |
|
return; |
|
} |
|
|
|
// at this point, no one needed a drain, so we just ran out of data |
|
// on the next readable event, start it over again. |
|
state.ranOut = true; |
|
} |
|
|
|
function pipeOnReadable() { |
|
if (this._readableState.ranOut) { |
|
this._readableState.ranOut = false; |
|
flow(this); |
|
} |
|
} |
|
|
|
|
|
Readable.prototype.unpipe = function(dest) { |
|
var state = this._readableState; |
|
|
|
// if we're not piping anywhere, then do nothing. |
|
if (state.pipesCount === 0) |
|
return this; |
|
|
|
// just one destination. most common case. |
|
if (state.pipesCount === 1) { |
|
// passed in one, but it's not the right one. |
|
if (dest && dest !== state.pipes) |
|
return this; |
|
|
|
if (!dest) |
|
dest = state.pipes; |
|
|
|
// got a match. |
|
state.pipes = null; |
|
state.pipesCount = 0; |
|
this.removeListener('readable', pipeOnReadable); |
|
state.flowing = false; |
|
if (dest) |
|
dest.emit('unpipe', this); |
|
return this; |
|
} |
|
|
|
// slow case. multiple pipe destinations. |
|
|
|
if (!dest) { |
|
// remove all. |
|
var dests = state.pipes; |
|
var len = state.pipesCount; |
|
state.pipes = null; |
|
state.pipesCount = 0; |
|
this.removeListener('readable', pipeOnReadable); |
|
state.flowing = false; |
|
|
|
for (var i = 0; i < len; i++) |
|
dests[i].emit('unpipe', this); |
|
return this; |
|
} |
|
|
|
// try to find the right one. |
|
var i = indexOf(state.pipes, dest); |
|
if (i === -1) |
|
return this; |
|
|
|
state.pipes.splice(i, 1); |
|
state.pipesCount -= 1; |
|
if (state.pipesCount === 1) |
|
state.pipes = state.pipes[0]; |
|
|
|
dest.emit('unpipe', this); |
|
|
|
return this; |
|
}; |
|
|
|
// set up data events if they are asked for |
|
// Ensure readable listeners eventually get something |
|
Readable.prototype.on = function(ev, fn) { |
|
var res = Stream.prototype.on.call(this, ev, fn); |
|
|
|
if (ev === 'data' && !this._readableState.flowing) |
|
emitDataEvents(this); |
|
|
|
if (ev === 'readable' && this.readable) { |
|
var state = this._readableState; |
|
if (!state.readableListening) { |
|
state.readableListening = true; |
|
state.emittedReadable = false; |
|
state.needReadable = true; |
|
if (!state.reading) { |
|
this.read(0); |
|
} else if (state.length) { |
|
emitReadable(this, state); |
|
} |
|
} |
|
} |
|
|
|
return res; |
|
}; |
|
Readable.prototype.addListener = Readable.prototype.on; |
|
|
|
// pause() and resume() are remnants of the legacy readable stream API |
|
// If the user uses them, then switch into old mode. |
|
Readable.prototype.resume = function() { |
|
emitDataEvents(this); |
|
this.read(0); |
|
this.emit('resume'); |
|
}; |
|
|
|
Readable.prototype.pause = function() { |
|
emitDataEvents(this, true); |
|
this.emit('pause'); |
|
}; |
|
|
|
function emitDataEvents(stream, startPaused) { |
|
var state = stream._readableState; |
|
|
|
if (state.flowing) { |
|
// https://github.com/isaacs/readable-stream/issues/16 |
|
throw new Error('Cannot switch to old mode now.'); |
|
} |
|
|
|
var paused = startPaused || false; |
|
var readable = false; |
|
|
|
// convert to an old-style stream. |
|
stream.readable = true; |
|
stream.pipe = Stream.prototype.pipe; |
|
stream.on = stream.addListener = Stream.prototype.on; |
|
|
|
stream.on('readable', function() { |
|
readable = true; |
|
|
|
var c; |
|
while (!paused && (null !== (c = stream.read()))) |
|
stream.emit('data', c); |
|
|
|
if (c === null) { |
|
readable = false; |
|
stream._readableState.needReadable = true; |
|
} |
|
}); |
|
|
|
stream.pause = function() { |
|
paused = true; |
|
this.emit('pause'); |
|
}; |
|
|
|
stream.resume = function() { |
|
paused = false; |
|
if (readable) |
|
process.nextTick(function() { |
|
stream.emit('readable'); |
|
}); |
|
else |
|
this.read(0); |
|
this.emit('resume'); |
|
}; |
|
|
|
// now make it start, just in case it hadn't already. |
|
stream.emit('readable'); |
|
} |
|
|
|
// wrap an old-style stream as the async data source. |
|
// This is *not* part of the readable stream interface. |
|
// It is an ugly unfortunate mess of history. |
|
Readable.prototype.wrap = function(stream) { |
|
var state = this._readableState; |
|
var paused = false; |
|
|
|
var self = this; |
|
stream.on('end', function() { |
|
if (state.decoder && !state.ended) { |
|
var chunk = state.decoder.end(); |
|
if (chunk && chunk.length) |
|
self.push(chunk); |
|
} |
|
|
|
self.push(null); |
|
}); |
|
|
|
stream.on('data', function(chunk) { |
|
if (state.decoder) |
|
chunk = state.decoder.write(chunk); |
|
if (!chunk || !state.objectMode && !chunk.length) |
|
return; |
|
|
|
var ret = self.push(chunk); |
|
if (!ret) { |
|
paused = true; |
|
stream.pause(); |
|
} |
|
}); |
|
|
|
// proxy all the other methods. |
|
// important when wrapping filters and duplexes. |
|
for (var i in stream) { |
|
if (typeof stream[i] === 'function' && |
|
typeof this[i] === 'undefined') { |
|
this[i] = function(method) { return function() { |
|
return stream[method].apply(stream, arguments); |
|
}}(i); |
|
} |
|
} |
|
|
|
// proxy certain important events. |
|
var events = ['error', 'close', 'destroy', 'pause', 'resume']; |
|
forEach(events, function(ev) { |
|
stream.on(ev, self.emit.bind(self, ev)); |
|
}); |
|
|
|
// when we try to consume some more bytes, simply unpause the |
|
// underlying stream. |
|
self._read = function(n) { |
|
if (paused) { |
|
paused = false; |
|
stream.resume(); |
|
} |
|
}; |
|
|
|
return self; |
|
}; |
|
|
|
|
|
|
|
// exposed for testing purposes only. |
|
Readable._fromList = fromList; |
|
|
|
// Pluck off n bytes from an array of buffers. |
|
// Length is the combined lengths of all the buffers in the list. |
|
function fromList(n, state) { |
|
var list = state.buffer; |
|
var length = state.length; |
|
var stringMode = !!state.decoder; |
|
var objectMode = !!state.objectMode; |
|
var ret; |
|
|
|
// nothing in the list, definitely empty. |
|
if (list.length === 0) |
|
return null; |
|
|
|
if (length === 0) |
|
ret = null; |
|
else if (objectMode) |
|
ret = list.shift(); |
|
else if (!n || n >= length) { |
|
// read it all, truncate the array. |
|
if (stringMode) |
|
ret = list.join(''); |
|
else |
|
ret = Buffer.concat(list, length); |
|
list.length = 0; |
|
} else { |
|
// read just some of it. |
|
if (n < list[0].length) { |
|
// just take a part of the first list item. |
|
// slice is the same for buffers and strings. |
|
var buf = list[0]; |
|
ret = buf.slice(0, n); |
|
list[0] = buf.slice(n); |
|
} else if (n === list[0].length) { |
|
// first list is a perfect match |
|
ret = list.shift(); |
|
} else { |
|
// complex case. |
|
// we have enough to cover it, but it spans past the first buffer. |
|
if (stringMode) |
|
ret = ''; |
|
else |
|
ret = new Buffer(n); |
|
|
|
var c = 0; |
|
for (var i = 0, l = list.length; i < l && c < n; i++) { |
|
var buf = list[0]; |
|
var cpy = Math.min(n - c, buf.length); |
|
|
|
if (stringMode) |
|
ret += buf.slice(0, cpy); |
|
else |
|
buf.copy(ret, c, 0, cpy); |
|
|
|
if (cpy < buf.length) |
|
list[0] = buf.slice(cpy); |
|
else |
|
list.shift(); |
|
|
|
c += cpy; |
|
} |
|
} |
|
} |
|
|
|
return ret; |
|
} |
|
|
|
function endReadable(stream) { |
|
var state = stream._readableState; |
|
|
|
// If we get here before consuming all the bytes, then that is a |
|
// bug in node. Should never happen. |
|
if (state.length > 0) |
|
throw new Error('endReadable called on non-empty stream'); |
|
|
|
if (!state.endEmitted && state.calledRead) { |
|
state.ended = true; |
|
process.nextTick(function() { |
|
// Check that we didn't get one last unshift. |
|
if (!state.endEmitted && state.length === 0) { |
|
state.endEmitted = true; |
|
stream.readable = false; |
|
stream.emit('end'); |
|
} |
|
}); |
|
} |
|
} |
|
|
|
function forEach (xs, f) { |
|
for (var i = 0, l = xs.length; i < l; i++) { |
|
f(xs[i], i); |
|
} |
|
} |
|
|
|
function indexOf (xs, x) { |
|
for (var i = 0, l = xs.length; i < l; i++) { |
|
if (xs[i] === x) return i; |
|
} |
|
return -1; |
|
} |
|
|
|
}).call(this,require('_process')) |
|
},{"_process":16,"buffer":9,"core-util-is":23,"events":12,"inherits":13,"isarray":14,"stream":29,"string_decoder/":24}],21:[function(require,module,exports){ |
|
// Copyright Joyent, Inc. and other Node contributors. |
|
// |
|
// Permission is hereby granted, free of charge, to any person obtaining a |
|
// copy of this software and associated documentation files (the |
|
// "Software"), to deal in the Software without restriction, including |
|
// without limitation the rights to use, copy, modify, merge, publish, |
|
// distribute, sublicense, and/or sell copies of the Software, and to permit |
|
// persons to whom the Software is furnished to do so, subject to the |
|
// following conditions: |
|
// |
|
// The above copyright notice and this permission notice shall be included |
|
// in all copies or substantial portions of the Software. |
|
// |
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
|
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN |
|
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, |
|
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE |
|
// USE OR OTHER DEALINGS IN THE SOFTWARE. |
|
|
|
|
|
// a transform stream is a readable/writable stream where you do |
|
// something with the data. Sometimes it's called a "filter", |
|
// but that's not a great name for it, since that implies a thing where |
|
// some bits pass through, and others are simply ignored. (That would |
|
// be a valid example of a transform, of course.) |
|
// |
|
// While the output is causally related to the input, it's not a |
|
// necessarily symmetric or synchronous transformation. For example, |
|
// a zlib stream might take multiple plain-text writes(), and then |
|
// emit a single compressed chunk some time in the future. |
|
// |
|
// Here's how this works: |
|
// |
|
// The Transform stream has all the aspects of the readable and writable |
|
// stream classes. When you write(chunk), that calls _write(chunk,cb) |
|
// internally, and returns false if there's a lot of pending writes |
|
// buffered up. When you call read(), that calls _read(n) until |
|
// there's enough pending readable data buffered up. |
|
// |
|
// In a transform stream, the written data is placed in a buffer. When |
|
// _read(n) is called, it transforms the queued up data, calling the |
|
// buffered _write cb's as it consumes chunks. If consuming a single |
|
// written chunk would result in multiple output chunks, then the first |
|
// outputted bit calls the readcb, and subsequent chunks just go into |
|
// the read buffer, and will cause it to emit 'readable' if necessary. |
|
// |
|
// This way, back-pressure is actually determined by the reading side, |
|
// since _read has to be called to start processing a new chunk. However, |
|
// a pathological inflate type of transform can cause excessive buffering |
|
// here. For example, imagine a stream where every byte of input is |
|
// interpreted as an integer from 0-255, and then results in that many |
|
// bytes of output. Writing the 4 bytes {ff,ff,ff,ff} would result in |
|
// 1kb of data being output. In this case, you could write a very small |
|
// amount of input, and end up with a very large amount of output. In |
|
// such a pathological inflating mechanism, there'd be no way to tell |
|
// the system to stop doing the transform. A single 4MB write could |
|
// cause the system to run out of memory. |
|
// |
|
// However, even in such a pathological case, only a single written chunk |
|
// would be consumed, and then the rest would wait (un-transformed) until |
|
// the results of the previous transformed chunk were consumed. |
|
|
|
module.exports = Transform; |
|
|
|
var Duplex = require('./_stream_duplex'); |
|
|
|
/*<replacement>*/ |
|
var util = require('core-util-is'); |
|
util.inherits = require('inherits'); |
|
/*</replacement>*/ |
|
|
|
util.inherits(Transform, Duplex); |
|
|
|
|
|
function TransformState(options, stream) { |
|
this.afterTransform = function(er, data) { |
|
return afterTransform(stream, er, data); |
|
}; |
|
|
|
this.needTransform = false; |
|
this.transforming = false; |
|
this.writecb = null; |
|
this.writechunk = null; |
|
} |
|
|
|
function afterTransform(stream, er, data) { |
|
var ts = stream._transformState; |
|
ts.transforming = false; |
|
|
|
var cb = ts.writecb; |
|
|
|
if (!cb) |
|
return stream.emit('error', new Error('no writecb in Transform class')); |
|
|
|
ts.writechunk = null; |
|
ts.writecb = null; |
|
|
|
if (data !== null && data !== undefined) |
|
stream.push(data); |
|
|
|
if (cb) |
|
cb(er); |
|
|
|
var rs = stream._readableState; |
|
rs.reading = false; |
|
if (rs.needReadable || rs.length < rs.highWaterMark) { |
|
stream._read(rs.highWaterMark); |
|
} |
|
} |
|
|
|
|
|
function Transform(options) { |
|
if (!(this instanceof Transform)) |
|
return new Transform(options); |
|
|
|
Duplex.call(this, options); |
|
|
|
var ts = this._transformState = new TransformState(options, this); |
|
|
|
// when the writable side finishes, then flush out anything remaining. |
|
var stream = this; |
|
|
|
// start out asking for a readable event once data is transformed. |
|
this._readableState.needReadable = true; |
|
|
|
// we have implemented the _read method, and done the other things |
|
// that Readable wants before the first _read call, so unset the |
|
// sync guard flag. |
|
this._readableState.sync = false; |
|
|
|
this.once('finish', function() { |
|
if ('function' === typeof this._flush) |
|
this._flush(function(er) { |
|
done(stream, er); |
|
}); |
|
else |
|
done(stream); |
|
}); |
|
} |
|
|
|
Transform.prototype.push = function(chunk, encoding) { |
|
this._transformState.needTransform = false; |
|
return Duplex.prototype.push.call(this, chunk, encoding); |
|
}; |
|
|
|
// This is the part where you do stuff! |
|
// override this function in implementation classes. |
|
// 'chunk' is an input chunk. |
|
// |
|
// Call `push(newChunk)` to pass along transformed output |
|
// to the readable side. You may call 'push' zero or more times. |
|
// |
|
// Call `cb(err)` when you are done with this chunk. If you pass |
|
// an error, then that'll put the hurt on the whole operation. If you |
|
// never call cb(), then you'll never get another chunk. |
|
Transform.prototype._transform = function(chunk, encoding, cb) { |
|
throw new Error('not implemented'); |
|
}; |
|
|
|
Transform.prototype._write = function(chunk, encoding, cb) { |
|
var ts = this._transformState; |
|
ts.writecb = cb; |
|
ts.writechunk = chunk; |
|
ts.writeencoding = encoding; |
|
if (!ts.transforming) { |
|
var rs = this._readableState; |
|
if (ts.needTransform || |
|
rs.needReadable || |
|
rs.length < rs.highWaterMark) |
|
this._read(rs.highWaterMark); |
|
} |
|
}; |
|
|
|
// Doesn't matter what the args are here. |
|
// _transform does all the work. |
|
// That we got here means that the readable side wants more data. |
|
Transform.prototype._read = function(n) { |
|
var ts = this._transformState; |
|
|
|
if (ts.writechunk !== null && ts.writecb && !ts.transforming) { |
|
ts.transforming = true; |
|
this._transform(ts.writechunk, ts.writeencoding, ts.afterTransform); |
|
} else { |
|
// mark that we need a transform, so that any data that comes in |
|
// will get processed, now that we've asked for it. |
|
ts.needTransform = true; |
|
} |
|
}; |
|
|
|
|
|
function done(stream, er) { |
|
if (er) |
|
return stream.emit('error', er); |
|
|
|
// if there's nothing in the write buffer, then that means |
|
// that nothing more will ever be provided |
|
var ws = stream._writableState; |
|
var rs = stream._readableState; |
|
var ts = stream._transformState; |
|
|
|
if (ws.length) |
|
throw new Error('calling transform done when ws.length != 0'); |
|
|
|
if (ts.transforming) |
|
throw new Error('calling transform done when still transforming'); |
|
|
|
return stream.push(null); |
|
} |
|
|
|
},{"./_stream_duplex":18,"core-util-is":23,"inherits":13}],22:[function(require,module,exports){ |
|
(function (process){ |
|
// Copyright Joyent, Inc. and other Node contributors. |
|
// |
|
// Permission is hereby granted, free of charge, to any person obtaining a |
|
// copy of this software and associated documentation files (the |
|
// "Software"), to deal in the Software without restriction, including |
|
// without limitation the rights to use, copy, modify, merge, publish, |
|
// distribute, sublicense, and/or sell copies of the Software, and to permit |
|
// persons to whom the Software is furnished to do so, subject to the |
|
// following conditions: |
|
// |
|
// The above copyright notice and this permission notice shall be included |
|
// in all copies or substantial portions of the Software. |
|
// |
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
|
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN |
|
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, |
|
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE |
|
// USE OR OTHER DEALINGS IN THE SOFTWARE. |
|
|
|
// A bit simpler than readable streams. |
|
// Implement an async ._write(chunk, cb), and it'll handle all |
|
// the drain event emission and buffering. |
|
|
|
module.exports = Writable; |
|
|
|
/*<replacement>*/ |
|
var Buffer = require('buffer').Buffer; |
|
/*</replacement>*/ |
|
|
|
Writable.WritableState = WritableState; |
|
|
|
|
|
/*<replacement>*/ |
|
var util = require('core-util-is'); |
|
util.inherits = require('inherits'); |
|
/*</replacement>*/ |
|
|
|
|
|
var Stream = require('stream'); |
|
|
|
util.inherits(Writable, Stream); |
|
|
|
function WriteReq(chunk, encoding, cb) { |
|
this.chunk = chunk; |
|
this.encoding = encoding; |
|
this.callback = cb; |
|
} |
|
|
|
function WritableState(options, stream) { |
|
options = options || {}; |
|
|
|
// the point at which write() starts returning false |
|
// Note: 0 is a valid value, means that we always return false if |
|
// the entire buffer is not flushed immediately on write() |
|
var hwm = options.highWaterMark; |
|
this.highWaterMark = (hwm || hwm === 0) ? hwm : 16 * 1024; |
|
|
|
// object stream flag to indicate whether or not this stream |
|
// contains buffers or objects. |
|
this.objectMode = !!options.objectMode; |
|
|
|
// cast to ints. |
|
this.highWaterMark = ~~this.highWaterMark; |
|
|
|
this.needDrain = false; |
|
// at the start of calling end() |
|
this.ending = false; |
|
// when end() has been called, and returned |
|
this.ended = false; |
|
// when 'finish' is emitted |
|
this.finished = false; |
|
|
|
// should we decode strings into buffers before passing to _write? |
|
// this is here so that some node-core streams can optimize string |
|
// handling at a lower level. |
|
var noDecode = options.decodeStrings === false; |
|
this.decodeStrings = !noDecode; |
|
|
|
// Crypto is kind of old and crusty. Historically, its default string |
|
// encoding is 'binary' so we have to make this configurable. |
|
// Everything else in the universe uses 'utf8', though. |
|
this.defaultEncoding = options.defaultEncoding || 'utf8'; |
|
|
|
// not an actual buffer we keep track of, but a measurement |
|
// of how much we're waiting to get pushed to some underlying |
|
// socket or file. |
|
this.length = 0; |
|
|
|
// a flag to see when we're in the middle of a write. |
|
this.writing = false; |
|
|
|
// a flag to be able to tell if the onwrite cb is called immediately, |
|
// or on a later tick. We set this to true at first, becuase any |
|
// actions that shouldn't happen until "later" should generally also |
|
// not happen before the first write call. |
|
this.sync = true; |
|
|
|
// a flag to know if we're processing previously buffered items, which |
|
// may call the _write() callback in the same tick, so that we don't |
|
// end up in an overlapped onwrite situation. |
|
this.bufferProcessing = false; |
|
|
|
// the callback that's passed to _write(chunk,cb) |
|
this.onwrite = function(er) { |
|
onwrite(stream, er); |
|
}; |
|
|
|
// the callback that the user supplies to write(chunk,encoding,cb) |
|
this.writecb = null; |
|
|
|
// the amount that is being written when _write is called. |
|
this.writelen = 0; |
|
|
|
this.buffer = []; |
|
|
|
// True if the error was already emitted and should not be thrown again |
|
this.errorEmitted = false; |
|
} |
|
|
|
function Writable(options) { |
|
var Duplex = require('./_stream_duplex'); |
|
|
|
// Writable ctor is applied to Duplexes, though they're not |
|
// instanceof Writable, they're instanceof Readable. |
|
if (!(this instanceof Writable) && !(this instanceof Duplex)) |
|
return new Writable(options); |
|
|
|
this._writableState = new WritableState(options, this); |
|
|
|
// legacy. |
|
this.writable = true; |
|
|
|
Stream.call(this); |
|
} |
|
|
|
// Otherwise people can pipe Writable streams, which is just wrong. |
|
Writable.prototype.pipe = function() { |
|
this.emit('error', new Error('Cannot pipe. Not readable.')); |
|
}; |
|
|
|
|
|
function writeAfterEnd(stream, state, cb) { |
|
var er = new Error('write after end'); |
|
// TODO: defer error events consistently everywhere, not just the cb |
|
stream.emit('error', er); |
|
process.nextTick(function() { |
|
cb(er); |
|
}); |
|
} |
|
|
|
// If we get something that is not a buffer, string, null, or undefined, |
|
// and we're not in objectMode, then that's an error. |
|
// Otherwise stream chunks are all considered to be of length=1, and the |
|
// watermarks determine how many objects to keep in the buffer, rather than |
|
// how many bytes or characters. |
|
function validChunk(stream, state, chunk, cb) { |
|
var valid = true; |
|
if (!Buffer.isBuffer(chunk) && |
|
'string' !== typeof chunk && |
|
chunk !== null && |
|
chunk !== undefined && |
|
!state.objectMode) { |
|
var er = new TypeError('Invalid non-string/buffer chunk'); |
|
stream.emit('error', er); |
|
process.nextTick(function() { |
|
cb(er); |
|
}); |
|
valid = false; |
|
} |
|
return valid; |
|
} |
|
|
|
Writable.prototype.write = function(chunk, encoding, cb) { |
|
var state = this._writableState; |
|
var ret = false; |
|
|
|
if (typeof encoding === 'function') { |
|
cb = encoding; |
|
encoding = null; |
|
} |
|
|
|
if (Buffer.isBuffer(chunk)) |
|
encoding = 'buffer'; |
|
else if (!encoding) |
|
encoding = state.defaultEncoding; |
|
|
|
if (typeof cb !== 'function') |
|
cb = function() {}; |
|
|
|
if (state.ended) |
|
writeAfterEnd(this, state, cb); |
|
else if (validChunk(this, state, chunk, cb)) |
|
ret = writeOrBuffer(this, state, chunk, encoding, cb); |
|
|
|
return ret; |
|
}; |
|
|
|
function decodeChunk(state, chunk, encoding) { |
|
if (!state.objectMode && |
|
state.decodeStrings !== false && |
|
typeof chunk === 'string') { |
|
chunk = new Buffer(chunk, encoding); |
|
} |
|
return chunk; |
|
} |
|
|
|
// if we're already writing something, then just put this |
|
// in the queue, and wait our turn. Otherwise, call _write |
|
// If we return false, then we need a drain event, so set that flag. |
|
function writeOrBuffer(stream, state, chunk, encoding, cb) { |
|
chunk = decodeChunk(state, chunk, encoding); |
|
if (Buffer.isBuffer(chunk)) |
|
encoding = 'buffer'; |
|
var len = state.objectMode ? 1 : chunk.length; |
|
|
|
state.length += len; |
|
|
|
var ret = state.length < state.highWaterMark; |
|
// we must ensure that previous needDrain will not be reset to false. |
|
if (!ret) |
|
state.needDrain = true; |
|
|
|
if (state.writing) |
|
state.buffer.push(new WriteReq(chunk, encoding, cb)); |
|
else |
|
doWrite(stream, state, len, chunk, encoding, cb); |
|
|
|
return ret; |
|
} |
|
|
|
function doWrite(stream, state, len, chunk, encoding, cb) { |
|
state.writelen = len; |
|
state.writecb = cb; |
|
state.writing = true; |
|
state.sync = true; |
|
stream._write(chunk, encoding, state.onwrite); |
|
state.sync = false; |
|
} |
|
|
|
function onwriteError(stream, state, sync, er, cb) { |
|
if (sync) |
|
process.nextTick(function() { |
|
cb(er); |
|
}); |
|
else |
|
cb(er); |
|
|
|
stream._writableState.errorEmitted = true; |
|
stream.emit('error', er); |
|
} |
|
|
|
function onwriteStateUpdate(state) { |
|
state.writing = false; |
|
state.writecb = null; |
|
state.length -= state.writelen; |
|
state.writelen = 0; |
|
} |
|
|
|
function onwrite(stream, er) { |
|
var state = stream._writableState; |
|
var sync = state.sync; |
|
var cb = state.writecb; |
|
|
|
onwriteStateUpdate(state); |
|
|
|
if (er) |
|
onwriteError(stream, state, sync, er, cb); |
|
else { |
|
// Check if we're actually ready to finish, but don't emit yet |
|
var finished = needFinish(stream, state); |
|
|
|
if (!finished && !state.bufferProcessing && state.buffer.length) |
|
clearBuffer(stream, state); |
|
|
|
if (sync) { |
|
process.nextTick(function() { |
|
afterWrite(stream, state, finished, cb); |
|
}); |
|
} else { |
|
afterWrite(stream, state, finished, cb); |
|
} |
|
} |
|
} |
|
|
|
function afterWrite(stream, state, finished, cb) { |
|
if (!finished) |
|
onwriteDrain(stream, state); |
|
cb(); |
|
if (finished) |
|
finishMaybe(stream, state); |
|
} |
|
|
|
// Must force callback to be called on nextTick, so that we don't |
|
// emit 'drain' before the write() consumer gets the 'false' return |
|
// value, and has a chance to attach a 'drain' listener. |
|
function onwriteDrain(stream, state) { |
|
if (state.length === 0 && state.needDrain) { |
|
state.needDrain = false; |
|
stream.emit('drain'); |
|
} |
|
} |
|
|
|
|
|
// if there's something in the buffer waiting, then process it |
|
function clearBuffer(stream, state) { |
|
state.bufferProcessing = true; |
|
|
|
for (var c = 0; c < state.buffer.length; c++) { |
|
var entry = state.buffer[c]; |
|
var chunk = entry.chunk; |
|
var encoding = entry.encoding; |
|
var cb = entry.callback; |
|
var len = state.objectMode ? 1 : chunk.length; |
|
|
|
doWrite(stream, state, len, chunk, encoding, cb); |
|
|
|
// if we didn't call the onwrite immediately, then |
|
// it means that we need to wait until it does. |
|
// also, that means that the chunk and cb are currently |
|
// being processed, so move the buffer counter past them. |
|
if (state.writing) { |
|
c++; |
|
break; |
|
} |
|
} |
|
|
|
state.bufferProcessing = false; |
|
if (c < state.buffer.length) |
|
state.buffer = state.buffer.slice(c); |
|
else |
|
state.buffer.length = 0; |
|
} |
|
|
|
Writable.prototype._write = function(chunk, encoding, cb) { |
|
cb(new Error('not implemented')); |
|
}; |
|
|
|
Writable.prototype.end = function(chunk, encoding, cb) { |
|
var state = this._writableState; |
|
|
|
if (typeof chunk === 'function') { |
|
cb = chunk; |
|
chunk = null; |
|
encoding = null; |
|
} else if (typeof encoding === 'function') { |
|
cb = encoding; |
|
encoding = null; |
|
} |
|
|
|
if (typeof chunk !== 'undefined' && chunk !== null) |
|
this.write(chunk, encoding); |
|
|
|
// ignore unnecessary end() calls. |
|
if (!state.ending && !state.finished) |
|
endWritable(this, state, cb); |
|
}; |
|
|
|
|
|
function needFinish(stream, state) { |
|
return (state.ending && |
|
state.length === 0 && |
|
!state.finished && |
|
!state.writing); |
|
} |
|
|
|
function finishMaybe(stream, state) { |
|
var need = needFinish(stream, state); |
|
if (need) { |
|
state.finished = true; |
|
stream.emit('finish'); |
|
} |
|
return need; |
|
} |
|
|
|
function endWritable(stream, state, cb) { |
|
state.ending = true; |
|
finishMaybe(stream, state); |
|
if (cb) { |
|
if (state.finished) |
|
process.nextTick(cb); |
|
else |
|
stream.once('finish', cb); |
|
} |
|
state.ended = true; |
|
} |
|
|
|
}).call(this,require('_process')) |
|
},{"./_stream_duplex":18,"_process":16,"buffer":9,"core-util-is":23,"inherits":13,"stream":29}],23:[function(require,module,exports){ |
|
(function (Buffer){ |
|
// Copyright Joyent, Inc. and other Node contributors. |
|
// |
|
// Permission is hereby granted, free of charge, to any person obtaining a |
|
// copy of this software and associated documentation files (the |
|
// "Software"), to deal in the Software without restriction, including |
|
// without limitation the rights to use, copy, modify, merge, publish, |
|
// distribute, sublicense, and/or sell copies of the Software, and to permit |
|
// persons to whom the Software is furnished to do so, subject to the |
|
// following conditions: |
|
// |
|
// The above copyright notice and this permission notice shall be included |
|
// in all copies or substantial portions of the Software. |
|
// |
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
|
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN |
|
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, |
|
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE |
|
// USE OR OTHER DEALINGS IN THE SOFTWARE. |
|
|
|
// NOTE: These type checking functions intentionally don't use `instanceof` |
|
// because it is fragile and can be easily faked with `Object.create()`. |
|
function isArray(ar) { |
|
return Array.isArray(ar); |
|
} |
|
exports.isArray = isArray; |
|
|
|
function isBoolean(arg) { |
|
return typeof arg === 'boolean'; |
|
} |
|
exports.isBoolean = isBoolean; |
|
|
|
function isNull(arg) { |
|
return arg === null; |
|
} |
|
exports.isNull = isNull; |
|
|
|
function isNullOrUndefined(arg) { |
|
return arg == null; |
|
} |
|
exports.isNullOrUndefined = isNullOrUndefined; |
|
|
|
function isNumber(arg) { |
|
return typeof arg === 'number'; |
|
} |
|
exports.isNumber = isNumber; |
|
|
|
function isString(arg) { |
|
return typeof arg === 'string'; |
|
} |
|
exports.isString = isString; |
|
|
|
function isSymbol(arg) { |
|
return typeof arg === 'symbol'; |
|
} |
|
exports.isSymbol = isSymbol; |
|
|
|
function isUndefined(arg) { |
|
return arg === void 0; |
|
} |
|
exports.isUndefined = isUndefined; |
|
|
|
function isRegExp(re) { |
|
return isObject(re) && objectToString(re) === '[object RegExp]'; |
|
} |
|
exports.isRegExp = isRegExp; |
|
|
|
function isObject(arg) { |
|
return typeof arg === 'object' && arg !== null; |
|
} |
|
exports.isObject = isObject; |
|
|
|
function isDate(d) { |
|
return isObject(d) && objectToString(d) === '[object Date]'; |
|
} |
|
exports.isDate = isDate; |
|
|
|
function isError(e) { |
|
return isObject(e) && |
|
(objectToString(e) === '[object Error]' || e instanceof Error); |
|
} |
|
exports.isError = isError; |
|
|
|
function isFunction(arg) { |
|
return typeof arg === 'function'; |
|
} |
|
exports.isFunction = isFunction; |
|
|
|
function isPrimitive(arg) { |
|
return arg === null || |
|
typeof arg === 'boolean' || |
|
typeof arg === 'number' || |
|
typeof arg === 'string' || |
|
typeof arg === 'symbol' || // ES6 symbol |
|
typeof arg === 'undefined'; |
|
} |
|
exports.isPrimitive = isPrimitive; |
|
|
|
function isBuffer(arg) { |
|
return Buffer.isBuffer(arg); |
|
} |
|
exports.isBuffer = isBuffer; |
|
|
|
function objectToString(o) { |
|
return Object.prototype.toString.call(o); |
|
} |
|
}).call(this,require("buffer").Buffer) |
|
},{"buffer":9}],24:[function(require,module,exports){ |
|
// Copyright Joyent, Inc. and other Node contributors. |
|
// |
|
// Permission is hereby granted, free of charge, to any person obtaining a |
|
// copy of this software and associated documentation files (the |
|
// "Software"), to deal in the Software without restriction, including |
|
// without limitation the rights to use, copy, modify, merge, publish, |
|
// distribute, sublicense, and/or sell copies of the Software, and to permit |
|
// persons to whom the Software is furnished to do so, subject to the |
|
// following conditions: |
|
// |
|
// The above copyright notice and this permission notice shall be included |
|
// in all copies or substantial portions of the Software. |
|
// |
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
|
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN |
|
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, |
|
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE |
|
// USE OR OTHER DEALINGS IN THE SOFTWARE. |
|
|
|
var Buffer = require('buffer').Buffer; |
|
|
|
var isBufferEncoding = Buffer.isEncoding |
|
|| function(encoding) { |
|
switch (encoding && encoding.toLowerCase()) { |
|
case 'hex': case 'utf8': case 'utf-8': case 'ascii': case 'binary': case 'base64': case 'ucs2': case 'ucs-2': case 'utf16le': case 'utf-16le': case 'raw': return true; |
|
default: return false; |
|
} |
|
} |
|
|
|
|
|
function assertEncoding(encoding) { |
|
if (encoding && !isBufferEncoding(encoding)) { |
|
throw new Error('Unknown encoding: ' + encoding); |
|
} |
|
} |
|
|
|
var StringDecoder = exports.StringDecoder = function(encoding) { |
|
this.encoding = (encoding || 'utf8').toLowerCase().replace(/[-_]/, ''); |
|
assertEncoding(encoding); |
|
switch (this.encoding) { |
|
case 'utf8': |
|
// CESU-8 represents each of Surrogate Pair by 3-bytes |
|
this.surrogateSize = 3; |
|
break; |
|
case 'ucs2': |
|
case 'utf16le': |
|
// UTF-16 represents each of Surrogate Pair by 2-bytes |
|
this.surrogateSize = 2; |
|
this.detectIncompleteChar = utf16DetectIncompleteChar; |
|
break; |
|
case 'base64': |
|
// Base-64 stores 3 bytes in 4 chars, and pads the remainder. |
|
this.surrogateSize = 3; |
|
this.detectIncompleteChar = base64DetectIncompleteChar; |
|
break; |
|
default: |
|
this.write = passThroughWrite; |
|
return; |
|
} |
|
|
|
this.charBuffer = new Buffer(6); |
|
this.charReceived = 0; |
|
this.charLength = 0; |
|
}; |
|
|
|
|
|
StringDecoder.prototype.write = function(buffer) { |
|
var charStr = ''; |
|
var offset = 0; |
|
|
|
// if our last write ended with an incomplete multibyte character |
|
while (this.charLength) { |
|
// determine how many remaining bytes this buffer has to offer for this char |
|
var i = (buffer.length >= this.charLength - this.charReceived) ? |
|
this.charLength - this.charReceived : |
|
buffer.length; |
|
|
|
// add the new bytes to the char buffer |
|
buffer.copy(this.charBuffer, this.charReceived, offset, i); |
|
this.charReceived += (i - offset); |
|
offset = i; |
|
|
|
if (this.charReceived < this.charLength) { |
|
// still not enough chars in this buffer? wait for more ... |
|
return ''; |
|
} |
|
|
|
// get the character that was split |
|
charStr = this.charBuffer.slice(0, this.charLength).toString(this.encoding); |
|
|
|
// lead surrogate (D800-DBFF) is also the incomplete character |
|
var charCode = charStr.charCodeAt(charStr.length - 1); |
|
if (charCode >= 0xD800 && charCode <= 0xDBFF) { |
|
this.charLength += this.surrogateSize; |
|
charStr = ''; |
|
continue; |
|
} |
|
this.charReceived = this.charLength = 0; |
|
|
|
// if there are no more bytes in this buffer, just emit our char |
|
if (i == buffer.length) return charStr; |
|
|
|
// otherwise cut off the characters end from the beginning of this buffer |
|
buffer = buffer.slice(i, buffer.length); |
|
break; |
|
} |
|
|
|
var lenIncomplete = this.detectIncompleteChar(buffer); |
|
|
|
var end = buffer.length; |
|
if (this.charLength) { |
|
// buffer the incomplete character bytes we got |
|
buffer.copy(this.charBuffer, 0, buffer.length - lenIncomplete, end); |
|
this.charReceived = lenIncomplete; |
|
end -= lenIncomplete; |
|
} |
|
|
|
charStr += buffer.toString(this.encoding, 0, end); |
|
|
|
var end = charStr.length - 1; |
|
var charCode = charStr.charCodeAt(end); |
|
// lead surrogate (D800-DBFF) is also the incomplete character |
|
if (charCode >= 0xD800 && charCode <= 0xDBFF) { |
|
var size = this.surrogateSize; |
|
this.charLength += size; |
|
this.charReceived += size; |
|
this.charBuffer.copy(this.charBuffer, size, 0, size); |
|
this.charBuffer.write(charStr.charAt(charStr.length - 1), this.encoding); |
|
return charStr.substring(0, end); |
|
} |
|
|
|
// or just emit the charStr |
|
return charStr; |
|
}; |
|
|
|
StringDecoder.prototype.detectIncompleteChar = function(buffer) { |
|
// determine how many bytes we have to check at the end of this buffer |
|
var i = (buffer.length >= 3) ? 3 : buffer.length; |
|
|
|
// Figure out if one of the last i bytes of our buffer announces an |
|
// incomplete char. |
|
for (; i > 0; i--) { |
|
var c = buffer[buffer.length - i]; |
|
|
|
// See http://en.wikipedia.org/wiki/UTF-8#Description |
|
|
|
// 110XXXXX |
|
if (i == 1 && c >> 5 == 0x06) { |
|
this.charLength = 2; |
|
break; |
|
} |
|
|
|
// 1110XXXX |
|
if (i <= 2 && c >> 4 == 0x0E) { |
|
this.charLength = 3; |
|
break; |
|
} |
|
|
|
// 11110XXX |
|
if (i <= 3 && c >> 3 == 0x1E) { |
|
this.charLength = 4; |
|
break; |
|
} |
|
} |
|
|
|
return i; |
|
}; |
|
|
|
StringDecoder.prototype.end = function(buffer) { |
|
var res = ''; |
|
if (buffer && buffer.length) |
|
res = this.write(buffer); |
|
|
|
if (this.charReceived) { |
|
var cr = this.charReceived; |
|
var buf = this.charBuffer; |
|
var enc = this.encoding; |
|
res += buf.slice(0, cr).toString(enc); |
|
} |
|
|
|
return res; |
|
}; |
|
|
|
function passThroughWrite(buffer) { |
|
return buffer.toString(this.encoding); |
|
} |
|
|
|
function utf16DetectIncompleteChar(buffer) { |
|
var incomplete = this.charReceived = buffer.length % 2; |
|
this.charLength = incomplete ? 2 : 0; |
|
return incomplete; |
|
} |
|
|
|
function base64DetectIncompleteChar(buffer) { |
|
var incomplete = this.charReceived = buffer.length % 3; |
|
this.charLength = incomplete ? 3 : 0; |
|
return incomplete; |
|
} |
|
|
|
},{"buffer":9}],25:[function(require,module,exports){ |
|
module.exports = require("./lib/_stream_passthrough.js") |
|
|
|
},{"./lib/_stream_passthrough.js":19}],26:[function(require,module,exports){ |
|
exports = module.exports = require('./lib/_stream_readable.js'); |
|
exports.Readable = exports; |
|
exports.Writable = require('./lib/_stream_writable.js'); |
|
exports.Duplex = require('./lib/_stream_duplex.js'); |
|
exports.Transform = require('./lib/_stream_transform.js'); |
|
exports.PassThrough = require('./lib/_stream_passthrough.js'); |
|
|
|
},{"./lib/_stream_duplex.js":18,"./lib/_stream_passthrough.js":19,"./lib/_stream_readable.js":20,"./lib/_stream_transform.js":21,"./lib/_stream_writable.js":22}],27:[function(require,module,exports){ |
|
module.exports = require("./lib/_stream_transform.js") |
|
|
|
},{"./lib/_stream_transform.js":21}],28:[function(require,module,exports){ |
|
module.exports = require("./lib/_stream_writable.js") |
|
|
|
},{"./lib/_stream_writable.js":22}],29:[function(require,module,exports){ |
|
// Copyright Joyent, Inc. and other Node contributors. |
|
// |
|
// Permission is hereby granted, free of charge, to any person obtaining a |
|
// copy of this software and associated documentation files (the |
|
// "Software"), to deal in the Software without restriction, including |
|
// without limitation the rights to use, copy, modify, merge, publish, |
|
// distribute, sublicense, and/or sell copies of the Software, and to permit |
|
// persons to whom the Software is furnished to do so, subject to the |
|
// following conditions: |
|
// |
|
// The above copyright notice and this permission notice shall be included |
|
// in all copies or substantial portions of the Software. |
|
// |
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
|
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN |
|
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, |
|
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE |
|
// USE OR OTHER DEALINGS IN THE SOFTWARE. |
|
|
|
module.exports = Stream; |
|
|
|
var EE = require('events').EventEmitter; |
|
var inherits = require('inherits'); |
|
|
|
inherits(Stream, EE); |
|
Stream.Readable = require('readable-stream/readable.js'); |
|
Stream.Writable = require('readable-stream/writable.js'); |
|
Stream.Duplex = require('readable-stream/duplex.js'); |
|
Stream.Transform = require('readable-stream/transform.js'); |
|
Stream.PassThrough = require('readable-stream/passthrough.js'); |
|
|
|
// Backwards-compat with node 0.4.x |
|
Stream.Stream = Stream; |
|
|
|
|
|
|
|
// old-style streams. Note that the pipe method (the only relevant |
|
// part of this class) is overridden in the Readable class. |
|
|
|
function Stream() { |
|
EE.call(this); |
|
} |
|
|
|
Stream.prototype.pipe = function(dest, options) { |
|
var source = this; |
|
|
|
function ondata(chunk) { |
|
if (dest.writable) { |
|
if (false === dest.write(chunk) && source.pause) { |
|
source.pause(); |
|
} |
|
} |
|
} |
|
|
|
source.on('data', ondata); |
|
|
|
function ondrain() { |
|
if (source.readable && source.resume) { |
|
source.resume(); |
|
} |
|
} |
|
|
|
dest.on('drain', ondrain); |
|
|
|
// If the 'end' option is not supplied, dest.end() will be called when |
|
// source gets the 'end' or 'close' events. Only dest.end() once. |
|
if (!dest._isStdio && (!options || options.end !== false)) { |
|
source.on('end', onend); |
|
source.on('close', onclose); |
|
} |
|
|
|
var didOnEnd = false; |
|
function onend() { |
|
if (didOnEnd) return; |
|
didOnEnd = true; |
|
|
|
dest.end(); |
|
} |
|
|
|
|
|
function onclose() { |
|
if (didOnEnd) return; |
|
didOnEnd = true; |
|
|
|
if (typeof dest.destroy === 'function') dest.destroy(); |
|
} |
|
|
|
// don't leave dangling pipes when there are errors. |
|
function onerror(er) { |
|
cleanup(); |
|
if (EE.listenerCount(this, 'error') === 0) { |
|
throw er; // Unhandled stream error in pipe. |
|
} |
|
} |
|
|
|
source.on('error', onerror); |
|
dest.on('error', onerror); |
|
|
|
// remove all the event listeners that were added. |
|
function cleanup() { |
|
source.removeListener('data', ondata); |
|
dest.removeListener('drain', ondrain); |
|
|
|
source.removeListener('end', onend); |
|
source.removeListener('close', onclose); |
|
|
|
source.removeListener('error', onerror); |
|
dest.removeListener('error', onerror); |
|
|
|
source.removeListener('end', cleanup); |
|
source.removeListener('close', cleanup); |
|
|
|
dest.removeListener('close', cleanup); |
|
} |
|
|
|
source.on('end', cleanup); |
|
source.on('close', cleanup); |
|
|
|
dest.on('close', cleanup); |
|
|
|
dest.emit('pipe', source); |
|
|
|
// Allow for unix-like usage: A.pipe(B).pipe(C) |
|
return dest; |
|
}; |
|
|
|
},{"events":12,"inherits":13,"readable-stream/duplex.js":17,"readable-stream/passthrough.js":25,"readable-stream/readable.js":26,"readable-stream/transform.js":27,"readable-stream/writable.js":28}],30:[function(require,module,exports){ |
|
// Copyright Joyent, Inc. and other Node contributors. |
|
// |
|
// Permission is hereby granted, free of charge, to any person obtaining a |
|
// copy of this software and associated documentation files (the |
|
// "Software"), to deal in the Software without restriction, including |
|
// without limitation the rights to use, copy, modify, merge, publish, |
|
// distribute, sublicense, and/or sell copies of the Software, and to permit |
|
// persons to whom the Software is furnished to do so, subject to the |
|
// following conditions: |
|
// |
|
// The above copyright notice and this permission notice shall be included |
|
// in all copies or substantial portions of the Software. |
|
// |
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
|
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN |
|
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, |
|
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE |
|
// USE OR OTHER DEALINGS IN THE SOFTWARE. |
|
|
|
var Buffer = require('buffer').Buffer; |
|
|
|
function assertEncoding(encoding) { |
|
if (encoding && !Buffer.isEncoding(encoding)) { |
|
throw new Error('Unknown encoding: ' + encoding); |
|
} |
|
} |
|
|
|
var StringDecoder = exports.StringDecoder = function(encoding) { |
|
this.encoding = (encoding || 'utf8').toLowerCase().replace(/[-_]/, ''); |
|
assertEncoding(encoding); |
|
switch (this.encoding) { |
|
case 'utf8': |
|
// CESU-8 represents each of Surrogate Pair by 3-bytes |
|
this.surrogateSize = 3; |
|
break; |
|
case 'ucs2': |
|
case 'utf16le': |
|
// UTF-16 represents each of Surrogate Pair by 2-bytes |
|
this.surrogateSize = 2; |
|
this.detectIncompleteChar = utf16DetectIncompleteChar; |
|
break; |
|
case 'base64': |
|
// Base-64 stores 3 bytes in 4 chars, and pads the remainder. |
|
this.surrogateSize = 3; |
|
this.detectIncompleteChar = base64DetectIncompleteChar; |
|
break; |
|
default: |
|
this.write = passThroughWrite; |
|
return; |
|
} |
|
|
|
this.charBuffer = new Buffer(6); |
|
this.charReceived = 0; |
|
this.charLength = 0; |
|
}; |
|
|
|
|
|
StringDecoder.prototype.write = function(buffer) { |
|
var charStr = ''; |
|
var offset = 0; |
|
|
|
// if our last write ended with an incomplete multibyte character |
|
while (this.charLength) { |
|
// determine how many remaining bytes this buffer has to offer for this char |
|
var i = (buffer.length >= this.charLength - this.charReceived) ? |
|
this.charLength - this.charReceived : |
|
buffer.length; |
|
|
|
// add the new bytes to the char buffer |
|
buffer.copy(this.charBuffer, this.charReceived, offset, i); |
|
this.charReceived += (i - offset); |
|
offset = i; |
|
|
|
if (this.charReceived < this.charLength) { |
|
// still not enough chars in this buffer? wait for more ... |
|
return ''; |
|
} |
|
|
|
// get the character that was split |
|
charStr = this.charBuffer.slice(0, this.charLength).toString(this.encoding); |
|
|
|
// lead surrogate (D800-DBFF) is also the incomplete character |
|
var charCode = charStr.charCodeAt(charStr.length - 1); |
|
if (charCode >= 0xD800 && charCode <= 0xDBFF) { |
|
this.charLength += this.surrogateSize; |
|
charStr = ''; |
|
continue; |
|
} |
|
this.charReceived = this.charLength = 0; |
|
|
|
// if there are no more bytes in this buffer, just emit our char |
|
if (i == buffer.length) return charStr; |
|
|
|
// otherwise cut off the characters end from the beginning of this buffer |
|
buffer = buffer.slice(i, buffer.length); |
|
break; |
|
} |
|
|
|
var lenIncomplete = this.detectIncompleteChar(buffer); |
|
|
|
var end = buffer.length; |
|
if (this.charLength) { |
|
// buffer the incomplete character bytes we got |
|
buffer.copy(this.charBuffer, 0, buffer.length - lenIncomplete, end); |
|
this.charReceived = lenIncomplete; |
|
end -= lenIncomplete; |
|
} |
|
|
|
charStr += buffer.toString(this.encoding, 0, end); |
|
|
|
var end = charStr.length - 1; |
|
var charCode = charStr.charCodeAt(end); |
|
// lead surrogate (D800-DBFF) is also the incomplete character |
|
if (charCode >= 0xD800 && charCode <= 0xDBFF) { |
|
var size = this.surrogateSize; |
|
this.charLength += size; |
|
this.charReceived += size; |
|
this.charBuffer.copy(this.charBuffer, size, 0, size); |
|
this.charBuffer.write(charStr.charAt(charStr.length - 1), this.encoding); |
|
return charStr.substring(0, end); |
|
} |
|
|
|
// or just emit the charStr |
|
return charStr; |
|
}; |
|
|
|
StringDecoder.prototype.detectIncompleteChar = function(buffer) { |
|
// determine how many bytes we have to check at the end of this buffer |
|
var i = (buffer.length >= 3) ? 3 : buffer.length; |
|
|
|
// Figure out if one of the last i bytes of our buffer announces an |
|
// incomplete char. |
|
for (; i > 0; i--) { |
|
var c = buffer[buffer.length - i]; |
|
|
|
// See http://en.wikipedia.org/wiki/UTF-8#Description |
|
|
|
// 110XXXXX |
|
if (i == 1 && c >> 5 == 0x06) { |
|
this.charLength = 2; |
|
break; |
|
} |
|
|
|
// 1110XXXX |
|
if (i <= 2 && c >> 4 == 0x0E) { |
|
this.charLength = 3; |
|
break; |
|
} |
|
|
|
// 11110XXX |
|
if (i <= 3 && c >> 3 == 0x1E) { |
|
this.charLength = 4; |
|
break; |
|
} |
|
} |
|
|
|
return i; |
|
}; |
|
|
|
StringDecoder.prototype.end = function(buffer) { |
|
var res = ''; |
|
if (buffer && buffer.length) |
|
res = this.write(buffer); |
|
|
|
if (this.charReceived) { |
|
var cr = this.charReceived; |
|
var buf = this.charBuffer; |
|
var enc = this.encoding; |
|
res += buf.slice(0, cr).toString(enc); |
|
} |
|
|
|
return res; |
|
}; |
|
|
|
function passThroughWrite(buffer) { |
|
return buffer.toString(this.encoding); |
|
} |
|
|
|
function utf16DetectIncompleteChar(buffer) { |
|
var incomplete = this.charReceived = buffer.length % 2; |
|
this.charLength = incomplete ? 2 : 0; |
|
return incomplete; |
|
} |
|
|
|
function base64DetectIncompleteChar(buffer) { |
|
var incomplete = this.charReceived = buffer.length % 3; |
|
this.charLength = incomplete ? 3 : 0; |
|
return incomplete; |
|
} |
|
|
|
},{"buffer":9}],31:[function(require,module,exports){ |
|
module.exports = function isBuffer(arg) { |
|
return arg && typeof arg === 'object' |
|
&& typeof arg.copy === 'function' |
|
&& typeof arg.fill === 'function' |
|
&& typeof arg.readUInt8 === 'function'; |
|
} |
|
},{}],32:[function(require,module,exports){ |
|
(function (process,global){ |
|
// Copyright Joyent, Inc. and other Node contributors. |
|
// |
|
// Permission is hereby granted, free of charge, to any person obtaining a |
|
// copy of this software and associated documentation files (the |
|
// "Software"), to deal in the Software without restriction, including |
|
// without limitation the rights to use, copy, modify, merge, publish, |
|
// distribute, sublicense, and/or sell copies of the Software, and to permit |
|
// persons to whom the Software is furnished to do so, subject to the |
|
// following conditions: |
|
// |
|
// The above copyright notice and this permission notice shall be included |
|
// in all copies or substantial portions of the Software. |
|
// |
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
|
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
|
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN |
|
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, |
|
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE |
|
// USE OR OTHER DEALINGS IN THE SOFTWARE. |
|
|
|
var formatRegExp = /%[sdj%]/g; |
|
exports.format = function(f) { |
|
if (!isString(f)) { |
|
var objects = []; |
|
for (var i = 0; i < arguments.length; i++) { |
|
objects.push(inspect(arguments[i])); |
|
} |
|
return objects.join(' '); |
|
} |
|
|
|
var i = 1; |
|
var args = arguments; |
|
var len = args.length; |
|
var str = String(f).replace(formatRegExp, function(x) { |
|
if (x === '%%') return '%'; |
|
if (i >= len) return x; |
|
switch (x) { |
|
case '%s': return String(args[i++]); |
|
case '%d': return Number(args[i++]); |
|
case '%j': |
|
try { |
|
return JSON.stringify(args[i++]); |
|
} catch (_) { |
|
return '[Circular]'; |
|
} |
|
default: |
|
return x; |
|
} |
|
}); |
|
for (var x = args[i]; i < len; x = args[++i]) { |
|
if (isNull(x) || !isObject(x)) { |
|
str += ' ' + x; |
|
} else { |
|
str += ' ' + inspect(x); |
|
} |
|
} |
|
return str; |
|
}; |
|
|
|
|
|
// Mark that a method should not be used. |
|
// Returns a modified function which warns once by default. |
|
// If --no-deprecation is set, then it is a no-op. |
|
exports.deprecate = function(fn, msg) { |
|
// Allow for deprecating things in the process of starting up. |
|
if (isUndefined(global.process)) { |
|
return function() { |
|
return exports.deprecate(fn, msg).apply(this, arguments); |
|
}; |
|
} |
|
|
|
if (process.noDeprecation === true) { |
|
return fn; |
|
} |
|
|
|
var warned = false; |
|
function deprecated() { |
|
if (!warned) { |
|
if (process.throwDeprecation) { |
|
throw new Error(msg); |
|
} else if (process.traceDeprecation) { |
|
console.trace(msg); |
|
} else { |
|
console.error(msg); |
|
} |
|
warned = true; |
|
} |
|
return fn.apply(this, arguments); |
|
} |
|
|
|
return deprecated; |
|
}; |
|
|
|
|
|
var debugs = {}; |
|
var debugEnviron; |
|
exports.debuglog = function(set) { |
|
if (isUndefined(debugEnviron)) |
|
debugEnviron = process.env.NODE_DEBUG || ''; |
|
set = set.toUpperCase(); |
|
if (!debugs[set]) { |
|
if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) { |
|
var pid = process.pid; |
|
debugs[set] = function() { |
|
var msg = exports.format.apply(exports, arguments); |
|
console.error('%s %d: %s', set, pid, msg); |
|
}; |
|
} else { |
|
debugs[set] = function() {}; |
|
} |
|
} |
|
return debugs[set]; |
|
}; |
|
|
|
|
|
/** |
|
* Echos the value of a value. Trys to print the value out |
|
* in the best way possible given the different types. |
|
* |
|
* @param {Object} obj The object to print out. |
|
* @param {Object} opts Optional options object that alters the output. |
|
*/ |
|
/* legacy: obj, showHidden, depth, colors*/ |
|
function inspect(obj, opts) { |
|
// default options |
|
var ctx = { |
|
seen: [], |
|
stylize: stylizeNoColor |
|
}; |
|
// legacy... |
|
if (arguments.length >= 3) ctx.depth = arguments[2]; |
|
if (arguments.length >= 4) ctx.colors = arguments[3]; |
|
if (isBoolean(opts)) { |
|
// legacy... |
|
ctx.showHidden = opts; |
|
} else if (opts) { |
|
// got an "options" object |
|
exports._extend(ctx, opts); |
|
} |
|
// set default options |
|
if (isUndefined(ctx.showHidden)) ctx.showHidden = false; |
|
if (isUndefined(ctx.depth)) ctx.depth = 2; |
|
if (isUndefined(ctx.colors)) ctx.colors = false; |
|
if (isUndefined(ctx.customInspect)) ctx.customInspect = true; |
|
if (ctx.colors) ctx.stylize = stylizeWithColor; |
|
return formatValue(ctx, obj, ctx.depth); |
|
} |
|
exports.inspect = inspect; |
|
|
|
|
|
// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics |
|
inspect.colors = { |
|
'bold' : [1, 22], |
|
'italic' : [3, 23], |
|
'underline' : [4, 24], |
|
'inverse' : [7, 27], |
|
'white' : [37, 39], |
|
'grey' : [90, 39], |
|
'black' : [30, 39], |
|
'blue' : [34, 39], |
|
'cyan' : [36, 39], |
|
'green' : [32, 39], |
|
'magenta' : [35, 39], |
|
'red' : [31, 39], |
|
'yellow' : [33, 39] |
|
}; |
|
|
|
// Don't use 'blue' not visible on cmd.exe |
|
inspect.styles = { |
|
'special': 'cyan', |
|
'number': 'yellow', |
|
'boolean': 'yellow', |
|
'undefined': 'grey', |
|
'null': 'bold', |
|
'string': 'green', |
|
'date': 'magenta', |
|
// "name": intentionally not styling |
|
'regexp': 'red' |
|
}; |
|
|
|
|
|
function stylizeWithColor(str, styleType) { |
|
var style = inspect.styles[styleType]; |
|
|
|
if (style) { |
|
return '\u001b[' + inspect.colors[style][0] + 'm' + str + |
|
'\u001b[' + inspect.colors[style][1] + 'm'; |
|
} else { |
|
return str; |
|
} |
|
} |
|
|
|
|
|
function stylizeNoColor(str, styleType) { |
|
return str; |
|
} |
|
|
|
|
|
function arrayToHash(array) { |
|
var hash = {}; |
|
|
|
array.forEach(function(val, idx) { |
|
hash[val] = true; |
|
}); |
|
|
|
return hash; |
|
} |
|
|
|
|
|
function formatValue(ctx, value, recurseTimes) { |
|
// Provide a hook for user-specified inspect functions. |
|
// Check that value is an object with an inspect function on it |
|
if (ctx.customInspect && |
|
value && |
|
isFunction(value.inspect) && |
|
// Filter out the util module, it's inspect function is special |
|
value.inspect !== exports.inspect && |
|
// Also filter out any prototype objects using the circular check. |
|
!(value.constructor && value.constructor.prototype === value)) { |
|
var ret = value.inspect(recurseTimes, ctx); |
|
if (!isString(ret)) { |
|
ret = formatValue(ctx, ret, recurseTimes); |
|
} |
|
return ret; |
|
} |
|
|
|
// Primitive types cannot have properties |
|
var primitive = formatPrimitive(ctx, value); |
|
if (primitive) { |
|
return primitive; |
|
} |
|
|
|
// Look up the keys of the object. |
|
var keys = Object.keys(value); |
|
var visibleKeys = arrayToHash(keys); |
|
|
|
if (ctx.showHidden) { |
|
keys = Object.getOwnPropertyNames(value); |
|
} |
|
|
|
// IE doesn't make error fields non-enumerable |
|
// http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx |
|
if (isError(value) |
|
&& (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) { |
|
return formatError(value); |
|
} |
|
|
|
// Some type of object without properties can be shortcutted. |
|
if (keys.length === 0) { |
|
if (isFunction(value)) { |
|
var name = value.name ? ': ' + value.name : ''; |
|
return ctx.stylize('[Function' + name + ']', 'special'); |
|
} |
|
if (isRegExp(value)) { |
|
return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); |
|
} |
|
if (isDate(value)) { |
|
return ctx.stylize(Date.prototype.toString.call(value), 'date'); |
|
} |
|
if (isError(value)) { |
|
return formatError(value); |
|
} |
|
} |
|
|
|
var base = '', array = false, braces = ['{', '}']; |
|
|
|
// Make Array say that they are Array |
|
if (isArray(value)) { |
|
array = true; |
|
braces = ['[', ']']; |
|
} |
|
|
|
// Make functions say that they are functions |
|
if (isFunction(value)) { |
|
var n = value.name ? ': ' + value.name : ''; |
|
base = ' [Function' + n + ']'; |
|
} |
|
|
|
// Make RegExps say that they are RegExps |
|
if (isRegExp(value)) { |
|
base = ' ' + RegExp.prototype.toString.call(value); |
|
} |
|
|
|
// Make dates with properties first say the date |
|
if (isDate(value)) { |
|
base = ' ' + Date.prototype.toUTCString.call(value); |
|
} |
|
|
|
// Make error with message first say the error |
|
if (isError(value)) { |
|
base = ' ' + formatError(value); |
|
} |
|
|
|
if (keys.length === 0 && (!array || value.length == 0)) { |
|
return braces[0] + base + braces[1]; |
|
} |
|
|
|
if (recurseTimes < 0) { |
|
if (isRegExp(value)) { |
|
return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); |
|
} else { |
|
return ctx.stylize('[Object]', 'special'); |
|
} |
|
} |
|
|
|
ctx.seen.push(value); |
|
|
|
var output; |
|
if (array) { |
|
output = formatArray(ctx, value, recurseTimes, visibleKeys, keys); |
|
} else { |
|
output = keys.map(function(key) { |
|
return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array); |
|
}); |
|
} |
|
|
|
ctx.seen.pop(); |
|
|
|
return reduceToSingleString(output, base, braces); |
|
} |
|
|
|
|
|
function formatPrimitive(ctx, value) { |
|
if (isUndefined(value)) |
|
return ctx.stylize('undefined', 'undefined'); |
|
if (isString(value)) { |
|
var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') |
|
.replace(/'/g, "\\'") |
|
.replace(/\\"/g, '"') + '\''; |
|
return ctx.stylize(simple, 'string'); |
|
} |
|
if (isNumber(value)) |
|
return ctx.stylize('' + value, 'number'); |
|
if (isBoolean(value)) |
|
return ctx.stylize('' + value, 'boolean'); |
|
// For some reason typeof null is "object", so special case here. |
|
if (isNull(value)) |
|
return ctx.stylize('null', 'null'); |
|
} |
|
|
|
|
|
function formatError(value) { |
|
return '[' + Error.prototype.toString.call(value) + ']'; |
|
} |
|
|
|
|
|
function formatArray(ctx, value, recurseTimes, visibleKeys, keys) { |
|
var output = []; |
|
for (var i = 0, l = value.length; i < l; ++i) { |
|
if (hasOwnProperty(value, String(i))) { |
|
output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, |
|
String(i), true)); |
|
} else { |
|
output.push(''); |
|
} |
|
} |
|
keys.forEach(function(key) { |
|
if (!key.match(/^\d+$/)) { |
|
output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, |
|
key, true)); |
|
} |
|
}); |
|
return output; |
|
} |
|
|
|
|
|
function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) { |
|
var name, str, desc; |
|
desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] }; |
|
if (desc.get) { |
|
if (desc.set) { |
|
str = ctx.stylize('[Getter/Setter]', 'special'); |
|
} else { |
|
str = ctx.stylize('[Getter]', 'special'); |
|
} |
|
} else { |
|
if (desc.set) { |
|
str = ctx.stylize('[Setter]', 'special'); |
|
} |
|
} |
|
if (!hasOwnProperty(visibleKeys, key)) { |
|
name = '[' + key + ']'; |
|
} |
|
if (!str) { |
|
if (ctx.seen.indexOf(desc.value) < 0) { |
|
if (isNull(recurseTimes)) { |
|
str = formatValue(ctx, desc.value, null); |
|
} else { |
|
str = formatValue(ctx, desc.value, recurseTimes - 1); |
|
} |
|
if (str.indexOf('\n') > -1) { |
|
if (array) { |
|
str = str.split('\n').map(function(line) { |
|
return ' ' + line; |
|
}).join('\n').substr(2); |
|
} else { |
|
str = '\n' + str.split('\n').map(function(line) { |
|
return ' ' + line; |
|
}).join('\n'); |
|
} |
|
} |
|
} else { |
|
str = ctx.stylize('[Circular]', 'special'); |
|
} |
|
} |
|
if (isUndefined(name)) { |
|
if (array && key.match(/^\d+$/)) { |
|
return str; |
|
} |
|
name = JSON.stringify('' + key); |
|
if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { |
|
name = name.substr(1, name.length - 2); |
|
name = ctx.stylize(name, 'name'); |
|
} else { |
|
name = name.replace(/'/g, "\\'") |
|
.replace(/\\"/g, '"') |
|
.replace(/(^"|"$)/g, "'"); |
|
name = ctx.stylize(name, 'string'); |
|
} |
|
} |
|
|
|
return name + ': ' + str; |
|
} |
|
|
|
|
|
function reduceToSingleString(output, base, braces) { |
|
var numLinesEst = 0; |
|
var length = output.reduce(function(prev, cur) { |
|
numLinesEst++; |
|
if (cur.indexOf('\n') >= 0) numLinesEst++; |
|
return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1; |
|
}, 0); |
|
|
|
if (length > 60) { |
|
return braces[0] + |
|
(base === '' ? '' : base + '\n ') + |
|
' ' + |
|
output.join(',\n ') + |
|
' ' + |
|
braces[1]; |
|
} |
|
|
|
return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; |
|
} |
|
|
|
|
|
// NOTE: These type checking functions intentionally don't use `instanceof` |
|
// because it is fragile and can be easily faked with `Object.create()`. |
|
function isArray(ar) { |
|
return Array.isArray(ar); |
|
} |
|
exports.isArray = isArray; |
|
|
|
function isBoolean(arg) { |
|
return typeof arg === 'boolean'; |
|
} |
|
exports.isBoolean = isBoolean; |
|
|
|
function isNull(arg) { |
|
return arg === null; |
|
} |
|
exports.isNull = isNull; |
|
|
|
function isNullOrUndefined(arg) { |
|
return arg == null; |
|
} |
|
exports.isNullOrUndefined = isNullOrUndefined; |
|
|
|
function isNumber(arg) { |
|
return typeof arg === 'number'; |
|
} |
|
exports.isNumber = isNumber; |
|
|
|
function isString(arg) { |
|
return typeof arg === 'string'; |
|
} |
|
exports.isString = isString; |
|
|
|
function isSymbol(arg) { |
|
return typeof arg === 'symbol'; |
|
} |
|
exports.isSymbol = isSymbol; |
|
|
|
function isUndefined(arg) { |
|
return arg === void 0; |
|
} |
|
exports.isUndefined = isUndefined; |
|
|
|
function isRegExp(re) { |
|
return isObject(re) && objectToString(re) === '[object RegExp]'; |
|
} |
|
exports.isRegExp = isRegExp; |
|
|
|
function isObject(arg) { |
|
return typeof arg === 'object' && arg !== null; |
|
} |
|
exports.isObject = isObject; |
|
|
|
function isDate(d) { |
|
return isObject(d) && objectToString(d) === '[object Date]'; |
|
} |
|
exports.isDate = isDate; |
|
|
|
function isError(e) { |
|
return isObject(e) && |
|
(objectToString(e) === '[object Error]' || e instanceof Error); |
|
} |
|
exports.isError = isError; |
|
|
|
function isFunction(arg) { |
|
return typeof arg === 'function'; |
|
} |
|
exports.isFunction = isFunction; |
|
|
|
function isPrimitive(arg) { |
|
return arg === null || |
|
typeof arg === 'boolean' || |
|
typeof arg === 'number' || |
|
typeof arg === 'string' || |
|
typeof arg === 'symbol' || // ES6 symbol |
|
typeof arg === 'undefined'; |
|
} |
|
exports.isPrimitive = isPrimitive; |
|
|
|
exports.isBuffer = require('./support/isBuffer'); |
|
|
|
function objectToString(o) { |
|
return Object.prototype.toString.call(o); |
|
} |
|
|
|
|
|
function pad(n) { |
|
return n < 10 ? '0' + n.toString(10) : n.toString(10); |
|
} |
|
|
|
|
|
var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', |
|
'Oct', 'Nov', 'Dec']; |
|
|
|
// 26 Feb 16:19:34 |
|
function timestamp() { |
|
var d = new Date(); |
|
var time = [pad(d.getHours()), |
|
pad(d.getMinutes()), |
|
pad(d.getSeconds())].join(':'); |
|
return [d.getDate(), months[d.getMonth()], time].join(' '); |
|
} |
|
|
|
|
|
// log is just a thin wrapper to console.log that prepends a timestamp |
|
exports.log = function() { |
|
console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments)); |
|
}; |
|
|
|
|
|
/** |
|
* Inherit the prototype methods from one constructor into another. |
|
* |
|
* The Function.prototype.inherits from lang.js rewritten as a standalone |
|
* function (not on Function.prototype). NOTE: If this file is to be loaded |
|
* during bootstrapping this function needs to be rewritten using some native |
|
* functions as prototype setup using normal JavaScript does not work as |
|
* expected during bootstrapping (see mirror.js in r114903). |
|
* |
|
* @param {function} ctor Constructor function which needs to inherit the |
|
* prototype. |
|
* @param {function} superCtor Constructor function to inherit prototype from. |
|
*/ |
|
exports.inherits = require('inherits'); |
|
|
|
exports._extend = function(origin, add) { |
|
// Don't do anything if add isn't an object |
|
if (!add || !isObject(add)) return origin; |
|
|
|
var keys = Object.keys(add); |
|
var i = keys.length; |
|
while (i--) { |
|
origin[keys[i]] = add[keys[i]]; |
|
} |
|
return origin; |
|
}; |
|
|
|
function hasOwnProperty(obj, prop) { |
|
return Object.prototype.hasOwnProperty.call(obj, prop); |
|
} |
|
|
|
}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) |
|
},{"./support/isBuffer":31,"_process":16,"inherits":13}]},{},[2])(2) |
|
}); |
thanks for sharing this - doing
scale.linear(lat1, lat2)
will distort things over larger distances though. I'm curious how big a map would have to be before this becomes noticable