text: ﻿var model
  var meshnet
  var signaler
  (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) {
              /* jshint node: true */
              'use strict'
              meshnet = {}
              meshnet.alone = true
          var mesh = require('rtc-mesh');
              var quickconnect = require('rtc-quickconnect');
              var crel = require('crel');
              var uuid = require('cuid');
              meshnet.myid = ""
          var qc = quickconnect('http://rtc.io/switchboard', {
                  // debug: true,
                  room: 'ribbit.me',
                  iceServers: require('freeice')()
              }).on('call:started', function(id, pc, data) {
                  if (verbose) console.log('we have a new connection to: ' + id);
                  if (meshnet.alone) {
                      openChat()
                  }
                  renderChatList()
              }).on('connected', function () {
                  newtables.peers.offline(null, function (response) {
                      if (verbose) console.log("everyone is now off line", response)
                      renderChatList()
                  })
              }).on('call:ended', function (id) {
                  if (verbose) console.log('connection closed: ' + id);
                  newtables.peers.offline(id, function(response) {
                      if (verbose) console.log("set id: " + id + " offline", response)
                      renderChatList()
                  })
              });
             
              meshnet.qc = qc 
              
              model = mesh(qc);
              
              meshnet.addObject = function(obj, label) {
                  obj._label = label || uuid();
                  model.set(obj._label, obj.toJSON());
              }
  
          function openChat() {
              $("#chatInput").prop('disabled', false);
              $("#chatInput").attr("placeholder", "Chat Here")
              meshnet.alone = false
          }
  
          function publicIdentityCommand(cmd, cb) {
              getPublicIdentity(function(ident) {
                  var pk = foundIdentity[0]
                  try {
                      ident.address = bitcore.HDPrivateKey(JSON.parse(pk).xprivkey).privateKey.toAddress().toString()
                  } catch (e) {
                      ident.address = bitcore.HDPrivateKey(pk.xprivkey).privateKey.toAddress().toString()
                  }
                  ident.peerid = meshnet.qc.id
                  meshnet.issueCommand(cmd, ident)
                  return cb()
              })
          }
  
          function checkInit() {
              if (settings.inFrame()) {
                  return
              }
              publicIdentityCommand("join", function() {
                  setInterval(function() {
                      meshnet.issueCommand("heartbeat", meshnet.qc.id)
                  }, 300000)
              })
          }
  
         /* //TODO Depricated
          function publicUpdateIdentity() {
                  getPublicIdentity(function (ident) {
                      var pk = foundIdentity[0]
                      //ident.address = bitcore.HDPrivateKey(pk.xprivkey).privateKey.toAddress().toString()
                      try {
                          ident.address = bitcore.HDPrivateKey(JSON.parse(pk).xprivkey).privateKey.toAddress().toString()
                      } catch (e) {
                          ident.address = bitcore.HDPrivateKey(pk.xprivkey).privateKey.toAddress().toString()
                      }
                      ident.peerid = meshnet.qc.id
                      meshnet.issueCommand("update", ident)
                  })
              }*/
              
              function broadcastChat(chat) {
                  meshnet.issueCommand("chat",chat.toObj())
              }
              meshnet.broadcastChat = broadcastChat
  
              meshnet.issueCommand = function(command, payload) {
                  model.set('msgbus-' + command, payload);
              }
              
              meshnet.setValue = function (key, value, cb) {
                  model.set(key, value)
                  return cb()
              }
              
              meshnet.retrieveData = function(key,cb) {
                  model.retrieve(key, function(err, result) {
                     return cb(err, result)
                  })
              }
              meshnet.checkInit = checkInit
              meshnet.publicIdentityCommand  = publicIdentityCommand
  
          function peerJoin(data) {
              data.online = true;
              if (verbose) console.log("joined", data)
              newtables.peers.insert(data.address, data, function(err, doc) {
                  meshnet.setValue(data.address, data, function() {
                      renderChatList()
                  })
              })
          }
  
          model.on('connected', function () {
                  if (verbose) console.log('talking to the signalling server, and my id is: ' + this.id);
              })
              
              model.on('change', function (key, value) {
                  switch (key) {
                  case "msgbus-join":
                  case "msgbus-update":
                      return peerJoin(value)
                  case "msgbus-heartbeat":
                      newtables.peers.online(value, function(response) {
                          if (!headless) {
                              renderChatList()
                          }
                          if (verbose) console.log("set id: " + value + " online", response)
                      })
                      break;
                  case "msgbus-chat":
                      if (verbose) console.log('captured chat :' + JSON.stringify(value));
                      var verified = Message(value.msg).verify(value.address, value.signature);
                      if (verbose) console.log("sigmatch? " + verified)
                      if (verified && !headless) {
                          addGroupChatMsg(value)
                          renderChatList()
                      }
                      break;
                      case "msgbus-blockchain":
                          if (verbose) {console.info("Received a blockchain msg from the mesh network: "+JSON.stringify(value))}
                          if (value.type === "tx") {
                              var transaction = value
                              me.interested(transaction.payload.vout, function(interested, address, amount) {
                                  if (interested) {
                                      popMsg("Found interesting transaction @address "+address+" for "+amount)
                                  }
                              })
                          }    
                      break;
                  }
                  /*if (key === "msgbus-join" || key === "msgbus-update") {
                      return peerJoin(value)
                  } else if (key === "msgbus-heartbeat") {
                      newtables.peers.online(value, function (response) {
                              renderChatList()
                          if (verbose) console.log("set id: " + value + " online", response)
                      })
                  } else if (key === "msgbus-chat") {
                      if (settings.inFrame()) { return }
                      if (verbose) console.log('captured chat :' + JSON.stringify(value));
                      var verified = Message(value.msg).verify(value.address, value.signature);
                      if (verbose) console.log("sigmatch? " + verified)
                      if (verified) {
                              addGroupChatMsg(value)
                              renderChatList()
                      }
                  }*/
              });
              
              model.on('add', function (row) {
                  if (verbose) console.log('new row created: '+ JSON.stringify(row));
              });
              
              model.on('closed' + name, function(data) { if (verbose) console.log(data)});
              model.on('leave', function (data) { if (verbose) console.log(data) });
           
             /* qc.on('roominfo', function (data) {
  				$(".hometabs .badge").text(data.memberCount)
  				console.log(data)
                  console.log('room info: '+ JSON.stringify(data));
              });*/
          }, { "crel": 31, "cuid": 32, "freeice": 33, "rtc-mesh": 37, "rtc-quickconnect": 47 }], 2: [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')
              var isArray = require('is-array')
              
              exports.Buffer = Buffer
              exports.SlowBuffer = Buffer
              exports.INSPECT_MAX_BYTES = 50
              Buffer.poolSize = 8192 // not used by this implementation
              
              var kMaxLength = 0x3fffffff
              
              /**
   * If `Buffer.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 `Buffer.TYPED_ARRAY_SUPPORT` to `false` so they will
   * get the Object implementation, which is slower but will work correctly.
   */
  Buffer.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 TypeError('must start with number, buffer, array or string')
                  
                  if (this.length > kMaxLength)
                      throw new RangeError('Attempt to allocate Buffer larger than maximum ' +
        'size: 0x' + kMaxLength.toString(16) + ' bytes')
                  
                  var buf
                  if (Buffer.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 (Buffer.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' && !Buffer.TYPED_ARRAY_SUPPORT && !noZero) {
                      for (i = 0; i < length; i++) {
                          buf[i] = 0
                      }
                  }
                  
                  return buf
              }
              
              Buffer.isBuffer = function (b) {
                  return !!(b != null && b._isBuffer)
              }
              
              Buffer.compare = function (a, b) {
                  if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b))
                      throw new TypeError('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.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.concat = function (list, totalLength) {
                  if (!isArray(list)) throw new TypeError('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.byteLength = function (str, encoding) {
                  var ret
                  str = str + ''
                  switch (encoding || 'utf8') {
                      case 'ascii':
                      case 'binary':
                      case 'raw':
                          ret = str.length
                          break
                      case 'ucs2':
                      case 'ucs-2':
                      case 'utf16le':
                      case 'utf-16le':
                          ret = str.length * 2
                          break
                      case 'hex':
                          ret = str.length >>> 1
                          break
                      case 'utf8':
                      case 'utf-8':
                          ret = utf8ToBytes(str).length
                          break
                      case 'base64':
                          ret = base64ToBytes(str).length
                          break
                      default:
                          ret = str.length
                  }
                  return ret
              }
              
              // pre-set for values that may exist in the future
              Buffer.prototype.length = undefined
              Buffer.prototype.parent = undefined
              
              // toString(encoding, start=0, end=buffer.length)
              Buffer.prototype.toString = function (encoding, start, end) {
                  var loweredCase = false
                  
                  start = start >>> 0
                  end = end === undefined || end === Infinity ? this.length : end >>> 0
                  
                  if (!encoding) encoding = 'utf8'
                  if (start < 0) start = 0
                  if (end > this.length) end = this.length
                  if (end <= start) return ''
                  
                  while (true) {
                      switch (encoding) {
                          case 'hex':
                              return hexSlice(this, start, end)
  
                          case 'utf8':
                          case 'utf-8':
                              return utf8Slice(this, start, end)
  
                          case 'ascii':
                              return asciiSlice(this, start, end)
  
                          case 'binary':
                              return binarySlice(this, start, end)
  
                          case 'base64':
                              return base64Slice(this, start, end)
  
                          case 'ucs2':
                          case 'ucs-2':
                          case 'utf16le':
                          case 'utf-16le':
                              return utf16leSlice(this, start, end)
  
                          default:
                              if (loweredCase)
                                  throw new TypeError('Unknown encoding: ' + encoding)
                              encoding = (encoding + '').toLowerCase()
                              loweredCase = true
                      }
                  }
              }
              
              Buffer.prototype.equals = function (b) {
                  if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer')
                  return Buffer.compare(this, b) === 0
              }
              
              Buffer.prototype.inspect = function () {
                  var str = ''
                  var max = exports.INSPECT_MAX_BYTES
                  if (this.length > 0) {
                      str = this.toString('hex', 0, max).match(/.{2}/g).join(' ')
                      if (this.length > max)
                          str += ' ... '
                  }
                  return '<Buffer ' + str + '>'
              }
              
              Buffer.prototype.compare = function (b) {
                  if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer')
                  return Buffer.compare(this, b)
              }
              
              // `get` will be removed in Node 0.13+
              Buffer.prototype.get = function (offset) {
                  if (verbose) 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) {
                  if (verbose) console.log('.set() is deprecated. Access using array indexes instead.')
                  return this.writeUInt8(v, offset)
              }
              
              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
                  if (strLen % 2 !== 0) throw new Error('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)
                      if (isNaN(byte)) throw new Error('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 TypeError('Unknown encoding: ' + encoding)
                  }
                  return ret
              }
              
              Buffer.prototype.toJSON = function () {
                  return {
                      type: 'Buffer',
                      data: Array.prototype.slice.call(this._arr || this, 0)
                  }
              }
              
              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 (Buffer.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
                  }
              }
              
              /*
   * Need to make sure that buffer isn't trying to write out of bounds.
   */
  function checkOffset(offset, ext, length) {
                  if ((offset % 1) !== 0 || offset < 0)
                      throw new RangeError('offset is not uint')
                  if (offset + ext > length)
                      throw new RangeError('Trying to access beyond buffer length')
              }
              
              Buffer.prototype.readUInt8 = function (offset, noAssert) {
                  if (!noAssert)
                      checkOffset(offset, 1, this.length)
                  return this[offset]
              }
              
              Buffer.prototype.readUInt16LE = function (offset, noAssert) {
                  if (!noAssert)
                      checkOffset(offset, 2, this.length)
                  return this[offset] | (this[offset + 1] << 8)
              }
              
              Buffer.prototype.readUInt16BE = function (offset, noAssert) {
                  if (!noAssert)
                      checkOffset(offset, 2, this.length)
                  return (this[offset] << 8) | this[offset + 1]
              }
              
              Buffer.prototype.readUInt32LE = function (offset, noAssert) {
                  if (!noAssert)
                      checkOffset(offset, 4, this.length)
                  
                  return ((this[offset]) |
        (this[offset + 1] << 8) |
        (this[offset + 2] << 16)) +
        (this[offset + 3] * 0x1000000)
              }
              
              Buffer.prototype.readUInt32BE = function (offset, noAssert) {
                  if (!noAssert)
                      checkOffset(offset, 4, this.length)
                  
                  return (this[offset] * 0x1000000) +
        ((this[offset + 1] << 16) |
        (this[offset + 2] << 8) |
        this[offset + 3])
              }
              
              Buffer.prototype.readInt8 = function (offset, noAssert) {
                  if (!noAssert)
                      checkOffset(offset, 1, this.length)
                  if (!(this[offset] & 0x80))
                      return (this[offset])
                  return ((0xff - this[offset] + 1) * -1)
              }
              
              Buffer.prototype.readInt16LE = function (offset, noAssert) {
                  if (!noAssert)
                      checkOffset(offset, 2, this.length)
                  var val = this[offset] | (this[offset + 1] << 8)
                  return (val & 0x8000) ? val | 0xFFFF0000 : val
              }
              
              Buffer.prototype.readInt16BE = function (offset, noAssert) {
                  if (!noAssert)
                      checkOffset(offset, 2, this.length)
                  var val = this[offset + 1] | (this[offset] << 8)
                  return (val & 0x8000) ? val | 0xFFFF0000 : val
              }
              
              Buffer.prototype.readInt32LE = function (offset, noAssert) {
                  if (!noAssert)
                      checkOffset(offset, 4, this.length)
                  
                  return (this[offset]) |
        (this[offset + 1] << 8) |
        (this[offset + 2] << 16) |
        (this[offset + 3] << 24)
              }
              
              Buffer.prototype.readInt32BE = function (offset, noAssert) {
                  if (!noAssert)
                      checkOffset(offset, 4, this.length)
                  
                  return (this[offset] << 24) |
        (this[offset + 1] << 16) |
        (this[offset + 2] << 8) |
        (this[offset + 3])
              }
              
              Buffer.prototype.readFloatLE = function (offset, noAssert) {
                  if (!noAssert)
                      checkOffset(offset, 4, this.length)
                  return ieee754.read(this, offset, true, 23, 4)
              }
              
              Buffer.prototype.readFloatBE = function (offset, noAssert) {
                  if (!noAssert)
                      checkOffset(offset, 4, this.length)
                  return ieee754.read(this, offset, false, 23, 4)
              }
              
              Buffer.prototype.readDoubleLE = function (offset, noAssert) {
                  if (!noAssert)
                      checkOffset(offset, 8, this.length)
                  return ieee754.read(this, offset, true, 52, 8)
              }
              
              Buffer.prototype.readDoubleBE = function (offset, noAssert) {
                  if (!noAssert)
                      checkOffset(offset, 8, this.length)
                  return ieee754.read(this, offset, false, 52, 8)
              }
              
              function checkInt(buf, value, offset, ext, max, min) {
                  if (!Buffer.isBuffer(buf)) throw new TypeError('buffer must be a Buffer instance')
                  if (value > max || value < min) throw new TypeError('value is out of bounds')
                  if (offset + ext > buf.length) throw new TypeError('index out of range')
              }
              
              Buffer.prototype.writeUInt8 = function (value, offset, noAssert) {
                  value = +value
                  offset = offset >>> 0
                  if (!noAssert)
                      checkInt(this, value, offset, 1, 0xff, 0)
                  if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value)
                  this[offset] = value
                  return offset + 1
              }
              
              function objectWriteUInt16(buf, value, offset, littleEndian) {
                  if (value < 0) value = 0xffff + value + 1
                  for (var i = 0, j = Math.min(buf.length - offset, 2); i < j; i++) {
                      buf[offset + i] = (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>>
        (littleEndian ? i : 1 - i) * 8
                  }
              }
              
              Buffer.prototype.writeUInt16LE = function (value, offset, noAssert) {
                  value = +value
                  offset = offset >>> 0
                  if (!noAssert)
                      checkInt(this, value, offset, 2, 0xffff, 0)
                  if (Buffer.TYPED_ARRAY_SUPPORT) {
                      this[offset] = value
                      this[offset + 1] = (value >>> 8)
                  } else objectWriteUInt16(this, value, offset, true)
                  return offset + 2
              }
              
              Buffer.prototype.writeUInt16BE = function (value, offset, noAssert) {
                  value = +value
                  offset = offset >>> 0
                  if (!noAssert)
                      checkInt(this, value, offset, 2, 0xffff, 0)
                  if (Buffer.TYPED_ARRAY_SUPPORT) {
                      this[offset] = (value >>> 8)
                      this[offset + 1] = value
                  } else objectWriteUInt16(this, value, offset, false)
                  return offset + 2
              }
              
              function objectWriteUInt32(buf, value, offset, littleEndian) {
                  if (value < 0) value = 0xffffffff + value + 1
                  for (var i = 0, j = Math.min(buf.length - offset, 4); i < j; i++) {
                      buf[offset + i] = (value >>> (littleEndian ? i : 3 - i) * 8) & 0xff
                  }
              }
              
              Buffer.prototype.writeUInt32LE = function (value, offset, noAssert) {
                  value = +value
                  offset = offset >>> 0
                  if (!noAssert)
                      checkInt(this, value, offset, 4, 0xffffffff, 0)
                  if (Buffer.TYPED_ARRAY_SUPPORT) {
                      this[offset + 3] = (value >>> 24)
                      this[offset + 2] = (value >>> 16)
                      this[offset + 1] = (value >>> 8)
                      this[offset] = value
                  } else objectWriteUInt32(this, value, offset, true)
                  return offset + 4
              }
              
              Buffer.prototype.writeUInt32BE = function (value, offset, noAssert) {
                  value = +value
                  offset = offset >>> 0
                  if (!noAssert)
                      checkInt(this, value, offset, 4, 0xffffffff, 0)
                  if (Buffer.TYPED_ARRAY_SUPPORT) {
                      this[offset] = (value >>> 24)
                      this[offset + 1] = (value >>> 16)
                      this[offset + 2] = (value >>> 8)
                      this[offset + 3] = value
                  } else objectWriteUInt32(this, value, offset, false)
                  return offset + 4
              }
              
              Buffer.prototype.writeInt8 = function (value, offset, noAssert) {
                  value = +value
                  offset = offset >>> 0
                  if (!noAssert)
                      checkInt(this, value, offset, 1, 0x7f, -0x80)
                  if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value)
                  if (value < 0) value = 0xff + value + 1
                  this[offset] = value
                  return offset + 1
              }
              
              Buffer.prototype.writeInt16LE = function (value, offset, noAssert) {
                  value = +value
                  offset = offset >>> 0
                  if (!noAssert)
                      checkInt(this, value, offset, 2, 0x7fff, -0x8000)
                  if (Buffer.TYPED_ARRAY_SUPPORT) {
                      this[offset] = value
                      this[offset + 1] = (value >>> 8)
                  } else objectWriteUInt16(this, value, offset, true)
                  return offset + 2
              }
              
              Buffer.prototype.writeInt16BE = function (value, offset, noAssert) {
                  value = +value
                  offset = offset >>> 0
                  if (!noAssert)
                      checkInt(this, value, offset, 2, 0x7fff, -0x8000)
                  if (Buffer.TYPED_ARRAY_SUPPORT) {
                      this[offset] = (value >>> 8)
                      this[offset + 1] = value
                  } else objectWriteUInt16(this, value, offset, false)
                  return offset + 2
              }
              
              Buffer.prototype.writeInt32LE = function (value, offset, noAssert) {
                  value = +value
                  offset = offset >>> 0
                  if (!noAssert)
                      checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)
                  if (Buffer.TYPED_ARRAY_SUPPORT) {
                      this[offset] = value
                      this[offset + 1] = (value >>> 8)
                      this[offset + 2] = (value >>> 16)
                      this[offset + 3] = (value >>> 24)
                  } else objectWriteUInt32(this, value, offset, true)
                  return offset + 4
              }
              
              Buffer.prototype.writeInt32BE = function (value, offset, noAssert) {
                  value = +value
                  offset = offset >>> 0
                  if (!noAssert)
                      checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000)
                  if (value < 0) value = 0xffffffff + value + 1
                  if (Buffer.TYPED_ARRAY_SUPPORT) {
                      this[offset] = (value >>> 24)
                      this[offset + 1] = (value >>> 16)
                      this[offset + 2] = (value >>> 8)
                      this[offset + 3] = value
                  } else objectWriteUInt32(this, value, offset, false)
                  return offset + 4
              }
              
              function checkIEEE754(buf, value, offset, ext, max, min) {
                  if (value > max || value < min) throw new TypeError('value is out of bounds')
                  if (offset + ext > buf.length) throw new TypeError('index out of range')
              }
              
              function writeFloat(buf, value, offset, littleEndian, noAssert) {
                  if (!noAssert)
                      checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38)
                  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)
                      checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308)
                  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)
              }
              
              // 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
                  if (end < start) throw new TypeError('sourceEnd < sourceStart')
                  if (target_start < 0 || target_start >= target.length)
                      throw new TypeError('targetStart out of bounds')
                  if (start < 0 || start >= source.length) throw new TypeError('sourceStart out of bounds')
                  if (end < 0 || end > source.length) throw new TypeError('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 || !Buffer.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)
                  }
              }
              
              // 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
                  
                  if (end < start) throw new TypeError('end < start')
                  
                  // Fill 0 bytes; we're done
                  if (end === start) return
                  if (this.length === 0) return
                  
                  if (start < 0 || start >= this.length) throw new TypeError('start out of bounds')
                  if (end < 0 || end > this.length) throw new TypeError('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
              }
              
              /**
   * 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 (Buffer.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 TypeError('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 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
                  }
              }
  
          }, { "base64-js": 3, "ieee754": 4, "is-array": 5 }], 3: [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))
  
          }, {}], 4: [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;
              };
  
          }, {}], 5: [function (require, module, exports) {
              
              /**
   * isArray
   */
  
  var isArray = Array.isArray;
              
              /**
   * toString
   */
  
  var str = Object.prototype.toString;
              
              /**
   * Whether or not the given `val`
   * is an array.
   *
   * example:
   *
   *        isArray([]);
   *        // > true
   *        isArray(arguments);
   *        // > false
   *        isArray('');
   *        // > false
   *
   * @param {mixed} val
   * @return {bool}
   */
  
  module.exports = isArray || function (val) {
                  return !!val && '[object Array]' == str.call(val);
              };
  
          }, {}], 6: [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
                          }
                          //throw TypeError('Uncaught, unspecified "error" event.');
                      }
                  }
                  
                  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;
              }
  
          }, {}], 7: [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
                  }
              }
  
          }, {}], 8: [function (require, module, exports) {
              module.exports = Array.isArray || function (arr) {
                  return Object.prototype.toString.call(arr) == '[object Array]';
              };
  
          }, {}], 9: [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 canMutationObserver = typeof window !== 'undefined' 
      && window.MutationObserver;
                  var canPost = typeof window !== 'undefined' 
      && window.postMessage && window.addEventListener
      ;
                  
                  if (canSetImmediate) {
                      return function (f) { return window.setImmediate(f) };
                  }
                  
                  var queue = [];
                  
                  if (canMutationObserver) {
                      var hiddenDiv = document.createElement("div");
                      var observer = new MutationObserver(function () {
                          var queueList = queue.slice();
                          queue.length = 0;
                          queueList.forEach(function (fn) {
                              fn();
                          });
                      });
                      
                      observer.observe(hiddenDiv, { attributes: true });
                      
                      return function nextTick(fn) {
                          if (!queue.length) {
                              hiddenDiv.setAttribute('yes', 'no');
                          }
                          queue.push(fn);
                      };
                  }
                  
                  if (canPost) {
                      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');
              };
  
          }, {}], 10: [function (require, module, exports) {
              module.exports = require("./lib/_stream_duplex.js")
  
          }, { "./lib/_stream_duplex.js": 11 }], 11: [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": 13, "./_stream_writable": 15, "_process": 9, "core-util-is": 16, "inherits": 7 }], 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.
              
              // 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": 14, "core-util-is": 16, "inherits": 7 }], 13: [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 (n === null || isNaN(n)) {
                          // 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;
                      var ret;
                      
                      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) {
                          ret = null;
                          
                          // In cases where the decoder did not receive enough data
                          // to produce a full chunk, then immediately received an
                          // EOF, state.buffer will contain [<Buffer >, <Buffer 00 ...>].
                          // howMuchToRead will see this and coerce the amount to
                          // read to zero (because it's looking at the length of the
                          // first <Buffer > in state.buffer), and we'll end up here.
                          //
                          // This can only happen via state.decoder -- no other venue
                          // exists for pushing a zero-length chunk into state.buffer
                          // and triggering this behavior. In this case, we return our
                          // remaining data and end the stream, if appropriate.
                          if (state.length > 0 && state.decoder) {
                              ret = fromList(n, state);
                              state.length -= ret.length;
                          }
                          
                          if (state.length === 0)
                              endReadable(this);
                          
                          return ret;
                      }
                      
                      // 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);
                      
                      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 = 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);
                          
                          // don't skip over falsy values in objectMode
                          //if (state.objectMode && util.isNullOrUndefined(chunk))
                          if (state.objectMode && (chunk === null || chunk === undefined))
                              return;
                          else if (!state.objectMode && (!chunk || !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": 9, "buffer": 2, "core-util-is": 16, "events": 6, "inherits": 7, "isarray": 8, "stream": 21, "string_decoder/": 22 }], 14: [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": 11, "core-util-is": 16, "inherits": 7 }], 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.
                  
                  // 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": 11, "_process": 9, "buffer": 2, "core-util-is": 16, "inherits": 7, "stream": 21 }], 16: [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": 2 }], 17: [function (require, module, exports) {
              module.exports = require("./lib/_stream_passthrough.js")
  
          }, { "./lib/_stream_passthrough.js": 12 }], 18: [function (require, module, exports) {
              require('stream'); // hack to fix a circular dependency issue when used with browserify
              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": 11, "./lib/_stream_passthrough.js": 12, "./lib/_stream_readable.js": 13, "./lib/_stream_transform.js": 14, "./lib/_stream_writable.js": 15, "stream": 21 }], 19: [function (require, module, exports) {
              module.exports = require("./lib/_stream_transform.js")
  
          }, { "./lib/_stream_transform.js": 14 }], 20: [function (require, module, exports) {
              module.exports = require("./lib/_stream_writable.js")
  
          }, { "./lib/_stream_writable.js": 15 }], 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.
              
              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": 6, "inherits": 7, "readable-stream/duplex.js": 10, "readable-stream/passthrough.js": 17, "readable-stream/readable.js": 18, "readable-stream/transform.js": 19, "readable-stream/writable.js": 20 }], 22: [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);
                  }
              }
              
              // StringDecoder provides an interface for efficiently splitting a series of
              // buffers into a series of JS strings without breaking apart multi-byte
              // characters. CESU-8 is handled as part of the UTF-8 encoding.
              //
              // @TODO Handling all encodings inside a single object makes it very difficult
              // to reason about this code, so it should be split up in the future.
              // @TODO There should be a utf8-strict encoding that rejects invalid UTF-8 code
              // points as used by CESU-8.
              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;
                  }
                  
                  // Enough space to store all bytes of a single character. UTF-8 needs 4
                  // bytes, but CESU-8 may require up to 6 (3 bytes per surrogate).
                  this.charBuffer = new Buffer(6);
                  // Number of bytes received for the current incomplete multi-byte character.
                  this.charReceived = 0;
                  // Number of bytes expected for the current incomplete multi-byte character.
                  this.charLength = 0;
              };
              
              
              // write decodes the given buffer and returns it as JS string that is
              // guaranteed to not contain any partial multi-byte characters. Any partial
              // character found at the end of the buffer is buffered up, and will be
              // returned when calling write again with the remaining bytes.
              //
              // Note: Converting a Buffer containing an orphan surrogate to a String
              // currently works, but converting a String to a Buffer (via `new Buffer`, or
              // Buffer#write) will replace incomplete surrogates with the unicode
              // replacement character. See https://codereview.chromium.org/121173009/ .
              StringDecoder.prototype.write = function (buffer) {
                  var charStr = '';
                  // 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 available = (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, 0, available);
                      this.charReceived += available;
                      
                      if (this.charReceived < this.charLength) {
                          // still not enough chars in this buffer? wait for more ...
                          return '';
                      }
                      
                      // remove bytes belonging to the current character from the buffer
                      buffer = buffer.slice(available, buffer.length);
                      
                      // get the character that was split
                      charStr = this.charBuffer.slice(0, this.charLength).toString(this.encoding);
                      
                      // CESU-8: 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 (buffer.length === 0) {
                          return charStr;
                      }
                      break;
                  }
                  
                  // determine and set charLength / charReceived
                  this.detectIncompleteChar(buffer);
                  
                  var end = buffer.length;
                  if (this.charLength) {
                      // buffer the incomplete character bytes we got
                      buffer.copy(this.charBuffer, 0, buffer.length - this.charReceived, end);
                      end -= this.charReceived;
                  }
                  
                  charStr += buffer.toString(this.encoding, 0, end);
                  
                  var end = charStr.length - 1;
                  var charCode = charStr.charCodeAt(end);
                  // CESU-8: 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);
                      buffer.copy(this.charBuffer, 0, 0, size);
                      return charStr.substring(0, end);
                  }
                  
                  // or just emit the charStr
                  return charStr;
              };
              
              // detectIncompleteChar determines if there is an incomplete UTF-8 character at
              // the end of the given buffer. If so, it sets this.charLength to the byte
              // length that character, and sets this.charReceived to the number of bytes
              // that are available for this character.
              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;
                      }
                  }
                  this.charReceived = 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) {
                  this.charReceived = buffer.length % 2;
                  this.charLength = this.charReceived ? 2 : 0;
              }
              
              function base64DetectIncompleteChar(buffer) {
                  this.charReceived = buffer.length % 3;
                  this.charLength = this.charReceived ? 3 : 0;
              }
  
          }, { "buffer": 2 }], 23: [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';
              }
          }, {}], 24: [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": 23, "_process": 9, "inherits": 7 }], 25: [function (require, module, exports) {
              /* jshint node: true */
              'use strict';
              
              /**
  ## cog/defaults
  
  ```js
  var defaults = require('cog/defaults');
  ```
  
  ### defaults(target, *)
  
  Shallow copy object properties from the supplied source objects (*) into
  the target object, returning the target object once completed.  Do not,
  however, overwrite existing keys with new values:
  
  ```js
  defaults({ a: 1, b: 2 }, { c: 3 }, { d: 4 }, { b: 5 }));
  ```
  
  See an example on [requirebin](http://requirebin.com/?gist=6079475).
  **/
  module.exports = function (target) {
                  // ensure we have a target
                  target = target || {};
                  
                  // iterate through the sources and copy to the target
                  [].slice.call(arguments, 1).forEach(function (source) {
                      if (!source) {
                          return;
                      }
                      
                      for (var prop in source) {
                          if (target[prop] === void 0) {
                              target[prop] = source[prop];
                          }
                      }
                  });
                  
                  return target;
              };
          }, {}], 26: [function (require, module, exports) {
              /* jshint node: true */
              'use strict';
              
              /**
  ## cog/extend
  
  ```js
  var extend = require('cog/extend');
  ```
  
  ### extend(target, *)
  
  Shallow copy object properties from the supplied source objects (*) into
  the target object, returning the target object once completed:
  
  ```js
  extend({ a: 1, b: 2 }, { c: 3 }, { d: 4 }, { b: 5 }));
  ```
  
  See an example on [requirebin](http://requirebin.com/?gist=6079475).
  **/
  module.exports = function (target) {
                  [].slice.call(arguments, 1).forEach(function (source) {
                      if (!source) {
                          return;
                      }
                      
                      for (var prop in source) {
                          target[prop] = source[prop];
                      }
                  });
                  
                  return target;
              };
          }, {}], 27: [function (require, module, exports) {
              /**
    ## cog/getable
  
    Take an object and provide a wrapper that allows you to `get` and
    `set` values on that object.
  
  **/
  module.exports = function (target) {
                  function get(key) {
                      return target[key];
                  }
                  
                  function set(key, value) {
                      target[key] = value;
                  }
                  
                  function remove(key) {
                      return delete target[key];
                  }
                  
                  function keys() {
                      return Object.keys(target);
                  }                ;
                  
                  function values() {
                      return Object.keys(target).map(function (key) {
                          return target[key];
                      });
                  }                ;
                  
                  if (typeof target != 'object') {
                      return target;
                  }
                  
                  return {
                      get: get,
                      set: set,
                      remove: remove,
                      delete: remove,
                      keys: keys,
                      values: values
                  };
              };
  
          }, {}], 28: [function (require, module, exports) {
              /* jshint node: true */
              'use strict';
              
              /**
    ## cog/jsonparse
  
    ```js
    var jsonparse = require('cog/jsonparse');
    ```
  
    ### jsonparse(input)
  
    This function will attempt to automatically detect stringified JSON, and
    when detected will parse into JSON objects.  The function looks for strings
    that look and smell like stringified JSON, and if found attempts to
    `JSON.parse` the input into a valid object.
  
  **/
  module.exports = function (input) {
                  var isString = typeof input == 'string' || (input instanceof String);
                  var reNumeric = /^\-?\d+\.?\d*$/;
                  var shouldParse;
                  var firstChar;
                  var lastChar;
                  
                  if ((!isString) || input.length < 2) {
                      if (isString && reNumeric.test(input)) {
                          return parseFloat(input);
                      }
                      
                      return input;
                  }
                  
                  // check for true or false
                  if (input === 'true' || input === 'false') {
                      return input === 'true';
                  }
                  
                  // check for null
                  if (input === 'null') {
                      return null;
                  }
                  
                  // get the first and last characters
                  firstChar = input.charAt(0);
                  lastChar = input.charAt(input.length - 1);
                  
                  // determine whether we should JSON.parse the input
                  shouldParse =
      (firstChar == '{' && lastChar == '}') ||
      (firstChar == '[' && lastChar == ']') ||
      (firstChar == '"' && lastChar == '"');
                  
                  if (shouldParse) {
                      try {
                          return JSON.parse(input);
                      }
      catch (e) {
        // apparently it wasn't valid json, carry on with regular processing
                      }
                  }
                  
                  
                  return reNumeric.test(input) ? parseFloat(input) : input;
              };
          }, {}], 29: [function (require, module, exports) {
              /* jshint node: true */
              'use strict';
              
              /**
    ## cog/logger
  
    ```js
    var logger = require('cog/logger');
    ```
  
    Simple browser logging offering similar functionality to the
    [debug](https://github.com/visionmedia/debug) module.
  
    ### Usage
  
    Create your self a new logging instance and give it a name:
  
    ```js
    var debug = logger('phil');
    ```
  
    Now do some debugging:
  
    ```js
    debug('hello');
    ```
  
    At this stage, no log output will be generated because your logger is
    currently disabled.  Enable it:
  
    ```js
    logger.enable('phil');
    ```
  
    Now do some more logger:
  
    ```js
    debug('Oh this is so much nicer :)');
    // --> phil: Oh this is some much nicer :)
    ```
  
    ### Reference
  **/
  
  var active = [];
              var unleashListeners = [];
              var targets = [console];
              
              /**
    #### logger(name)
  
    Create a new logging instance.
  **/
  var logger = module.exports = function (name) {
                  // initial enabled check
                  var enabled = checkActive();
                  
                  function checkActive() {
                      return enabled = active.indexOf('*') >= 0 || active.indexOf(name) >= 0;
                  }
                  
                  // register the check active with the listeners array
                  unleashListeners[unleashListeners.length] = checkActive;
                  
                  // return the actual logging function
                  return function () {
                      var args = [].slice.call(arguments);
                      
                      // if we have a string message
                      if (typeof args[0] == 'string' || (args[0] instanceof String)) {
                          args[0] = name + ': ' + args[0];
                      }
                      
                      // if not enabled, bail
                      if (!enabled) {
                          return;
                      }
                      
                      // log
                      targets.forEach(function (target) {
                          target.log.apply(target, args);
                      });
                  };
              };
              
              /**
    #### logger.reset()
  
    Reset logging (remove the default console logger, flag all loggers as
    inactive, etc, etc.
  **/
  logger.reset = function () {
                  // reset targets and active states
                  targets = [];
                  active = [];
                  
                  return logger.enable();
              };
              
              /**
    #### logger.to(target)
  
    Add a logging target.  The logger must have a `log` method attached.
  
  **/
  logger.to = function (target) {
                  targets = targets.concat(target || []);
                  
                  return logger;
              };
              
              /**
    #### logger.enable(names*)
  
    Enable logging via the named logging instances.  To enable logging via all
    instances, you can pass a wildcard:
  
    ```js
    logger.enable('*');
    ```
  
    __TODO:__ wildcard enablers
  **/
  logger.enable = function () {
                  // update the active
                  active = active.concat([].slice.call(arguments));
                  
                  // trigger the unleash listeners
                  unleashListeners.forEach(function (listener) {
                      listener();
                  });
                  
                  return logger;
              };
          }, {}], 30: [function (require, module, exports) {
              /* jshint node: true */
              'use strict';
              
              /**
    ## cog/throttle
  
    ```js
    var throttle = require('cog/throttle');
    ```
  
    ### throttle(fn, delay, opts)
  
    A cherry-pickable throttle function.  Used to throttle `fn` to ensure
    that it can be called at most once every `delay` milliseconds.  Will
    fire first event immediately, ensuring the next event fired will occur
    at least `delay` milliseconds after the first, and so on.
  
  **/
  module.exports = function (fn, delay, opts) {
                  var lastExec = (opts || {}).leading !== false ? 0 : Date.now();
                  var trailing = (opts || {}).trailing;
                  var timer;
                  var queuedArgs;
                  var queuedScope;
                  
                  // trailing defaults to true
                  trailing = trailing || trailing === undefined;
                  
                  function invokeDefered() {
                      fn.apply(queuedScope, queuedArgs || []);
                      lastExec = Date.now();
                  }
                  
                  return function () {
                      var tick = Date.now();
                      var elapsed = tick - lastExec;
                      
                      // always clear the defered timer
                      clearTimeout(timer);
                      
                      if (elapsed < delay) {
                          queuedArgs = [].slice.call(arguments, 0);
                          queuedScope = this;
                          
                          return trailing && (timer = setTimeout(invokeDefered, delay - elapsed));
                      }
                      
                      // call the function
                      lastExec = tick;
                      fn.apply(this, arguments);
                  };
              };
          }, {}], 31: [function (require, module, exports) {
              //Copyright (C) 2012 Kory Nunn
              
              //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.
              
              /*
  
      This code is not formatted for readability, but rather run-speed and to assist compilers.
  
      However, the code's intention should be transparent.
  
      *** IE SUPPORT ***
  
      If you require this library to work in IE7, add the following after declaring crel.
  
      var testDiv = document.createElement('div'),
          testLabel = document.createElement('label');
  
      testDiv.setAttribute('class', 'a');
      testDiv['className'] !== 'a' ? crel.attrMap['class'] = 'className':undefined;
      testDiv.setAttribute('name','a');
      testDiv['name'] !== 'a' ? crel.attrMap['name'] = function(element, value){
          element.id = value;
      }:undefined;
  
  
      testLabel.setAttribute('for', 'a');
      testLabel['htmlFor'] !== 'a' ? crel.attrMap['for'] = 'htmlFor':undefined;
  
  
  
  */
  
  (function (root, factory) {
                  if (typeof exports === 'object') {
                      module.exports = factory();
                  } else if (typeof define === 'function' && define.amd) {
                      define(factory);
                  } else {
                      root.crel = factory();
                  }
              }(this, function () {
                  var fn = 'function',
                      obj = 'object',
                      isType = function (a, type) {
                          return typeof a === type;
                      },
                      isNode = typeof Node === fn ? function (object) {
                          return object instanceof Node;
                      } :
          // in IE <= 8 Node is an object, obviously..
          function (object) {
                          return object &&
                  isType(object, obj) &&
                  ('nodeType' in object) &&
                  isType(object.ownerDocument, obj);
                      },
                      isElement = function (object) {
                          return crel.isNode(object) && object.nodeType === 1;
                      },
                      isArray = function (a) {
                          return a instanceof Array;
                      },
                      appendChild = function (element, child) {
                          if (!isNode(child)) {
                              child = document.createTextNode(child);
                          }
                          element.appendChild(child);
                      };
                  
                  
                  function crel() {
                      var args = arguments, //Note: assigned to a variable to assist compilers. Saves about 40 bytes in closure compiler. Has negligable effect on performance.
                          element = args[0],
                          child,
                          settings = args[1],
                          childIndex = 2,
                          argumentsLength = args.length,
                          attributeMap = crel.attrMap;
                      
                      element = crel.isElement(element) ? element : document.createElement(element);
                      // shortcut
                      if (argumentsLength === 1) {
                          return element;
                      }
                      
                      if (!isType(settings, obj) || crel.isNode(settings) || isArray(settings)) {
                          --childIndex;
                          settings = null;
                      }
                      
                      // shortcut if there is only one child that is a string
                      if ((argumentsLength - childIndex) === 1 && isType(args[childIndex], 'string') && element.textContent !== undefined) {
                          element.textContent = args[childIndex];
                      } else {
                          for (; childIndex < argumentsLength; ++childIndex) {
                              child = args[childIndex];
                              
                              if (child == null) {
                                  continue;
                              }
                              
                              if (isArray(child)) {
                                  for (var i = 0; i < child.length; ++i) {
                                      appendChild(element, child[i]);
                                  }
                              } else {
                                  appendChild(element, child);
                              }
                          }
                      }
                      
                      for (var key in settings) {
                          if (!attributeMap[key]) {
                              element.setAttribute(key, settings[key]);
                          } else {
                              var attr = crel.attrMap[key];
                              if (typeof attr === fn) {
                                  attr(element, settings[key]);
                              } else {
                                  element.setAttribute(attr, settings[key]);
                              }
                          }
                      }
                      
                      return element;
                  }
                  
                  // Used for mapping one kind of attribute to the supported version of that in bad browsers.
                  // String referenced so that compilers maintain the property name.
                  crel['attrMap'] = {};
                  
                  // String referenced so that compilers maintain the property name.
                  crel["isElement"] = isElement;
                  crel["isNode"] = isNode;
                  
                  return crel;
              }));
  
          }, {}], 32: [function (require, module, exports) {
              /**
   * cuid.js
   * Collision-resistant UID generator for browsers and node.
   * Sequential for fast db lookups and recency sorting.
   * Safe for element IDs and server-side lookups.
   *
   * Extracted from CLCTR
   * 
   * Copyright (c) Eric Elliott 2012
   * MIT License
   */
  
  /*global window, navigator, document, require, process, module */
  (function (app) {
                  'use strict';
                  var namespace = 'cuid',
                      c = 0,
                      blockSize = 4,
                      base = 36,
                      discreteValues = Math.pow(base, blockSize),
  
                      pad = function pad(num, size) {
                          var s = "000000000" + num;
                          return s.substr(s.length - size);
                      },
  
                      randomBlock = function randomBlock() {
                          return pad((Math.random() *
              discreteValues << 0)
              .toString(base), blockSize);
                      },
  
                      safeCounter = function () {
                          c = (c < discreteValues) ? c : 0;
                          c++; // this is not subliminal
                          return c - 1;
                      },
  
                      api = function cuid() {
                          // Starting with a lowercase letter makes
                          // it HTML element ID friendly.
                          var letter = 'c', // hard-coded allows for sequential access
  
          // timestamp
          // warning: this exposes the exact date and time
          // that the uid was created.
                              timestamp = (new Date().getTime()).toString(base),
  
          // Prevent same-machine collisions.
                              counter,
  
          // A few chars to generate distinct ids for different
          // clients (so different computers are far less
          // likely to generate the same id)
                              fingerprint = api.fingerprint(),
  
          // Grab some more chars from Math.random()
                              random = randomBlock() + randomBlock();
                          
                          counter = pad(safeCounter().toString(base), blockSize);
                          
                          return (letter + timestamp + counter + fingerprint + random);
                      };
                  
                  api.slug = function slug() {
                      var date = new Date().getTime().toString(36),
                          counter,
                          print = api.fingerprint().slice(0, 1) +
          api.fingerprint().slice(-1),
                          random = randomBlock().slice(-2);
                      
                      counter = safeCounter().toString(36).slice(-4);
                      
                      return date.slice(-2) + 
        counter + print + random;
                  };
                  
                  api.globalCount = function globalCount() {
                      // We want to cache the results of this
                      var cache = (function calc() {
                          var i,
                              count = 0;
                          
                          for (i in window) {
                              count++;
                          }
                          
                          return count;
                      }());
                      
                      api.globalCount = function () { return cache; };
                      return cache;
                  };
                  
                  api.fingerprint = function browserPrint() {
                      return pad((navigator.mimeTypes.length +
        navigator.userAgent.length).toString(36) +
        api.globalCount().toString(36), 4);
                  };
                  
                  // don't change anything from here down.
                  if (app.register) {
                      app.register(namespace, api);
                  } else if (typeof module !== 'undefined') {
                      module.exports = api;
                  } else {
                      app[namespace] = api;
                  }
  
              }(this.applitude || this));
  
          }, {}], 33: [function (require, module, exports) {
              /* jshint node: true */
              'use strict';
              
              var normalice = require('normalice');
              
              /**
    # freeice
  
    The `freeice` module is a simple way of getting random STUN or TURN server
    for your WebRTC application.  The list of servers (just STUN at this stage)
    were sourced from this [gist](https://gist.github.com/zziuni/3741933).
  
    ## Example Use
  
    The following demonstrates how you can use `freeice` with
    [rtc-quickconnect](https://github.com/rtc-io/rtc-quickconnect):
  
    <<< examples/quickconnect.js
  
    As the `freeice` module generates ice servers in a list compliant with the
    WebRTC spec you will be able to use it with raw `RTCPeerConnection`
    constructors and other WebRTC libraries.
  
    ## Hey, don't use my STUN/TURN server!
  
    If for some reason your free STUN or TURN server ends up in the
    [list](servers.js) of servers that is used in this module, you can feel
    free to open an issue on this repository and those servers will be removed
    within 24 hours (or sooner).  This is the quickest and probably the most
    polite way to have something removed (and provides us some visibility
    if someone opens a pull request requesting that a server is added).
  
    ## Please add my server!
  
    If you have a server that you wish to add to the list, that's awesome! I'm
    sure I speak on behalf of a whole pile of WebRTC developers who say thanks.
    To get it into the list, feel free to either open a pull request or if you
    find that process a bit daunting then just create an issue requesting
    the addition of the server (make sure you provide all the details, and if
    you have a Terms of Service then including that in the PR/issue would be
    awesome).
  
    ## I know of a free server, can I add it?
  
    Sure, if you do your homework and make sure it is ok to use (I'm currently
    in the process of reviewing the terms of those STUN servers included from
    the original list).  If it's ok to go, then please see the previous entry
    for how to add it.
  
    ## Current List of Servers
  
    * current as at the time of last `README.md` file generation
  
    ### STUN
  
    <<< stun.json
  
    ### TURN
  
    <<< turn.json
  
  **/
  
  var freeice = module.exports = function (opts) {
                  // if a list of servers has been provided, then use it instead of defaults
                  var servers = {
                      stun: (opts || {}).stun || require('./stun.json'),
                      turn: (opts || {}).turn || require('./turn.json')
                  };
                  
                  var stunCount = (opts || {}).stunCount || 2;
                  var turnCount = (opts || {}).turnCount || 0;
                  var selected;
                  
                  function getServers(type, count) {
                      var out = [];
                      var input = [].concat(servers[type]);
                      var idx;
                      
                      while (input.length && out.length < count) {
                          idx = (Math.random() * input.length) | 0;
                          out = out.concat(input.splice(idx, 1));
                      }
                      
                      return out.map(function (url) {
                          return normalice(type + ':' + url);
                      });
                  }
                  
                  // add stun servers
                  selected = [].concat(getServers('stun', stunCount));
                  
                  if (turnCount) {
                      selected = selected.concat(getServers('turn', turnCount));
                  }
                  
                  return selected;
              };
  
          }, { "./stun.json": 35, "./turn.json": 36, "normalice": 34 }], 34: [function (require, module, exports) {
              /**
    # normalice
  
    Normalize an ice server configuration object (or plain old string) into a format
    that is usable in all browsers supporting WebRTC.  Primarily this module is designed
    to help with the transition of the `url` attribute of the configuration object to
    the `urls` attribute.
  
    ## Example Usage
  
    <<< examples/simple.js
  
  **/
  
  var protocols = [
                  'stun:',
                  'turn:'
              ];
              
              module.exports = function (input) {
                  var url = (input || {}).url || input;
                  var protocol;
                  var parts;
                  var output = {};
                  
                  // if we don't have a string url, then allow the input to passthrough
                  if (typeof url != 'string' && (!(url instanceof String))) {
                      return input;
                  }
                  
                  // trim the url string, and convert to an array
                  url = url.trim();
                  
                  // if the protocol is not known, then passthrough
                  protocol = protocols[protocols.indexOf(url.slice(0, 5))];
                  if (!protocol) {
                      return input;
                  }
                  
                  // now let's attack the remaining url parts
                  url = url.slice(5);
                  parts = url.split('@');
                  
                  output.username = input.username;
                  output.credential = input.credential;
                  // if we have an authentication part, then set the credentials
                  if (parts.length > 1) {
                      url = parts[1];
                      parts = parts[0].split(':');
                      
                      // add the output credential and username
                      output.username = parts[0];
                      output.credential = (input || {}).credential || parts[1] || '';
                  }
                  
                  output.url = protocol + url;
                  output.urls = [output.url];
                  
                  return output;
              };
  
          }, {}], 35: [function (require, module, exports) {
              module.exports = [
                  "stun.l.google.com:19302",
                  "stun1.l.google.com:19302",
                  "stun2.l.google.com:19302",
                  "stun3.l.google.com:19302",
                  "stun4.l.google.com:19302",
                  "stun.ekiga.net",
                  "stun.ideasip.com",
                  "stun.rixtelecom.se",
                  "stun.schlund.de",
                  "stun.stunprotocol.org:3478",
                  "stun.voiparound.com",
                  "stun.voipbuster.com",
                  "stun.voipstunt.com",
                  "stun.voxgratia.org"
              ]
  
          }, {}], 36: [function (require, module, exports) {
              module.exports = []
  
          }, {}], 37: [function (require, module, exports) {
              /* jshint node: true */
              'use strict';
              
              var debug = require('cog/logger')('rtc-mesh');
              var dcstream = require('rtc-dcstream');
              var Model = require('scuttlebutt/model');
              
              /**
    # rtc-mesh
  
    __NOTE:__ From version `0.5` onwards `rtc-mesh` is now an
    [rtc-quickconnect](https://github.com/rtc-io/rtc-quickconnect) plugin
    (which is heaps better and cleaner).
  
    The `rtc-mesh` module provides a way of sharing data between clients using
    [scuttlebutt](https://github.com/dominictarr/scuttlebutt).
  
    ## Simple Example
  
    <<< examples/simple.js
  
    ## Using Scuttlebutt Subclasses
  
    Here's an example using
    [CRDT](https://github.com/dominictarr/crdt):
  
    <<< examples/crdt.js
  
    ## Synchronizing Multiple Datasets
  
    It's also possible to create invoke multiple meshes on a single data
    channel using custom channel names (by default the a channel is created with
    the name of `mesh`).
  
    <<< examples/multichannel.js
  
    ## Reference
  
  **/
  
  /**
    ### mesh
  
    ```
    mesh(qc, opts?) => Model
    ```
  
    As displayed in the examples, the `mesh` function expects to be passed a
    [quickconnect](https://github.com/rtc-io/rtc-quickconnect) created signaller. Using
    this object, it will create a data channel that will be responsible for sharing
    [scuttlebutt](https://github.com/dominictarr/scuttlebutt) model information with peers.
  
    In addition to the functions exposed by a scuttlebutt Model, the following helpers
    have also been added:
  
  **/
  module.exports = function (qc, opts) {
                  // create the model
                  var model = (opts || {}).model || new Model();
                  var name = (opts || {}).channelName || 'mesh';
                  var channels = {};
                  
                  function joinMesh(id, dc) {
                      // create a new stream
                      var stream = dcstream(dc);
                      var reader = model.createReadStream();
                      var writer = model.createWriteStream();
                      
                      debug('connecting mesh with peer: ' + id);
                      
                      // register the channel
                      channels[id] = dc;
                      
                      stream.on('error', function (err) {
                          console.warn('captured stream error: ', err.message)
                      });
                      
                      reader.on('error', function (err) {
                          console.warn('captured reader stream error: ', err.message);
                      });
                      
                      writer.on('error', function (err) {
                          console.warn('captured writer stream error: ', err.message);
                      });
                      
                      // connect the stream to the data
                      reader.pipe(stream).pipe(writer);
                      
                      // bubble sync events
                      writer.on('sync', model.emit.bind(model, 'sync'));
                  }
                  
                  function joinMeshDeprecated(dc, id) {
                      joinMesh(id, dc);
                  }
                  
                  function leaveMesh(id) {
                      // remove the channel reference
                      channels[id] = null;
                  }
                  
                  /**
      #### retrieve
  
      ```
      retrieve(key, callback)
      ```
  
      Get the value of the specified key and pass the result back through the
      provided `callback` (node error first style).  If the value is already
      available in the local Model, then the callback will be triggered immediately.
      If not, the callback will be triggered once the value has been set in the
      local Model.
    **/
    function retrieve(key, callback) {
                      var value = model.get(key);
                      
                      // if we have the value, then trigger the callback immediately
                      if (typeof value != 'undefined') {
                          return callback(null, value);
                      }
                      
                      // otherwise, wait for the value
                      model.once('change:' + key, callback.bind(model, null));
                      return callback("record not found",null)
                  }
                  
                  // patch in the retrieveValue function
                  model.retrieve = retrieve;
                  
                  // create the data channel
                  qc.createDataChannel(name, (opts || {}).channelOpts)
      .on(name + ':open', joinMeshDeprecated)
      .on('channel:opened:' + name, joinMesh)
      .on(name + ':close', leaveMesh)
      .on('channel:closed:' + name, leaveMesh);
                  
                  return model;
              };
  
          }, { "cog/logger": 29, "rtc-dcstream": 38, "scuttlebutt/model": 41 }], 38: [function (require, module, exports) {
              (function (Buffer) {
                  /* jshint node: true */
                  'use strict';
                  
                  var debug = require('cog/logger')('rtc-dcstream');
                  var stream = require('stream');
                  var toBuffer = require('typedarray-to-buffer');
                  var util = require('util');
                  var closingStates = ['closing', 'closed'];
                  var ENDOFSTREAM = '::endofstream';
                  
                  /**
    # rtc-dcstream
  
    Node streams2 interface for working with WebRTC data channels. This stream
    implementation will cater for current data size limits in the WebRTC
    data channels.
  
    ## Example Usage
  
    The example below shows how to use the `rtc-dcstream` module to stream data
    via a datachannel to *n* remote participants.  In this case we are using
    the W3C FileReader API and streaming dropped data files over the data
    channel:
  
    <<< examples/file-transfer.js
  
    ## Alternative Implementations
  
    In addition to this module, the following are other modules that wrap
    WebRTC data channel communication via a node streaming interface:
  
    - [rtc-data-stream](https://github.com/kumavis/rtc-data-stream)
  
    ## Reference
  
    To be completed.
  
  **/
  
  function RTCChannelStream(channel) {
                      if (!(this instanceof RTCChannelStream)) {
                          return new RTCChannelStream(channel);
                      }
                      
                      // super
                      stream.Duplex.call(this, {
                          decodeStrings: false,
                          objectMode: true
                      });
                      
                      // create the internal read and write queues
                      this._rq = [];
                      this._wq = [];
                      
                      // save a reference to the channel
                      this.channel = channel;
                      
                      // set the channel binaryType to arraybuffer
                      channel.binaryType = 'arraybuffer';
                      
                      // bind some local event handlers
                      this._handleClose = handleChannelClose.bind(this);
                      this._handleMessage = handleChannelMessage.bind(this);
                      this._handleOpen = handleChannelOpen.bind(this);
                      
                      // attach channel listeners
                      channel.addEventListener('message', this._handleMessage);
                      channel.addEventListener('close', this._handleClose);
                      channel.addEventListener('open', this._handleOpen);
                      
                      // listen for finish events on the stream
                      this.once('finish', function () {
                          // if the channel is still open send an EOF message
                          if (channel.readyState === 'open') {
                              channel.send(ENDOFSTREAM);
                          }
                      });
                  }
                  
                  module.exports = RTCChannelStream;
                  util.inherits(RTCChannelStream, stream.Duplex);
                  
                  RTCChannelStream.prototype._debindChannel = function () {
                      var channel = this.channel;
                      
                      // remove the message listener
                      channel.removeEventListener('message', this._handleMessage);
                      channel.removeEventListener('close', this._handleClose);
                      channel.removeEventListener('open', this._handleOpen);
                  };
                  
                  RTCChannelStream.prototype._read = function (n) {
                      var ready = true;
                      var next;
                      
                      // if we have no data queued, then wait until we have been told we
                      // do as _read will not be called again until we have pushed something
                      if (this._rq.length === 0) {
                          return this.once('readable', this._read.bind(this, n));
                      }
                      
                      // TODO: honour the request for a particular number of bytes
                      // this.push(evt.data);
                      while (ready && this._rq.length > 0) {
                          // get the next chunk
                          next = this._rq.shift();
                          
                          // if the next chunk is an array buffer, convert to a node buffer
                          if (next instanceof ArrayBuffer) {
                              this.push(toBuffer(new Uint8Array(next)));
                          }
                          else {
                              this.push(next);
                          }
                      }
                      
                      return ready;
                  };
                  
                  RTCChannelStream.prototype._write = function (chunk, encoding, callback) {
                      var closed = (!this.channel) ||
      closingStates.indexOf(this.channel.readyState) >= 0;
                      
                      // if closed then abort
                      if (closed) {
                          return callback(new Error('data channel is closed'));
                      }
                      
                      // if we are connecting, then wait
                      if (this._wq.length || this.channel.readyState === 'connecting') {
                          return this._wq.push([chunk, encoding, callback]);
                      }
                      
                      if (this.channel.bufferedAmount > 0) {
                          debug('channel buffering: ', this.channel.bufferedAmount);
                      }
                      
                      // if we have a buffer convert into a Uint8Array
                      if (Buffer.isBuffer(chunk)) {
                          this.channel.send(chunk);
                      }
    // otherwise, send as is
                      else {
                          try {
                              this.channel.send(chunk);
                          }
      catch (e) {
                              debug('error sending text: ', e);
                          }
                      }
                      
                      return callback();
                  };
                  
                  /* event handlers */
                  
                  function handleChannelClose(evt) {
                      debug('dc closed');
                      this.emit('close');
                  }
                  
                  function handleChannelMessage(evt) {
                      var data = evt && evt.data;
                      
                      // if we have an end of stream marker, end
                      if (typeof data == 'string' && data === ENDOFSTREAM) {
                          // remove the channel event bindings
                          this._debindChannel();
                          
                          // emit the end
                          return this.emit('end');
                      }
                      
                      this._rq.push(data);
                      this.emit('readable');
                  }
                  
                  function handleChannelOpen(evt) {
                      
                      var peer = this;
                      var queue = this._wq;
                      
                      function sendNext(args) {
                          var callback;
                          
                          // if we have no args, then abort
                          if (!args) {
                              return queue.length ? sendNext(queue.shift()) : null;
                          }
                          
                          // save the callback
                          callback = args[2];
                          
                          // replace with a new callback
                          args[2] = function () {
                              sendNext(queue.shift());
                              
                              // trigger the callback
                              if (typeof callback == 'function') {
                                  callback();
                              }
                          };
                          
                          peer._write.apply(peer, args);
                      }
                      
                      // send the queued messages
                      debug('channel open, sending queued ' + queue.length + ' messages');
                      sendNext(queue.shift());
                  }
  
              }).call(this, require("buffer").Buffer)
          }, { "buffer": 2, "cog/logger": 29, "stream": 21, "typedarray-to-buffer": 39, "util": 24 }], 39: [function (require, module, exports) {
              (function (Buffer) {
                  /**
   * Convert a typed array to a Buffer without a copy
   *
   * Author:   Feross Aboukhadijeh <feross@feross.org> <http://feross.org>
   * License:  MIT
   *
   * `npm install typedarray-to-buffer`
   */
  
  module.exports = function (arr) {
                      if (typeof Buffer._augment === 'function' && Buffer.TYPED_ARRAY_SUPPORT) {
                          // If `Buffer` is from the `buffer` module and this browser supports typed arrays,
                          // then augment it with all the `Buffer` methods.
                          return Buffer._augment(arr)
                      } else {
                          // Otherwise, fallback to creating a `Buffer` with a copy.
                          return new Buffer(arr)
                      }
                  }
  
              }).call(this, require("buffer").Buffer)
          }, { "buffer": 2 }], 40: [function (require, module, exports) {
              (function (process) {
                  var EventEmitter = require('events').EventEmitter
                  var i = require('iterate')
                  var duplex = require('duplex')
                  var inherits = require('util').inherits
                  var serializer = require('stream-serializer')
                  var u = require('./util')
                  var timestamp = require('monotonic-timestamp')
                  
                  exports = 
  module.exports = Scuttlebutt
                  
                  exports.createID = u.createID
                  exports.updateIsRecent = u.filter
                  exports.filter = u.filter
                  exports.timestamp = timestamp
                  
                  function dutyOfSubclass() {
                      throw new Error('method must be implemented by subclass')
                  }
                  
                  function validate(data) {
                      if (!(Array.isArray(data) 
                      && 'string' === typeof data[2] 
                      && '__proto__' !== data[2] //THIS WOULD BREAK STUFF
                      && 'number' === typeof data[1]
                      )) return false
                      
                      return true
                  }
                  
                  inherits(Scuttlebutt, EventEmitter)
                  
                  function Scuttlebutt(opts) {
                      
                      if (!(this instanceof Scuttlebutt)) return new Scuttlebutt(opts)
                      var id = 'string' === typeof opts ? opts : opts && opts.id
                      this.sources = {}
                      this.setMaxListeners(Number.MAX_VALUE)
                      //count how many other instances we are replicating to.
                      this._streams = 0
                      if (opts && opts.sign && opts.verify) {
                          this.setId(opts.id || opts.createId())
                          this._sign = opts.sign
                          this._verify = opts.verify
                      } else {
                          this.setId(id || u.createId())
                      }
                  }
                  
                  var sb = Scuttlebutt.prototype
                  
                  var emit = EventEmitter.prototype.emit
                  
                  sb.applyUpdate = dutyOfSubclass
                  sb.history = dutyOfSubclass
                  
                  sb.localUpdate = function (trx) {
                      this._update([trx, timestamp(), this.id])
                      return this
                  }
                  
                  sb._update = function (update) {
                      //validated when it comes into the stream
                      var ts = update[1]
                      var source = update[2]
                      //if this message is old for it's source,
                      //ignore it. it's out of order.
                      //each node must emit it's changes in order!
                      
                      var latest = this.sources[source]
                      if (latest && latest >= ts)
                          return emit.call(this, 'old_data', update), false
                      
                      this.sources[source] = ts
                      
                      var self = this
                      function didVerification(err, verified) {
                          
                          // I'm not sure how what should happen if a async verification
                          // errors. if it's an key not found - that is a verification fail,
                          // not a error. if it's genunie error, really you should queue and 
                          // try again? or replay the message later
                          // -- this should be done my the security plugin though, not scuttlebutt.
                          
                          if (err)
                              return emit.call(self, 'error', err)
                          
                          if (!verified)
                              return emit.call(self, 'unverified_data', update)
                          
                          // check if this message is older than
                          // the value we already have.
                          // do nothing if so
                          // emit an 'old_data' event because i'll want to track how many
                          // unnecessary messages are sent.
                          
                          if (self.applyUpdate(update))
                              emit.call(self, '_update', update) //write to stream.
                      }
                      
                      if (source !== this.id) {
                          if (this._verify)
                              this._verify(update, didVerification)
                          else
                              didVerification(null, true)
                      } else {
                          if (this._sign) {
                              //could make this async easily enough.
                              update[3] = this._sign(update)
                          }
                          didVerification(null, true)
                      }
                      
                      return true
                  }
                  
                  sb.createStream = function (opts) {
                      var self = this
                      //the sources for the remote end.
                      var sources = {}, other
                      var syncSent = false, syncRecv = false
                      
                      this._streams++
                      
                      opts = opts || {}
                      var d = duplex()
                      d.name = opts.name
                      var outer = serializer(opts && opts.wrapper)(d)
                      outer.inner = d
                      
                      d.writable = opts.writable !== false
                      d.readable = opts.readable !== false
                      
                      syncRecv = !d.writable
                      syncSent = !d.readable
                      
                      var tail = opts.tail !== false//default to tail=true
                      
                      function start(data) {
                          //when the digest is recieved from the other end,
                          //send the history.
                          //merge with the current list of sources.
                          if (!data || !data.clock) {
                              d.emit('error');
                              return d._end()
                          }
                          
                          sources = data.clock
                          
                          i.each(self.history(sources), function (data) { d._data(data) })
                          
                          //the _update listener must be set after the history is queued.
                          //otherwise there is a race between the first client message
                          //and the next update (which may come in on another stream)
                          //this problem will probably not be encountered until you have 
                          //thousands of scuttlebutts.
                          
                          self.on('_update', onUpdate)
                          
                          d._data('SYNC')
                          syncSent = true
                          //when we have sent all history
                          outer.emit('header', data)
                          outer.emit('syncSent')
                          //when we have recieved all histoyr
                          //emit 'synced' when this stream has synced.
                          if (syncRecv) outer.emit('sync'), outer.emit('synced')
                          if (!tail) d._end()
                      }
                      
                      d
      .on('_data', function (data) {
                          //if it's an array, it's an update.
                          if (Array.isArray(data)) {
                              //check whether we are accepting writes.
                              if (!d.writable)
                                  return
                              if (validate(data))
                                  return self._update(data)
                          }
        //if it's an object, it's a scuttlebut digest.
                          else if ('object' === typeof data && data)
                              start(data)
                          else if ('string' === typeof data && data == 'SYNC') {
                              syncRecv = true
                              outer.emit('syncRecieved')
                              if (syncSent) outer.emit('sync'), outer.emit('synced')
                          }
                      }).on('_end', function () {
                          d._end()
                      })
      .on('close', function () {
                          self.removeListener('_update', onUpdate)
                          self.removeListener('dispose', dispose)
                          //emit the number of streams that are remaining...
                          //this will be used for memory management...
                          self._streams--
                          emit.call(self, 'unstream', self._streams)
                      })
                      
                      if (opts && opts.tail === false) {
                          outer.on('sync', function () {
                              process.nextTick(function () {
                                  d._end()
                              })
                          })
                      }
                      function onUpdate(update) { //value, source, ts
                          if (!validate(update) || !u.filter(update, sources))
                              return
                          
                          d._data(update)
                          
                          //really, this should happen before emitting.
                          var ts = update[1]
                          var source = update[2]
                          sources[source] = ts
                      }
                      
                      function dispose() {
                          d.end()
                      }
                      
                      var outgoing = { id : self.id, clock : self.sources }
                      
                      if (opts && opts.meta) outgoing.meta = opts.meta
                      
                      if (d.readable) {
                          d._data(outgoing)
                          if (!d.writable && !opts.clock)
                              start({ clock: {} })
  
                      } else if (opts.sendClock) {
                          //send my current clock.
                          //so the other side knows what to send
                          d._data(outgoing)
                      }
                      
                      self.once('dispose', dispose)
                      
                      return outer
                  }
                  
                  sb.createWriteStream = function (opts) {
                      opts = opts || {}
                      opts.writable = true; opts.readable = false
                      return this.createStream(opts)
                  }
                  
                  sb.createReadStream = function (opts) {
                      opts = opts || {}
                      opts.writable = false; opts.readable = true
                      return this.createStream(opts)
                  }
                  
                  sb.dispose = function () {
                      emit.call(this, 'dispose')
                  }
                  
                  sb.setId = function (id) {
                      if ('__proto__' === id) throw new Error('__proto__ is invalid id')
                      if (id == null) throw new Error('null is not invalid id')
                      this.id = id
                      return this
                  }
                  
                  function streamDone(stream, listener) {
                      
                      function remove() {
                          stream.removeListener('end', onDone)
                          stream.removeListener('error', onDone)
                          stream.removeListener('close', onDone)
                      }
                      function onDone(arg) {
                          remove()
                          listener.call(this, arg)
                      }
                      
                      //this makes emitter.removeListener(event, listener) still work
                      onDone.listener = listener
                      
                      stream.on('end', onDone)
                      stream.on('error', onDone)
                      stream.on('close', onDone)
                  }
                  
                  //create another instance of this scuttlebutt,
                  //that is in sync and attached to this instance.
                  sb.clone = function () {
                      var A = this
                      var B = new (A.constructor)
                      B.setId(A.id) //same id. think this will work...
                      
                      A._clones = (A._clones || 0) + 1
                      
                      var a = A.createStream({ wrapper: 'raw' })
                      var b = B.createStream({ wrapper: 'raw' })
                      
                      //all updates must be sync, so make sure pause never happens.
                      a.pause = b.pause = function noop() { }
                      
                      streamDone(b, function () {
                          A._clones--
                          emit.call(A, 'unclone', A._clones)
                      })
                      
                      a.pipe(b).pipe(a)
                      //resume both streams, so that the new instance is brought up to date immediately.
                      a.resume()
                      b.resume()
                      
                      return B
                  }
  
  
              }).call(this, require('_process'))
          }, { "./util": 46, "_process": 9, "duplex": 42, "events": 6, "iterate": 43, "monotonic-timestamp": 44, "stream-serializer": 45, "util": 24 }], 41: [function (require, module, exports) {
              var Scuttlebutt = require('./index')
              var inherits = require('util').inherits
              var each = require('iterate').each
              var u = require('./util')
              
              module.exports = Model
              
              inherits(Model, Scuttlebutt)
              
              function Model(opts) {
                  if (!(this instanceof Model)) return new Model(opts)
                  Scuttlebutt.call(this, opts)
                  this.store = {}
              }
              
              var m = Model.prototype
              
              m.set = function (k, v) {
                  if (k === '__proto__') return u.protoIsIllegal(this)
                  this.localUpdate([k, v])
                  return this
              }
              
              
              m.get = function (k) {
                  if (k === '__proto__') return u.protoIsIllegal(this)
                  if (this.store[k])
                      return this.store[k][0][1]
              }
              
              m.keys = function () {
                  var a = []
                  for (var k in this.store)
                      a.push(k)
                  return a
              }
              
              m.forEach =
  m.each = function (iter) {
                  for (var k in this.store)
                      iter(this.store[k][0][1], k, this.store)
                  return this
              }
              
              //return this history since sources.
              //sources is a hash of { ID: TIMESTAMP }
              
              m.applyUpdate = function (update) {
                  var key = update[0][0]
                  if ('__proto__' === key) return u.protoIsIllegal(this)
                  //ignore if we already have a more recent value
                  
                  if ('undefined' !== typeof this.store[key] 
                      && this.store[key][1] > update[1])
                      return this.emit('_remove', update)
                  
                  if (this.store[key]) this.emit('_remove', this.store[key])
                  
                  this.store[key] = update
                  
                  this.emit.apply(this, ['update'].concat(update))
                  this.emit('change', key, update[0][1])
                  this.emit('change:' + key, update[0][1])
                  
                  return true
              }
              
              m.history = function (sources) {
                  var self = this
                  var h = []
                  each(this.store, function (e) {
                      if (u.filter(e, sources))
                          h.push(e)
                  })
                  return u.sort(h)
              }
              
              m.toJSON = function () {
                  var o = {}, notNull = false
                  for (var k in this.store) {
                      var v = this.get(k)
                      if (v != null)
                          o[k] = this.get(k)
                  }
                  return o
              }
  
          }, { "./index": 40, "./util": 46, "iterate": 43, "util": 24 }], 42: [function (require, module, exports) {
              (function (process) {
                  var Stream = require('stream')
                  
                  module.exports = function (write, end) {
                      var stream = new Stream()
                      var buffer = [], ended = false, destroyed = false, emitEnd
                      stream.writable = stream.readable = true
                      stream.paused = false
                      stream._paused = false
                      stream.buffer = buffer
                      
                      stream
      .on('pause', function () {
                          stream._paused = true
                      })
      .on('drain', function () {
                          stream._paused = false
                      })
                      
                      function destroySoon() {
                          process.nextTick(stream.destroy.bind(stream))
                      }
                      
                      if (write)
                          stream.on('_data', write)
                      if (end)
                          stream.on('_end', end)
                      
                      //destroy the stream once both ends are over
                      //but do it in nextTick, so that other listeners
                      //on end have time to respond
                      stream.once('end', function () {
                          stream.readable = false
                          if (!stream.writable) {
                              process.nextTick(function () {
                                  stream.destroy()
                              })
                          }
                      })
                      
                      stream.once('_end', function () {
                          stream.writable = false
                          if (!stream.readable)
                              stream.destroy()
                      })
                      
                      // this is the default write method,
                      // if you overide it, you are resposible
                      // for pause state.
                      
                      
                      stream._data = function (data) {
                          if (!stream.paused && !buffer.length)
                              stream.emit('data', data)
                          else
                              buffer.push(data)
                          return !(stream.paused || buffer.length)
                      }
                      
                      stream._end = function (data) {
                          if (data) stream._data(data)
                          if (emitEnd) return
                          emitEnd = true
                          //destroy is handled above.
                          stream.drain()
                      }
                      
                      stream.write = function (data) {
                          stream.emit('_data', data)
                          return !stream._paused
                      }
                      
                      stream.end = function () {
                          stream.writable = false
                          if (stream.ended) return
                          stream.ended = true
                          stream.emit('_end')
                      }
                      
                      stream.drain = function () {
                          if (!buffer.length && !emitEnd) return
                          //if the stream is paused after just before emitEnd()
                          //end should be buffered.
                          while (!stream.paused) {
                              if (buffer.length) {
                                  stream.emit('data', buffer.shift())
                                  if (buffer.length == 0) {
                                      stream.emit('_drain')
                                  }
                              }
                              else if (emitEnd && stream.readable) {
                                  stream.readable = false
                                  stream.emit('end')
                                  return
                              } else {
                                  //if the buffer has emptied. emit drain.
                                  return true
                              }
                          }
                      }
                      var started = false
                      stream.resume = function () {
                          //this is where I need pauseRead, and pauseWrite.
                          //here the reading side is unpaused,
                          //but the writing side may still be paused.
                          //the whole buffer might not empity at once.
                          //it might pause again.
                          //the stream should never emit data inbetween pause()...resume()
                          //and write should return !buffer.length
                          started = true
                          stream.paused = false
                          stream.drain() //will emit drain if buffer empties.
                          return stream
                      }
                      
                      stream.destroy = function () {
                          if (destroyed) return
                          destroyed = ended = true
                          buffer.length = 0
                          stream.emit('close')
                      }
                      var pauseCalled = false
                      stream.pause = function () {
                          started = true
                          stream.paused = true
                          stream.emit('_pause')
                          return stream
                      }
                      stream._pause = function () {
                          if (!stream._paused) {
                              stream._paused = true
                              stream.emit('pause')
                          }
                          return this
                      }
                      stream.paused = true
                      process.nextTick(function () {
                          //unless the user manually paused
                          if (started) return
                          stream.resume()
                      })
                      
                      return stream
                  }
  
  
              }).call(this, require('_process'))
          }, { "_process": 9, "stream": 21 }], 43: [function (require, module, exports) {
              
              //
              // adds all the fields from obj2 onto obj1
              //
              
              var each = exports.each = function (obj, iterator) {
                  var keys = Object.keys(obj)
                  keys.forEach(function (key) {
                      iterator(obj[key], key, obj)
                  })
              }
              
              var RX = /sadf/.constructor
              function rx(iterator) {
                  return iterator instanceof RX ? function (str) {
                      var m = iterator.exec(str)
                      return m && (m[1] ? m[1] : m[0])
                  } : iterator
              }
              
              var times = exports.times = function () {
                  var args = [].slice.call(arguments)
      , iterator = rx(args.pop())
      , m = args.pop()
      , i = args.shift()
      , j = args.shift()
      , diff, dir
      , a = []
                  
                  i = 'number' === typeof i ? i : 1
                  diff = j ? j - i : 1
                  dir = i < m
                  if (m == i)
                      throw new Error('steps cannot be the same: ' + m + ', ' + i)
                  for (; dir ? i <= m : m <= i; i += diff)
                      a.push(iterator(i))
                  return a
              }
              
              var map = exports.map = function (obj, iterator) {
                  iterator = rx(iterator)
                  if (Array.isArray(obj))
                      return obj.map(iterator)
                  if ('number' === typeof obj)
                      return times.apply(null, [].slice.call(arguments))
                  //return if null ?  
                  var keys = Object.keys(obj)
      , r = {}
                  keys.forEach(function (key) {
                      r[key] = iterator(obj[key], key, obj)
                  })
                  return r
              }
              
              var findReturn = exports.findReturn = function (obj, iterator) {
                  iterator = rx(iterator)
                  if (obj == null)
                      return
                  var keys = Object.keys(obj)
      , l = keys.length
                  for (var i = 0; i < l; i++) {
                      var key = keys[i]
        , value = obj[key]
                      var r = iterator(value, key)
                      if (r) return r
                  }
              }
              
              var find = exports.find = function (obj, iterator) {
                  iterator = rx(iterator)
                  return findReturn(obj, function (v, k) {
                      var r = iterator(v, k)
                      if (r) return v
                  })
              }
              
              var findKey = exports.findKey = function (obj, iterator) {
                  iterator = rx(iterator)
                  return findReturn(obj, function (v, k) {
                      var r = iterator(v, k)
                      if (r) return k
                  })
              }
              
              var filter = exports.filter = function (obj, iterator) {
                  iterator = rx(iterator)
                  
                  if (Array.isArray(obj))
                      return obj.filter(iterator)
                  
                  var keys = Object.keys(obj)
      , r = {}
                  keys.forEach(function (key) {
                      var v
                      if (iterator(v = obj[key], key, obj))
                          r[key] = v
                  })
                  return r
              }
              
              var mapKeys = exports.mapKeys = function (ary, iterator) {
                  var r = {}
                  iterator = rx(iterator)
                  each(ary, function (v, k) {
                      r[v] = iterator(v, k)
                  })
                  return r
              }
              
              
              var mapToArray = exports.mapToArray = function (ary, iterator) {
                  var r = []
                  iterator = rx(iterator)
                  each(ary, function (v, k) {
                      r.push(iterator(v, k))
                  })
                  return r
              }
              
              var path = exports.path = function (object, path) {
                  
                  for (var i in path) {
                      if (object == null) return undefined
                      var key = path[i]
                      object = object[key]
                  }
                  return object
              }
              
              /*
  NOTE: naive implementation. 
  `match` must not contain circular references.
  */
  
  var setPath = exports.setPath = function (object, path, value) {
                  
                  for (var i in path) {
                      var key = path[i]
                      if (object[key] == null) object[key] = (
        i + 1 == path.length ? value : {}
  )
                      object = object[key]
                  }
              }
              
              var join = exports.join = function (A, B, it) {
                  each(A, function (a, ak) {
                      each(B, function (b, bk) {
                          it(a, b, ak, bk)
                      })
                  })
              }
  
          }, {}], 44: [function (require, module, exports) {
              // If `Date.now()` is invoked twice quickly, it's possible to get two
              // identical time stamps. To avoid generation duplications, subsequent
              // calls are manually ordered to force uniqueness.
              
              var _last = 0
              var _count = 1
              var adjusted = 0
              var _adjusted = 0
              
              module.exports =
  function timestamp() {
                  /**
    Returns NOT an accurate representation of the current time.
    Since js only measures time as ms, if you call `Date.now()`
    twice quickly, it's possible to get two identical time stamps.
    This function guarantees unique but maybe inaccurate results
    on each call.
    **/
    //uncomment this wen
    var time = Date.now()
                  //time = ~~ (time / 1000) 
                  //^^^uncomment when testing...
                  
                  /**
    If time returned is same as in last call, adjust it by
    adding a number based on the counter. 
    Counter is incremented so that next call get's adjusted properly.
    Because floats have restricted precision, 
    may need to step past some values...
    **/
    if (_last === time) {
                      do {
                          adjusted = time + ((_count++) / (_count + 999))
                      } while (adjusted === _adjusted)
                      _adjusted = adjusted
                  }
    // If last time was different reset timer back to `1`.
                  else {
                      _count = 1
                      adjusted = time
                  }
                  _adjusted = adjusted
                  _last = time
                  return adjusted
              }
  
          }, {}], 45: [function (require, module, exports) {
              
              var EventEmitter = require('events').EventEmitter
              
              exports = module.exports = function (wrapper) {
                  
                  if ('function' == typeof wrapper)
                      return wrapper
                  
                  return exports[wrapper] || exports.json
              }
              
              exports.json = function (stream, _JSON) {
                  _JSON = _JSON || JSON
                  
                  var write = stream.write
                  var soFar = ''
                  
                  function parse(line) {
                      var js
                      try {
                          js = _JSON.parse(line)
        //ignore lines of whitespace...
                      } catch (err) {
                          err.line = line
                          return stream.emit('error', err)
        //return console.error('invalid JSON', line)
                      }
                      if (js !== undefined)
                          write.call(stream, js)
                  }
                  
                  function onData(data) {
                      var lines = (soFar + data).split('\n')
                      soFar = lines.pop()
                      while (lines.length) {
                          parse(lines.shift())
                      }
                  }
                  
                  stream.write = onData
                  
                  var end = stream.end
                  
                  stream.end = function (data) {
                      if (data)
                          stream.write(data)
                      //if there is any left over...
                      if (soFar) {
                          parse(soFar)
                      }
                      return end.call(stream)
                  }
                  
                  stream.emit = function (event, data) {
                      
                      if (event == 'data') {
                          data = _JSON.stringify(data) + '\n'
                      }
                      //since all stream events only use one argument, this is okay...
                      EventEmitter.prototype.emit.call(stream, event, data)
                  }
                  
                  return stream
              }
              
              exports.raw = function (stream) {
                  return stream
              }
  
  
          }, { "events": 6 }], 46: [function (require, module, exports) {
              exports.createId = 
  function () {
                  return [1, 1, 1].map(function () {
                      return Math.random().toString(16).substring(2).toUpperCase()
                  }).join('')
              }
              
              exports.filter = function (update, sources) {
                  var ts = update[1]
                  var source = update[2]
                  return (!sources || !sources[source] || sources[source] < ts)
              }
              
              exports.protoIsIllegal = function (s) {
                  s.emit('invalid', new Error('"__proto__" is illegal property name'))
                  return null
              }
              
              function invalidUpdate(t) {
                  t.emit('invalid', new Error('invalid update'))
              }
              
              exports.validUpdate = function (t, update) {
                  if (!Array.isArray(update)) return invalidUpdate(t)
                  if ('string' !== typeof update[1] || 'number' !== typeof update[2])
                      return invalidUpdate(t)
              }
              
              exports.sort = function (hist) {
                  return hist.sort(function (a, b) {
                      //sort by timestamps, then ids.
                      //there should never be a pair with equal timestamps
                      //and ids.
                      return a[1] - b[1] || (a[2] > b[2] ? 1 : -1)
                  })
              }
  
          }, {}], 47: [function (require, module, exports) {
              (function (process) {
                  /* jshint node: true */
                  'use strict';
                  
                  var rtc = require('rtc-tools');
                  var mbus = require('mbus');
                  var cleanup = require('rtc-tools/cleanup');
                  var detectPlugin = require('rtc-core/plugin');
                  var debug = rtc.logger('rtc-quickconnect');
                  var defaults = require('cog/defaults');
                  var extend = require('cog/extend');
                  var getable = require('cog/getable');
                  var reTrailingSlash = /\/$/;
                  
                  /**
    # rtc-quickconnect
  
    This is a high level helper module designed to help you get up
    an running with WebRTC really, really quickly.  By using this module you
    are trading off some flexibility, so if you need a more flexible
    configuration you should drill down into lower level components of the
    [rtc.io](http://www.rtc.io) suite.  In particular you should check out
    [rtc](https://github.com/rtc-io/rtc).
  
    ## Example Usage
  
    In the simplest case you simply call quickconnect with a single string
    argument which tells quickconnect which server to use for signaling:
  
    <<< examples/simple.js
  
    <<< docs/events.md
  
    <<< docs/examples.md
  
    ## Regarding Signalling and a Signalling Server
  
    Signaling is an important part of setting up a WebRTC connection and for
    our examples we use our own test instance of the
    [rtc-switchboard](https://github.com/rtc-io/rtc-switchboard). For your
    testing and development you are more than welcome to use this also, but
    just be aware that we use this for our testing so it may go up and down
    a little.  If you need something more stable, why not consider deploying
    an instance of the switchboard yourself - it's pretty easy :)
  
    ## Reference
  
    ```
    quickconnect(signalhost, opts?) => rtc-sigaller instance (+ helpers)
    ```
  
    ### Valid Quick Connect Options
  
    The options provided to the `rtc-quickconnect` module function influence the
    behaviour of some of the underlying components used from the rtc.io suite.
  
    Listed below are some of the commonly used options:
  
    - `ns` (default: '')
  
      An optional namespace for your signalling room.  While quickconnect
      will generate a unique hash for the room, this can be made to be more
      unique by providing a namespace.  Using a namespace means two demos
      that have generated the same hash but use a different namespace will be
      in different rooms.
  
    - `room` (default: null) _added 0.6_
  
      Rather than use the internal hash generation
      (plus optional namespace) for room name generation, simply use this room
      name instead.  __NOTE:__ Use of the `room` option takes precendence over
      `ns`.
  
    - `debug` (default: false)
  
    Write rtc.io suite debug output to the browser console.
  
    - `expectedLocalStreams` (default: not specified) _added 3.0_
  
      By providing a positive integer value for this option will mean that
      the created quickconnect instance will wait until the specified number of
      streams have been added to the quickconnect "template" before announcing
      to the signaling server.
  
    - `manualJoin` (default: `false`)
  
      Set this value to `true` if you would prefer to call the `join` function
      to connecting to the signalling server, rather than having that happen
      automatically as soon as quickconnect is ready to.
  
    #### Options for Peer Connection Creation
  
    Options that are passed onto the
    [rtc.createConnection](https://github.com/rtc-io/rtc#createconnectionopts-constraints)
    function:
  
    - `iceServers`
  
    This provides a list of ice servers that can be used to help negotiate a
    connection between peers.
  
    #### Options for P2P negotiation
  
    Under the hood, quickconnect uses the
    [rtc/couple](https://github.com/rtc-io/rtc#rtccouple) logic, and the options
    passed to quickconnect are also passed onto this function.
  
  **/
  module.exports = function (signalhost, opts) {
                      var hash = typeof location != 'undefined' && location.hash.slice(1);
                      var signaller = require('rtc-signaller')(signalhost, opts);
                      
                      // init configurable vars
                      var ns = (opts || {}).ns || '';
                      var room = (opts || {}).room;
                      var debugging = (opts || {}).debug;
                      var allowJoin = !(opts || {}).manualJoin;
                      var profile = {};
                      var announced = false;
                      
                      // initialise iceServers to undefined
                      // we will not announce until these have been properly initialised
                      var iceServers;
                      
                      // collect the local streams
                      var localStreams = [];
                      
                      // create the calls map
                      var calls = signaller.calls = getable({});
                      
                      // create the known data channels registry
                      var channels = {};
                      
                      // save the plugins passed to the signaller
                      var plugins = signaller.plugins = (opts || {}).plugins || [];
                      var plugin = detectPlugin(signaller.plugins);
                      var pluginReady;
                      
                      // check how many local streams have been expected (default: 0)
                      var expectedLocalStreams = parseInt((opts || {}).expectedLocalStreams, 10) || 0;
                      var announceTimer = 0;
                      
                      function callCreate(id, pc, data) {
                          calls.set(id, {
                              active: false,
                              pc: pc,
                              channels: getable({}),
                              data: data,
                              streams: []
                          });
                      }
                      
                      function callEnd(id) {
                          var call = calls.get(id);
                          
                          // if we have no data, then do nothing
                          if (!call) {
                              return;
                          }
                          
                          debug('ending call to: ' + id);
                          
                          // if we have no data, then return
                          call.channels.keys().forEach(function (label) {
                              var channel = call.channels.get(label);
                              var args = [id, channel, label];
                              
                              // emit the plain channel:closed event
                              signaller.apply(signaller, ['channel:closed'].concat(args));
                              
                              // emit the labelled version of the event
                              signaller.apply(signaller, ['channel:closed:' + label].concat(args));
                              
                              // decouple the events
                              channel.onopen = null;
                          });
                          
                          // trigger stream:removed events for each of the remotestreams in the pc
                          call.streams.forEach(function (stream) {
                              signaller('stream:removed', id, stream);
                          });
                          
                          // delete the call data
                          calls.delete(id);
                          
                          // trigger the call:ended event
                          signaller('call:ended', id, call.pc);
                          
                          // ensure the peer connection is properly cleaned up
                          cleanup(call.pc);
                      }
                      
                      function callStart(id, pc, data) {
                          var call = calls.get(id);
                          var streams = [].concat(pc.getRemoteStreams());
                          
                          // flag the call as active
                          call.active = true;
                          call.streams = [].concat(pc.getRemoteStreams());
                          
                          pc.onaddstream = createStreamAddHandler(id);
                          pc.onremovestream = createStreamRemoveHandler(id);
                          
                          debug(signaller.id + ' - ' + id + ' call start: ' + streams.length + ' streams');
                          signaller('call:started', id, pc, data);
                          
                          // examine the existing remote streams after a short delay
                          process.nextTick(function () {
                              // iterate through any remote streams
                              streams.forEach(receiveRemoteStream(id));
                          });
                      }
                      
                      function checkReadyToAnnounce() {
                          clearTimeout(announceTimer);
                          // if we have already announced do nothing!
                          if (announced) {
                              return;
                          }
                          
                          if (!allowJoin) {
                              return;
                          }
                          
                          // if we have a plugin but it's not initialized we aren't ready
                          if (plugin && (!pluginReady)) {
                              return;
                          }
                          
                          // if we have no iceServers we aren't ready
                          if (!iceServers) {
                              return;
                          }
                          
                          // if we are waiting for a set number of streams, then wait until we have
                          // the required number
                          if (expectedLocalStreams && localStreams.length < expectedLocalStreams) {
                              return;
                          }
                          
                          // announce ourselves to our new friend
                          announceTimer = setTimeout(function () {
                              var data = extend({}, profile, { room: room });
                              
                              // announce and emit the local announce event
                              signaller.announce(data);
                              announced = true;
                          }, 0);
                      }
                      
                      function createStreamAddHandler(id) {
                          return function (evt) {
                              debug('peer ' + id + ' added stream');
                              updateRemoteStreams(id);
                              receiveRemoteStream(id)(evt.stream);
                          }
                      }
                      
                      function createStreamRemoveHandler(id) {
                          return function (evt) {
                              debug('peer ' + id + ' removed stream');
                              updateRemoteStreams(id);
                              signaller('stream:removed', id, evt.stream);
                          };
                      }
                      
                      function getActiveCall(peerId) {
                          var call = calls.get(peerId);
                          
                          if (!call) {
                              throw new Error('No active call for peer: ' + peerId);
                          }
                          
                          return call;
                      }
                      
                      function gotPeerChannel(channel, pc, data) {
                          var channelMonitor;
                          
                          function channelReady() {
                              var call = calls.get(data.id);
                              var args = [data.id, channel, data, pc];
                              
                              // decouple the channel.onopen listener
                              debug('reporting channel "' + channel.label + '" ready, have call: ' + (!!call));
                              clearInterval(channelMonitor);
                              channel.onopen = null;
                              
                              // save the channel
                              if (call) {
                                  call.channels.set(channel.label, channel);
                              }
                              
                              // trigger the %channel.label%:open event
                              debug('triggering channel:opened events for channel: ' + channel.label);
                              
                              // emit the plain channel:opened event
                              signaller.apply(signaller, ['channel:opened'].concat(args));
                              
                              // emit the channel:opened:%label% eve
                              signaller.apply(
                                  signaller,
          ['channel:opened:' + channel.label].concat(args)
                              );
                          }
                          
                          debug('channel ' + channel.label + ' discovered for peer: ' + data.id);
                          if (channel.readyState === 'open') {
                              return channelReady();
                          }
                          
                          debug('channel not ready, current state = ' + channel.readyState);
                          channel.onopen = channelReady;
                          
                          // monitor the channel open (don't trust the channel open event just yet)
                          channelMonitor = setInterval(function () {
                              debug('checking channel state, current state = ' + channel.readyState);
                              if (channel.readyState === 'open') {
                                  channelReady();
                              }
                          }, 500);
                      }
                      
                      function initPlugin() {
                          return plugin && plugin.init(opts, function (err) {
                              if (err) {
                                  return console.error('Could not initialize plugin: ', err);
                              }
                              
                              pluginReady = true;
                              checkReadyToAnnounce();
                          });
                      }
                      
                      function handleLocalAnnounce(data) {
                          // if we send an announce with an updated room then update our local room name
                          if (data && typeof data.room != 'undefined') {
                              room = data.room;
                          }
                      }
                      
                      function handlePeerAnnounce(data) {
                          var pc;
                          var monitor;
                          
                          // if the room is not a match, abort
                          if (data.room !== room) {
                              return;
                          }
                          
                          // create a peer connection
                          // iceServers that have been created using genice taking precendence
                          pc = rtc.createConnection(
                              extend({}, opts, { iceServers: iceServers }),
        (opts || {}).constraints
                          );
                          
                          signaller('peer:connect', data.id, pc, data);
                          
                          // add this connection to the calls list
                          callCreate(data.id, pc, data);
                          
                          // add the local streams
                          localStreams.forEach(function (stream, idx) {
                              pc.addStream(stream);
                          });
                          
                          // add the data channels
                          // do this differently based on whether the connection is a
                          // master or a slave connection
                          if (signaller.isMaster(data.id)) {
                              debug('is master, creating data channels: ', Object.keys(channels));
                              
                              // create the channels
                              Object.keys(channels).forEach(function (label) {
                                  gotPeerChannel(pc.createDataChannel(label, channels[label]), pc, data);
                              });
                          }
                          else {
                              pc.ondatachannel = function (evt) {
                                  var channel = evt && evt.channel;
                                  
                                  // if we have no channel, abort
                                  if (!channel) {
                                      return;
                                  }
                                  
                                  if (channels[channel.label] !== undefined) {
                                      gotPeerChannel(channel, pc, data);
                                  }
                              };
                          }
                          
                          // couple the connections
                          debug('coupling ' + signaller.id + ' to ' + data.id);
                          monitor = rtc.couple(pc, data.id, signaller, extend({}, opts, {
                              logger: mbus('pc.' + data.id, signaller)
                          }));
                          
                          signaller('peer:couple', data.id, pc, data, monitor);
                          
                          // once active, trigger the peer connect event
                          monitor.once('connected', callStart.bind(null, data.id, pc, data))
                          monitor.once('closed', callEnd.bind(null, data.id));
                          
                          // if we are the master connnection, create the offer
                          // NOTE: this only really for the sake of politeness, as rtc couple
                          // implementation handles the slave attempting to create an offer
                          if (signaller.isMaster(data.id)) {
                              monitor.createOffer();
                          }
                      }
                      
                      function handlePeerFilter(evt) {
                          // only connect with the peer if we are ready
                          evt.allow = evt.allow && (localStreams.length >= expectedLocalStreams);
                      }
                      
                      function handlePeerUpdate(data) {
                          var id = data && data.id;
                          var activeCall = id && calls.get(id);
                          
                          // if we have received an update for a peer that has no active calls,
                          // then pass this onto the announce handler
                          if (id && (!activeCall)) {
                              debug('received peer update from peer ' + id + ', no active calls');
                              return handlePeerAnnounce(data);
                          }
                      }
                      
                      function receiveRemoteStream(id) {
                          var call = calls.get(id);
                          
                          return function (stream) {
                              signaller('stream:added', id, stream, call && call.data);
                          };
                      }
                      
                      function updateRemoteStreams(id) {
                          var call = calls.get(id);
                          
                          if (call && call.pc) {
                              call.streams = [].concat(call.pc.getRemoteStreams());
                          }
                      }
                      
                      // if the room is not defined, then generate the room name
                      if (!room) {
                          // if the hash is not assigned, then create a random hash value
                          if (!hash) {
                              hash = location.hash = '' + (Math.pow(2, 53) * Math.random());
                          }
                          
                          room = ns + '#' + hash;
                      }
                      
                      if (debugging) {
                          rtc.logger.enable.apply(rtc.logger, Array.isArray(debug) ? debugging : ['*']);
                      }
                      
                      signaller.on('peer:announce', handlePeerAnnounce);
                      signaller.on('peer:update', handlePeerUpdate);
                      
                      /**
      ### Quickconnect Broadcast and Data Channel Helper Functions
  
      The following are functions that are patched into the `rtc-signaller`
      instance that make working with and creating functional WebRTC applications
      a lot simpler.
  
    **/
  
    /**
      #### addStream
  
      ```
      addStream(stream:MediaStream) => qc
      ```
  
      Add the stream to active calls and also save the stream so that it
      can be added to future calls.
  
    **/
    signaller.broadcast = signaller.addStream = function (stream) {
                          localStreams.push(stream);
                          
                          // if we have any active calls, then add the stream
                          calls.values().forEach(function (data) {
                              data.pc.addStream(stream);
                          });
                          
                          checkReadyToAnnounce();
                          return signaller;
                      };
                      
                      /**
      #### endCalls()
  
      The `endCalls` function terminates all the active calls that have been
      created in this quickconnect instance.  Calling `endCalls` does not
      kill the connection with the signalling server.
  
    **/
    signaller.endCalls = function () {
                          calls.keys().forEach(callEnd);
                      };
                      
                      /**
      #### close()
  
      The `close` function provides a convenient way of closing all associated
      peer connections.  This function simply uses the `endCalls` function and
      the underlying `leave` function of the signaller to do a "full cleanup"
      of all connections.
    **/
    signaller.close = function () {
                          signaller.endCalls();
                          signaller.leave();
                      };
                      
                      /**
      #### createDataChannel(label, config)
  
      Request that a data channel with the specified `label` is created on
      the peer connection.  When the data channel is open and available, an
      event will be triggered using the label of the data channel.
  
      For example, if a new data channel was requested using the following
      call:
  
      ```js
      var qc = quickconnect('http://rtc.io/switchboard').createDataChannel('test');
      ```
  
      Then when the data channel is ready for use, a `test:open` event would
      be emitted by `qc`.
  
    **/
    signaller.createDataChannel = function (label, opts) {
                          // create a channel on all existing calls
                          calls.keys().forEach(function (peerId) {
                              var call = calls.get(peerId);
                              var dc;
                              
                              // if we are the master connection, create the data channel
                              if (call && call.pc && signaller.isMaster(peerId)) {
                                  dc = call.pc.createDataChannel(label, opts);
                                  gotPeerChannel(dc, call.pc, call.data);
                              }
                          });
                          
                          // save the data channel opts in the local channels dictionary
                          channels[label] = opts || null;
                          
                          return signaller;
                      };
                      
                      /**
      #### join()
  
      The `join` function is used when `manualJoin` is set to true when creating
      a quickconnect instance.  Call the `join` function once you are ready to
      join the signalling server and initiate connections with other people.
  
    **/
    signaller.join = function () {
                          allowJoin = true;
                          checkReadyToAnnounce();
                      };
                      
                      /**
      #### reactive()
  
      Flag that this session will be a reactive connection.
  
    **/
    signaller.reactive = function () {
                          // add the reactive flag
                          opts = opts || {};
                          opts.reactive = true;
                          
                          // chain
                          return signaller;
                      };
                      
                      /**
      #### removeStream
  
      ```
      removeStream(stream:MediaStream)
      ```
  
      Remove the specified stream from both the local streams that are to
      be connected to new peers, and also from any active calls.
  
    **/
    signaller.removeStream = function (stream) {
                          var localIndex = localStreams.indexOf(stream);
                          
                          // remove the stream from any active calls
                          calls.values().forEach(function (call) {
                              call.pc.removeStream(stream);
                          });
                          
                          // remove the stream from the localStreams array
                          if (localIndex >= 0) {
                              localStreams.splice(localIndex, 1);
                          }
                          
                          return signaller;
                      };
                      
                      /**
      #### requestChannel
  
      ```
      requestChannel(targetId, label, callback)
      ```
  
      This is a function that can be used to respond to remote peers supplying
      a data channel as part of their configuration.  As per the `receiveStream`
      function this function will either fire the callback immediately if the
      channel is already available, or once the channel has been discovered on
      the call.
  
    **/
    signaller.requestChannel = function (targetId, label, callback) {
                          var call = getActiveCall(targetId);
                          var channel = call && call.channels.get(label);
                          
                          // if we have then channel trigger the callback immediately
                          if (channel) {
                              callback(null, channel);
                              return signaller;
                          }
                          
                          // if not, wait for it
                          signaller.once('channel:opened:' + label, function (id, dc) {
                              callback(null, dc);
                          });
                          
                          return signaller;
                      };
                      
                      /**
      #### requestStream
  
      ```
      requestStream(targetId, idx, callback)
      ```
  
      Used to request a remote stream from a quickconnect instance. If the
      stream is already available in the calls remote streams, then the callback
      will be triggered immediately, otherwise this function will monitor
      `stream:added` events and wait for a match.
  
      In the case that an unknown target is requested, then an exception will
      be thrown.
    **/
    signaller.requestStream = function (targetId, idx, callback) {
                          var call = getActiveCall(targetId);
                          var stream;
                          
                          function waitForStream(peerId) {
                              if (peerId !== targetId) {
                                  return;
                              }
                              
                              // get the stream
                              stream = call.pc.getRemoteStreams()[idx];
                              
                              // if we have the stream, then remove the listener and trigger the cb
                              if (stream) {
                                  signaller.removeListener('stream:added', waitForStream);
                                  callback(null, stream);
                              }
                          }
                          
                          // look for the stream in the remote streams of the call
                          stream = call.pc.getRemoteStreams()[idx];
                          
                          // if we found the stream then trigger the callback
                          if (stream) {
                              callback(null, stream);
                              return signaller;
                          }
                          
                          // otherwise wait for the stream
                          signaller.on('stream:added', waitForStream);
                          return signaller;
                      };
                      
                      /**
      #### profile(data)
  
      Update the profile data with the attached information, so when
      the signaller announces it includes this data in addition to any
      room and id information.
  
    **/
    signaller.profile = function (data) {
                          extend(profile, data);
                          
                          // if we have already announced, then reannounce our profile to provide
                          // others a `peer:update` event
                          if (announced) {
                              signaller.announce(profile);
                          }
                          
                          return signaller;
                      };
                      
                      /**
      #### waitForCall
  
      ```
      waitForCall(targetId, callback)
      ```
  
      Wait for a call from the specified targetId.  If the call is already
      active the callback will be fired immediately, otherwise we will wait
      for a `call:started` event that matches the requested `targetId`
  
    **/
    signaller.waitForCall = function (targetId, callback) {
                          var call = calls.get(targetId);
                          
                          if (call && call.active) {
                              callback(null, call.pc);
                              return signaller;
                          }
                          
                          signaller.on('call:started', function handleNewCall(id) {
                              if (id === targetId) {
                                  signaller.removeListener('call:started', handleNewCall);
                                  callback(null, calls.get(id).pc);
                              }
                          });
                      };
                      
                      // if we have an expected number of local streams, then use a filter to
                      // check if we should respond
                      if (expectedLocalStreams) {
                          signaller.on('peer:filter', handlePeerFilter);
                      }
                      
                      // respond to local announce messages
                      signaller.on('local:announce', handleLocalAnnounce);
                      
                      // use genice to find our iceServers
                      require('rtc-core/genice')(opts, function (err, servers) {
                          if (err) {
                              return console.error('could not find iceServers: ', err);
                          }
                          
                          iceServers = servers;
                          checkReadyToAnnounce();
                      });
                      
                      // if we plugin is active, then initialize it
                      if (plugin) {
                          initPlugin();
                      }
                      
                      // pass the signaller on
                      return signaller;
                  };
  
              }).call(this, require('_process'))
          }, { "_process": 9, "cog/defaults": 25, "cog/extend": 26, "cog/getable": 27, "mbus": 48, "rtc-core/genice": 52, "rtc-core/plugin": 54, "rtc-signaller": 55, "rtc-tools": 69, "rtc-tools/cleanup": 65 }], 48: [function (require, module, exports) {
              var createTrie = require('array-trie');
              var reDelim = /[\.\:]/;
              
              /**
    # mbus
  
    If Node's EventEmitter and Eve were to have a child, it might look something like this.
    No wildcard support at this stage though...
  
    ## Example Usage
  
    <<< docs/usage.md
  
    ## Reference
  
    ### `mbus(namespace?, parent?, scope?)`
  
    Create a new message bus with `namespace` inheriting from the `parent`
    mbus instance.  If events from this message bus should be triggered with
    a specific `this` scope, then specify it using the `scope` argument.
  
  **/
  
  var createBus = module.exports = function (namespace, parent, scope) {
                  var registry = createTrie();
                  var feeds = [];
                  
                  function bus(name) {
                      var args = [].slice.call(arguments, 1);
                      var parts = getNameParts(name);
                      var delimited = parts.join('.');
                      var handlers = registry.get(parts) || [];
                      var results;
                      
                      // send through the feeds
                      feeds.forEach(function (feed) {
                          feed({ name: delimited, args: args });
                      });
                      
                      // run the registered handlers
                      results = [].concat(handlers).map(function (handler) {
                          return handler.apply(scope || this, args);
                      });
                      
                      // run the parent handlers
                      if (bus.parent) {
                          results = results.concat(
                              bus.parent.apply(scope || this, [namespace.concat(parts)].concat(args))
                          );
                      }
                      
                      return results;
                  }
                  
                  /**
      ### `mbus#clear()`
  
      Reset the handler registry, which essential deregisters all event listeners.
  
      _Alias:_ `removeAllListeners`
    **/
    function clear(name) {
                      // if we have a name, reset handlers for that handler
                      if (name) {
                          registry.set(getNameParts(name), []);
                      }
      // otherwise, reset the entire handler registry
                      else {
                          registry = createTrie();
                      }
                  }
                  
                  /**
      ### `mbus#feed(handler)`
  
      Attach a handler function that will see all events that are sent through
      this bus in an "object stream" format that matches the following format:
  
      ```
      { name: 'event.name', args: [ 'event', 'args' ] }
      ```
  
      The feed function returns a function that can be called to stop the feed
      sending data.
  
    **/
    function feed(handler) {
                      function stop() {
                          feeds.splice(feeds.indexOf(handler), 1);
                      }
                      
                      feeds.push(handler);
                      return stop;
                  }
                  
                  function getNameParts(name) {
                      return Array.isArray(name) ? name : name.split(reDelim);
                  }
                  
                  /**
      ### `mbus#off(name, handler)`
  
      Deregister an event handler.
    **/
    function off(name, handler) {
                      var handlers = registry.get(getNameParts(name));
                      var idx = handlers ? handlers.indexOf(handler) : -1;
                      
                      if (idx >= 0) {
                          handlers.splice(idx, 1);
                      }
                  }
                  
                  /**
      ### `mbus#on(name, handler)`
  
      Register an event handler for the event `name`.
  
    **/
    function on(name, handler) {
                      var parts = getNameParts(name);
                      var handlers = registry.get(parts);
                      
                      if (handlers) {
                          handlers.push(handler);
                      }
                      else {
                          registry.set(parts, [handler]);
                      }
                      
                      return bus;
                  }
                  
                  
                  /**
      ### `mbus#once(name, handler)`
  
      Register an event handler for the event `name` that will only
      trigger once (i.e. the handler will be deregistered immediately after
      being triggered the first time).
  
    **/
    function once(name, handler) {
                      return on(name, function handleEvent() {
                          var result = handler.apply(this, arguments);
                          bus.off(name, handleEvent);
                          
                          return result;
                      });
                  }
                  
                  if (typeof namespace == 'function') {
                      parent = namespace;
                      namespace = '';
                  }
                  
                  namespace = (namespace && namespace.split(reDelim)) || [];
                  
                  bus.clear = bus.removeAllListeners = clear;
                  bus.feed = feed;
                  bus.on = bus.addListener = on;
                  bus.once = once;
                  bus.off = bus.removeListener = off;
                  bus.parent = parent || (namespace && namespace.length > 0 && createBus());
                  
                  return bus;
              };
  
          }, { "array-trie": 50 }], 49: [function (require, module, exports) {
              "use strict"
              
              function compileSearch(funcName, predicate, reversed, extraArgs, useNdarray, earlyOut) {
                  var code = [
                      "function ", funcName, "(a,l,h,", extraArgs.join(","), "){",
                      earlyOut ? "" : "var i=", (reversed ? "l-1" : "h+1"),
                      ";while(l<=h){\
  var m=(l+h)>>>1,x=a", useNdarray ? ".get(m)" : "[m]"]
                  if (earlyOut) {
                      if (predicate.indexOf("c") < 0) {
                          code.push(";if(x===y){return m}else if(x<=y){")
                      } else {
                          code.push(";var p=c(x,y);if(p===0){return m}else if(p<=0){")
                      }
                  } else {
                      code.push(";if(", predicate, "){i=m;")
                  }
                  if (reversed) {
                      code.push("l=m+1}else{h=m-1}")
                  } else {
                      code.push("h=m-1}else{l=m+1}")
                  }
                  code.push("}")
                  if (earlyOut) {
                      code.push("return -1};")
                  } else {
                      code.push("return i};")
                  }
                  return code.join("")
              }
              
              function compileBoundsSearch(predicate, reversed, suffix, earlyOut) {
                  var result = new Function([
                      compileSearch("A", "x" + predicate + "y", reversed, ["y"], false, earlyOut),
                      compileSearch("B", "x" + predicate + "y", reversed, ["y"], true, earlyOut),
                      compileSearch("P", "c(x,y)" + predicate + "0", reversed, ["y", "c"], false, earlyOut),
                      compileSearch("Q", "c(x,y)" + predicate + "0", reversed, ["y", "c"], true, earlyOut),
                      "function dispatchBsearch", suffix, "(a,y,c,l,h){\
  if(a.shape){\
  if(typeof(c)==='function'){\
  return Q(a,(l===undefined)?0:l|0,(h===undefined)?a.shape[0]-1:h|0,y,c)\
  }else{\
  return B(a,(c===undefined)?0:c|0,(l===undefined)?a.shape[0]-1:l|0,y)\
  }}else{\
  if(typeof(c)==='function'){\
  return P(a,(l===undefined)?0:l|0,(h===undefined)?a.length-1:h|0,y,c)\
  }else{\
  return A(a,(c===undefined)?0:c|0,(l===undefined)?a.length-1:l|0,y)\
  }}}\
  return dispatchBsearch", suffix].join(""))
                  return result()
              }
              
              module.exports = {
                  ge: compileBoundsSearch(">=", false, "GE"),
                  gt: compileBoundsSearch(">", false, "GT"),
                  lt: compileBoundsSearch("<", true, "LT"),
                  le: compileBoundsSearch("<=", true, "LE"),
                  eq: compileBoundsSearch("-", true, "EQ", true)
              }
  
          }, {}], 50: [function (require, module, exports) {
              "use strict"
              
              var bounds = require("binary-search-bounds")
              
              module.exports = createTrie
              
              function Trie(symbols, children, value) {
                  this.symbols = symbols
                  this.children = children
                  this.value = value
              }
              
              var proto = Trie.prototype
              
              proto.set = function (s, value) {
                  if (s.shape) {
                      var v = this
                      var n = s.shape[0]
                      for (var i = 0; i < n; ++i) {
                          var c = s.get(i)
                          var j = bounds.ge(v.symbols, c)
                          if (j < v.symbols.length && v.symbols[j] === c) {
                              v = v.children[j]
                          } else {
                              var l = new Trie([], [], value)
                              for (var k = n - 1; k > i; --k) {
                                  l = new Trie([s.get(k)], [l])
                              }
                              v.symbols.splice(j, 0, c)
                              v.children.splice(j, 0, l)
                              return value
                          }
                      }
                      return v.value = value
                  } else {
                      var v = this
                      var n = s.length
                      for (var i = 0; i < n; ++i) {
                          var c = s[i]
                          var j = bounds.ge(v.symbols, c)
                          if (j < v.symbols.length && v.symbols[j] === c) {
                              v = v.children[j]
                          } else {
                              var l = new Trie([], [], value)
                              for (var k = n - 1; k > i; --k) {
                                  l = new Trie([s[k]], [l])
                              }
                              v.symbols.splice(j, 0, c)
                              v.children.splice(j, 0, l)
                              return value
                          }
                      }
                      return v.value = value
                  }
              }
              
              proto.get = function (s) {
                  if (s.shape) {
                      var v = this
                      var n = s.shape[0]
                      for (var i = 0; i < n; ++i) {
                          var c = s.get(i)
                          var j = bounds.eq(v.symbols, c)
                          if (j < 0) {
                              return
                          }
                          v = v.children[j]
                      }
                      return v.value
                  } else {
                      var v = this
                      var n = s.length
                      for (var i = 0; i < n; ++i) {
                          var c = s[i]
                          var j = bounds.eq(v.symbols, c)
                          if (j < 0) {
                              return
                          }
                          v = v.children[j]
                      }
                      return v.value
                  }
              }
              
              function createTrie() {
                  return new Trie([], [])
              }
          }, { "binary-search-bounds": 49 }], 51: [function (require, module, exports) {
              /* jshint node: true */
              /* global window: false */
              /* global navigator: false */
              
              'use strict';
              
              var browser = require('detect-browser');
              
              /**
    ### `rtc-core/detect`
  
    A browser detection helper for accessing prefix-free versions of the various
    WebRTC types.
  
    ### Example Usage
  
    If you wanted to get the native `RTCPeerConnection` prototype in any browser
    you could do the following:
  
    ```js
    var detect = require('rtc-core/detect'); // also available in rtc/detect
    var RTCPeerConnection = detect('RTCPeerConnection');
    ```
  
    This would provide whatever the browser prefixed version of the
    RTCPeerConnection is available (`webkitRTCPeerConnection`,
    `mozRTCPeerConnection`, etc).
  **/
  var detect = module.exports = function (target, prefixes) {
                  var prefixIdx;
                  var prefix;
                  var testName;
                  var hostObject = this || (typeof window != 'undefined' ? window : undefined);
                  
                  // if we have no host object, then abort
                  if (!hostObject) {
                      return;
                  }
                  
                  // initialise to default prefixes
                  // (reverse order as we use a decrementing for loop)
                  prefixes = (prefixes || ['ms', 'o', 'moz', 'webkit']).concat('');
                  
                  // iterate through the prefixes and return the class if found in global
                  for (prefixIdx = prefixes.length; prefixIdx--; ) {
                      prefix = prefixes[prefixIdx];
                      
                      // construct the test class name
                      // if we have a prefix ensure the target has an uppercase first character
                      // such that a test for getUserMedia would result in a
                      // search for webkitGetUserMedia
                      testName = prefix + (prefix ?
                              target.charAt(0).toUpperCase() + target.slice(1) :
                              target);
                      
                      if (typeof hostObject[testName] != 'undefined') {
                          // update the last used prefix
                          detect.browser = detect.browser || prefix.toLowerCase();
                          
                          // return the host object member
                          return hostObject[target] = hostObject[testName];
                      }
                  }
              };
              
              // detect mozilla (yes, this feels dirty)
              detect.moz = typeof navigator != 'undefined' && !!navigator.mozGetUserMedia;
              
              // set the browser and browser version
              detect.browser = browser.name;
              detect.browserVersion = detect.version = browser.version;
  
          }, { "detect-browser": 53 }], 52: [function (require, module, exports) {
              /**
    ### `rtc-core/genice`
  
    Respond appropriately to options that are passed to packages like
    `rtc-quickconnect` and trigger a `callback` (error first) with iceServer
    values.
  
    The function looks for either of the following keys in the options, in
    the following order or precedence:
  
    1. `ice` - this can either be an array of ice server values or a generator
       function (in the same format as this function).  If this key contains a
       value then any servers specified in the `iceServers` key (2) will be
       ignored.
  
    2. `iceServers` - an array of ice server values.
  **/
  module.exports = function (opts, callback) {
                  var ice = (opts || {}).ice;
                  var iceServers = (opts || {}).iceServers;
                  
                  if (typeof ice == 'function') {
                      return ice(opts, callback);
                  }
                  else if (Array.isArray(ice)) {
                      return callback(null, [].concat(ice));
                  }
                  
                  callback(null, [].concat(iceServers || []));
              };
  
          }, {}], 53: [function (require, module, exports) {
              var browsers = [
                  ['chrome', /Chrom(?:e|ium)\/([0-9\.]+)(:?\s|$)/],
                  ['firefox', /Firefox\/([0-9\.]+)(?:\s|$)/],
                  ['opera', /Opera\/([0-9\.]+)(?:\s|$)/],
                  ['ie', /Trident\/7\.0.*rv\:([0-9\.]+)\).*Gecko$/],
                  ['ie', /MSIE\s([0-9\.]+);.*Trident\/[4-6].0/],
                  ['ie', /MSIE\s(7\.0)/],
                  ['bb10', /BB10;\sTouch.*Version\/([0-9\.]+)/],
                  ['android', /Android\s([0-9\.]+)/],
                  ['ios', /iPad\;\sCPU\sOS\s([0-9\._]+)/],
                  ['ios', /iPhone\;\sCPU\siPhone\sOS\s([0-9\._]+)/],
                  ['safari', /Safari\/([0-9\._]+)/]
              ];
              
              var match = browsers.map(match).filter(isMatch)[0];
              var parts = match && match[3].split(/[._]/).slice(0, 3);
              
              while (parts && parts.length < 3) {
                  parts.push('0');
              }
              
              // set the name and version
              exports.name = match && match[0];
              exports.version = parts && parts.join('.');
              
              function match(pair) {
                  return pair.concat(pair[1].exec(navigator.userAgent));
              }
              
              function isMatch(pair) {
                  return !!pair[2];
              }
  
          }, {}], 54: [function (require, module, exports) {
              var detect = require('./detect');
              var requiredFunctions = [
                  'init'
              ];
              
              function isSupported(plugin) {
                  return plugin && typeof plugin.supported == 'function' && plugin.supported(detect);
              }
              
              function isValid(plugin) {
                  var supportedFunctions = requiredFunctions.filter(function (fn) {
                      return typeof plugin[fn] == 'function';
                  });
                  
                  return supportedFunctions.length === requiredFunctions.length;
              }
              
              module.exports = function (plugins) {
                  return [].concat(plugins || []).filter(isSupported).filter(isValid)[0];
              }
  
          }, { "./detect": 51 }], 55: [function (require, module, exports) {
              var extend = require('cog/extend');
              
              module.exports = function (messenger, opts) {
                  return require('./signaller.js')(messenger, extend({
                      connect: require('./primus-loader')
                  }, opts));
              };
  
          }, { "./primus-loader": 62, "./signaller.js": 64, "cog/extend": 26 }], 56: [function (require, module, exports) {
              module.exports = {
                  // messenger events
                  dataEvent: 'data',
                  openEvent: 'open',
                  closeEvent: 'close',
                  errorEvent: 'error',
                  
                  // messenger functions
                  writeMethod: 'write',
                  closeMethod: 'close',
                  
                  // leave timeout (ms)
                  leaveTimeout: 3000
              };
  
          }, {}], 57: [function (require, module, exports) {
              /* jshint node: true */
              'use strict';
              
              var debug = require('cog/logger')('rtc-signaller');
              var extend = require('cog/extend');
              var roles = ['a', 'b'];
              
              /**
    #### announce
  
    ```
    /announce|%metadata%|{"id": "...", ... }
    ```
  
    When an announce message is received by the signaller, the attached
    object data is decoded and the signaller emits an `announce` message.
  
  **/
  module.exports = function (signaller) {
                  
                  function copyData(target, source) {
                      if (target && source) {
                          for (var key in source) {
                              target[key] = source[key];
                          }
                      }
                      
                      return target;
                  }
                  
                  function dataAllowed(data) {
                      var evt = {
                          data: data,
                          allow: true
                      };
                      
                      signaller('peer:filter', evt);
                      
                      return evt.allow;
                  }
                  
                  return function (args, messageType, srcData, srcState, isDM) {
                      var data = args[0];
                      var peer;
                      
                      debug('announce handler invoked, received data: ', data);
                      
                      // if we have valid data then process
                      if (data && data.id && data.id !== signaller.id) {
                          if (!dataAllowed(data)) {
                              return;
                          }
                          // check to see if this is a known peer
                          peer = signaller.peers.get(data.id);
                          
                          // trigger the peer connected event to flag that we know about a
                          // peer connection. The peer has passed the "filter" check but may
                          // be announced / updated depending on previous connection status
                          signaller('peer:connected', data.id, data);
                          
                          // if the peer is existing, then update the data
                          if (peer && (!peer.inactive)) {
                              debug('signaller: ' + signaller.id + ' received update, data: ', data);
                              
                              // update the data
                              copyData(peer.data, data);
                              
                              // trigger the peer update event
                              return signaller('peer:update', data, srcData);
                          }
                          
                          // create a new peer
                          peer = {
                              id: data.id,
                              
                              // initialise the local role index
                              roleIdx: [data.id, signaller.id].sort().indexOf(data.id),
                              
                              // initialise the peer data
                              data: {}
                          };
                          
                          // initialise the peer data
                          copyData(peer.data, data);
                          
                          // reset inactivity state
                          clearTimeout(peer.leaveTimer);
                          peer.inactive = false;
                          
                          // set the peer data
                          signaller.peers.set(data.id, peer);
                          
                          // if this is an initial announce message (no vector clock attached)
                          // then send a announce reply
                          if (signaller.autoreply && (!isDM)) {
                              signaller
            .to(data.id)
            .send('/announce', signaller.attributes);
                          }
                          
                          // emit a new peer announce event
                          return signaller('peer:announce', data, peer);
                      }
                  };
              };
  
          }, { "cog/extend": 26, "cog/logger": 29 }], 58: [function (require, module, exports) {
              /* jshint node: true */
              'use strict';
              
              /**
    ### signaller message handlers
  
  **/
  
  module.exports = function (signaller, opts) {
                  return {
                      announce: require('./announce')(signaller, opts),
                      leave: require('./leave')(signaller, opts)
                  };
              };
          }, { "./announce": 57, "./leave": 59 }], 59: [function (require, module, exports) {
              /* jshint node: true */
              'use strict';
              
              /**
    #### leave
  
    ```
    /leave|{"id":"..."}
    ```
  
    When a leave message is received from a peer, we check to see if that is
    a peer that we are managing state information for and if we are then the
    peer state is removed.
  
  **/
  module.exports = function (signaller, opts) {
                  return function (args) {
                      var data = args[0];
                      var peer = signaller.peers.get(data && data.id);
                      
                      if (peer) {
                          // start the inactivity timer
                          peer.leaveTimer = setTimeout(function () {
                              peer.inactive = true;
                              signaller('peer:leave', data.id, peer);
                          }, opts.leaveTimeout);
                      }
                      
                      // emit the event
                      signaller('peer:disconnected', data.id, peer);
                  };
              };
  
          }, {}], 60: [function (require, module, exports) {
              /* jshint node: true */
              'use strict';
              
              var reVariable = /\{\{\s*([^\}]+?)\s*\}\}/;
              var mods = require('./mods');
              
              /**
    # formatter
  
    This is a simple library designed to do one thing and one thing only -
    replace variables in strings with variable values.  It is built in such a
    way that the formatter strings are parsed and you are provided with a
    function than can efficiently be called to provide the custom output.
  
    ## Example Usage
  
    <<< examples/likefood.js
  
    __NOTE__: Formatter is not designed to be a templating library and if
    you are already using something like Handlebars or
    [hogan](https://github.com/twitter/hogan.js) in your library or application
    stack consider using them instead.
  
    ## Using named variables
  
    In the examples above we saw how the formatter can be used to replace
    function arguments in a formatter string.  We can also set up a formatter
    to use particular key values from an input string instead if that is more
    suitable:
  
    <<< examples/likefood-named.js
  
    ## Nested Property Values
  
    Since version `0.1.0` you can also access nested property values, as you
    can with templates like handlebars.
  
    ## Partial Execution
  
    Since version `0.3.x` formatter also supports partial execution when using
    indexed arguments (e.g. `{{ 0 }}`, `{{ 1 }}`, etc).  For example:
  
    <<< examples/partial.js
  
    In the case above, the original formatter function returned by `formatter`
    did not receive enough values to resolve all the required variables.  As
    such it returned a function ready to accept the remaining values.
  
    Once all values have been received the output will be generated.
  
    ## Performance
  
    I've done some
    [performance benchmarks](http://jsperf.com/formatter-performance) and
    formatter is faster than handlebars, but that isn't surprising as it is far
    simpler and doesn't have the smarts of HBS.  The test is really there to
    ensure that I didn't do anything too silly...
  
    Additionally, it should be noted that using formatter is 100% slower than
    concatenating strings, so don't use it where performance is critical. 
    Do use it where not repeating yourself is.
  **/
  
  var formatter = module.exports = function (format, opts) {
                  // extract the matches from the string
                  var parts = [];
                  var output = [];
                  var chunk;
                  var varname;
                  var varParts;
                  var match = reVariable.exec(format);
                  var isNumeric;
                  var outputIdx = 0;
                  var ignoreNumeric = (opts || {}).ignoreNumeric;
                  
                  while (match) {
                      // get the prematch chunk
                      chunk = format.slice(0, match.index);
                      
                      // if we have a valid chunk, add it to the parts
                      if (chunk) {
                          output[outputIdx++] = chunk;
                      }
                      
                      varParts = match[1].split(/\s*\|\s*/);
                      match[1] = varParts[0];
                      
                      // extract the varname
                      varname = parseInt(match[1], 10);
                      isNumeric = !isNaN(varname);
                      
                      // if this is a numeric replacement expression, and we are ignoring
                      // those expressions then pass it through to the output
                      if (ignoreNumeric && isNumeric) {
                          output[outputIdx++] = match[0];
                      }
      // otherwise, handle normally
                      else {
                          // extract the expression and add it as a function
                          parts[parts.length] = {
                              idx: (outputIdx++),
                              numeric: isNumeric,
                              varname: isNumeric ? varname : match[1],
                              modifiers: varParts.length > 1 ? createModifiers(varParts.slice(1)) : []
                          };
                      }
                      
                      // remove this matched chunk and replacer from the string
                      format = format.slice(match.index + match[0].length);
                      
                      // check for the next match
                      match = reVariable.exec(format);
                  }
                  
                  // if we still have some of the format string remaining, add it to the list
                  if (format) {
                      output[outputIdx++] = format;
                  }
                  
                  return collect(parts, output);
              };
              
              formatter.error = function (message) {
                  // create the format
                  var format = formatter(message);
                  
                  return function (err) {
                      var output;
                      
                      // if no error has been supplied, then pass it straight through
                      if (!err) {
                          return;
                      }
                      
                      output = new Error(
                          format.apply(null, Array.prototype.slice.call(arguments, 1)));
                      
                      output._original = err;
                      
                      // return the new error
                      return output;
                  };
              };
              
              function collect(parts, resolved, indexShift) {
                  // default optionals
                  indexShift = indexShift || 0;
                  
                  return function () {
                      var output = [].concat(resolved);
                      var unresolved;
                      var ii;
                      var part;
                      var partIdx;
                      var propNames;
                      var val;
                      var numericResolved = [];
                      
                      // find the unresolved parts
                      unresolved = parts.filter(function (part) {
                          return typeof output[part.idx] == 'undefined';
                      });
                      
                      // initialise the counter
                      ii = unresolved.length;
                      
                      // iterate through the unresolved parts and attempt to resolve the value
                      for (; ii--; ) {
                          part = unresolved[ii];
                          
                          if (typeof part == 'object') {
                              // if this is a numeric part, this is a simple index lookup
                              if (part.numeric) {
                                  partIdx = part.varname - indexShift;
                                  if (arguments.length > partIdx) {
                                      output[part.idx] = arguments[partIdx];
                                      if (numericResolved.indexOf(part.varname) < 0) {
                                          numericResolved[numericResolved.length] = part.varname;
                                      }
                                  }
                              }
          // otherwise, we are doing a recursive property search
                              else if (arguments.length > 0) {
                                  propNames = (part.varname || '').split('.');
                                  
                                  // initialise the output from the last valid argument
                                  output[part.idx] = (arguments[arguments.length - 1] || {});
                                  while (output[part.idx] && propNames.length > 0) {
                                      val = output[part.idx][propNames.shift()];
                                      output[part.idx] = typeof val != 'undefined' ? val : '';
                                  }
                              }
                              
                              // if the output was resolved, then apply the modifier
                              if (typeof output[part.idx] != 'undefined' && part.modifiers) {
                                  output[part.idx] = applyModifiers(part.modifiers, output[part.idx]);
                              }
                          }
                      }
                      
                      // reasses unresolved (only caring about numeric parts)
                      unresolved = parts.filter(function (part) {
                          return part.numeric && typeof output[part.idx] == 'undefined';
                      });
                      
                      // if we have no unresolved parts, then return the value
                      if (unresolved.length === 0) {
                          return output.join('');
                      }
                      
                      // otherwise, return the collect function again
                      return collect(
                          parts,
        output,
        indexShift + numericResolved.length
                      );
                  };
              }
              
              function applyModifiers(modifiers, value) {
                  // if we have modifiers, then tweak the output
                  for (var ii = 0, count = modifiers.length; ii < count; ii++) {
                      value = modifiers[ii](value);
                  }
                  
                  return value;
              }
              
              function createModifiers(modifierStrings) {
                  var modifiers = [];
                  var parts;
                  var fn;
                  
                  for (var ii = 0, count = modifierStrings.length; ii < count; ii++) {
                      parts = modifierStrings[ii].split(':');
                      fn = mods[parts[0].toLowerCase()];
                      
                      if (fn) {
                          modifiers[modifiers.length] = fn.apply(null, parts.slice(1));
                      }
                  }
                  
                  return modifiers;
              }
  
          }, { "./mods": 61 }], 61: [function (require, module, exports) {
              /* jshint node: true */
              'use strict';
              
              /**
    ## Modifiers
  
  **/
  
  /**
    ### Length Modifier (len)
  
    The length modifier is used to ensure that a string is exactly the length specified.  The string is sliced to the required max length, and then padded out with spaces (or a specified character) to meet the required length.
  
    ```js
    // pad the string test to 10 characters
    formatter('{{ 0|len:10 }}')('test');   // 'test      '
  
    // pad the string test to 10 characters, using a as the padding character
    formatter('{{ 0|len:10:a }}')('test'); // 'testaaaaaa'
    ```
  **/
  exports.len = function (length, padder) {
                  var testInt = parseInt(padder, 10);
                  var isNumber;
                  
                  // default the padder to a space
                  padder = (!isNaN(testInt)) ? testInt : (padder || ' ');
                  
                  // check whether we have a number for padding (we will pad left if we do)
                  isNumber = typeof padder == 'number';
                  
                  return function (input) {
                      var output = input.toString().slice(0, length);
                      
                      // pad the string to the required length
                      while (output.length < length) {
                          output = isNumber ? padder + output : output + padder;
                      }
                      
                      return output;
                  };
              };
          }, {}], 62: [function (require, module, exports) {
              /* jshint node: true */
              /* global document, location, Primus: false */
              'use strict';
              
              var reTrailingSlash = /\/$/;
              var formatter = require('formatter');
              var primusUrl = formatter('{{ signalhost }}{{ primusPath }}');
              
              /**
    ### loadPrimus(signalhost, opts?, callback)
  
    This is a convenience function that is patched into the signaller to assist
    with loading the `primus.js` client library from an `rtc-switchboard`
    signaling server.
  
    In the case that you wish to load `primus.js` from a location other than
    the default location of `{{ signalhost }}/rtc.io/primus.js` you can
    provide an options object which allows for the following customizations:
  
    - `primusPath` (default: `/rtc.io/primus.js`)
  
      The path at which the `primus.js` file can be found on the signalhost.
  
     __NOTE:__ The above options are passed through when creating a
     signaller object, and thus packages such as
     [rtc-quickconnect](https://github.com/rtc-io/rtc-quickconnect)
     will allow you to make the customisation with it's top level
     options also.
  
  **/
  module.exports = function (signalhost, opts, callback) {
                  var anchor = document.createElement('a');
                  var script;
                  var scriptSrc;
                  
                  if (typeof opts == 'function') {
                      callback = opts;
                      opts = {};
                  }
                  
                  // initialise the anchor with the signalhost
                  anchor.href = signalhost;
                  
                  // initialise the script location
                  scriptSrc = primusUrl({
                      signalhost: signalhost.replace(reTrailingSlash, ''),
                      primusPath: (opts || {}).primusPath || '/rtc.io/primus.js'
                  });
                  
                  // look for the script first
                  script = document.querySelector('script[src="' + scriptSrc + '"]');
                  
                  // if we found, the script trigger the callback immediately
                  if (script && typeof Primus != 'undefined') {
                      return callback(null, Primus);
                  }
    // otherwise, if the script exists but Primus is not loaded,
    // then wait for the load
                  else if (script) {
                      script.addEventListener('load', function () {
                          callback(null, Primus);
                      });
                      
                      return;
                  }
                  
                  // otherwise create the script and load primus
                  script = document.createElement('script');
                  script.src = scriptSrc;
                  
                  script.onerror = callback;
                  script.addEventListener('load', function () {
                      // if we have a signalhost that is not basepathed at /
                      // then tweak the primus prototype
                      if (anchor.pathname !== '/') {
                          Primus.prototype.pathname = anchor.pathname.replace(reTrailingSlash, '') +
          Primus.prototype.pathname;
                      }
                      
                      callback(null, Primus);
                  });
                  
                  document.body.appendChild(script);
              };
  
          }, { "formatter": 60 }], 63: [function (require, module, exports) {
              /* jshint node: true */
              'use strict';
              
              var debug = require('cog/logger')('rtc-signaller');
              var jsonparse = require('cog/jsonparse');
              
              /**
    ### signaller process handling
  
    When a signaller's underling messenger emits a `data` event this is
    delegated to a simple message parser, which applies the following simple
    logic:
  
    - Is the message a `/to` message. If so, see if the message is for this
      signaller (checking the target id - 2nd arg).  If so pass the
      remainder of the message onto the standard processing chain.  If not,
      discard the message.
  
    - Is the message a command message (prefixed with a forward slash). If so,
      look for an appropriate message handler and pass the message payload on
      to it.
  
    - Finally, does the message match any patterns that we are listening for?
      If so, then pass the entire message contents onto the registered handler.
  **/
  module.exports = function (signaller, opts) {
                  var handlers = require('./handlers')(signaller, opts);
                  
                  function sendEvent(parts, srcState, data) {
                      // initialise the event name
                      var evtName = parts[0].slice(1);
                      
                      // convert any valid json objects to json
                      var args = parts.slice(2).map(jsonparse);
                      
                      signaller.apply(
                          signaller,
        [evtName].concat(args).concat([srcState, data])
                      );
                  }
                  
                  return function (originalData) {
                      var data = originalData;
                      var isMatch = true;
                      var parts;
                      var handler;
                      var srcData;
                      var srcState;
                      var isDirectMessage = false;
                      
                      // discard primus messages
                      if (data && data.slice(0, 6) === 'primus') {
                          return;
                      }
                      
                      // force the id into string format so we can run length and comparison tests on it
                      var id = signaller.id + '';
                      debug('signaller ' + id + ' received data: ' + originalData);
                      
                      // process /to messages
                      if (data.slice(0, 3) === '/to') {
                          isMatch = data.slice(4, id.length + 4) === id;
                          if (isMatch) {
                              parts = data.slice(5 + id.length).split('|').map(jsonparse);
                              
                              // get the source data
                              isDirectMessage = true;
                              
                              // extract the vector clock and update the parts
                              parts = parts.map(jsonparse);
                          }
                      }
                      
                      // if this is not a match, then bail
                      if (!isMatch) {
                          return;
                      }
                      
                      // chop the data into parts
                      parts = parts || data.split('|').map(jsonparse);
                      
                      // if we have a specific handler for the action, then invoke
                      if (typeof parts[0] == 'string') {
                          // extract the metadata from the input data
                          srcData = parts[1];
                          
                          // if we got data from ourself, then this is pretty dumb
                          // but if we have then throw it away
                          if (srcData && srcData.id === signaller.id) {
                              return console.warn('got data from ourself, discarding');
                          }
                          
                          // get the source state
                          srcState = signaller.peers.get(srcData && srcData.id) || srcData;
                          
                          // handle commands
                          if (parts[0].charAt(0) === '/') {
                              // look for a handler for the message type
                              handler = handlers[parts[0].slice(1)];
                              
                              if (typeof handler == 'function') {
                                  handler(
                                      parts.slice(2),
              parts[0].slice(1),
              srcData,
              srcState,
              isDirectMessage
                                  );
                              }
                              else {
                                  sendEvent(parts, srcState, originalData);
                              }
                          }
        // otherwise, emit data
                          else {
                              signaller(
                                  'data',
            parts.slice(0, 1).concat(parts.slice(2)),
            srcData,
            srcState,
            isDirectMessage
                              );
                          }
                      }
                  };
              };
  
          }, { "./handlers": 58, "cog/jsonparse": 28, "cog/logger": 29 }], 64: [function (require, module, exports) {
              /* jshint node: true */
              'use strict';
              
              var debug = require('cog/logger')('rtc-signaller');
              var detect = require('rtc-core/detect');
              var defaults = require('cog/defaults');
              var extend = require('cog/extend');
              var mbus = require('mbus');
              var throttle = require('cog/throttle');
              var getable = require('cog/getable');
              var uuid = require('cuid');
              
              // initialise the list of valid "write" methods
              var WRITE_METHODS = ['write', 'send'];
              var CLOSE_METHODS = ['close', 'end'];
              
              // initialise signaller metadata so we don't have to include the package.json
              // TODO: make this checkable with some kind of prepublish script
              var metadata = {
                  version: '1.0.1'
              };
              
              /**
    # rtc-signaller
  
    The `rtc-signaller` module provides a transportless signalling
    mechanism for WebRTC.
  
    ## Purpose
  
    <<< docs/purpose.md
  
    ## Getting Started
  
    While the signaller is capable of communicating by a number of different
    messengers (i.e. anything that can send and receive messages over a wire)
    it comes with support for understanding how to connect to an
    [rtc-switchboard](https://github.com/rtc-io/rtc-switchboard) out of the box.
  
    The following code sample demonstrates how:
  
    <<< examples/getting-started.js
  
    <<< docs/events.md
  
    <<< docs/signalflow-diagrams.md
  
    ## Reference
  
    The `rtc-signaller` module is designed to be used primarily in a functional
    way and when called it creates a new signaller that will enable
    you to communicate with other peers via your messaging network.
  
    ```js
    // create a signaller from something that knows how to send messages
    var signaller = require('rtc-signaller')(messenger);
    ```
  
    As demonstrated in the getting started guide, you can also pass through
    a string value instead of a messenger instance if you simply want to
    connect to an existing `rtc-switchboard` instance.
  
  **/
  module.exports = function (messenger, opts) {
                  // get the autoreply setting
                  var autoreply = (opts || {}).autoreply;
                  var connect = (opts || {}).connect;
                  
                  // initialise the metadata
                  var localMeta = {};
                  
                  // create the signaller
                  var signaller = mbus('', (opts || {}).logger);
                  
                  // initialise the id
                  var id = signaller.id = (opts || {}).id || uuid();
                  
                  // initialise the attributes
                  var attributes = signaller.attributes = {
                      browser: detect.browser,
                      browserVersion: detect.browserVersion,
                      id: id,
                      agent: 'signaller@' + metadata.version
                  };
                  
                  // create the peers map
                  var peers = signaller.peers = getable({});
                  
                  // initialise the data event name
                  
                  var connected = false;
                  var write;
                  var close;
                  var processor;
                  var announceTimer = 0;
                  
                  function announceOnReconnect() {
                      signaller.announce();
                  }
                  
                  function bindBrowserEvents() {
                      messenger.addEventListener('message', function (evt) {
                          processor(evt.data);
                      });
                      
                      messenger.addEventListener('open', handleMessengerOpen);
                      messenger.addEventListener('close', handleMessengerClose);
                  }
                  
                  function bindEvents() {
                      // handle message data events
                      messenger.on(opts.dataEvent, processor);
                      messenger.on(opts.openEvent, handleMessengerOpen);
                      messenger.on(opts.closeEvent, handleMessengerClose);
                      messenger.on(opts.errorEvent, handleMessengerClose);
                  }
                  
                  function connectToHost(url) {
                      if (typeof connect != 'function') {
                          return signaller('error', new Error('no connect function'));
                      }
                      
                      // load primus
                      connect(url, opts, function (err, socket) {
                          if (err) {
                              return signaller('error', err);
                          }
                          
                          // create the actual messenger from a primus connection
                          signaller._messenger = messenger = socket.connect(url);
                          
                          // now init
                          init();
                      });
                  }
                  
                  function createDataLine(args) {
                      return args.map(prepareArg).join('|');
                  }
                  
                  function createMetadata() {
                      return extend({}, localMeta, { id: signaller.id });
                  }
                  
                  function extractProp(name) {
                      return messenger[name];
                  }
                  
                  function handleMessengerClose(err) {
                      if (err instanceof Error) {
                          if (verbose) console.log('socket closed with error: ', err);
                      }
                      
                      connected = false;
                      signaller('disconnected');
                  }
                  
                  function handleMessengerOpen() {
                      connected = true;
                      signaller('open');
                      signaller('connected');
                  }
                  
                  // attempt to detect whether the underlying messenger is closing
                  // this can be tough as we deal with both native (or simulated native)
                  // sockets or an abstraction layer such as primus
                  function isClosing() {
                      var isAbstraction = messenger &&
          // a primus socket has a socket attribute
          typeof messenger.socket != 'undefined';
                      
                      return isAbstraction ? false : (
        messenger &&
        typeof messenger.readyState != 'undefined' &&
        messenger.readyState >= 2
  );
                  }
                  
                  function isF(target) {
                      return typeof target == 'function';
                  }
                  
                  function init() {
                      // extract the write and close function references
                      write = [opts.writeMethod].concat(WRITE_METHODS).map(extractProp).filter(isF)[0];
                      close = [opts.closeMethod].concat(CLOSE_METHODS).map(extractProp).filter(isF)[0];
                      
                      // create the processor
                      signaller.process = processor = require('./processor')(signaller, opts);
                      
                      // if the messenger doesn't provide a valid write method, then complain
                      if (typeof write != 'function') {
                          throw new Error('provided messenger does not implement a "' +
          opts.writeMethod + '" write method');
                      }
                      
                      // handle core browser messenging apis
                      if (typeof messenger.on == 'function') {
                          bindEvents();
                      }
                      else if (typeof messenger.addEventListener == 'function') {
                          bindBrowserEvents();
                      }
                      
                      // determine if we are connected or not
                      connected = messenger.connected || false;
                      if (!connected) {
                          signaller.once('connected', function () {
                              // always announce on reconnect
                              signaller.on('connected', announceOnReconnect);
                          });
                      }
                      
                      // emit the initialized event
                      setTimeout(signaller.bind(signaller, 'init'), 0);
                  }
                  
                  function prepareArg(arg) {
                      if (typeof arg == 'object' && (!(arg instanceof String))) {
                          return JSON.stringify(arg);
                      }
                      else if (typeof arg == 'function') {
                          return null;
                      }
                      
                      return arg;
                  }
                  
                  /**
      ### signaller#send(message, data*)
  
      Use the send function to send a message to other peers in the current
      signalling scope (if announced in a room this will be a room, otherwise
      broadcast to all peers connected to the signalling server).
  
    **/
    var send = signaller.send = function () {
                      // iterate over the arguments and stringify as required
                      // var metadata = { id: signaller.id };
                      var args = [].slice.call(arguments);
                      var dataline;
                      
                      // inject the metadata
                      args.splice(1, 0, createMetadata());
                      dataline = createDataLine(args);
                      
                      // perform an isclosing check
                      if (isClosing()) {
                          return;
                      }
                      
                      // if we are not initialized, then wait until we are
                      if (!connected) {
                          return signaller.once('connected', function () {
                              write.call(messenger, dataline);
                          });
                      }
                      
                      // send the data over the messenger
                      return write.call(messenger, dataline);
                  };
                  
                  /**
      ### announce(data?)
  
      The `announce` function of the signaller will pass an `/announce` message
      through the messenger network.  When no additional data is supplied to
      this function then only the id of the signaller is sent to all active
      members of the messenging network.
  
      #### Joining Rooms
  
      To join a room using an announce call you simply provide the name of the
      room you wish to join as part of the data block that you annouce, for
      example:
  
      ```js
      signaller.announce({ room: 'testroom' });
      ```
  
      Signalling servers (such as
      [rtc-switchboard](https://github.com/rtc-io/rtc-switchboard)) will then
      place your peer connection into a room with other peers that have also
      announced in this room.
  
      Once you have joined a room, the server will only deliver messages that
      you `send` to other peers within that room.
  
      #### Providing Additional Announce Data
  
      There may be instances where you wish to send additional data as part of
      your announce message in your application.  For instance, maybe you want
      to send an alias or nick as part of your announce message rather than just
      use the signaller's generated id.
  
      If for instance you were writing a simple chat application you could join
      the `webrtc` room and tell everyone your name with the following announce
      call:
  
      ```js
      signaller.announce({
        room: 'webrtc',
        nick: 'Damon'
      });
      ```
  
      #### Announcing Updates
  
      The signaller is written to distinguish between initial peer announcements
      and peer data updates (see the docs on the announce handler below). As
      such it is ok to provide any data updates using the announce method also.
  
      For instance, I could send a status update as an announce message to flag
      that I am going offline:
  
      ```js
      signaller.announce({ status: 'offline' });
      ```
  
    **/
    signaller.announce = function (data, sender) {
                      
                      function sendAnnounce() {
                          (sender || send)('/announce', attributes);
                          signaller('local:announce', attributes);
                      }
                      
                      clearTimeout(announceTimer);
                      
                      // update internal attributes
                      extend(attributes, data, { id: signaller.id });
                      
                      // if we are already connected, then ensure we announce on
                      // reconnect
                      if (connected) {
                          // always announce on reconnect
                          signaller.removeListener('connected', announceOnReconnect);
                          signaller.on('connected', announceOnReconnect);
                      }
                      
                      // send the attributes over the network
                      return announceTimer = setTimeout(function () {
                          if (!connected) {
                              return signaller.once('connected', sendAnnounce);
                          }
                          
                          sendAnnounce();
                      }, (opts || {}).announceDelay || 10);
                  };
                  
                  /**
      ### isMaster(targetId)
  
      A simple function that indicates whether the local signaller is the master
      for it's relationship with peer signaller indicated by `targetId`.  Roles
      are determined at the point at which signalling peers discover each other,
      and are simply worked out by whichever peer has the lowest signaller id
      when lexigraphically sorted.
  
      For example, if we have two signaller peers that have discovered each
      others with the following ids:
  
      - `b11f4fd0-feb5-447c-80c8-c51d8c3cced2`
      - `8a07f82e-49a5-4b9b-a02e-43d911382be6`
  
      They would be assigned roles:
  
      - `b11f4fd0-feb5-447c-80c8-c51d8c3cced2`
      - `8a07f82e-49a5-4b9b-a02e-43d911382be6` (master)
  
    **/
    signaller.isMaster = function (targetId) {
                      var peer = peers.get(targetId);
                      
                      return peer && peer.roleIdx !== 0;
                  };
                  
                  /**
      ### leave()
  
      Tell the signalling server we are leaving.  Calling this function is
      usually not required though as the signalling server should issue correct
      `/leave` messages when it detects a disconnect event.
  
    **/
    signaller.leave = signaller.close = function () {
                      // send the leave signal
                      send('/leave', { id: id });
                      
                      // stop announcing on reconnect
                      signaller.removeListener('connected', announceOnReconnect);
                      
                      // call the close method
                      if (typeof close == 'function') {
                          close.call(messenger);
                      }
                  };
                  
                  /**
      ### metadata(data?)
  
      Get (pass no data) or set the metadata that is passed through with each
      request sent by the signaller.
  
      __NOTE:__ Regardless of what is passed to this function, metadata
      generated by the signaller will **always** include the id of the signaller
      and this cannot be modified.
    **/
    signaller.metadata = function (data) {
                      if (arguments.length === 0) {
                          return extend({}, localMeta);
                      }
                      
                      localMeta = extend({}, data);
                  };
                  
                  /**
      ### to(targetId)
  
      Use the `to` function to send a message to the specified target peer.
      A large parge of negotiating a WebRTC peer connection involves direct
      communication between two parties which must be done by the signalling
      server.  The `to` function provides a simple way to provide a logical
      communication channel between the two parties:
  
      ```js
      var send = signaller.to('e95fa05b-9062-45c6-bfa2-5055bf6625f4').send;
  
      // create an offer on a local peer connection
      pc.createOffer(
        function(desc) {
          // set the local description using the offer sdp
          // if this occurs successfully send this to our peer
          pc.setLocalDescription(
            desc,
            function() {
              send('/sdp', desc);
            },
            handleFail
          );
        },
        handleFail
      );
      ```
  
    **/
    signaller.to = function (targetId) {
                      // create a sender that will prepend messages with /to|targetId|
                      var sender = function () {
                          // get the peer (yes when send is called to make sure it hasn't left)
                          var peer = signaller.peers.get(targetId);
                          var args;
                          
                          if (!peer) {
                              throw new Error('Unknown peer: ' + targetId);
                          }
                          
                          // if the peer is inactive, then abort
                          if (peer.inactive) {
                              return;
                          }
                          
                          args = [
                              '/to',
                              targetId
                          ].concat([].slice.call(arguments));
                          
                          // inject metadata
                          args.splice(3, 0, createMetadata());
                          
                          setTimeout(function () {
                              var msg = createDataLine(args);
                              debug('TX (' + targetId + '): ' + msg);
                              
                              write.call(messenger, msg);
                          }, 0);
                      };
                      
                      return {
                          announce: function (data) {
                              return signaller.announce(data, sender);
                          },
                          
                          send: sender,
                      }
                  };
                  
                  // initialise opts defaults
                  opts = defaults({}, opts, require('./defaults'));
                  
                  // set the autoreply flag
                  signaller.autoreply = autoreply === undefined || autoreply;
                  
                  // if the messenger is a string, then we are going to attach to a
                  // ws endpoint and automatically set up primus
                  if (typeof messenger == 'string' || (messenger instanceof String)) {
                      connectToHost(messenger);
                  }
    // otherwise, initialise the connection
                  else {
                      init();
                  }
                  
                  // connect an instance of the messenger to the signaller
                  signaller._messenger = messenger;
                  
                  // expose the process as a process function
                  signaller.process = processor;
                  
                  return signaller;
              };
  
          }, { "./defaults": 56, "./processor": 63, "cog/defaults": 25, "cog/extend": 26, "cog/getable": 27, "cog/logger": 29, "cog/throttle": 30, "cuid": 32, "mbus": 48, "rtc-core/detect": 51 }], 65: [function (require, module, exports) {
              /* jshint node: true */
              'use strict';
              
              var debug = require('cog/logger')('rtc/cleanup');
              
              var CANNOT_CLOSE_STATES = [
                  'closed'
              ];
              
              var EVENTS_DECOUPLE_BC = [
                  'addstream',
                  'datachannel',
                  'icecandidate',
                  'negotiationneeded',
                  'removestream',
                  'signalingstatechange'
              ];
              
              var EVENTS_DECOUPLE_AC = [
                  'iceconnectionstatechange'
              ];
              
              /**
    ### rtc-tools/cleanup
  
    ```
    cleanup(pc)
    ```
  
    The `cleanup` function is used to ensure that a peer connection is properly
    closed and ready to be cleaned up by the browser.
  
  **/
  module.exports = function (pc) {
                  // see if we can close the connection
                  var currentState = pc.iceConnectionState;
                  var canClose = CANNOT_CLOSE_STATES.indexOf(currentState) < 0;
                  
                  function decouple(events) {
                      events.forEach(function (evtName) {
                          if (pc['on' + evtName]) {
                              pc['on' + evtName] = null;
                          }
                      });
                  }
                  
                  // decouple "before close" events
                  decouple(EVENTS_DECOUPLE_BC);
                  
                  if (canClose) {
                      debug('attempting connection close, current state: ' + pc.iceConnectionState);
                      pc.close();
                  }
                  
                  // remove the event listeners
                  // after a short delay giving the connection time to trigger
                  // close and iceconnectionstatechange events
                  setTimeout(function () {
                      decouple(EVENTS_DECOUPLE_AC);
                  }, 100);
              };
  
          }, { "cog/logger": 29 }], 66: [function (require, module, exports) {
              /* jshint node: true */
              'use strict';
              
              var mbus = require('mbus');
              var queue = require('rtc-taskqueue');
              var cleanup = require('./cleanup');
              var monitor = require('./monitor');
              var throttle = require('cog/throttle');
              var CLOSED_STATES = ['closed', 'failed'];
              
              /**
    ### rtc-tools/couple
  
    #### couple(pc, targetId, signaller, opts?)
  
    Couple a WebRTC connection with another webrtc connection identified by
    `targetId` via the signaller.
  
    The following options can be provided in the `opts` argument:
  
    - `sdpfilter` (default: null)
  
      A simple function for filtering SDP as part of the peer
      connection handshake (see the Using Filters details below).
  
    ##### Example Usage
  
    ```js
    var couple = require('rtc/couple');
  
    couple(pc, '54879965-ce43-426e-a8ef-09ac1e39a16d', signaller);
    ```
  
    ##### Using Filters
  
    In certain instances you may wish to modify the raw SDP that is provided
    by the `createOffer` and `createAnswer` calls.  This can be done by passing
    a `sdpfilter` function (or array) in the options.  For example:
  
    ```js
    // run the sdp from through a local tweakSdp function.
    couple(pc, '54879965-ce43-426e-a8ef-09ac1e39a16d', signaller, {
      sdpfilter: tweakSdp
    });
    ```
  
  **/
  function couple(pc, targetId, signaller, opts) {
                  var debugLabel = (opts || {}).debugLabel || 'rtc';
                  var debug = require('cog/logger')(debugLabel + '/couple');
                  
                  // create a monitor for the connection
                  var mon = monitor(pc, targetId, signaller, (opts || {}).logger);
                  var emit = mbus('', mon);
                  var reactive = (opts || {}).reactive;
                  var endOfCandidates = true;
                  
                  // configure the time to wait between receiving a 'disconnect'
                  // iceConnectionState and determining that we are closed
                  var disconnectTimeout = (opts || {}).disconnectTimeout || 10000;
                  var disconnectTimer;
                  
                  // initilaise the negotiation helpers
                  var isMaster = signaller.isMaster(targetId);
                  
                  // initialise the processing queue (one at a time please)
                  var q = queue(pc, opts);
                  
                  var createOrRequestOffer = throttle(function () {
                      if (!isMaster) {
                          return signaller.to(targetId).send('/negotiate');
                      }
                      
                      q.createOffer();
                  }, 100, { leading: false });
                  
                  var debounceOffer = throttle(q.createOffer, 100, { leading: false });
                  
                  function decouple() {
                      debug('decoupling ' + signaller.id + ' from ' + targetId);
                      
                      // stop the monitor
                      //     mon.removeAllListeners();
                      mon.stop();
                      
                      // cleanup the peerconnection
                      cleanup(pc);
                      
                      // remove listeners
                      signaller.removeListener('sdp', handleSdp);
                      signaller.removeListener('candidate', handleCandidate);
                      signaller.removeListener('negotiate', handleNegotiateRequest);
                  }
                  
                  function handleCandidate(data) {
                      q.addIceCandidate(data);
                  }
                  
                  function handleSdp(sdp, src) {
                      emit('sdp.remote', sdp);
                      
                      // if the source is unknown or not a match, then don't process
                      if ((!src) || (src.id !== targetId)) {
                          return;
                      }
                      
                      q.setRemoteDescription(sdp);
                  }
                  
                  function handleConnectionClose() {
                      debug('captured pc close, iceConnectionState = ' + pc.iceConnectionState);
                      decouple();
                  }
                  
                  function handleDisconnect() {
                      debug('captured pc disconnect, monitoring connection status');
                      
                      // start the disconnect timer
                      disconnectTimer = setTimeout(function () {
                          debug('manually closing connection after disconnect timeout');
                          pc.close();
                      }, disconnectTimeout);
                      
                      mon.on('statechange', handleDisconnectAbort);
                  }
                  
                  function handleDisconnectAbort() {
                      debug('connection state changed to: ' + pc.iceConnectionState);
                      resetDisconnectTimer();
                      
                      // if we have a closed or failed status, then close the connection
                      if (CLOSED_STATES.indexOf(pc.iceConnectionState) >= 0) {
                          return mon('closed');
                      }
                      
                      mon.once('disconnect', handleDisconnect);
                  }
                  
                  function handleLocalCandidate(evt) {
                      var data;
                      
                      if (evt.candidate) {
                          resetDisconnectTimer();
                          
                          // formulate into a specific data object so we won't be upset by plugin
                          // specific implementations of the candidate data format (i.e. extra fields)
                          data = {
                              candidate: evt.candidate.candidate,
                              sdpMid: evt.candidate.sdpMid,
                              sdpMLineIndex: evt.candidate.sdpMLineIndex
                          };
                          
                          emit('ice.local', data);
                          signaller.to(targetId).send('/candidate', data);
                          endOfCandidates = false;
                      }
                      else if (!endOfCandidates) {
                          endOfCandidates = true;
                          emit('ice.gathercomplete');
                          signaller.to(targetId).send('/endofcandidates', {});
                      }
                  }
                  
                  function handleNegotiateRequest(src) {
                      if (src.id === targetId) {
                          emit('negotiate.request', src.id);
                          debounceOffer();
                      }
                  }
                  
                  function resetDisconnectTimer() {
                      mon.off('statechange', handleDisconnectAbort);
                      
                      // clear the disconnect timer
                      debug('reset disconnect timer, state: ' + pc.iceConnectionState);
                      clearTimeout(disconnectTimer);
                  }
                  
                  // when regotiation is needed look for the peer
                  if (reactive) {
                      pc.onnegotiationneeded = function () {
                          emit('negotiate.renegotiate');
                          createOrRequestOffer();
                      };
                  }
                  
                  pc.onicecandidate = handleLocalCandidate;
                  
                  // when the task queue tells us we have sdp available, send that over the wire
                  q.on('sdp.local', function (desc) {
                      signaller.to(targetId).send('/sdp', desc);
                  });
                  
                  // when we receive sdp, then
                  signaller.on('sdp', handleSdp);
                  signaller.on('candidate', handleCandidate);
                  
                  // if this is a master connection, listen for negotiate events
                  if (isMaster) {
                      signaller.on('negotiate', handleNegotiateRequest);
                  }
                  
                  // when the connection closes, remove event handlers
                  mon.once('closed', handleConnectionClose);
                  mon.once('disconnected', handleDisconnect);
                  
                  // patch in the create offer functions
                  mon.createOffer = createOrRequestOffer;
                  
                  return mon;
              }
              
              module.exports = couple;
  
          }, { "./cleanup": 65, "./monitor": 70, "cog/logger": 29, "cog/throttle": 30, "mbus": 48, "rtc-taskqueue": 71 }], 67: [function (require, module, exports) {
              /* jshint node: true */
              'use strict';
              
              /**
    ### rtc-tools/detect
  
    Provide the [rtc-core/detect](https://github.com/rtc-io/rtc-core#detect)
    functionality.
  **/
  module.exports = require('rtc-core/detect');
  
          }, { "rtc-core/detect": 51 }], 68: [function (require, module, exports) {
              /* jshint node: true */
              'use strict';
              
              var debug = require('cog/logger')('generators');
              var detect = require('./detect');
              var defaults = require('cog/defaults');
              
              var mappings = {
                  create: {
                      dtls: function (c) {
                          if (!detect.moz) {
                              c.optional = (c.optional || []).concat({ DtlsSrtpKeyAgreement: true });
                          }
                      }
                  }
              };
              
              /**
    ### rtc-tools/generators
  
    The generators package provides some utility methods for generating
    constraint objects and similar constructs.
  
    ```js
    var generators = require('rtc/generators');
    ```
  
  **/
  
  /**
    #### generators.config(config)
  
    Generate a configuration object suitable for passing into an W3C
    RTCPeerConnection constructor first argument, based on our custom config.
  
    In the event that you use short term authentication for TURN, and you want
    to generate new `iceServers` regularly, you can specify an iceServerGenerator
    that will be used prior to coupling. This generator should return a fully
    compliant W3C (RTCIceServer dictionary)[http://www.w3.org/TR/webrtc/#idl-def-RTCIceServer].
  
    If you pass in both a generator and iceServers, the iceServers _will be
    ignored and the generator used instead.
  **/
  
  exports.config = function (config) {
                  var iceServerGenerator = (config || {}).iceServerGenerator;
                  
                  return defaults({}, config, {
                      iceServers: typeof iceServerGenerator == 'function' ? iceServerGenerator() : []
                  });
              };
              
              /**
    #### generators.connectionConstraints(flags, constraints)
  
    This is a helper function that will generate appropriate connection
    constraints for a new `RTCPeerConnection` object which is constructed
    in the following way:
  
    ```js
    var conn = new RTCPeerConnection(flags, constraints);
    ```
  
    In most cases the constraints object can be left empty, but when creating
    data channels some additional options are required.  This function
    can generate those additional options and intelligently combine any
    user defined constraints (in `constraints`) with shorthand flags that
    might be passed while using the `rtc.createConnection` helper.
  **/
  exports.connectionConstraints = function (flags, constraints) {
                  var generated = {};
                  var m = mappings.create;
                  var out;
                  
                  // iterate through the flags and apply the create mappings
                  Object.keys(flags || {}).forEach(function (key) {
                      if (m[key]) {
                          m[key](generated);
                      }
                  });
                  
                  // generate the connection constraints
                  out = defaults({}, constraints, generated);
                  debug('generated connection constraints: ', out);
                  
                  return out;
              };
  
          }, { "./detect": 67, "cog/defaults": 25, "cog/logger": 29 }], 69: [function (require, module, exports) {
              /* jshint node: true */
              
              'use strict';
              
              /**
    # rtc-tools
  
    The `rtc-tools` module does most of the heavy lifting within the
    [rtc.io](http://rtc.io) suite.  Primarily it handles the logic of coupling
    a local `RTCPeerConnection` with it's remote counterpart via an
    [rtc-signaller](https://github.com/rtc-io/rtc-signaller) signalling
    channel.
  
    ## Getting Started
  
    If you decide that the `rtc-tools` module is a better fit for you than either
    [rtc-quickconnect](https://github.com/rtc-io/rtc-quickconnect) or
    [rtc-glue](https://github.com/rtc-io/rtc-glue) then the code snippet below
    will provide you a guide on how to get started using it in conjunction with
    the [rtc-signaller](https://github.com/rtc-io/rtc-signaller) and
    [rtc-media](https://github.com/rtc-io/rtc-media) modules:
  
    <<< examples/getting-started.js
  
    This code definitely doesn't cover all the cases that you need to consider
    (i.e. peers leaving, etc) but it should demonstrate how to:
  
    1. Capture video and add it to a peer connection
    2. Couple a local peer connection with a remote peer connection
    3. Deal with the remote steam being discovered and how to render
       that to the local interface.
  
    ## Reference
  
  **/
  
  var gen = require('./generators');
              
              // export detect
              var detect = exports.detect = require('./detect');
              var findPlugin = require('rtc-core/plugin');
              
              // export cog logger for convenience
              exports.logger = require('cog/logger');
              
              // export peer connection
              var RTCPeerConnection =
   exports.RTCPeerConnection = detect('RTCPeerConnection');
              
              // add the couple utility
              exports.couple = require('./couple');
              
              /**
    ### createConnection
  
    ```
    createConnection(opts?, constraints?) => RTCPeerConnection
    ```
  
    Create a new `RTCPeerConnection` auto generating default opts as required.
  
    ```js
    var conn;
  
    // this is ok
    conn = rtc.createConnection();
  
    // and so is this
    conn = rtc.createConnection({
      iceServers: []
    });
    ```
  **/
  exports.createConnection = function (opts, constraints) {
                  var plugin = findPlugin((opts || {}).plugins);
                  var PeerConnection = (opts || {}).RTCPeerConnection || RTCPeerConnection;
                  
                  // generate the config based on options provided
                  var config = gen.config(opts);
                  
                  // generate appropriate connection constraints
                  constraints = gen.connectionConstraints(opts, constraints);
                  
                  if (plugin && typeof plugin.createConnection == 'function') {
                      return plugin.createConnection(config, constraints);
                  }
                  
                  return new PeerConnection(config, constraints);
              };
  
          }, { "./couple": 66, "./detect": 67, "./generators": 68, "cog/logger": 29, "rtc-core/plugin": 54 }], 70: [function (require, module, exports) {
              /* jshint node: true */
              'use strict';
              
              var mbus = require('mbus');
              
              // define some state mappings to simplify the events we generate
              var stateMappings = {
                  completed: 'connected'
              };
              
              // define the events that we need to watch for peer connection
              // state changes
              var peerStateEvents = [
                  'signalingstatechange',
                  'iceconnectionstatechange',
              ];
              
              /**
    ### rtc-tools/monitor
  
    ```
    monitor(pc, targetId, signaller, parentBus) => mbus
    ```
  
    The monitor is a useful tool for determining the state of `pc` (an
    `RTCPeerConnection`) instance in the context of your application. The
    monitor uses both the `iceConnectionState` information of the peer
    connection and also the various
    [signaller events](https://github.com/rtc-io/rtc-signaller#signaller-events)
    to determine when the connection has been `connected` and when it has
    been `disconnected`.
  
    A monitor created `mbus` is returned as the result of a
    [couple](https://github.com/rtc-io/rtc#rtccouple) between a local peer
    connection and it's remote counterpart.
  
  **/
  module.exports = function (pc, targetId, signaller, parentBus) {
                  var monitor = mbus('', parentBus);
                  var state;
                  
                  function checkState() {
                      var newState = getMappedState(pc.iceConnectionState);
                      
                      // flag the we had a state change
                      monitor('statechange', pc, newState);
                      
                      // if the active state has changed, then send the appopriate message
                      if (state !== newState) {
                          monitor(newState);
                          state = newState;
                      }
                  }
                  
                  function handleClose() {
                      monitor('closed');
                  }
                  
                  function handlePeerLeave(peerId) {
                      // if the peer leaving is not the peer we are connected to
                      // then we aren't interested
                      if (peerId !== targetId) {
                          return;
                      }
                      
                      // trigger a closed event
                      monitor('closed');
                  }
                  
                  pc.onclose = handleClose;
                  peerStateEvents.forEach(function (evtName) {
                      pc['on' + evtName] = checkState;
                  });
                  
                  monitor.stop = function () {
                      pc.onclose = null;
                      peerStateEvents.forEach(function (evtName) {
                          pc['on' + evtName] = null;
                      });
                      
                      // remove the peer:leave listener
                      if (signaller && typeof signaller.removeListener == 'function') {
                          signaller.removeListener('peer:leave', handlePeerLeave);
                      }
                  };
                  
                  monitor.checkState = checkState;
                  
                  // if we haven't been provided a valid peer connection, abort
                  if (!pc) {
                      return monitor;
                  }
                  
                  // determine the initial is active state
                  state = getMappedState(pc.iceConnectionState);
                  
                  // if we've been provided a signaller, then watch for peer:leave events
                  if (signaller && typeof signaller.on == 'function') {
                      signaller.on('peer:leave', handlePeerLeave);
                  }
                  
                  return monitor;
              };
              
              /* internal helpers */
              
              function getMappedState(state) {
                  return stateMappings[state] || state;
              }
  
          }, { "mbus": 48 }], 71: [function (require, module, exports) {
              var detect = require('rtc-core/detect');
              var findPlugin = require('rtc-core/plugin');
              var PriorityQueue = require('priorityqueuejs');
              
              // some validation routines
              var checkCandidate = require('rtc-validator/candidate');
              
              // the sdp cleaner
              var sdpclean = require('rtc-sdpclean');
              
              var PRIORITY_LOW = 100;
              var PRIORITY_WAIT = 1000;
              
              // priority order (lower is better)
              var DEFAULT_PRIORITIES = [
                  'candidate',
                  'setLocalDescription',
                  'setRemoteDescription',
                  'createAnswer',
                  'createOffer'
              ];
              
              // define event mappings
              var METHOD_EVENTS = {
                  setLocalDescription: 'setlocaldesc',
                  setRemoteDescription: 'setremotedesc',
                  createOffer: 'offer',
                  createAnswer: 'answer'
              };
              
              // define states in which we will attempt to finalize a connection on receiving a remote offer
              var VALID_RESPONSE_STATES = ['have-remote-offer', 'have-local-pranswer'];
              
              /**
    # rtc-taskqueue
  
    This is a package that assists with applying actions to an `RTCPeerConnection`
    in as reliable order as possible. It is primarily used by the coupling logic
    of the [`rtc-tools`](https://github.com/rtc-io/rtc-tools).
  
    ## Example Usage
  
    To be completed
  **/
  module.exports = function (pc, opts) {
                  // create the task queue
                  var queue = new PriorityQueue(orderTasks);
                  var tq = require('mbus')('', (opts || {}).logger);
                  
                  // initialise task importance
                  var priorities = (opts || {}).priorities || DEFAULT_PRIORITIES;
                  
                  // check for plugin usage
                  var plugin = findPlugin((opts || {}).plugins);
                  
                  // initialise state tracking
                  var checkQueueTimer = 0;
                  var currentTask;
                  var defaultFail = tq.bind(tq, 'fail');
                  
                  // look for an sdpfilter function (allow slight mis-spellings)
                  var sdpFilter = (opts || {}).sdpfilter || (opts || {}).sdpFilter;
                  
                  // initialise session description and icecandidate objects
                  var RTCSessionDescription = (opts || {}).RTCSessionDescription ||
      detect('RTCSessionDescription');
                  
                  var RTCIceCandidate = (opts || {}).RTCIceCandidate ||
      detect('RTCIceCandidate');
                  
                  function abortQueue(err) {
                      console.error(err);
                  }
                  
                  function applyCandidate(task, next) {
                      var candidate;
                      var data = task.args[0];
                      
                      // we have a null candidate, we have finished gathering candidates
                      if (!data.candidate) {
                          return next();
                      }
                      
                      try {
                          candidate = createIceCandidate(data);
                          pc.addIceCandidate(candidate);
                          tq('ice.remote.applied', candidate);
                      }
      catch (e) {
                          tq('ice.remote.invalid', candidate);
                          return next(e);
                      }
                      
                      next();
                  }
                  
                  function checkQueue() {
                      // peek at the next item on the queue
                      var next = (!queue.isEmpty()) && (!currentTask) && queue.peek();
                      var ready = next && testReady(next);
                      var retry = (!queue.isEmpty()) && isNotClosed(pc);
                      
                      // reset the queue timer
                      checkQueueTimer = 0;
                      
                      // if we don't have a task ready, then abort
                      if (!ready) {
                          return retry && triggerQueueCheck();
                      }
                      
                      // update the current task (dequeue)
                      currentTask = queue.deq();
                      
                      // process the task
                      currentTask.fn(currentTask, function (err) {
                          var fail = currentTask.fail || defaultFail;
                          var pass = currentTask.pass;
                          var taskName = currentTask.name;
                          
                          // if errored, fail
                          if (err) {
                              if (verbose) console.log(taskName + ' task failed: ', err);
                              return fail(err);
                          }
                          
                          if (typeof pass == 'function') {
                              pass.apply(currentTask, [].slice.call(arguments, 1));
                          }
                          
                          setTimeout(function () {
                              currentTask = null;
                              triggerQueueCheck();
                          }, 0);
                      });
                  }
                  
                  function cleansdp(desc) {
                      // ensure we have clean sdp
                      var sdpErrors = [];
                      var sdp = desc && sdpclean(desc.sdp, { collector: sdpErrors });
                      
                      // if we don't have a match, log some info
                      if (desc && sdp !== desc.sdp) {
                          console.info('invalid lines removed from sdp: ', sdpErrors);
                          desc.sdp = sdp;
                      }
                      
                      // if a filter has been specified, then apply the filter
                      if (typeof sdpFilter == 'function') {
                          desc.sdp = sdpFilter(desc.sdp, pc, methodName);
                      }
                      
                      return desc;
                  }
                  
                  function completeConnection() {
                      if (VALID_RESPONSE_STATES.indexOf(pc.signalingState) >= 0) {
                          return tq.createAnswer();
                      }
                  }
                  
                  function createIceCandidate(data) {
                      if (plugin && typeof plugin.createIceCandidate == 'function') {
                          return plugin.createIceCandidate(data);
                      }
                      
                      return new RTCIceCandidate(data);
                  }
                  
                  function createSessionDescription(data) {
                      if (plugin && typeof plugin.createSessionDescription == 'function') {
                          return plugin.createSessionDescription(data);
                      }
                      
                      return new RTCSessionDescription(data);
                  }
                  
                  function emitSdp() {
                      tq('sdp.local', this.args[0]);
                  }
                  
                  function enqueue(name, handler, opts) {
                      return function () {
                          var args = [].slice.call(arguments);
                          
                          if (opts && typeof opts.processArgs == 'function') {
                              args = args.map(opts.processArgs);
                          }
                          
                          queue.enq({
                              args: args,
                              name: name,
                              fn: handler,
                              
                              // initilaise any checks that need to be done prior
                              // to the task executing
                              checks: [isNotClosed].concat((opts || {}).checks || []),
                              
                              // initialise the pass and fail handlers
                              pass: (opts || {}).pass,
                              fail: (opts || {}).fail
                          });
                          
                          triggerQueueCheck();
                      };
                  }
                  
                  function execMethod(task, next) {
                      var fn = pc[task.name];
                      var eventName = METHOD_EVENTS[task.name] || (task.name || '').toLowerCase();
                      var cbArgs = [success, fail];
                      var isOffer = task.name === 'createOffer';
                      
                      function fail(err) {
                          tq.apply(tq, ['negotiate.error', task.name, err].concat(task.args));
                          next(err);
                      }
                      
                      function success() {
                          tq.apply(tq, [['negotiate', eventName, 'ok'], task.name].concat(task.args));
                          next.apply(null, [null].concat([].slice.call(arguments)));
                      }
                      
                      if (typeof fn != 'function') {
                          return next(new Error('cannot call "' + task.name + '" on RTCPeerConnection'));
                      }
                      
                      // invoke the function
                      tq.apply(tq, ['negotiate.' + eventName].concat(task.args));
                      fn.apply(
                          pc,
        task.args.concat(cbArgs).concat(isOffer ? generateConstraints() : [])
                      );
                  }
                  
                  function extractCandidateEventData(data) {
                      // if we have been passed an event, then extract the candidate from the data
                      if (data.srcElement && data.candidate) {
                          data = data.candidate;
                      }
                      
                      return data;
                  }
                  
                  function generateConstraints() {
                      var allowedKeys = {
                          offertoreceivevideo: 'OfferToReceiveVideo',
                          offertoreceiveaudio: 'OfferToReceiveAudio',
                          icerestart: 'IceRestart',
                          voiceactivitydetection: 'VoiceActivityDetection'
                      };
                      
                      var constraints = {
                          OfferToReceiveVideo: true,
                          OfferToReceiveAudio: true
                      };
                      
                      // update known keys to match
                      Object.keys(opts || {}).forEach(function (key) {
                          if (allowedKeys[key.toLowerCase]) {
                              constraints[allowedKeys[key.toLowerCase()]] = opts[key];
                          }
                      });
                      
                      return { mandatory: constraints };
                  }
                  
                  function hasLocalOrRemoteDesc(pc, task) {
                      return pc.__hasDesc || (pc.__hasDesc = !!pc.remoteDescription);
                  }
                  
                  function isNotNegotiating(pc) {
                      return pc.signalingState !== 'have-local-offer';
                  }
                  
                  function isNotClosed(pc) {
                      return pc.signalingState !== 'closed';
                  }
                  
                  function isStable(pc) {
                      return pc.signalingState === 'stable';
                  }
                  
                  function isValidCandidate(pc, data) {
                      return data.__valid ||
        (data.__valid = checkCandidate(data.args[0]).length === 0);
                  }
                  
                  function orderTasks(a, b) {
                      // apply each of the checks for each task
                      var tasks = [a, b];
                      var readiness = tasks.map(testReady);
                      var taskPriorities = tasks.map(function (task, idx) {
                          var ready = readiness[idx];
                          var priority = ready && priorities.indexOf(task.name);
                          
                          return ready ? (priority >= 0 ? priority : PRIORITY_LOW) : PRIORITY_WAIT;
                      });
                      
                      return taskPriorities[1] - taskPriorities[0];
                  }
                  
                  // check whether a task is ready (does it pass all the checks)
                  function testReady(task) {
                      return (task.checks || []).reduce(function (memo, check) {
                          return memo && check(pc, task);
                      }, true);
                  }
                  
                  function triggerQueueCheck() {
                      if (checkQueueTimer) return;
                      checkQueueTimer = setTimeout(checkQueue, 50);
                  }
                  
                  // patch in the queue helper methods
                  tq.addIceCandidate = enqueue('addIceCandidate', applyCandidate, {
                      processArgs: extractCandidateEventData,
                      checks: [hasLocalOrRemoteDesc, isValidCandidate]
                  });
                  
                  tq.setLocalDescription = enqueue('setLocalDescription', execMethod, {
                      processArgs: cleansdp,
                      pass: emitSdp
                  });
                  
                  tq.setRemoteDescription = enqueue('setRemoteDescription', execMethod, {
                      processArgs: createSessionDescription,
                      pass: completeConnection
                  });
                  
                  tq.createOffer = enqueue('createOffer', execMethod, {
                      checks: [isNotNegotiating],
                      pass: tq.setLocalDescription
                  });
                  
                  tq.createAnswer = enqueue('createAnswer', execMethod, {
                      pass: tq.setLocalDescription
                  });
                  
                  return tq;
              };
  
          }, { "mbus": 48, "priorityqueuejs": 72, "rtc-core/detect": 51, "rtc-core/plugin": 54, "rtc-sdpclean": 73, "rtc-validator/candidate": 74 }], 72: [function (require, module, exports) {
              /**
   * Expose `PriorityQueue`.
   */
  module.exports = PriorityQueue;
              
              /**
   * Initializes a new empty `PriorityQueue` with the given `comparator(a, b)`
   * function, uses `.DEFAULT_COMPARATOR()` when no function is provided.
   *
   * The comparator function must return a positive number when `a > b`, 0 when
   * `a == b` and a negative number when `a < b`.
   *
   * @param {Function}
   * @return {PriorityQueue}
   * @api public
   */
  function PriorityQueue(comparator) {
                  this._comparator = comparator || PriorityQueue.DEFAULT_COMPARATOR;
                  this._elements = [];
              }
              
              /**
   * Compares `a` and `b`, when `a > b` it returns a positive number, when
   * it returns 0 and when `a < b` it returns a negative number.
   *
   * @param {String|Number} a
   * @param {String|Number} b
   * @return {Number}
   * @api public
   */
  PriorityQueue.DEFAULT_COMPARATOR = function (a, b) {
                  if (a instanceof Number && b instanceof Number) {
                      return a - b;
                  } else {
                      a = a.toString();
                      b = b.toString();
                      
                      if (a == b) return 0;
                      
                      return (a > b) ? 1 : -1;
                  }
              };
              
              /**
   * Returns whether the priority queue is empty or not.
   *
   * @return {Boolean}
   * @api public
   */
  PriorityQueue.prototype.isEmpty = function () {
                  return this.size() === 0;
              };
              
              /**
   * Peeks at the top element of the priority queue.
   *
   * @return {Object}
   * @throws {Error} when the queue is empty.
   * @api public
   */
  PriorityQueue.prototype.peek = function () {
                  if (this.isEmpty()) throw new Error('PriorityQueue is empty');
                  
                  return this._elements[0];
              };
              
              /**
   * Dequeues the top element of the priority queue.
   *
   * @return {Object}
   * @throws {Error} when the queue is empty.
   * @api public
   */
  PriorityQueue.prototype.deq = function () {
                  var first = this.peek();
                  var last = this._elements.pop();
                  var size = this.size();
                  
                  if (size === 0) return first;
                  
                  this._elements[0] = last;
                  var current = 0;
                  
                  while (current < size) {
                      var largest = current;
                      var left = (2 * current) + 1;
                      var right = (2 * current) + 2;
                      
                      if (left < size && this._compare(left, largest) > 0) {
                          largest = left;
                      }
                      
                      if (right < size && this._compare(right, largest) > 0) {
                          largest = right;
                      }
                      
                      if (largest === current) break;
                      
                      this._swap(largest, current);
                      current = largest;
                  }
                  
                  return first;
              };
              
              /**
   * Enqueues the `element` at the priority queue and returns its new size.
   *
   * @param {Object} element
   * @return {Number}
   * @api public
   */
  PriorityQueue.prototype.enq = function (element) {
                  var size = this._elements.push(element);
                  var current = size - 1;
                  
                  while (current > 0) {
                      var parent = Math.floor((current - 1) / 2);
                      
                      if (this._compare(current, parent) < 0) break;
                      
                      this._swap(parent, current);
                      current = parent;
                  }
                  
                  return size;
              };
              
              /**
   * Returns the size of the priority queue.
   *
   * @return {Number}
   * @api public
   */
  PriorityQueue.prototype.size = function () {
                  return this._elements.length;
              };
              
              /**
   *  Iterates over queue elements
   *
   *  @param {Function} fn
   */
  PriorityQueue.prototype.forEach = function (fn) {
                  return this._elements.forEach(fn);
              };
              
              /**
   * Compares the values at position `a` and `b` in the priority queue using its
   * comparator function.
   *
   * @param {Number} a
   * @param {Number} b
   * @return {Number}
   * @api private
   */
  PriorityQueue.prototype._compare = function (a, b) {
                  return this._comparator(this._elements[a], this._elements[b]);
              };
              
              /**
   * Swaps the values at position `a` and `b` in the priority queue.
   *
   * @param {Number} a
   * @param {Number} b
   * @api private
   */
  PriorityQueue.prototype._swap = function (a, b) {
                  var aux = this._elements[a];
                  this._elements[a] = this._elements[b];
                  this._elements[b] = aux;
              };
  
          }, {}], 73: [function (require, module, exports) {
              var validators = [
                  [/^(a\=candidate.*)$/, require('rtc-validator/candidate')]
              ];
              
              var reSdpLineBreak = /(\r?\n|\\r\\n)/;
              
              /**
    # rtc-sdpclean
  
    Remove invalid lines from your SDP.
  
    ## Why?
  
    This module removes the occasional "bad egg" that will slip into SDP when it
    is generated by the browser.  In particular these situations are catered for:
  
    - invalid ICE candidates
  
  **/
  module.exports = function (input, opts) {
                  var lineBreak = detectLineBreak(input);
                  var lines = input.split(lineBreak);
                  var collector = (opts || {}).collector;
                  
                  // filter out invalid lines
                  lines = lines.filter(function (line) {
                      // iterate through the validators and use the one that matches
                      var validator = validators.reduce(function (memo, data, idx) {
                          return typeof memo != 'undefined' ? memo : (data[0].exec(line) && {
                              line: line.replace(data[0], '$1'),
                              fn: data[1]
                          });
                      }, undefined);
                      
                      // if we have a validator, ensure we have no errors
                      var errors = validator ? validator.fn(validator.line) : [];
                      
                      // if we have errors and an error collector, then add to the collector
                      if (collector) {
                          errors.forEach(function (err) {
                              collector.push(err);
                          });
                      }
                      
                      return errors.length === 0;
                  });
                  
                  return lines.join(lineBreak);
              };
              
              function detectLineBreak(input) {
                  var match = reSdpLineBreak.exec(input);
                  
                  return match && match[0];
              }
  
          }, { "rtc-validator/candidate": 74 }], 74: [function (require, module, exports) {
              var debug = require('cog/logger')('rtc-validator');
              var rePrefix = /^(?:a=)?candidate:/;
              var reIP = /^(\d+\.){3}\d+$/;
              
              /*
  
  validation rules as per:
  http://tools.ietf.org/html/draft-ietf-mmusic-ice-sip-sdp-03#section-8.1
  
     candidate-attribute   = "candidate" ":" foundation SP component-id SP
                             transport SP
                             priority SP
                             connection-address SP     ;from RFC 4566
                             port         ;port from RFC 4566
                             SP cand-type
                             [SP rel-addr]
                             [SP rel-port]
                             *(SP extension-att-name SP
                                  extension-att-value)
  
     foundation            = 1*32ice-char
     component-id          = 1*5DIGIT
     transport             = "UDP" / transport-extension
     transport-extension   = token              ; from RFC 3261
     priority              = 1*10DIGIT
     cand-type             = "typ" SP candidate-types
     candidate-types       = "host" / "srflx" / "prflx" / "relay" / token
     rel-addr              = "raddr" SP connection-address
     rel-port              = "rport" SP port
     extension-att-name    = token
     extension-att-value   = *VCHAR
     ice-char              = ALPHA / DIGIT / "+" / "/"
  */
  var partValidation = [
                  [/.+/, 'invalid foundation component', 'foundation'],
                  [/\d+/, 'invalid component id', 'component-id'],
                  [/(UDP|TCP)/i, 'transport must be TCP or UDP', 'transport'],
                  [/\d+/, 'numeric priority expected', 'priority'],
                  [reIP, 'invalid connection address', 'connection-address'],
                  [/\d+/, 'invalid connection port', 'connection-port'],
                  [/typ/, 'Expected "typ" identifier', 'type classifier'],
                  [/.+/, 'Invalid candidate type specified', 'candidate-type']
              ];
              
              /**
    ### `rtc-validator/candidate`
  
    Validate that an `RTCIceCandidate` (or plain old object with data, sdpMid,
    etc attributes) is a valid ice candidate.
  
    Specs reviewed as part of the validation implementation:
  
    - <http://tools.ietf.org/html/draft-ietf-mmusic-ice-sip-sdp-03#section-8.1>
    - <http://tools.ietf.org/html/rfc5245>
  
  **/
  module.exports = function (data) {
                  var errors = [];
                  var candidate = data && (data.candidate || data);
                  var prefixMatch = candidate && rePrefix.exec(candidate);
                  var parts = prefixMatch && candidate.slice(prefixMatch[0].length).split(/\s/);
                  
                  if (!candidate) {
                      return [new Error('empty candidate')];
                  }
                  
                  // check that the prefix matches expected
                  if (!prefixMatch) {
                      return [new Error('candidate did not match expected sdp line format')];
                  }
                  
                  // perform the part validation
                  errors = errors.concat(parts.map(validateParts)).filter(Boolean);
                  
                  return errors;
              };
              
              function validateParts(part, idx) {
                  var validator = partValidation[idx];
                  
                  if (validator && (!validator[0].test(part))) {
                      debug(validator[2] + ' part failed validation: ' + part);
                      return new Error(validator[1]);
                  }
              }
  
          }, { "cog/logger": 29 }]
  }, {}, [1]);