parse-torrent
Version:
Parse a torrent and return an object of keys/values
1,783 lines (1,532 loc) • 210 kB
JavaScript
(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);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.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){
var bncode = require('bncode')
var path = require('path')
var Rusha = require('rusha') // Fast SHA1 (works in browser)
/**
* Parse a torrent. Throws an exception if the torrent is missing required fields.
* @param {Buffer} torrent
* @return {Object} parsed torrent
*/
module.exports = function (torrent) {
torrent = bncode.decode(torrent)
var result = {}
result.infoHash = (new Rusha()).digestFromBuffer(bncode.encode(torrent.info))
result.name = torrent.info.name.toString()
result.private = !!torrent.info.private
result.created = new Date(torrent['creation date'] * 1000)
result.announce = (torrent['announce-list'] || [torrent.announce]).map(function (obj) {
return obj.toString().split(',')[0]
})
result.files = (torrent.info.files || [torrent.info]).map(function (file, i, files) {
var parts = [].concat(file.name || result.name, file.path || []).map(function (p) {
return p.toString()
})
return {
path: path.join.apply(null, [path.sep].concat(parts)).slice(1),
name: parts[parts.length - 1],
length: file.length,
offset: files.slice(0, i).reduce(sumLength, 0)
}
})
var lastFile = result.files[result.files.length-1]
result.pieceLength = torrent.info['piece length']
result.lastPieceLength = ((lastFile.offset + lastFile.length) % result.pieceLength) || result.pieceLength
result.pieces = splitPieces(torrent.info.pieces)
return result
}
function sumLength (sum, file) {
return sum + file.length
}
function splitPieces (buf) {
var pieces = []
for (var i = 0; i < buf.length; i += 20) {
pieces.push(buf.slice(i, i + 20).toString('hex'))
}
return pieces
}
},{"bncode":2,"path":26,"rusha":3}],2:[function(require,module,exports){
(function (process,Buffer){
/*jshint es5:false, asi:true, quotmark:false, eqeqeq:false, forin: false */
/*
* (c) 2011 Tim Becker, see file LICENSE for details
*/
/*
* Provides functionality for bencoding and decoding as use in
* bittorrent and described in:
* http://www.bittorrent.org/beps/bep_0003.html
*
* Encoding is as follows:
*
* var benc = require("bncode"),
* exmp = {}
*
* exmp.bla = "blup"
* exmp.foo = "bar"
* exmp.one = 1
* exmp.woah = {}
* exmp.woah.arr = []
* exmp.woah.arr.push(1)
* exmp.woah.arr.push(2)
* exmp.woah.arr.push(3)
* exmp.str = new Buffer("Buffers work too")
*
* var bencBuffer = benc.encode(exmp) i
*
* // d3:bla4:blup3:foo3:bar3:onei1e4:woahd3:arr \
* // li1ei2ei3eee3:str16:Buffers work tooe
*
*
* Decoding will work in progressively, e.g. if you're receiving partial
* bencoded strings on the network:
*
* var benc = require("bncode"),
* buf = null
*
* decoder = new bncode.decoder()
* while (buf = receiveData()) {
* decoder.decode(buf)
* }
*
* log(decoder.result())
*
*
* Or "all in one"
*
* var benc = require("bncode"),
* buf = getBuffer(),
* dec = benc.decode(buf)
*
* log(dec.bla)
*
*
* There are some subtleties concerning bencoded strings. These are
* decoded as Buffer objects because they are just strings of raw bytes
* and as such would wreak havoc with multi byte strings in javascript.
*
* The exception to this is strings that appear as keys in bencoded
* dicts. These are decoded as Javascript Strings, as they should always
* be strings of (ascii) characters and if they weren't decoded as JS
* Strings, dict's would map to Javascript objects with properties.
*
*/
var Transform = require('stream').Transform;
var inherits = require('util').inherits
var I = "i".charCodeAt(0)
var L = "l".charCodeAt(0)
var E = "e".charCodeAt(0)
var D = "d".charCodeAt(0)
var COLON = ":".charCodeAt(0)
var DASH = "-".charCodeAt(0)
var STATE_INITIAL = 0
var STATE_STATE_STRING_LEN = STATE_INITIAL + 1
var STATE_STRING = STATE_STATE_STRING_LEN + 1
var STATE_COLON = STATE_STRING + 1
var STATE_STATE_INTEGER = STATE_COLON + 1
var STATE_INTEGER = STATE_STATE_INTEGER + 1
function log (m) {console.log(m); process.stdout.flush()}
/*
* This is the internal state machine for taking apart bencoded strings,
* it's not exposed in the eports. It's constructed with four callbacks
* that get fired when:
*
* cb: a value (string or number) is encountered
* cb_list: a begin list element is encountered
* cb_dict: a beginning of dictionary is encountered.
* cd_end: an end element, wheter dict or list is encountered
*
* Once constructed, the machine may be fed with buffers containing
* partial bencoded string. Call `consistent` to check whether the
* current state is consistent, e.g. not smack-dap in the middle of
* a string or a number and if the dict, list and end calls balance
*
*
* The functionality being so rudimentary requires some more state and
* logic in the code executing the machine, for this see Context, below.
*
*/
var BdecodeSMachine = function (cb, cb_list, cb_dict, cb_end) {
var depth = 0
var state = STATE_INITIAL
var cb = cb
var cb_list = cb_list
var cb_dict = cb_dict
var cb_end = cb_end
this.consistent = function() {
return (state === STATE_INITIAL && depth === 0)
}
var strLen = 0
var str = ""
var _int = 0
var neg = false
this.parse = function (buffer, encoding) {
encoding = encoding ? encoding : "utf8"
if ("string" === typeof(buffer)) {
buffer = new Buffer(buffer, encoding)
}
for (var pos = 0; pos != buffer.length; ++pos) {
switch(state) {
case STATE_INITIAL:
switch(buffer[pos]){
case 0x30:
case 0x31:
case 0x32:
case 0x33:
case 0x34:
case 0x35:
case 0x36:
case 0x37:
case 0x38:
case 0x39:
state = STATE_STATE_STRING_LEN
strLen = 0
strLen += buffer[pos] - 0x30
break
case I:
state = STATE_STATE_INTEGER
_int = 0
neg = false
break
case L:
state = STATE_INITIAL
depth += 1
cb_list()
break
case D:
state = STATE_INITIAL
depth += 1
cb_dict()
break
case E:
state = STATE_INITIAL
depth -= 1
if (depth < 0) {
throw new Error("end with no beginning: "+pos)
} else {
cb_end()
}
break
}
break;
case STATE_STATE_STRING_LEN:
if (integer(buffer[pos])) {
strLen *= 10
strLen += buffer[pos] - 0x30
} else {
str = new Buffer(strLen)
pos -=1
state = STATE_COLON
}
break
case STATE_COLON:
if (buffer[pos] != COLON) {
throw new Error("not a colon at:"+pos.toString(16))
}
state = STATE_STRING
// in case this is a zero length string, there's
// no bytes to be collected.
if (0 === strLen) {
cb(new Buffer(0))
state = STATE_INITIAL
}
break
case STATE_STRING:
if (0 === strLen) {
cb(str)
state = STATE_INITIAL
} else {
//str += String.fromCharCode(buffer[pos]) // not unicode safe..
str[str.length-strLen] = buffer[pos]
strLen -= 1
if (0 === strLen) {
cb(str)
state = STATE_INITIAL
}
}
break
case STATE_STATE_INTEGER:
state = STATE_INTEGER
if (buffer[pos] == DASH) {
neg = true // handle neg and zero within value.
break
} // else fall through
case STATE_INTEGER:
if (integer(buffer[pos])) {
_int *= 10
_int += buffer[pos] - 0x30
} else if (buffer[pos] == E) {
var ret = neg ? 0 - _int : _int
cb(ret)
state = STATE_INITIAL
} else {
throw new Error("not part of int at:"+pos.toString(16))
}
break;
} // switch state
} // for buffer
} // function parse
var integer = function (value) {
// check that value is a number and that
// its value is ascii integer.
if (! (typeof(value)==='number') ) {
return false
}
return between(value, 0x30, 0x39)
}
var between = function(val, min, max) {
return (min <= val && val <= max)
}
} // end BdecodeSMachine
/*
* The exported decode functionality.
*/
var Bdecode = function () {
// markers
var DICTIONARY_START = {}
var LIST_START = {}
var Context = function() {
var self = this
var stack = []
this.cb = function(o){
stack.push(o)
}
this.cb_list = function(){
self.cb(LIST_START)
}
this.cb_dict = function(){
self.cb(DICTIONARY_START)
}
this.cb_end = function(){
// unwind the stack until either a DICTIONARY_START or LIST_START is
// found, create arr or hash, stick unwound stack on, push arr or hash
// back onto stack
var obj = null,
tmp_stack = []
while ( undefined !== (obj = stack.pop()) ) {
if (LIST_START === obj) {
var obj2 = null
var list = []
while( undefined !== (obj2 = tmp_stack.pop()) ) {
list.push(obj2)
}
self.cb(list)
break
} else if (DICTIONARY_START === obj) {
var key = null,
val = null,
dic = {}
while ( (undefined !== (key = tmp_stack.pop())) && (undefined !== (val = tmp_stack.pop())) ) {
dic[key.toString()] = val
}
if (undefined !== key && undefined === dic[key]) {
throw new Error("uneven number of keys and values A")
}
self.cb(dic)
break
} else {
tmp_stack.push(obj)
}
}
if (tmp_stack.length > 0) {
// could this case even occur?
throw new Error("uneven number of keys and values B")
}
}
this.result = function () {
return stack
}
}
var self = this,
ctx = new Context(),
smachine = new BdecodeSMachine(ctx.cb, ctx.cb_list, ctx.cb_dict, ctx.cb_end)
this.result = function () {
if (!smachine.consistent()) {
throw new Error("not in consistent state. More bytes coming?")
}
return ctx.result()
}
this.decode = function(buf, encoding) {
smachine.parse(buf, encoding)
}
}
var Bencode = function(obj) {
var self = this
var to_encode = obj
var buffer = null
switch (typeof (obj) ) {
case "string":
return encodeString(obj)
case "number":
return encodeNumber(obj)
break
case "object":
if (obj instanceof Array) {
return encodeList(obj)
} else if (Buffer.isBuffer(obj)) {
return encodeBuffer(obj)
}
{
// assume it's a hash
return encodeDict(obj)
}
}
function encodeString(obj) {
var blen = Buffer.byteLength(obj),
len = blen.toString(10),
buf = new Buffer(len.length + 1 + blen)
buf.write(len, 0, "ascii")
buf.write(":", len.length, "ascii")
buf.write(obj, len.length+1, "utf8")
return buf
}
function encodeNumber(num) {
var n = num.toString(10),
buf = new Buffer(n.length+2)
buf.write("i", 0)
buf.write(n, 1)
buf.write("e", n.length+1)
return buf
}
function encodeDict(obj) {
var func = function (obj, pos) {
var keys = Object.keys(obj).sort()
for (var i in keys) {
var key = Bencode(keys[i]),
val = Bencode(obj[keys[i]])
ensure(key.length + val.length, pos)
key.copy(buffer, pos, 0)
pos += key.length
val.copy(buffer, pos, 0)
pos += val.length
}
return pos
}
return assemble(obj, "d", func)
}
function encodeList(obj) {
var func = function(obj, pos) {
obj.forEach (function(o){
var elem = Bencode(o)
ensure(elem.length, pos)
elem.copy(buffer, pos, 0)
pos += elem.length
})
return pos
}
return assemble(obj, "l", func)
}
function encodeBuffer(obj) {
var len = obj.length.toString(10),
buf = new Buffer(len.length+1+obj.length);
buf.write(len, 0, "ascii")
buf.write(":", len.length, "ascii")
obj.copy(buf, len.length+1, 0)
return buf
}
function assemble (obj, prefix, func) {
var pos = 0
ensure(1024, 0)
buffer.write(prefix, pos++)
pos = func(obj, pos)
ensure(1, pos)
buffer.write("e", pos++)
return buffer.slice(0, pos)
}
function ensure (num, pos) {
if (!buffer) {
buffer = new Buffer(num)
} else {
if (buffer.length > num+pos+1) {
return
} else {
var buf2 = new Buffer(buffer.length + num)
buffer.copy(buf2, 0, 0)
buffer = buf2
}
}
}
}
function decode (buffer, encoding) {
var decoder = new Bdecode()
decoder.decode(buffer, encoding)
return decoder.result()[0]
}
function Stream (options) {
options = options || {};
options.objectMode = true;
Transform.call(this, options);
this._decoder = new Bdecode()
}
inherits(Stream, Transform);
Stream.prototype._transform = function (chunk, encoding, callback) {
try {
this._decoder.decode(chunk, encoding)
callback(null);
} catch(err) {
callback(err);
}
}
Stream.prototype._flush = function (callback) {
this.push(this._decoder.result()[0]);
callback(null);
}
exports.encode = Bencode
exports.decoder = Bdecode
exports.decode = decode
exports.Stream = Stream
}).call(this,require("/usr/local/lib/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js"),require("buffer").Buffer)
},{"/usr/local/lib/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js":25,"buffer":20,"stream":28,"util":36}],3:[function(require,module,exports){
(function (global){
(function () {
// If we'e running in Node.JS, export a module.
if (typeof module !== 'undefined') {
module.exports = Rusha;
}
// If we're running in a DOM context, export
// the Rusha object to toplevel.
if (typeof window !== 'undefined') {
window.Rusha = Rusha;
}
// If we're running in a webworker, accept
// messages containing a jobid and a buffer
// or blob object, and return the hash result.
if (typeof FileReaderSync !== 'undefined') {
var reader = new FileReaderSync(),
hasher = new Rusha(4 * 1024 * 1024);
self.onmessage = function onMessage (event) {
var hash, data = event.data.data;
if (data instanceof Blob) {
try {
data = reader.readAsBinaryString(data);
} catch (e) {
self.postMessage({id: event.data.id, error: e.name});
return;
}
}
hash = hasher.digest(data);
self.postMessage({id: event.data.id, hash: hash});
};
}
// The Rusha object is a wrapper around the low-level RushaCore.
// It provides means of converting different inputs to the
// format accepted by RushaCore as well as other utility methods.
function Rusha (sizeHint) {
"use strict";
// Private object structure.
var self = {fill: 0};
// Calculate the length of buffer that the sha1 routine uses
// including the padding.
var padlen = function (len) {
return len + 1 + ((len ) % 64 < 56 ? 56 : 56 + 64) - (len ) % 64 + 8;
};
var padZeroes = function (bin, len) {
for (var i = len >> 2; i < bin.length; i++) bin[i] = 0;
};
var padData = function (bin, len) {
bin[len>>2] |= 0x80 << (24 - (len % 4 << 3));
bin[(((len >> 2) + 2) & ~0x0f) + 15] = len << 3;
};
// Convert a binary string to a big-endian Int32Array using
// four characters per slot and pad it per the sha1 spec.
// A binary string is expected to only contain char codes < 256.
var convStr = function (str, bin, len) {
var i;
for (i = 0; i < len; i = i + 4 |0) {
bin[i>>2] = str.charCodeAt(i) << 24 |
str.charCodeAt(i+1) << 16 |
str.charCodeAt(i+2) << 8 |
str.charCodeAt(i+3);
}
};
// Convert a buffer or array to a big-endian Int32Array using
// four elements per slot and pad it per the sha1 spec.
// The buffer or array is expected to only contain elements < 256.
var convBuf = function (buf, bin, len) {
var i, m = len % 4, j = len - m;
for (i = 0; i < j; i = i + 4 |0) {
bin[i>>2] = buf[i] << 24 |
buf[i+1] << 16 |
buf[i+2] << 8 |
buf[i+3];
}
switch (m) {
case 0: bin[j>>2] |= buf[j+3];
case 3: bin[j>>2] |= buf[j+2] << 8;
case 2: bin[j>>2] |= buf[j+1] << 16;
case 1: bin[j>>2] |= buf[j] << 24;
}
};
// Convert general data to a big-endian Int32Array written on the
// heap and return it's length;
var conv = function (data, bin, len) {
if (typeof data === 'string') {
return convStr(data, bin, len);
} else if (data instanceof Array || (typeof global !== 'undefined' &&
typeof global.Buffer !== 'undefined' &&
global.Buffer.isBuffer(data))) {
return convBuf(data, bin, len);
} else if (data instanceof ArrayBuffer) {
return convBuf(new Uint8Array(data), bin, len);
} else if (data.buffer instanceof ArrayBuffer) {
return convBuf(new Uint8Array(data.buffer), bin, len);
} else {
throw new Error('Unsupported data type.');
}
};
// Convert an ArrayBuffer into its hexadecimal string representation.
var hex = function (arrayBuffer) {
var i, x, hex_tab = "0123456789abcdef", res = [], binarray = new Uint8Array(arrayBuffer);
for (i = 0; i < binarray.length; i++) {
x = binarray[i];
res[i] = hex_tab.charAt((x >> 4) & 0xF) +
hex_tab.charAt((x >> 0) & 0xF);
}
return res.join('');
};
var nextPow2 = function (v) {
var p = 1; while (p < v) p = p << 1; return p;
};
// Resize the internal data structures to a new capacity.
var resize = function (size) {
self.sizeHint = size;
self.heap = new ArrayBuffer(nextPow2(padlen(size) + 320));
self.core = RushaCore({Int32Array: Int32Array, DataView: DataView}, {}, self.heap);
};
// On initialize, resize the datastructures according
// to an optional size hint.
resize(sizeHint || 0);
// Initialize and call the RushaCore,
// assuming an input buffer of length len * 4.
var coreCall = function (len) {
var h = new Int32Array(self.heap, len << 2, 5);
h[0] = 1732584193;
h[1] = -271733879;
h[2] = -1732584194;
h[3] = 271733878;
h[4] = -1009589776;
self.core.hash(len);
};
// Calculate the hash digest as an array of 5 32bit integers.
var rawDigest = this.rawDigest = function (str) {
var len = str.byteLength || str.length;
if (len > self.sizeHint) {
resize(len);
}
var view = new Int32Array(self.heap, 0, padlen(len) >> 2);
padZeroes(view, len);
conv(str, view, len);
padData(view, len);
coreCall(view.length);
var out = new Int32Array(5);
var arr = new DataView(out.buffer);
arr.setInt32(0, view[0], false);
arr.setInt32(4, view[1], false);
arr.setInt32(8, view[2], false);
arr.setInt32(12, view[3], false);
arr.setInt32(16, view[4], false);
return out;
};
// The digest and digestFrom* interface returns the hash digest
// as a hex string.
this.digest = this.digestFromString =
this.digestFromBuffer = this.digestFromArrayBuffer =
function (str) {
return hex(rawDigest(str).buffer);
};
};
// The low-level RushCore module provides the heart of Rusha,
// a high-speed sha1 implementation working on an Int32Array heap.
// At first glance, the implementation seems complicated, however
// with the SHA1 spec at hand, it is obvious this almost a textbook
// implementation that has a few functions hand-inlined and a few loops
// hand-unrolled.
function RushaCore (stdlib, foreign, heap) {
"use asm";
var H = new stdlib.Int32Array(heap);
function hash (k) {
k = k|0;
var i = 0, j = 0,
y0 = 0, z0 = 0, y1 = 0, z1 = 0,
y2 = 0, z2 = 0, y3 = 0, z3 = 0,
y4 = 0, z4 = 0, t0 = 0, t1 = 0;
y0 = H[k+0<<2>>2]|0;
y1 = H[k+1<<2>>2]|0;
y2 = H[k+2<<2>>2]|0;
y3 = H[k+3<<2>>2]|0;
y4 = H[k+4<<2>>2]|0;
for (i = 0; (i|0) < (k|0); i = i + 16 |0) {
z0 = y0;
z1 = y1;
z2 = y2;
z3 = y3;
z4 = y4;
for (j = 0; (j|0) < 16; j = j + 1 |0) {
t1 = H[i+j<<2>>2]|0;
t0 = ((((y0) << 5 | (y0) >>> 27) + (y1 & y2 | ~y1 & y3) |0) + ((t1 + y4 | 0) +1518500249 |0) |0);
y4 = y3; y3 = y2; y2 = ((y1) << 30 | (y1) >>> 2); y1 = y0; y0 = t0;
H[k+j<<2>>2] = t1;
}
for (j = k + 16 |0; (j|0) < (k + 20 |0); j = j + 1 |0) {
t1 = (((H[j-3<<2>>2] ^ H[j-8<<2>>2] ^ H[j-14<<2>>2] ^ H[j-16<<2>>2]) << 1 | (H[j-3<<2>>2] ^ H[j-8<<2>>2] ^ H[j-14<<2>>2] ^ H[j-16<<2>>2]) >>> 31));
t0 = ((((y0) << 5 | (y0) >>> 27) + (y1 & y2 | ~y1 & y3) |0) + ((t1 + y4 | 0) +1518500249 |0) |0);
y4 = y3; y3 = y2; y2 = ((y1) << 30 | (y1) >>> 2); y1 = y0; y0 = t0;
H[j<<2>>2] = t1;
}
for (j = k + 20 |0; (j|0) < (k + 40 |0); j = j + 1 |0) {
t1 = (((H[j-3<<2>>2] ^ H[j-8<<2>>2] ^ H[j-14<<2>>2] ^ H[j-16<<2>>2]) << 1 | (H[j-3<<2>>2] ^ H[j-8<<2>>2] ^ H[j-14<<2>>2] ^ H[j-16<<2>>2]) >>> 31));
t0 = ((((y0) << 5 | (y0) >>> 27) + (y1 ^ y2 ^ y3) |0) + ((t1 + y4 | 0) +1859775393 |0) |0);
y4 = y3; y3 = y2; y2 = ((y1) << 30 | (y1) >>> 2); y1 = y0; y0 = t0;
H[j<<2>>2] = t1;
}
for (j = k + 40 |0; (j|0) < (k + 60 |0); j = j + 1 |0) {
t1 = (((H[j-3<<2>>2] ^ H[j-8<<2>>2] ^ H[j-14<<2>>2] ^ H[j-16<<2>>2]) << 1 | (H[j-3<<2>>2] ^ H[j-8<<2>>2] ^ H[j-14<<2>>2] ^ H[j-16<<2>>2]) >>> 31));
t0 = ((((y0) << 5 | (y0) >>> 27) + (y1 & y2 | y1 & y3 | y2 & y3) |0) + ((t1 + y4 | 0) -1894007588 |0) |0);
y4 = y3; y3 = y2; y2 = ((y1) << 30 | (y1) >>> 2); y1 = y0; y0 = t0;
H[j<<2>>2] = t1;
}
for (j = k + 60 |0; (j|0) < (k + 80 |0); j = j + 1 |0) {
t1 = (((H[j-3<<2>>2] ^ H[j-8<<2>>2] ^ H[j-14<<2>>2] ^ H[j-16<<2>>2]) << 1 | (H[j-3<<2>>2] ^ H[j-8<<2>>2] ^ H[j-14<<2>>2] ^ H[j-16<<2>>2]) >>> 31));
t0 = ((((y0) << 5 | (y0) >>> 27) + (y1 ^ y2 ^ y3) |0) + ((t1 + y4 | 0) -899497514 |0) |0);
y4 = y3; y3 = y2; y2 = ((y1) << 30 | (y1) >>> 2); y1 = y0; y0 = t0;
H[j<<2>>2] = t1;
}
y0 = y0 + z0 |0;
y1 = y1 + z1 |0;
y2 = y2 + z2 |0;
y3 = y3 + z3 |0;
y4 = y4 + z4 |0;
}
H[0] = y0;
H[1] = y1;
H[2] = y2;
H[3] = y3;
H[4] = y4;
}
return {hash: hash};
}
})();
}).call(this,typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{}],4:[function(require,module,exports){
(function (process){
var defined = require('defined');
var createDefaultStream = require('./lib/default_stream');
var Test = require('./lib/test');
var createResult = require('./lib/results');
var canEmitExit = typeof process !== 'undefined' && process
&& typeof process.on === 'function'
;
var canExit = typeof process !== 'undefined' && process
&& typeof process.exit === 'function'
;
var nextTick = typeof setImmediate !== 'undefined'
? setImmediate
: process.nextTick
;
exports = module.exports = (function () {
var harness;
var lazyLoad = function () {
if (!harness) harness = createExitHarness({
autoclose: !canEmitExit
});
return harness.apply(this, arguments);
};
lazyLoad.only = function () {
if (!harness) harness = createExitHarness({
autoclose: !canEmitExit
});
return harness.only.apply(this, arguments);
}
return lazyLoad
})();
function createExitHarness (conf) {
if (!conf) conf = {};
var harness = createHarness({
autoclose: defined(conf.autoclose, false)
});
var stream = harness.createStream();
var es = stream.pipe(createDefaultStream());
if (canEmitExit) {
es.on('error', function (err) { harness._exitCode = 1 });
}
var ended = false;
stream.on('end', function () { ended = true });
if (conf.exit === false) return harness;
if (!canEmitExit || !canExit) return harness;
var _error;
process.on('uncaughtException', function (err) {
if (err && err.code === 'EPIPE' && err.errno === 'EPIPE'
&& err.syscall === 'write') return;
_error = err
throw err
})
process.on('exit', function (code) {
if (_error) {
return
}
if (!ended) {
for (var i = 0; i < harness._tests.length; i++) {
var t = harness._tests[i];
t._exit();
}
}
harness.close();
process.exit(code || harness._exitCode);
});
return harness;
}
exports.createHarness = createHarness;
exports.Test = Test;
exports.test = exports; // tap compat
var exitInterval;
function createHarness (conf_) {
if (!conf_) conf_ = {};
var results = createResult();
if (conf_.autoclose !== false) {
results.once('done', function () { results.close() });
}
var test = function (name, conf, cb) {
var t = new Test(name, conf, cb);
test._tests.push(t);
(function inspectCode (st) {
st.on('test', function sub (st_) {
inspectCode(st_);
});
st.on('result', function (r) {
if (!r.ok) test._exitCode = 1
});
})(t);
results.push(t);
return t;
};
test._tests = [];
test.createStream = function () {
return results.createStream();
};
var only = false;
test.only = function (name) {
if (only) throw new Error('there can only be one only test');
results.only(name);
only = true;
return test.apply(null, arguments);
};
test._exitCode = 0;
test.close = function () { results.close() };
return test;
}
}).call(this,require("/usr/local/lib/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js"))
},{"./lib/default_stream":5,"./lib/results":6,"./lib/test":7,"/usr/local/lib/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js":25,"defined":11}],5:[function(require,module,exports){
var through = require('through');
module.exports = function () {
var line = '';
var stream = through(write, flush);
return stream;
function write (buf) {
for (var i = 0; i < buf.length; i++) {
var c = typeof buf === 'string'
? buf.charAt(i)
: String.fromCharCode(buf[i])
;
if (c === '\n') flush();
else line += c;
}
}
function flush () {
try { console.log(line); }
catch (e) { stream.emit('error', e) }
line = '';
}
};
},{"through":17}],6:[function(require,module,exports){
(function (process){
var EventEmitter = require('events').EventEmitter;
var inherits = require('inherits');
var json = typeof JSON === 'object' ? JSON : require('jsonify');
var through = require('through');
var resumer = require('resumer');
var nextTick = typeof setImmediate !== 'undefined'
? setImmediate
: process.nextTick
;
module.exports = Results;
inherits(Results, EventEmitter);
function Results () {
if (!(this instanceof Results)) return new Results;
this.count = 0;
this.fail = 0;
this.pass = 0;
this._stream = through();
this.tests = [];
}
Results.prototype.createStream = function () {
var self = this;
var output = resumer();
output.queue('TAP version 13\n');
nextTick(function next() {
var t;
while (t = getNextTest(self)) {
t.run();
if (!t.ended) return t.once('end', function(){ nextTick(next); });
}
self.emit('done');
});
self._stream.pipe(output);
return output;
};
Results.prototype.push = function (t) {
var self = this;
self.tests.push(t);
self._watch(t);
};
Results.prototype.only = function (name) {
if (this._only) {
self.count ++;
self.fail ++;
write('not ok ' + self.count + ' already called .only()\n');
}
this._only = name;
};
Results.prototype._watch = function (t) {
var self = this;
var write = function (s) { self._stream.queue(s) };
t.once('prerun', function () {
write('# ' + t.name + '\n');
});
t.on('result', function (res) {
if (typeof res === 'string') {
write('# ' + res + '\n');
return;
}
write(encodeResult(res, self.count + 1));
self.count ++;
if (res.ok) self.pass ++
else self.fail ++
});
t.on('test', function (st) { self._watch(st) });
};
Results.prototype.close = function () {
var self = this;
if (self.closed) self._stream.emit('error', new Error('ALREADY CLOSED'));
self.closed = true;
var write = function (s) { self._stream.queue(s) };
write('\n1..' + self.count + '\n');
write('# tests ' + self.count + '\n');
write('# pass ' + self.pass + '\n');
if (self.fail) write('# fail ' + self.fail + '\n')
else write('\n# ok\n')
self._stream.queue(null);
};
function encodeResult (res, count) {
var output = '';
output += (res.ok ? 'ok ' : 'not ok ') + count;
output += res.name ? ' ' + res.name.toString().replace(/\s+/g, ' ') : '';
if (res.skip) output += ' # SKIP';
else if (res.todo) output += ' # TODO';
output += '\n';
if (res.ok) return output;
var outer = ' ';
var inner = outer + ' ';
output += outer + '---\n';
output += inner + 'operator: ' + res.operator + '\n';
var ex = json.stringify(res.expected, getSerialize()) || '';
var ac = json.stringify(res.actual, getSerialize()) || '';
if (Math.max(ex.length, ac.length) > 65) {
output += inner + 'expected:\n' + inner + ' ' + ex + '\n';
output += inner + 'actual:\n' + inner + ' ' + ac + '\n';
}
else {
output += inner + 'expected: ' + ex + '\n';
output += inner + 'actual: ' + ac + '\n';
}
if (res.at) {
output += inner + 'at: ' + res.at + '\n';
}
if (res.operator === 'error' && res.actual && res.actual.stack) {
var lines = String(res.actual.stack).split('\n');
output += inner + 'stack:\n';
output += inner + ' ' + lines[0] + '\n';
for (var i = 1; i < lines.length; i++) {
output += inner + lines[i] + '\n';
}
}
output += outer + '...\n';
return output;
}
function getSerialize () {
var seen = [];
return function (key, value) {
var ret = value;
if (typeof value === 'object' && value) {
var found = false;
for (var i = 0; i < seen.length; i++) {
if (seen[i] === value) {
found = true
break;
}
}
if (found) ret = '[Circular]'
else seen.push(value)
}
return ret;
};
}
function getNextTest(results) {
if (!results._only) {
return results.tests.shift();
}
do {
var t = results.tests.shift();
if (!t) {
return null;
}
if (results._only === t.name) {
return t;
}
} while (results.tests.length !== 0)
}
}).call(this,require("/usr/local/lib/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js"))
},{"/usr/local/lib/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js":25,"events":23,"inherits":12,"jsonify":13,"resumer":16,"through":17}],7:[function(require,module,exports){
(function (process,__dirname){
var Stream = require('stream');
var deepEqual = require('deep-equal');
var defined = require('defined');
var path = require('path');
var inherits = require('util').inherits;
var EventEmitter = require('events').EventEmitter;
module.exports = Test;
var nextTick = typeof setImmediate !== 'undefined'
? setImmediate
: process.nextTick
;
inherits(Test, EventEmitter);
function Test (name_, opts_, cb_) {
var self = this;
var name = '(anonymous)';
var opts = {};
var cb;
for (var i = 0; i < arguments.length; i++) {
switch (typeof arguments[i]) {
case 'string':
name = arguments[i];
break;
case 'object':
opts = arguments[i] || opts;
break;
case 'function':
cb = arguments[i];
}
}
this.readable = true;
this.name = name || '(anonymous)';
this.assertCount = 0;
this.pendingCount = 0;
this._skip = opts.skip || false;
this._plan = undefined;
this._cb = cb;
this._progeny = [];
this._ok = true;
}
Test.prototype.run = function () {
if (!this._cb || this._skip) {
return this.end();
}
this.emit('prerun');
try {
this._cb(this);
}
catch (err) {
this.error(err);
this.end();
return;
}
this.emit('run');
};
Test.prototype.test = function (name, opts, cb) {
var self = this;
var t = new Test(name, opts, cb);
this._progeny.push(t);
this.pendingCount++;
this.emit('test', t);
t.on('prerun', function () {
self.assertCount++;
})
if (!self._pendingAsserts()) {
nextTick(function () {
self.end();
});
}
nextTick(function() {
if (!self._plan && self.pendingCount == self._progeny.length) {
self.end();
}
});
};
Test.prototype.comment = function (msg) {
this.emit('result', msg.trim().replace(/^#\s*/, ''));
};
Test.prototype.plan = function (n) {
this._plan = n;
this.emit('plan', n);
};
Test.prototype.end = function () {
var self = this;
if (this._progeny.length) {
var t = this._progeny.shift();
t.on('end', function () {
self.end();
});
t.run();
return;
}
if (!this.ended) this.emit('end');
var pendingAsserts = this._pendingAsserts();
if (!this._planError && this._plan !== undefined && pendingAsserts) {
this._planError = true;
this.fail('plan != count', {
expected : this._plan,
actual : this.assertCount
});
}
this.ended = true;
};
Test.prototype._exit = function () {
if (this._plan !== undefined &&
!this._planError && this.assertCount !== this._plan) {
this._planError = true;
this.fail('plan != count', {
expected : this._plan,
actual : this.assertCount,
exiting : true
});
}
else if (!this.ended) {
this.fail('test exited without ending', {
exiting: true
});
}
};
Test.prototype._pendingAsserts = function () {
if (this._plan === undefined) {
return 1;
} else {
return this._plan -
(this._progeny.length + this.assertCount);
}
}
Test.prototype._assert = function assert (ok, opts) {
var self = this;
var extra = opts.extra || {};
var res = {
id : self.assertCount ++,
ok : Boolean(ok),
skip : defined(extra.skip, opts.skip),
name : defined(extra.message, opts.message, '(unnamed assert)'),
operator : defined(extra.operator, opts.operator),
actual : defined(extra.actual, opts.actual),
expected : defined(extra.expected, opts.expected)
};
this._ok = Boolean(this._ok && ok);
if (!ok) {
res.error = defined(extra.error, opts.error, new Error(res.name));
}
var e = new Error('exception');
var err = (e.stack || '').split('\n');
var dir = path.dirname(__dirname) + '/';
for (var i = 0; i < err.length; i++) {
var m = /^\s*\bat\s+(.+)/.exec(err[i]);
if (!m) continue;
var s = m[1].split(/\s+/);
var filem = /(\/[^:\s]+:(\d+)(?::(\d+))?)/.exec(s[1]);
if (!filem) {
filem = /(\/[^:\s]+:(\d+)(?::(\d+))?)/.exec(s[3]);
if (!filem) continue;
}
if (filem[1].slice(0, dir.length) === dir) continue;
res.functionName = s[0];
res.file = filem[1];
res.line = Number(filem[2]);
if (filem[3]) res.column = filem[3];
res.at = m[1];
break;
}
self.emit('result', res);
var pendingAsserts = self._pendingAsserts();
if (!pendingAsserts) {
if (extra.exiting) {
self.end();
} else {
nextTick(function () {
self.end();
});
}
}
if (!self._planError && pendingAsserts < 0) {
self._planError = true;
self.fail('plan != count', {
expected : self._plan,
actual : self._plan - pendingAsserts
});
}
};
Test.prototype.fail = function (msg, extra) {
this._assert(false, {
message : msg,
operator : 'fail',
extra : extra
});
};
Test.prototype.pass = function (msg, extra) {
this._assert(true, {
message : msg,
operator : 'pass',
extra : extra
});
};
Test.prototype.skip = function (msg, extra) {
this._assert(true, {
message : msg,
operator : 'skip',
skip : true,
extra : extra
});
};
Test.prototype.ok
= Test.prototype['true']
= Test.prototype.assert
= function (value, msg, extra) {
this._assert(value, {
message : msg,
operator : 'ok',
expected : true,
actual : value,
extra : extra
});
};
Test.prototype.notOk
= Test.prototype['false']
= Test.prototype.notok
= function (value, msg, extra) {
this._assert(!value, {
message : msg,
operator : 'notOk',
expected : false,
actual : value,
extra : extra
});
};
Test.prototype.error
= Test.prototype.ifError
= Test.prototype.ifErr
= Test.prototype.iferror
= function (err, msg, extra) {
this._assert(!err, {
message : defined(msg, String(err)),
operator : 'error',
actual : err,
extra : extra
});
};
Test.prototype.equal
= Test.prototype.equals
= Test.prototype.isEqual
= Test.prototype.is
= Test.prototype.strictEqual
= Test.prototype.strictEquals
= function (a, b, msg, extra) {
this._assert(a === b, {
message : defined(msg, 'should be equal'),
operator : 'equal',
actual : a,
expected : b,
extra : extra
});
};
Test.prototype.notEqual
= Test.prototype.notEquals
= Test.prototype.notStrictEqual
= Test.prototype.notStrictEquals
= Test.prototype.isNotEqual
= Test.prototype.isNot
= Test.prototype.not
= Test.prototype.doesNotEqual
= Test.prototype.isInequal
= function (a, b, msg, extra) {
this._assert(a !== b, {
message : defined(msg, 'should not be equal'),
operator : 'notEqual',
actual : a,
notExpected : b,
extra : extra
});
};
Test.prototype.deepEqual
= Test.prototype.deepEquals
= Test.prototype.isEquivalent
= Test.prototype.same
= function (a, b, msg, extra) {
this._assert(deepEqual(a, b, { strict: true }), {
message : defined(msg, 'should be equivalent'),
operator : 'deepEqual',
actual : a,
expected : b,
extra : extra
});
};
Test.prototype.deepLooseEqual
= Test.prototype.looseEqual
= Test.prototype.looseEquals
= function (a, b, msg, extra) {
this._assert(deepEqual(a, b), {
message : defined(msg, 'should be equivalent'),
operator : 'deepLooseEqual',
actual : a,
expected : b,
extra : extra
});
};
Test.prototype.notDeepEqual
= Test.prototype.notEquivalent
= Test.prototype.notDeeply
= Test.prototype.notSame
= Test.prototype.isNotDeepEqual
= Test.prototype.isNotDeeply
= Test.prototype.isNotEquivalent
= Test.prototype.isInequivalent
= function (a, b, msg, extra) {
this._assert(!deepEqual(a, b, { strict: true }), {
message : defined(msg, 'should not be equivalent'),
operator : 'notDeepEqual',
actual : a,
notExpected : b,
extra : extra
});
};
Test.prototype.notDeepLooseEqual
= Test.prototype.notLooseEqual
= Test.prototype.notLooseEquals
= function (a, b, msg, extra) {
this._assert(deepEqual(a, b), {
message : defined(msg, 'should be equivalent'),
operator : 'notDeepLooseEqual',
actual : a,
expected : b,
extra : extra
});
};
Test.prototype['throws'] = function (fn, expected, msg, extra) {
if (typeof expected === 'string') {
msg = expected;
expected = undefined;
}
var caught = undefined;
try {
fn();
}
catch (err) {
caught = { error : err };
var message = err.message;
delete err.message;
err.message = message;
}
var passed = caught;
if (expected instanceof RegExp) {
passed = expected.test(caught && caught.error);
expected = String(expected);
}
this._assert(passed, {
message : defined(msg, 'should throw'),
operator : 'throws',
actual : caught && caught.error,
expected : expected,
error: !passed && caught && caught.error,
extra : extra
});
};
Test.prototype.doesNotThrow = function (fn, expected, msg, extra) {
if (typeof expected === 'string') {
msg = expected;
expected = undefined;
}
var caught = undefined;
try {
fn();
}
catch (err) {
caught = { error : err };
}
this._assert(!caught, {
message : defined(msg, 'should not throw'),
operator : 'throws',
actual : caught && caught.error,
expected : expected,
error : caught && caught.error,
extra : extra
});
};
// vim: set softtabstop=4 shiftwidth=4:
}).call(this,require("/usr/local/lib/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js"),"/../node_modules/tape/lib")
},{"/usr/local/lib/node_modules/browserify/node_modules/insert-module-globals/node_modules/process/browser.js":25,"deep-equal":8,"defined":11,"events":23,"path":26,"stream":28,"util":36}],8:[function(require,module,exports){
var pSlice = Array.prototype.slice;
var objectKeys = require('./lib/keys.js');
var isArguments = require('./lib/is_arguments.js');
var deepEqual = module.exports = function (actual, expected, opts) {
if (!opts) opts = {};
// 7.1. All identical values are equivalent, as determined by ===.
if (actual === expected) {
return true;
} else if (actual instanceof Date && expected instanceof Date) {
return actual.getTime() === expected.getTime();
// 7.3. Other pairs that do not both pass typeof value == 'object',
// equivalence is determined by ==.
} else if (typeof actual != 'object' && typeof expected != 'object') {
return opts.strict ? actual === expected : actual == expected;
// 7.4. For all other Object pairs, including Array objects, equivalence is
// determined by having the same number of owned properties (as verified
// with Object.prototype.hasOwnProperty.call), the same set of keys
// (although not necessarily the same order), equivalent values for every
// corresponding key, and an identical 'prototype' property. Note: this
// accounts for both named and indexed properties on Arrays.
} else {
return objEquiv(actual, expected, opts);
}
}
function isUndefinedOrNull(value) {
return value === null || value === undefined;
}
function isBuffer (x) {
if (!x || typeof x !== 'object' || typeof x.length !== 'number') return false;
if (typeof x.copy !== 'function' || typeof x.slice !== 'function') {
return false;
}
if (x.length > 0 && typeof x[0] !== 'number') return false;
return true;
}
function objEquiv(a, b, opts) {
var i, key;
if (isUndefinedOrNull(a) || isUndefinedOrNull(b))
return false;
// an identical 'prototype' property.
if (a.prototype !== b.prototype) return false;
//~~~I've managed to break Object.keys through screwy arguments passing.
// Converting to array solves the problem.
if (isArguments(a)) {
if (!isArguments(b)) {
return false;
}
a = pSlice.call(a);
b = pSlice.call(b);
return deepEqual(a, b, opts);
}
if (isBuffer(a)) {
if (!isBuffer(b)) {
return false;
}
if (a.length !== b.length) return false;
for (i = 0; i < a.length; i++) {
if (a[i] !== b[i]) return false;
}
return true;
}
try {
var ka = objectKeys(a),
kb = objectKeys(b);
} catch (e) {//happens when one is a string literal and the other isn't
return false;
}
// having the same number of owned properties (keys incorporates
// hasOwnProperty)
if (ka.length != kb.length)
return false;
//the same set of keys (although not necessarily the same order),
ka.sort();
kb.sort();
//~~~cheap key test
for (i = ka.length - 1; i >= 0; i--) {
if (ka[i] != kb[i])
return false;
}
//equivalent values for every corresponding key, and
//~~~possibly expensive deep test
for (i = ka.length - 1; i >= 0; i--) {
key = ka[i];
if (!deepEqual(a[key], b[key], opts)) return false;
}
return true;
}
},{"./lib/is_arguments.js":9,"./lib/keys.js":10}],9:[function(require,module,exports){
var supportsArgumentsClass = (function(){
return Object.prototype.toString.call(arguments)
})() == '[object Arguments]';
exports = module.exports = supportsArgumentsClass ? supported : unsupported;
exports.supported = supported;
function supported(object) {
return Object.prototype.toString.call(object) == '[object Arguments]';
};
exports.unsupported = unsupported;
function unsupported(object){
return object &&
typeof object == 'object' &&
typeof object.length == 'number' &&
Object.prototype.hasOwnProperty.call(object, 'callee') &&
!Object.prototype.propertyIsEnumerable.call(object, 'callee') ||
false;
};
},{}],10:[function(require,module,exports){
exports = module.exports = typeof Object.keys === 'function'
? Object.keys : shim;
exports.shim = shim;
function shim (obj) {
var keys = [];
for (var key in obj) keys.push(key);
return keys;
}
},{}],11:[function(require,module,exports){
module.exports = function () {
for (var i = 0; i < arguments.length; i++) {
if (arguments[i] !== undefined) return arguments[i];
}
};
},{}],12:[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
}
}
},{}],13:[function(require,module,exports){
exports.parse = require('./lib/parse');
exports.stringify = require('./lib/stringify');
},{"./lib/parse":14,"./lib/stringify":15}],14:[function(require,module,exports){
var at, // The index of the current character
ch, // The current character
escapee = {
'"': '"',
'\\': '\\',
'/': '/',
b: '\b',
f: '\f',
n: '\n',
r: '\r',
t: '\t'
},
text,
error = function (m) {
// Call error when something is wrong.
throw {
name: 'SyntaxError',
message