UNPKG

parse-torrent

Version:

Parse a torrent and return an object of keys/values

1,783 lines (1,532 loc) 210 kB
(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