text: require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
  var Connection = require('node-xmpp-core').Connection
    , Client = require('./index')
    , JID = require('node-xmpp-core').JID
    , Element = require('node-xmpp-core').Stanza.Element
    , Stanza = require('node-xmpp-core').Stanza
    , ltx = require('node-xmpp-core').ltx
  
  exports.Connection = Connection
  exports.Client = Client
  exports.JID = JID
  exports.Element = Element
  exports.Stanza = Stanza.Stanza
  exports.Message = Stanza.Message
  exports.Presence = Stanza.Presence
  exports.Iq = Stanza.Iq
  exports.ltx = ltx
  
  window.XMPP = exports
  
  },{"./index":2,"node-xmpp-core":39}],2:[function(require,module,exports){
  var __dirname="/";'use strict';
  
  var Session = require('./lib/session')
    , Connection = require('node-xmpp-core').Connection
    , JID = require('node-xmpp-core').JID
    , Stanza = require ('node-xmpp-core').Stanza
    , sasl = require('./lib/sasl')
    , Anonymous = require('./lib/authentication/anonymous')
    , Plain = require('./lib/authentication/plain')
    , DigestMD5 = require('./lib/authentication/digestmd5')
    , XOAuth2 = require('./lib/authentication/xoauth2')
    , XFacebookPlatform = require('./lib/authentication/xfacebook')
    , External = require('./lib/authentication/external')
    , exec = require('child_process').exec
    , util = require('util')
    , debug = require('debug')('xmpp:client')
    , ltx = require('node-xmpp-core').ltx
  
  var NS_CLIENT = 'jabber:client'
  var NS_REGISTER = 'jabber:iq:register'
  var NS_XMPP_SASL = 'urn:ietf:params:xml:ns:xmpp-sasl'
  var NS_XMPP_BIND = 'urn:ietf:params:xml:ns:xmpp-bind'
  var NS_XMPP_SESSION = 'urn:ietf:params:xml:ns:xmpp-session'
  
  var STATE_PREAUTH = 0
    , STATE_AUTH = 1
    , STATE_AUTHED = 2
    , STATE_BIND = 3
    , STATE_SESSION = 4
    , STATE_ONLINE = 5
  
  var IQID_SESSION = 'sess'
    , IQID_BIND = 'bind'
  
  /* jshint latedef: false */
  /* jshint -W079 */
  /* jshint -W020 */
  var decode64, encode64, Buffer
  if (typeof btoa === 'undefined') {
      var btoa = null
      var atob = null
  }
  
  if (typeof btoa === 'function') {
      decode64 = function(encoded) {
          return atob(encoded)
      }
  } else {
      Buffer = require('buffer').Buffer
      decode64 = function(encoded) {
          return (new Buffer(encoded, 'base64')).toString('utf8')
      }
  }
  if (typeof atob === 'function') {
      encode64 = function(decoded) {
          return btoa(decoded)
      }
  } else {
      Buffer = require('buffer').Buffer
      encode64 = function(decoded) {
          return (new Buffer(decoded, 'utf8')).toString('base64')
      }
  }
  
  /**
   * params object:
   *   jid: String (required)
   *   password: String (required)
   *   host: String (optional)
   *   port: Number (optional)
   *   reconnect: Boolean (optional)
   *   autostart: Boolean (optional) - if we start connecting to a given port
   *   register: Boolean (option) - register account before authentication
   *   legacySSL: Boolean (optional) - connect to the legacy SSL port, requires at least the host to be specified
   *   credentials: Dictionary (optional) - TLS or SSL key and certificate credentials
   *   actAs: String (optional) - if admin user act on behalf of another user (just user)
   *   disallowTLS: Boolean (optional) - prevent upgrading the connection to a secure one via TLS
   *   preferred: String (optional) - Preferred SASL mechanism to use
   *   bosh.url: String (optional) - BOSH endpoint to use
   *   bosh.prebind: Function(error, data) (optional) - Just prebind a new BOSH session for browser client use
   *            error String - Result of XMPP error. Ex : [Error: XMPP authentication failure]
   *            data Object - Result of XMPP BOSH connection.
   *
   * Examples:
   *   var cl = new xmpp.Client({
   *       jid: "me@example.com",
   *       password: "secret"
   *   })
   *   var facebook = new xmpp.Client({
   *       jid: '-' + fbUID + '@chat.facebook.com',
   *       api_key: '54321', // api key of your facebook app
   *       access_token: 'abcdefg', // user access token
   *       host: 'chat.facebook.com'
   *   })
   *   var gtalk = new xmpp.Client({
   *       jid: 'me@gmail.com',
   *       oauth2_token: 'xxxx.xxxxxxxxxxx', // from OAuth2
   *       oauth2_auth: 'http://www.google.com/talk/protocol/auth',
   *       host: 'talk.google.com'
   *   })
   *   var prebind = new xmpp.Client({
   *       jid: "me@example.com",
   *       password: "secret",
   *       bosh: {
   *           url: "http://example.com/http-bind",
   *           prebind: function(error, data) {
   *               if (error) {}
   *               res.send({ rid: data.rid, sid: data.sid })
   *           }
   *       }
   *   })
   *
   * Example SASL EXTERNAL:
   *
   * var myCredentials = {
   *   // These are necessary only if using the client certificate authentication
   *   key: fs.readFileSync('key.pem'),
   *   cert: fs.readFileSync('cert.pem'),
   *   // passphrase: 'optional'
   * }
   * var cl = new xmppClient({
   *     jid: "me@example.com",
   *     credentials: myCredentials
   *     preferred: 'EXTERNAL' // not really required, but possible
   * })
   *
   */
  function Client(options) {
      this.options = {}
      if (options) this.options = options
      this.availableSaslMechanisms = [
          XOAuth2, XFacebookPlatform, External, DigestMD5, Plain, Anonymous
      ]
  
      if (this.options.autostart !== false)
          this.connect()
  }
  
  util.inherits(Client, Session)
  
  Client.NS_CLIENT = NS_CLIENT
  
  Client.prototype.connect = function() {
      if (this.options.bosh && this.options.bosh.prebind) {
          debug('load bosh prebind')
          var cb = this.options.bosh.prebind
          delete this.options.bosh.prebind
          var cmd = 'node ' + __dirname +
              '/lib/prebind.js '
          delete this.options.bosh.prebind
          cmd += encodeURI(JSON.stringify(this.options))
          exec(
              cmd,
              function (error, stdout, stderr) {
                  if (error) {
                      cb(error, null)
                  } else {
                      var r = stdout.match(/rid:+[ 0-9]*/i)
                      r = (r[0].split(':'))[1].trim()
                      var s = stdout.match(/sid:+[ a-z+'"-_A-Z+0-9]*/i)
                      s = (s[0].split(':'))[1]
                          .replace('\'','')
                          .replace('\'','')
                          .trim()
                      if (r && s) {
                          return cb(null, { rid: r, sid: s })
                      }
                      cb(stderr)
                  }
              }
          )
      } else {
          this.options.xmlns = NS_CLIENT
          /* jshint camelcase: false */
          delete this.did_bind
          delete this.did_session
  
          this.state = STATE_PREAUTH
          this.on('end', function() {
              this.state = STATE_PREAUTH
              delete this.did_bind
              delete this.did_session
          })
  
          Session.call(this, this.options)
          this.options.jid = this.jid
  
          this.connection.on('disconnect', function(error) {
              this.state = STATE_PREAUTH
              if (!this.connection.reconnect) {
                  if (error) this.emit('error', error)
                  this.emit('offline')
              }
              delete this.did_bind
              delete this.did_session
          }.bind(this))
  
          // If server and client have multiple possible auth mechanisms
          // we try to select the preferred one
          if (this.options.preferred) {
              this.preferredSaslMechanism = this.options.preferred
          } else {
              this.preferredSaslMechanism = 'DIGEST-MD5'
          }
  
          var mechs = sasl.detectMechanisms(this.options, this.availableSaslMechanisms)
          this.availableSaslMechanisms = mechs
      }
  }
  
  Client.prototype.onStanza = function(stanza) {
      /* Actually, we shouldn't wait for <stream:features/> if
         this.streamAttrs.version is missing, but who uses pre-XMPP-1.0
         these days anyway? */
      if ((this.state !== STATE_ONLINE) && stanza.is('features')) {
          this.streamFeatures = stanza
          this.useFeatures()
      } else if (this.state === STATE_PREAUTH) {
          this.emit('stanza:preauth', stanza)
      } else if (this.state === STATE_AUTH) {
          this._handleAuthState(stanza)
      } else if ((this.state === STATE_BIND) && stanza.is('iq') && (stanza.attrs.id === IQID_BIND)) {
          this._handleBindState(stanza)
      } else if ((this.state === STATE_SESSION) && (true === stanza.is('iq')) &&
          (stanza.attrs.id === IQID_SESSION)) {
          this._handleSessionState(stanza)
      } else if (stanza.name === 'stream:error') {
          if (!this.reconnect)
              this.emit('error', stanza)
      } else if (this.state === STATE_ONLINE) {
          this.emit('stanza', stanza)
      }
  }
  
  Client.prototype._handleSessionState = function(stanza) {
      if (stanza.attrs.type === 'result') {
          this.state = STATE_AUTHED
          /* jshint camelcase: false */
          this.did_session = true
  
          /* no stream restart, but next feature (most probably
             we'll go online next) */
          this.useFeatures()
      } else {
          this.emit('error', 'Cannot bind resource')
      }
  }
  
  Client.prototype._handleBindState = function(stanza) {
      if (stanza.attrs.type === 'result') {
          this.state = STATE_AUTHED
          /*jshint camelcase: false */
          this.did_bind = true
  
          var bindEl = stanza.getChild('bind', NS_XMPP_BIND)
          if (bindEl && bindEl.getChild('jid')) {
              this.jid = new JID(bindEl.getChild('jid').getText())
          }
  
          /* no stream restart, but next feature */
          this.useFeatures()
      } else {
          this.emit('error', 'Cannot bind resource')
      }
  }
  
  Client.prototype._handleAuthState = function(stanza) {
      if (stanza.is('challenge', NS_XMPP_SASL)) {
          var challengeMsg = decode64(stanza.getText())
          var responseMsg = encode64(this.mech.challenge(challengeMsg))
          var response = new Stanza.Element(
              'response', { xmlns: NS_XMPP_SASL }
          ).t(responseMsg)
          this.send(response)
      } else if (stanza.is('success', NS_XMPP_SASL)) {
          this.mech = null
          this.state = STATE_AUTHED
          this.emit('auth')
      } else {
          this.emit('error', 'XMPP authentication failure')
      }
  }
  
  Client.prototype._handlePreAuthState = function() {
      this.state = STATE_AUTH
      var offeredMechs = this.streamFeatures.
          getChild('mechanisms', NS_XMPP_SASL).
          getChildren('mechanism', NS_XMPP_SASL).
          map(function(el) { return el.getText() })
      this.mech = sasl.selectMechanism(
          offeredMechs,
          this.preferredSaslMechanism,
          this.availableSaslMechanisms
      )
      if (this.mech) {
          this.mech.authzid = this.jid.bare().toString()
          this.mech.authcid = this.jid.user
          this.mech.password = this.password
          /*jshint camelcase: false */
          this.mech.api_key = this.api_key
          this.mech.access_token = this.access_token
          this.mech.oauth2_token = this.oauth2_token
          this.mech.oauth2_auth = this.oauth2_auth
          this.mech.realm = this.jid.domain  // anything?
          if (this.actAs) this.mech.actAs = this.actAs.user
          this.mech.digest_uri = 'xmpp/' + this.jid.domain
          var authMsg = encode64(this.mech.auth())
          var attrs = this.mech.authAttrs()
          attrs.xmlns = NS_XMPP_SASL
          attrs.mechanism = this.mech.name
          this.send(new Stanza.Element('auth', attrs)
              .t(authMsg))
      } else {
          this.emit('error', 'No usable SASL mechanism')
      }
  }
  
  /**
   * Either we just received <stream:features/>, or we just enabled a
   * feature and are looking for the next.
   */
  Client.prototype.useFeatures = function() {
      /* jshint camelcase: false */
      if ((this.state === STATE_PREAUTH) && this.register) {
          delete this.register
          this.doRegister()
      } else if ((this.state === STATE_PREAUTH) &&
          this.streamFeatures.getChild('mechanisms', NS_XMPP_SASL)) {
          this._handlePreAuthState()
      } else if ((this.state === STATE_AUTHED) &&
                 !this.did_bind &&
                 this.streamFeatures.getChild('bind', NS_XMPP_BIND)) {
          this.state = STATE_BIND
          var bindEl = new Stanza.Element(
              'iq',
              { type: 'set', id: IQID_BIND }
          ).c('bind', { xmlns: NS_XMPP_BIND })
          if (this.jid.resource)
              bindEl.c('resource').t(this.jid.resource)
          this.send(bindEl)
      } else if ((this.state === STATE_AUTHED) &&
                 !this.did_session &&
                 this.streamFeatures.getChild('session', NS_XMPP_SESSION)) {
          this.state = STATE_SESSION
          var stanza = new Stanza.Element(
            'iq',
            { type: 'set', to: this.jid.domain, id: IQID_SESSION  }
          ).c('session', { xmlns: NS_XMPP_SESSION })
          this.send(stanza)
      } else if (this.state === STATE_AUTHED) {
          /* Ok, we're authenticated and all features have been
             processed */
          this.state = STATE_ONLINE
          this.emit('online', { jid: this.jid })
      }
  }
  
  Client.prototype.doRegister = function() {
      var id = 'register' + Math.ceil(Math.random() * 99999)
      var iq = new Stanza.Element(
          'iq',
          { type: 'set', id: id, to: this.jid.domain }
      ).c('query', { xmlns: NS_REGISTER })
      .c('username').t(this.jid.user).up()
      .c('password').t(this.password)
      this.send(iq)
  
      var self = this
      var onReply = function(reply) {
          if (reply.is('iq') && (reply.attrs.id === id)) {
              self.removeListener('stanza', onReply)
  
              if (reply.attrs.type === 'result') {
                  /* Registration successful, proceed to auth */
                  self.useFeatures()
              } else {
                  self.emit('error', new Error('Registration error'))
              }
          }
      }
      this.on('stanza:preauth', onReply)
  }
  
  /**
   * returns all registered sasl mechanisms
   */
  Client.prototype.getSaslMechanisms = function() {
      return this.availableSaslMechanisms
  }
  
  /**
   * removes all registered sasl mechanisms
   */
  Client.prototype.clearSaslMechanism = function() {
      this.availableSaslMechanisms = []
  }
  
  /**
   * register a new sasl mechanism
   */
  Client.prototype.registerSaslMechanism = function(method) {
      // check if method is registered
      if (this.availableSaslMechanisms.indexOf(method) === -1 ) {
          this.availableSaslMechanisms.push(method)
      }
  }
  
  /**
   * unregister an existing sasl mechanism
   */
  Client.prototype.unregisterSaslMechanism = function(method) {
      // check if method is registered
      var index = this.availableSaslMechanisms.indexOf(method)
      if (index >= 0) {
          this.availableSaslMechanisms = this.availableSaslMechanisms.splice(index, 1)
      }
  }
  
  Client.SASL = sasl
  Client.Client = Client
  Client.Stanza = Stanza
  Client.ltx = ltx
  module.exports = Client
  },{"./lib/authentication/anonymous":3,"./lib/authentication/digestmd5":4,"./lib/authentication/external":5,"./lib/authentication/plain":7,"./lib/authentication/xfacebook":8,"./lib/authentication/xoauth2":9,"./lib/sasl":11,"./lib/session":12,"buffer":27,"child_process":16,"debug":36,"node-xmpp-core":39,"util":35}],3:[function(require,module,exports){
  'use strict';
  
  var util = require('util')
    , Mechanism = require('./mechanism')
  
  /**
   * @see http://tools.ietf.org/html/rfc4505
   * @see http://xmpp.org/extensions/xep-0175.html
   */
  function Anonymous() {}
  
  util.inherits(Anonymous, Mechanism)
  
  Anonymous.prototype.name = 'ANONYMOUS'
  
  Anonymous.prototype.auth = function() {
      return this.authzid
  };
  
  Anonymous.prototype.match = function() {
      return true
  }
  
  module.exports = Anonymous
  },{"./mechanism":6,"util":35}],4:[function(require,module,exports){
  'use strict';
  
  var util = require('util')
    , crypto = require('crypto')
    , Mechanism = require('./mechanism')
  
  
  /**
   * Hash a string
   */
  function md5(s, encoding) {
      var hash = crypto.createHash('md5')
      hash.update(s)
      return hash.digest(encoding || 'binary')
  }
  function md5Hex(s) {
      return md5(s, 'hex')
  }
  
  /**
   * Parse SASL serialization
   */
  function parseDict(s) {
      var result = {}
      while (s) {
          var m
          if ((m = /^(.+?)=(.*?[^\\]),\s*(.*)/.exec(s))) {
              result[m[1]] = m[2].replace(/\"/g, '')
              s = m[3]
          } else if ((m = /^(.+?)=(.+?),\s*(.*)/.exec(s))) {
              result[m[1]] = m[2]
              s = m[3]
          } else if ((m = /^(.+?)="(.*?[^\\])"$/.exec(s))) {
              result[m[1]] = m[2]
              s = m[3]
          } else if ((m = /^(.+?)=(.+?)$/.exec(s))) {
              result[m[1]] = m[2]
              s = m[3]
          } else {
              s = null
          }
      }
      return result
  }
  
  /**
   * SASL serialization
   */
  function encodeDict(dict) {
      var s = ''
      for (var k in dict) {
          var v = dict[k]
          if (v) s += ',' + k + '="' + v + '"'
      }
      return s.substr(1) // without first ','
  }
  
  /**
   * Right-justify a string,
   * eg. pad with 0s
   */
  function rjust(s, targetLen, padding) {
      while (s.length < targetLen)
          s = padding + s
      return s
  }
  
  /**
   * Generate a string of 8 digits
   * (number used once)
   */
  function generateNonce() {
      var result = ''
      for (var i = 0; i < 8; i++)
          result += String.fromCharCode(48 +
              Math.ceil(Math.random() * 10))
      return result
  }
  
  /**
   * @see http://tools.ietf.org/html/rfc2831
   * @see http://wiki.xmpp.org/web/SASLandDIGEST-MD5
   */
  function DigestMD5() {
      /*jshint camelcase: false */
      this.nonce_count = 0
      this.cnonce = generateNonce()
      this.authcid = null
      this.actAs = null
      this.realm = null
      this.password = null
  }
  
  util.inherits(DigestMD5, Mechanism)
  
  DigestMD5.prototype.name = 'DIGEST-MD5'
  
  DigestMD5.prototype.auth = function() {
      return ''
  }
  
  DigestMD5.prototype.getNC = function() {
      /*jshint camelcase: false */
      return rjust(this.nonce_count.toString(), 8, '0')
  }
  
  DigestMD5.prototype.responseValue = function(s) {
      var dict = parseDict(s)
      if (dict.realm)
          this.realm = dict.realm
  
      var value
      /*jshint camelcase: false */
      if (dict.nonce && dict.qop) {
          this.nonce_count++
          var a1 = md5(this.authcid + ':' +
              this.realm + ':' +
              this.password) + ':' +
              dict.nonce + ':' +
              this.cnonce
          if (this.actAs) a1 += ':' + this.actAs
  
          var a2 = 'AUTHENTICATE:' + this.digest_uri
          if ((dict.qop === 'auth-int') || (dict.qop === 'auth-conf'))
              a2 += ':00000000000000000000000000000000'
  
          value = md5Hex(md5Hex(a1) + ':' +
              dict.nonce + ':' +
              this.getNC() + ':' +
              this.cnonce + ':' +
              dict.qop + ':' +
              md5Hex(a2))
      }
      return value
  }
  
  DigestMD5.prototype.challenge = function(s) {
      var dict = parseDict(s)
      if (dict.realm)
          this.realm = dict.realm
  
      var response
      /*jshint camelcase: false */
      if (dict.nonce && dict.qop) {
          var responseValue = this.responseValue(s)
          response = {
              username: this.authcid,
              realm: this.realm,
              nonce: dict.nonce,
              cnonce: this.cnonce,
              nc: this.getNC(),
              qop: dict.qop,
              'digest-uri': this.digest_uri,
              response: responseValue,
              charset: 'utf-8'
          }
          if (this.actAs) response.authzid = this.actAs
      } else if (dict.rspauth) {
          return ''
      }
      return encodeDict(response)
  }
  
  DigestMD5.prototype.serverChallenge = function() {
      var dict = {}
      dict.realm = ''
      this.nonce = dict.nonce = generateNonce()
      dict.qop = 'auth'
      this.charset = dict.charset = 'utf-8'
      dict.algorithm = 'md5-sess'
      return encodeDict(dict)
  }
  
  // Used on the server to check for auth!
  DigestMD5.prototype.response = function(s) {
      var dict = parseDict(s)
      this.authcid = dict.username
  
      if (dict.nonce !== this.nonce) return false
      if (!dict.cnonce) return false
  
      this.cnonce = dict.cnonce
      if (this.charset !== dict.charset) return false
  
      this.response = dict.response
      return true
  }
  
  DigestMD5.prototype.match = function(options) {
      if (options.password) return true
      return false
  }
  
  module.exports = DigestMD5
  
  },{"./mechanism":6,"crypto":19,"util":35}],5:[function(require,module,exports){
  'use strict';
  
  var util = require('util')
    , Mechanism = require('./mechanism')
  
  /**
   * @see http://xmpp.org/extensions/xep-0178.html
   */
  function External() {}
  
  util.inherits(External, Mechanism)
  
  External.prototype.name = 'EXTERNAL'
  
  External.prototype.auth = function() {
      return (this.authzid)
  }
  
  External.prototype.match = function(options) {
      if (options.credentials) return true
      return false
  }
  
  module.exports = External
  },{"./mechanism":6,"util":35}],6:[function(require,module,exports){
  'use strict';
  
  /**
   * Each implemented mechanism offers multiple methods
   * - name : name of the auth method
   * - auth :
   * - match: checks if the client has enough options to
   *          offer this mechanis to xmpp servers
   * - authServer: takes a stanza and extracts the information
   */
  
  var util = require('util')
    , EventEmitter = require('events').EventEmitter
  
  // Mechanisms
  function Mechanism() {}
  
  util.inherits(Mechanism, EventEmitter)
  
  Mechanism.prototype.authAttrs = function() {
      return {}
  }
  
  module.exports = Mechanism
  },{"events":24,"util":35}],7:[function(require,module,exports){
  'use strict';
  
  var util = require('util')
    , Mechanism = require('./mechanism')
  
  function Plain() {}
  
  util.inherits(Plain, Mechanism)
  
  Plain.prototype.name = 'PLAIN'
  
  Plain.prototype.auth = function() {
      return this.authzid + '\0' +
          this.authcid + '\0' +
          this.password;
  }
  
  Plain.prototype.match = function(options) {
      if (options.password) return true
      return false
  }
  
  module.exports = Plain
  },{"./mechanism":6,"util":35}],8:[function(require,module,exports){
  'use strict';
  
  var util = require('util')
    , Mechanism = require('./mechanism')
    , querystring = require('querystring')
  
  /**
   * @see https://developers.facebook.com/docs/chat/#platauth
   */
  var XFacebookPlatform = function() {}
  
  util.inherits(XFacebookPlatform, Mechanism)
  
  XFacebookPlatform.prototype.name = 'X-FACEBOOK-PLATFORM'
  XFacebookPlatform.prototype.host = 'chat.facebook.com'
  
  XFacebookPlatform.prototype.auth = function() {
      return ''
  }
  
  XFacebookPlatform.prototype.challenge = function(s) {
      var dict = querystring.parse(s)
  
      /*jshint camelcase: false */
      var response = {
          api_key: this.api_key,
          call_id: new Date().getTime(),
          method: dict.method,
          nonce: dict.nonce,
          access_token: this.access_token,
          v: '1.0'
      }
  
      return querystring.stringify(response)
  }
  
  XFacebookPlatform.prototype.match = function(options) {
      var host = XFacebookPlatform.prototype.host
      if ((options.host === host) ||
          (options.jid && (options.jid.getDomain() === host))) {
          return true
      }
      return false
  }
  
  module.exports = XFacebookPlatform
  },{"./mechanism":6,"querystring":33,"util":35}],9:[function(require,module,exports){
  'use strict';
  
  var util = require('util')
    , Mechanism = require('./mechanism')
  
  /**
   * @see https://developers.google.com/talk/jep_extensions/oauth
   */
  /*jshint camelcase: false */
  function XOAuth2() {
      this.oauth2_auth = null
      this.authzid = null
  }
  
  util.inherits(XOAuth2, Mechanism)
  
  XOAuth2.prototype.name = 'X-OAUTH2'
  XOAuth2.prototype.NS_GOOGLE_AUTH = 'http://www.google.com/talk/protocol/auth'
  
  XOAuth2.prototype.auth = function() {
      return '\0' + this.authzid + '\0' + this.oauth2_token
  }
  
  XOAuth2.prototype.authAttrs = function() {
      return {
          'auth:service': 'oauth2',
          'xmlns:auth': this.oauth2_auth
      }
  }
  
  XOAuth2.prototype.match = function(options) {
      return (options.oauth2_auth === XOAuth2.prototype.NS_GOOGLE_AUTH)
  }
  
  module.exports = XOAuth2
  
  },{"./mechanism":6,"util":35}],10:[function(require,module,exports){
  var process=require("__browserify_process");'use strict';
  
  var EventEmitter = require('events').EventEmitter
    , util = require('util')
    , request = require('request')
    , ltx = require('node-xmpp-core').ltx
    , debug = require('debug')('xmpp:client:bosh')
  
  function BOSHConnection(opts) {
      var that = this
      EventEmitter.call(this)
  
      this.boshURL = opts.bosh.url
      this.jid = opts.jid
      this.wait = opts.wait;
      this.xmlnsAttrs = {
          xmlns: 'http://jabber.org/protocol/httpbind',
          'xmlns:xmpp': 'urn:xmpp:xbosh',
          'xmlns:stream': 'http://etherx.jabber.org/streams'
      }
      if (opts.xmlns) {
          for (var prefix in opts.xmlns) {
              if (prefix) {
                  this.xmlnsAttrs['xmlns:' + prefix] = opts.xmlns[prefix]
              } else {
                  this.xmlnsAttrs.xmlns = opts.xmlns[prefix]
              }
          }
      }
      this.currentRequests = 0
      this.queue = []
      this.rid = Math.ceil(Math.random() * 9999999999)
  
      this.request({
              to: this.jid.domain,
              ver: '1.6',
              wait: this.wait,
              hold: '1',
              content: this.contentType
          },
          [],
          function(err, bodyEl) {
              if (err) {
                  that.emit('error', err)
              } else if (bodyEl && bodyEl.attrs) {
                  that.sid = bodyEl.attrs.sid
                  that.maxRequests = parseInt(bodyEl.attrs.requests, 10) || 2
                  if (that.sid && (that.maxRequests > 0)) {
                      that.emit('connect')
                      that.processResponse(bodyEl)
                      process.nextTick(that.mayRequest.bind(that))
                  } else {
                      that.emit('error', 'Invalid parameters')
                  }
              }
          })
  }
  
  util.inherits(BOSHConnection, EventEmitter)
  
  BOSHConnection.prototype.contentType = 'text/xml charset=utf-8'
  
  BOSHConnection.prototype.send = function(stanza) {
      this.queue.push(stanza.root())
      process.nextTick(this.mayRequest.bind(this))
  }
  
  BOSHConnection.prototype.processResponse = function(bodyEl) {
      debug('process bosh server response ' + bodyEl.toString())
      if (bodyEl && bodyEl.children) {
          for(var i = 0; i < bodyEl.children.length; i++) {
              var child = bodyEl.children[i]
              if (child.name && child.attrs && child.children)
                  this.emit('stanza', child)
          }
      }
      if (bodyEl && (bodyEl.attrs.type === 'terminate')) {
          if (!this.shutdown || bodyEl.attrs.condition)
              this.emit('error',
                        new Error(bodyEl.attrs.condition || 'Session terminated'))
          this.emit('disconnect')
          this.emit('end')
          this.emit('close')
      }
  }
  
  BOSHConnection.prototype.mayRequest = function() {
      var canRequest =
          /* Must have a session already */
          this.sid &&
          /* We can only receive when one request is in flight */
          ((this.currentRequests === 0) ||
           /* Is there something to send, and are we allowed? */
           (((this.queue.length > 0) && (this.currentRequests < this.maxRequests)))
          )
  
      if (!canRequest) return
  
      var stanzas = this.queue
      this.queue = []
      this.rid++
      this.request({}, stanzas, function(err, bodyEl) {
          if (err) {
              this.emit('error', err)
              this.emit('disconnect')
              this.emit('end')
              delete this.sid
              this.emit('close')
          } else {
              if (bodyEl) this.processResponse(bodyEl)
  
              process.nextTick(this.mayRequest.bind(this))
          }
      }.bind(this))
  }
  
  BOSHConnection.prototype.end = function(stanzas) {
      stanzas = stanzas || []
      if (typeof stanzas !== Array) stanzas = [stanzas]
  
      stanzas = this.queue.concat(stanzas)
      this.shutdown = true
      this.queue = []
      this.rid++
      this.request({ type: 'terminate' }, stanzas, function(err, bodyEl) {
          if (bodyEl) this.processResponse(bodyEl)
  
          this.emit('disconnect')
          this.emit('end')
          delete this.sid
          this.emit('close')
      }.bind(this))
  }
  
  BOSHConnection.prototype.maxHTTPRetries = 5
  
  BOSHConnection.prototype.request = function(attrs, children, cb, retry) {
      var that = this
      retry = retry || 0
  
      attrs.rid = this.rid.toString()
      if (this.sid) attrs.sid = this.sid
  
      for (var k in this.xmlnsAttrs) {
          attrs[k] = this.xmlnsAttrs[k]
      }
      var boshEl = new ltx.Element('body', attrs)
      for (var i = 0; i < children.length; i++) {
          boshEl.cnode(children[i])
      }
  
      request({
              uri: this.boshURL,
              method: 'POST',
              headers: { 'Content-Type': this.contentType },
              body: boshEl.toString()
          },
          function(err, res, body) {
              that.currentRequests--
  
              if (err) {
                  if (retry < that.maxHTTPRetries) {
                      return that.request(attrs, children, cb, retry + 1)
                  } else {
                      return cb(err)
                  }
              }
              if ((res.statusCode < 200) || (res.statusCode >= 400)) {
                  return cb(new Error('HTTP status ' + res.statusCode))
              }
  
              var bodyEl
              try {
                  bodyEl = ltx.parse(body)
              } catch(e) {
                  return cb(e)
              }
  
              if (bodyEl &&
                  (bodyEl.attrs.type === 'terminate') &&
                  bodyEl.attrs.condition) {
                  cb(new Error(bodyEl.attrs.condition))
              } else if (bodyEl) {
                  cb(null, bodyEl)
              } else {
                  cb(new Error('no <body/>'))
              }
          }
      )
      this.currentRequests++
  }
  
  module.exports = BOSHConnection
  
  },{"__browserify_process":26,"debug":36,"events":24,"node-xmpp-core":39,"request":"B+8hfE","util":35}],11:[function(require,module,exports){
  'use strict';
  
  var Mechanism = require('./authentication/mechanism')
  
  /**
   * Available methods for client-side authentication (Client)
   * @param  Array offeredMechs  methods offered by server
   * @param  Array preferredMech preferred methods by client
   * @param  Array availableMech available methods on client
   */
  function selectMechanism(offeredMechs, preferredMech, availableMech) {
      var mechClasses = []
      var byName = {}
      var Mech
      if (Array.isArray(availableMech)) {
          mechClasses = mechClasses.concat(availableMech)
      }
      mechClasses.forEach(function(mechClass) {
          byName[mechClass.prototype.name] = mechClass
      })
      /* Any preferred? */
      if (byName[preferredMech] &&
          (offeredMechs.indexOf(preferredMech) >= 0)) {
          Mech = byName[preferredMech]
      }
      /* By priority */
      mechClasses.forEach(function(mechClass) {
          if (!Mech &&
              (offeredMechs.indexOf(mechClass.prototype.name) >= 0))
              Mech = mechClass
      })
  
      return Mech ? new Mech() : null
  }
  
  /**
   * Will detect the available mechanisms based on the given options
   * @param  {[type]} options client configuration
   * @param  Array availableMech available methods on client
   * @return {[type]}         available options
   */
  function detectMechanisms(options, availableMech) {
      var mechClasses = availableMech ? availableMech : []
  
      var detect = []
      mechClasses.forEach(function(mechClass) {
          var match = mechClass.prototype.match
          if (match(options)) detect.push(mechClass)
      })
      return detect
  }
  
  exports.selectMechanism = selectMechanism
  exports.detectMechanisms = detectMechanisms
  exports.AbstractMechanism = Mechanism
  
  },{"./authentication/mechanism":6}],12:[function(require,module,exports){
  var process=require("__browserify_process");'use strict';
  
  var util = require('util')
    , tls = require('tls')
    , crypto = require('crypto')
    , EventEmitter = require('events').EventEmitter
    , Connection = require('node-xmpp-core').Connection
    , JID = require('node-xmpp-core').JID
    , SRV = require('node-xmpp-core').SRV
    , BOSHConnection = require('./bosh')
    , WSConnection = require('./websockets')
    , debug = require('debug')('xmpp:client:session')
  
  function Session(opts) {
      EventEmitter.call(this)
  
      this.setOptions(opts)
  
      if (opts.websocket && opts.websocket.url) {
          debug('start websocket connection')
          this._setupWebsocketConnection(opts)
      } else if (opts.bosh && opts.bosh.url) {
          debug('start bosh connection')
          this._setupBoshConnection(opts)
      } else {
          debug('start socket connection')
          this._setupSocketConnection(opts)
      }
  }
  
  util.inherits(Session, EventEmitter)
  
  Session.prototype._setupSocketConnection = function(opts) {
      var params = {
          xmlns: { '': opts.xmlns },
          streamAttrs: {
              version: '1.0',
              to: this.jid.domain
          },
          serialized: opts.serialized
      }
      for (var  key in opts)
          if (!(key in params))
              params[key] = opts[key]
  
      this.connection = new Connection(params)
      this._addConnectionListeners()
  
      if (opts.host) {
          this._socketConnectionToHost(opts)
      } else if (!SRV) {
          throw 'Cannot load SRV'
      } else {
          this._performSrvLookup(opts)
      }
  }
  
  Session.prototype._socketConnectionToHost = function(opts) {
      if (opts.legacySSL) {
          this.connection.allowTLS = false
          this.connection.connect({
              socket:function () {
                  return tls.connect(
                      opts.port || 5223,
                      opts.host,
                      opts.credentials || {},
                      function() {
                          if (this.socket.authorized)
                              this.emit('connect', this.socket)
                          else
                              this.emit('error', 'unauthorized')
                      }.bind(this)
                  )
              }
          })
      } else {
          if (opts.credentials) {
              this.connection.credentials = crypto
                  .createCredentials(opts.credentials)
          }
          if (opts.disallowTLS) this.connection.allowTLS = false
          this.connection.listen({
              socket:function () {
                  // wait for connect event listeners
                  process.nextTick(function () {
                      this.socket.connect(opts.port || 5222, opts.host)
                  }.bind(this))
                  var socket = opts.socket
                  opts.socket = null
                  return socket // maybe create new socket
              }
          })
      }
  }
  
  Session.prototype._performSrvLookup = function(opts) {
      if (opts.legacySSL) {
          throw 'LegacySSL mode does not support DNS lookups'
      }
      if (opts.credentials)
          this.connection.credentials = crypto.createCredentials(opts.credentials)
      if (opts.disallowTLS)
          this.connection.allowTLS = false
      this.connection.listen({socket:SRV.connect({
          socket:      opts.socket,
          services:    ['_xmpp-client._tcp'],
          domain:      this.jid.domain,
          defaultPort: 5222
      })})
  }
  
  Session.prototype._setupBoshConnection = function(opts) {
      this.connection = new BOSHConnection({
          jid: this.jid,
          bosh: opts.bosh,
          wait: this.wait
      })
      this._addConnectionListeners()
  }
  
  Session.prototype._setupWebsocketConnection = function(opts) {
      this.connection = new WSConnection({
          jid: this.jid,
          websocket: opts.websocket
      })
      this._addConnectionListeners()
      this.connection.on('connected', function() {
          // Clients start <stream:stream>, servers reply
          if (this.connection.startStream)
              this.connection.startStream()
      }.bind(this))
  }
  
  Session.prototype.setOptions = function(opts) {
      /* jshint camelcase: false */
      this.jid = (typeof opts.jid === 'string') ? new JID(opts.jid) : opts.jid
      this.password = opts.password
      this.preferredSaslMechanism = opts.preferredSaslMechanism
      this.api_key = opts.api_key
      this.access_token = opts.access_token
      this.oauth2_token = opts.oauth2_token
      this.oauth2_auth = opts.oauth2_auth
      this.register = opts.register
      this.wait = opts.wait || '10'
      if (typeof opts.actAs === 'string') {
          this.actAs = new JID(opts.actAs)
      } else {
          this.actAs = opts.actAs
      }
  }
  
  Session.prototype._addConnectionListeners = function (con) {
      con = con || this.connection
      con.on('stanza', this.onStanza.bind(this))
      con.on('drain', this.emit.bind(this, 'drain'))
      con.on('end', this.emit.bind(this, 'end'))
      con.on('close', this.emit.bind(this, 'close'))
      con.on('error', this.emit.bind(this, 'error'))
      con.on('connect', this.emit.bind(this, 'connect'))
      con.on('reconnect', this.emit.bind(this, 'reconnect'))
      con.on('disconnect', this.emit.bind(this, 'disconnect'))
      if (con.startStream) {
          con.on('connect', function () {
              // Clients start <stream:stream>, servers reply
              con.startStream()
          })
          this.on('auth', function () {
              con.startStream()
          })
      }
  }
  
  Session.prototype.pause = function() {
      if (this.connection && this.connection.pause)
          this.connection.pause()
  }
  
  Session.prototype.resume = function() {
      if (this.connection && this.connection.resume)
          this.connection.resume()
  }
  
  Session.prototype.send = function(stanza) {
      return this.connection ? this.connection.send(stanza) : false
  }
  
  Session.prototype.end = function() {
      if (this.connection)
          this.connection.end()
  }
  
  Session.prototype.onStanza = function() {}
  
  module.exports = Session
  
  },{"./bosh":10,"./websockets":13,"__browserify_process":26,"crypto":19,"debug":36,"events":24,"node-xmpp-core":39,"tls":16,"util":35}],13:[function(require,module,exports){
  'use strict';
  
  var EventEmitter = require('events').EventEmitter
    , util = require('util')
    , ltx = require('node-xmpp-core').ltx
    , StreamParser = require('node-xmpp-core').StreamParser
    , WebSocket = require('faye-websocket') && require('faye-websocket').Client ?
        require('faye-websocket').Client : window.WebSocket
    , Connection = require('node-xmpp-core').Connection
    , debug = require('debug')('xmpp:client:websockets')
  
  function WSConnection(opts) {
      EventEmitter.call(this)
  
      this.url = opts.websocket.url
      this.jid = opts.jid
      this.xmlns = {}
      this.websocket = new WebSocket(this.url, ['xmpp'])
      this.websocket.onopen = this.onopen.bind(this)
      this.websocket.onmessage = this.onmessage.bind(this)
      this.websocket.onclose = this.onclose.bind(this)
      this.websocket.onerror = this.onerror.bind(this)
  }
  
  util.inherits(WSConnection, EventEmitter)
  
  WSConnection.prototype.maxStanzaSize = 65535
  WSConnection.prototype.xmppVersion = '1.0'
  
  WSConnection.prototype.onopen = function() {
      this.startParser()
      this.emit('connected')
  }
  
  WSConnection.prototype.startParser = function() {
      var self = this
      this.parser = new StreamParser.StreamParser(this.maxStanzaSize)
  
      this.parser.on('start', function(attrs) {
          self.streamAttrs = attrs
          /* We need those xmlns often, store them extra */
          self.streamNsAttrs = {}
          for (var k in attrs) {
              if ((k === 'xmlns') ||
                  (k.substr(0, 6) === 'xmlns:')) {
                  self.streamNsAttrs[k] = attrs[k]
              }
          }
  
          /* Notify in case we don't wait for <stream:features/>
             (Component or non-1.0 streams)
           */
          self.emit('streamStart', attrs)
      })
      this.parser.on('stanza', function(stanza) {
          //self.onStanza(self.addStreamNs(stanza))
          self.onStanza(stanza)
      })
      this.parser.on('error', this.onerror.bind(this))
      this.parser.on('end', function() {
          self.stopParser()
          self.end()
      })
  }
  
  WSConnection.prototype.stopParser = function() {
      /* No more events, please (may happen however) */
      if (this.parser) {
          /* Get GC'ed */
          delete this.parser
      }
  }
  
  WSConnection.prototype.onmessage = function(msg) {
      debug('ws msg <--', msg.data)
      if (msg && msg.data && this.parser)
          this.parser.write(msg.data)
  }
  
  WSConnection.prototype.onStanza = function(stanza) {
      if (stanza.is('error', Connection.NS_STREAM)) {
          /* TODO: extract error text */
          this.emit('error', stanza)
      } else {
          this.emit('stanza', stanza)
      }
  }
  
  WSConnection.prototype.startStream = function() {
      var attrs = {}
      for(var k in this.xmlns) {
          if (this.xmlns.hasOwnProperty(k)) {
              if (!k) {
                  attrs.xmlns = this.xmlns[k]
              } else {
                  attrs['xmlns:' + k] = this.xmlns[k]
              }
          }
      }
      if (this.xmppVersion)
          attrs.version = this.xmppVersion
      if (this.streamTo)
          attrs.to = this.streamTo
      if (this.streamId)
          attrs.id = this.streamId
      if (this.jid)
          attrs.to = this.jid.domain
      attrs.xmlns = 'jabber:client'
      attrs['xmlns:stream'] = Connection.NS_STREAM
  
      var el = new ltx.Element('stream:stream', attrs)
      // make it non-empty to cut the closing tag
      el.t(' ')
      var s = el.toString()
      this.send(s.substr(0, s.indexOf(' </stream:stream>')))
  
      this.streamOpened = true
  }
  
  WSConnection.prototype.send = function(stanza) {
      if (stanza.root) stanza = stanza.root()
      stanza = stanza.toString()
      debug('ws send -->', stanza)
      this.websocket.send(stanza)
  }
  
  WSConnection.prototype.onclose = function() {
      this.emit('disconnect')
      this.emit('close')
  }
  
  WSConnection.prototype.end = function() {
      this.send('</stream:stream>')
      this.emit('disconnect')
      this.emit('end')
      if (this.websocket)
          this.websocket.close()
  }
  
  WSConnection.prototype.onerror = function(e) {
      this.emit('error', e)
  }
  
  module.exports = WSConnection
  
  },{"debug":36,"events":24,"faye-websocket":16,"node-xmpp-core":39,"util":35}],"browser-request":[function(require,module,exports){
  module.exports=require('B+8hfE');
  },{}],"B+8hfE":[function(require,module,exports){
  // Browser Request
  //
  // Licensed under the Apache License, Version 2.0 (the "License");
  // you may not use this file except in compliance with the License.
  // You may obtain a copy of the License at
  //
  //     http://www.apache.org/licenses/LICENSE-2.0
  //
  // Unless required by applicable law or agreed to in writing, software
  // distributed under the License is distributed on an "AS IS" BASIS,
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  // See the License for the specific language governing permissions and
  // limitations under the License.
  
  // UMD HEADER START 
  (function (root, factory) {
      if (typeof define === 'function' && define.amd) {
          // AMD. Register as an anonymous module.
          define([], factory);
      } else if (typeof exports === 'object') {
          // Node. Does not work with strict CommonJS, but
          // only CommonJS-like enviroments that support module.exports,
          // like Node.
          module.exports = factory();
      } else {
          // Browser globals (root is window)
          root.returnExports = factory();
    }
  }(this, function () {
  // UMD HEADER END
  
  var XHR = XMLHttpRequest
  if (!XHR) throw new Error('missing XMLHttpRequest')
  request.log = {
    'trace': noop, 'debug': noop, 'info': noop, 'warn': noop, 'error': noop
  }
  
  var DEFAULT_TIMEOUT = 3 * 60 * 1000 // 3 minutes
  
  //
  // request
  //
  
  function request(options, callback) {
    // The entry-point to the API: prep the options object and pass the real work to run_xhr.
    if(typeof callback !== 'function')
      throw new Error('Bad callback given: ' + callback)
  
    if(!options)
      throw new Error('No options given')
  
    var options_onResponse = options.onResponse; // Save this for later.
  
    if(typeof options === 'string')
      options = {'uri':options};
    else
      options = JSON.parse(JSON.stringify(options)); // Use a duplicate for mutating.
  
    options.onResponse = options_onResponse // And put it back.
  
    if (options.verbose) request.log = getLogger();
  
    if(options.url) {
      options.uri = options.url;
      delete options.url;
    }
  
    if(!options.uri && options.uri !== "")
      throw new Error("options.uri is a required argument");
  
    if(typeof options.uri != "string")
      throw new Error("options.uri must be a string");
  
    var unsupported_options = ['proxy', '_redirectsFollowed', 'maxRedirects', 'followRedirect']
    for (var i = 0; i < unsupported_options.length; i++)
      if(options[ unsupported_options[i] ])
        throw new Error("options." + unsupported_options[i] + " is not supported")
  
    options.callback = callback
    options.method = options.method || 'GET';
    options.headers = options.headers || {};
    options.body    = options.body || null
    options.timeout = options.timeout || request.DEFAULT_TIMEOUT
  
    if(options.headers.host)
      throw new Error("Options.headers.host is not supported");
  
    if(options.json) {
      options.headers.accept = options.headers.accept || 'application/json'
      if(options.method !== 'GET')
        options.headers['content-type'] = 'application/json'
  
      if(typeof options.json !== 'boolean')
        options.body = JSON.stringify(options.json)
      else if(typeof options.body !== 'string')
        options.body = JSON.stringify(options.body)
    }
    
    //BEGIN QS Hack
    var serialize = function(obj) {
      var str = [];
      for(var p in obj)
        if (obj.hasOwnProperty(p)) {
          str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
        }
      return str.join("&");
    }
    
    if(options.qs){
      var qs = (typeof options.qs == 'string')? options.qs : serialize(options.qs);
      if(options.uri.indexOf('?') !== -1){ //no get params
          options.uri = options.uri+'&'+qs;
      }else{ //existing get params
          options.uri = options.uri+'?'+qs;
      }
    }
    //END QS Hack
    
    //BEGIN FORM Hack
    var multipart = function(obj) {
      //todo: support file type (useful?)
      var result = {};
      result.boundry = '-------------------------------'+Math.floor(Math.random()*1000000000);
      var lines = [];
      for(var p in obj){
          if (obj.hasOwnProperty(p)) {
              lines.push(
                  '--'+result.boundry+"\n"+
                  'Content-Disposition: form-data; name="'+p+'"'+"\n"+
                  "\n"+
                  obj[p]+"\n"
              );
          }
      }
      lines.push( '--'+result.boundry+'--' );
      result.body = lines.join('');
      result.length = result.body.length;
      result.type = 'multipart/form-data; boundary='+result.boundry;
      return result;
    }
    
    if(options.form){
      if(typeof options.form == 'string') throw('form name unsupported');
      if(options.method === 'POST'){
          var encoding = (options.encoding || 'application/x-www-form-urlencoded').toLowerCase();
          options.headers['content-type'] = encoding;
          switch(encoding){
              case 'application/x-www-form-urlencoded':
                  options.body = serialize(options.form).replace(/%20/g, "+");
                  break;
              case 'multipart/form-data':
                  var multi = multipart(options.form);
                  //options.headers['content-length'] = multi.length;
                  options.body = multi.body;
                  options.headers['content-type'] = multi.type;
                  break;
              default : throw new Error('unsupported encoding:'+encoding);
          }
      }
    }
    //END FORM Hack
  
    // If onResponse is boolean true, call back immediately when the response is known,
    // not when the full request is complete.
    options.onResponse = options.onResponse || noop
    if(options.onResponse === true) {
      options.onResponse = callback
      options.callback = noop
    }
  
    // XXX Browsers do not like this.
    //if(options.body)
    //  options.headers['content-length'] = options.body.length;
  
    // HTTP basic authentication
    if(!options.headers.authorization && options.auth)
      options.headers.authorization = 'Basic ' + b64_enc(options.auth.username + ':' + options.auth.password);
  
    return run_xhr(options)
  }
  
  var req_seq = 0
  function run_xhr(options) {
    var xhr = new XHR
      , timed_out = false
      , is_cors = is_crossDomain(options.uri)
      , supports_cors = ('withCredentials' in xhr)
  
    req_seq += 1
    xhr.seq_id = req_seq
    xhr.id = req_seq + ': ' + options.method + ' ' + options.uri
    xhr._id = xhr.id // I know I will type "_id" from habit all the time.
  
    if(is_cors && !supports_cors) {
      var cors_err = new Error('Browser does not support cross-origin request: ' + options.uri)
      cors_err.cors = 'unsupported'
      return options.callback(cors_err, xhr)
    }
  
    xhr.timeoutTimer = setTimeout(too_late, options.timeout)
    function too_late() {
      timed_out = true
      var er = new Error('ETIMEDOUT')
      er.code = 'ETIMEDOUT'
      er.duration = options.timeout
  
      request.log.error('Timeout', { 'id':xhr._id, 'milliseconds':options.timeout })
      return options.callback(er, xhr)
    }
  
    // Some states can be skipped over, so remember what is still incomplete.
    var did = {'response':false, 'loading':false, 'end':false}
  
    xhr.onreadystatechange = on_state_change
    xhr.open(options.method, options.uri, true) // asynchronous
    if(is_cors)
      xhr.withCredentials = !! options.withCredentials
    xhr.send(options.body)
    return xhr
  
    function on_state_change(event) {
      if(timed_out)
        return request.log.debug('Ignoring timed out state change', {'state':xhr.readyState, 'id':xhr.id})
  
      request.log.debug('State change', {'state':xhr.readyState, 'id':xhr.id, 'timed_out':timed_out})
  
      if(xhr.readyState === XHR.OPENED) {
        request.log.debug('Request started', {'id':xhr.id})
        for (var key in options.headers)
          xhr.setRequestHeader(key, options.headers[key])
      }
  
      else if(xhr.readyState === XHR.HEADERS_RECEIVED)
        on_response()
  
      else if(xhr.readyState === XHR.LOADING) {
        on_response()
        on_loading()
      }
  
      else if(xhr.readyState === XHR.DONE) {
        on_response()
        on_loading()
        on_end()
      }
    }
  
    function on_response() {
      if(did.response)
        return
  
      did.response = true
      request.log.debug('Got response', {'id':xhr.id, 'status':xhr.status})
      clearTimeout(xhr.timeoutTimer)
      xhr.statusCode = xhr.status // Node request compatibility
  
      // Detect failed CORS requests.
      if(is_cors && xhr.statusCode == 0) {
        var cors_err = new Error('CORS request rejected: ' + options.uri)
        cors_err.cors = 'rejected'
  
        // Do not process this request further.
        did.loading = true
        did.end = true
  
        return options.callback(cors_err, xhr)
      }
  
      options.onResponse(null, xhr)
    }
  
    function on_loading() {
      if(did.loading)
        return
  
      did.loading = true
      request.log.debug('Response body loading', {'id':xhr.id})
      // TODO: Maybe simulate "data" events by watching xhr.responseText
    }
  
    function on_end() {
      if(did.end)
        return
  
      did.end = true
      request.log.debug('Request done', {'id':xhr.id})
  
      xhr.body = xhr.responseText
      if(options.json) {
        try        { xhr.body = JSON.parse(xhr.responseText) }
        catch (er) { return options.callback(er, xhr)        }
      }
  
      options.callback(null, xhr, xhr.body)
    }
  
  } // request
  
  request.withCredentials = false;
  request.DEFAULT_TIMEOUT = DEFAULT_TIMEOUT;
  
  //
  // defaults
  //
  
  request.defaults = function(options, requester) {
    var def = function (method) {
      var d = function (params, callback) {
        if(typeof params === 'string')
          params = {'uri': params};
        else {
          params = JSON.parse(JSON.stringify(params));
        }
        for (var i in options) {
          if (params[i] === undefined) params[i] = options[i]
        }
        return method(params, callback)
      }
      return d
    }
    var de = def(request)
    de.get = def(request.get)
    de.post = def(request.post)
    de.put = def(request.put)
    de.head = def(request.head)
    return de
  }
  
  //
  // HTTP method shortcuts
  //
  
  var shortcuts = [ 'get', 'put', 'post', 'head' ];
  shortcuts.forEach(function(shortcut) {
    var method = shortcut.toUpperCase();
    var func   = shortcut.toLowerCase();
  
    request[func] = function(opts) {
      if(typeof opts === 'string')
        opts = {'method':method, 'uri':opts};
      else {
        opts = JSON.parse(JSON.stringify(opts));
        opts.method = method;
      }
  
      var args = [opts].concat(Array.prototype.slice.apply(arguments, [1]));
      return request.apply(this, args);
    }
  })
  
  //
  // CouchDB shortcut
  //
  
  request.couch = function(options, callback) {
    if(typeof options === 'string')
      options = {'uri':options}
  
    // Just use the request API to do JSON.
    options.json = true
    if(options.body)
      options.json = options.body
    delete options.body
  
    callback = callback || noop
  
    var xhr = request(options, couch_handler)
    return xhr
  
    function couch_handler(er, resp, body) {
      if(er)
        return callback(er, resp, body)
  
      if((resp.statusCode < 200 || resp.statusCode > 299) && body.error) {
        // The body is a Couch JSON object indicating the error.
        er = new Error('CouchDB error: ' + (body.error.reason || body.error.error))
        for (var key in body)
          er[key] = body[key]
        return callback(er, resp, body);
      }
  
      return callback(er, resp, body);
    }
  }
  
  //
  // Utility
  //
  
  function noop() {}
  
  function getLogger() {
    var logger = {}
      , levels = ['trace', 'debug', 'info', 'warn', 'error']
      , level, i
  
    for(i = 0; i < levels.length; i++) {
      level = levels[i]
  
      logger[level] = noop
      if(typeof console !== 'undefined' && console && console[level])
        logger[level] = formatted(console, level)
    }
  
    return logger
  }
  
  function formatted(obj, method) {
    return formatted_logger
  
    function formatted_logger(str, context) {
      if(typeof context === 'object')
        str += ' ' + JSON.stringify(context)
  
      return obj[method].call(obj, str)
    }
  }
  
  // Return whether a URL is a cross-domain request.
  function is_crossDomain(url) {
    var rurl = /^([\w\+\.\-]+:)(?:\/\/([^\/?#:]*)(?::(\d+))?)?/
  
    // jQuery #8138, IE may throw an exception when accessing
    // a field from window.location if document.domain has been set
    var ajaxLocation
    try { ajaxLocation = location.href }
    catch (e) {
      // Use the href attribute of an A element since IE will modify it given document.location
      ajaxLocation = document.createElement( "a" );
      ajaxLocation.href = "";
      ajaxLocation = ajaxLocation.href;
    }
  
    var ajaxLocParts = rurl.exec(ajaxLocation.toLowerCase()) || []
      , parts = rurl.exec(url.toLowerCase() )
  
    var result = !!(
      parts &&
      (  parts[1] != ajaxLocParts[1]
      || parts[2] != ajaxLocParts[2]
      || (parts[3] || (parts[1] === "http:" ? 80 : 443)) != (ajaxLocParts[3] || (ajaxLocParts[1] === "http:" ? 80 : 443))
      )
    )
  
    //console.debug('is_crossDomain('+url+') -> ' + result)
    return result
  }
  
  // MIT License from http://phpjs.org/functions/base64_encode:358
  function b64_enc (data) {
      // Encodes string using MIME base64 algorithm
      var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
      var o1, o2, o3, h1, h2, h3, h4, bits, i = 0, ac = 0, enc="", tmp_arr = [];
  
      if (!data) {
          return data;
      }
  
      // assume utf8 data
      // data = this.utf8_encode(data+'');
  
      do { // pack three octets into four hexets
          o1 = data.charCodeAt(i++);
          o2 = data.charCodeAt(i++);
          o3 = data.charCodeAt(i++);
  
          bits = o1<<16 | o2<<8 | o3;
  
          h1 = bits>>18 & 0x3f;
          h2 = bits>>12 & 0x3f;
          h3 = bits>>6 & 0x3f;
          h4 = bits & 0x3f;
  
          // use hexets to index into b64, and append result to encoded string
          tmp_arr[ac++] = b64.charAt(h1) + b64.charAt(h2) + b64.charAt(h3) + b64.charAt(h4);
      } while (i < data.length);
  
      enc = tmp_arr.join('');
  
      switch (data.length % 3) {
          case 1:
              enc = enc.slice(0, -2) + '==';
          break;
          case 2:
              enc = enc.slice(0, -1) + '=';
          break;
      }
  
      return enc;
  }
      return request;
  //UMD FOOTER START
  }));
  //UMD FOOTER END
  
  },{}],16:[function(require,module,exports){
  
  },{}],17:[function(require,module,exports){
  // http://wiki.commonjs.org/wiki/Unit_Testing/1.0
  //
  // THIS IS NOT TESTED NOR LIKELY TO WORK OUTSIDE V8!
  //
  // Originally from narwhal.js (http://narwhaljs.org)
  // Copyright (c) 2009 Thomas Robinson <280north.com>
  //
  // 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 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.
  
  // when used in node, this will actually load the util module we depend on
  // versus loading the builtin util module as happens otherwise
  // this is a bug in node module loading as far as I am concerned
  var util = require('util/');
  
  var pSlice = Array.prototype.slice;
  var hasOwn = Object.prototype.hasOwnProperty;
  
  // 1. The assert module provides functions that throw
  // AssertionError's when particular conditions are not met. The
  // assert module must conform to the following interface.
  
  var assert = module.exports = ok;
  
  // 2. The AssertionError is defined in assert.
  // new assert.AssertionError({ message: message,
  //                             actual: actual,
  //                             expected: expected })
  
  assert.AssertionError = function AssertionError(options) {
    this.name = 'AssertionError';
    this.actual = options.actual;
    this.expected = options.expected;
    this.operator = options.operator;
    if (options.message) {
      this.message = options.message;
      this.generatedMessage = false;
    } else {
      this.message = getMessage(this);
      this.generatedMessage = true;
    }
    var stackStartFunction = options.stackStartFunction || fail;
  
    if (Error.captureStackTrace) {
      Error.captureStackTrace(this, stackStartFunction);
    }
    else {
      // non v8 browsers so we can have a stacktrace
      var err = new Error();
      if (err.stack) {
        var out = err.stack;
  
        // try to strip useless frames
        var fn_name = stackStartFunction.name;
        var idx = out.indexOf('\n' + fn_name);
        if (idx >= 0) {
          // once we have located the function frame
          // we need to strip out everything before it (and its line)
          var next_line = out.indexOf('\n', idx + 1);
          out = out.substring(next_line + 1);
        }
  
        this.stack = out;
      }
    }
  };
  
  // assert.AssertionError instanceof Error
  util.inherits(assert.AssertionError, Error);
  
  function replacer(key, value) {
    if (util.isUndefined(value)) {
      return '' + value;
    }
    if (util.isNumber(value) && (isNaN(value) || !isFinite(value))) {
      return value.toString();
    }
    if (util.isFunction(value) || util.isRegExp(value)) {
      return value.toString();
    }
    return value;
  }
  
  function truncate(s, n) {
    if (util.isString(s)) {
      return s.length < n ? s : s.slice(0, n);
    } else {
      return s;
    }
  }
  
  function getMessage(self) {
    return truncate(JSON.stringify(self.actual, replacer), 128) + ' ' +
           self.operator + ' ' +
           truncate(JSON.stringify(self.expected, replacer), 128);
  }
  
  // At present only the three keys mentioned above are used and
  // understood by the spec. Implementations or sub modules can pass
  // other keys to the AssertionError's constructor - they will be
  // ignored.
  
  // 3. All of the following functions must throw an AssertionError
  // when a corresponding condition is not met, with a message that
  // may be undefined if not provided.  All assertion methods provide
  // both the actual and expected values to the assertion error for
  // display purposes.
  
  function fail(actual, expected, message, operator, stackStartFunction) {
    throw new assert.AssertionError({
      message: message,
      actual: actual,
      expected: expected,
      operator: operator,
      stackStartFunction: stackStartFunction
    });
  }
  
  // EXTENSION! allows for well behaved errors defined elsewhere.
  assert.fail = fail;
  
  // 4. Pure assertion tests whether a value is truthy, as determined
  // by !!guard.
  // assert.ok(guard, message_opt);
  // This statement is equivalent to assert.equal(true, !!guard,
  // message_opt);. To test strictly for the value true, use
  // assert.strictEqual(true, guard, message_opt);.
  
  function ok(value, message) {
    if (!value) fail(value, true, message, '==', assert.ok);
  }
  assert.ok = ok;
  
  // 5. The equality assertion tests shallow, coercive equality with
  // ==.
  // assert.equal(actual, expected, message_opt);
  
  assert.equal = function equal(actual, expected, message) {
    if (actual != expected) fail(actual, expected, message, '==', assert.equal);
  };
  
  // 6. The non-equality assertion tests for whether two objects are not equal
  // with != assert.notEqual(actual, expected, message_opt);
  
  assert.notEqual = function notEqual(actual, expected, message) {
    if (actual == expected) {
      fail(actual, expected, message, '!=', assert.notEqual);
    }
  };
  
  // 7. The equivalence assertion tests a deep equality relation.
  // assert.deepEqual(actual, expected, message_opt);
  
  assert.deepEqual = function deepEqual(actual, expected, message) {
    if (!_deepEqual(actual, expected)) {
      fail(actual, expected, message, 'deepEqual', assert.deepEqual);
    }
  };
  
  function _deepEqual(actual, expected) {
    // 7.1. All identical values are equivalent, as determined by ===.
    if (actual === expected) {
      return true;
  
    } else if (util.isBuffer(actual) && util.isBuffer(expected)) {
      if (actual.length != expected.length) return false;
  
      for (var i = 0; i < actual.length; i++) {
        if (actual[i] !== expected[i]) return false;
      }
  
      return true;
  
    // 7.2. If the expected value is a Date object, the actual value is
    // equivalent if it is also a Date object that refers to the same time.
    } else if (util.isDate(actual) && util.isDate(expected)) {
      return actual.getTime() === expected.getTime();
  
    // 7.3 If the expected value is a RegExp object, the actual value is
    // equivalent if it is also a RegExp object with the same source and
    // properties (`global`, `multiline`, `lastIndex`, `ignoreCase`).
    } else if (util.isRegExp(actual) && util.isRegExp(expected)) {
      return actual.source === expected.source &&
             actual.global === expected.global &&
             actual.multiline === expected.multiline &&
             actual.lastIndex === expected.lastIndex &&
             actual.ignoreCase === expected.ignoreCase;
  
    // 7.4. Other pairs that do not both pass typeof value == 'object',
    // equivalence is determined by ==.
    } else if (!util.isObject(actual) && !util.isObject(expected)) {
      return actual == expected;
  
    // 7.5 For all other Object pairs, including Array objects, equivalence is
    // determined by having the same number of owned properties (as verified
    // with Object.prototype.hasOwnProperty.call), the same set of keys
    // (although not necessarily the same order), equivalent values for every
    // corresponding key, and an identical 'prototype' property. Note: this
    // accounts for both named and indexed properties on Arrays.
    } else {
      return objEquiv(actual, expected);
    }
  }
  
  function isArguments(object) {
    return Object.prototype.toString.call(object) == '[object Arguments]';
  }
  
  function objEquiv(a, b) {
    if (util.isNullOrUndefined(a) || util.isNullOrUndefined(b))
      return false;
    // an identical 'prototype' property.
    if (a.prototype !== b.prototype) return false;
    //~~~I've managed to break Object.keys through screwy arguments passing.
    //   Converting to array solves the problem.
    if (isArguments(a)) {
      if (!isArguments(b)) {
        return false;
      }
      a = pSlice.call(a);
      b = pSlice.call(b);
      return _deepEqual(a, b);
    }
    try {
      var ka = objectKeys(a),
          kb = objectKeys(b),
          key, i;
    } catch (e) {//happens when one is a string literal and the other isn't
      return false;
    }
    // having the same number of owned properties (keys incorporates
    // hasOwnProperty)
    if (ka.length != kb.length)
      return false;
    //the same set of keys (although not necessarily the same order),
    ka.sort();
    kb.sort();
    //~~~cheap key test
    for (i = ka.length - 1; i >= 0; i--) {
      if (ka[i] != kb[i])
        return false;
    }
    //equivalent values for every corresponding key, and
    //~~~possibly expensive deep test
    for (i = ka.length - 1; i >= 0; i--) {
      key = ka[i];
      if (!_deepEqual(a[key], b[key])) return false;
    }
    return true;
  }
  
  // 8. The non-equivalence assertion tests for any deep inequality.
  // assert.notDeepEqual(actual, expected, message_opt);
  
  assert.notDeepEqual = function notDeepEqual(actual, expected, message) {
    if (_deepEqual(actual, expected)) {
      fail(actual, expected, message, 'notDeepEqual', assert.notDeepEqual);
    }
  };
  
  // 9. The strict equality assertion tests strict equality, as determined by ===.
  // assert.strictEqual(actual, expected, message_opt);
  
  assert.strictEqual = function strictEqual(actual, expected, message) {
    if (actual !== expected) {
      fail(actual, expected, message, '===', assert.strictEqual);
    }
  };
  
  // 10. The strict non-equality assertion tests for strict inequality, as
  // determined by !==.  assert.notStrictEqual(actual, expected, message_opt);
  
  assert.notStrictEqual = function notStrictEqual(actual, expected, message) {
    if (actual === expected) {
      fail(actual, expected, message, '!==', assert.notStrictEqual);
    }
  };
  
  function expectedException(actual, expected) {
    if (!actual || !expected) {
      return false;
    }
  
    if (Object.prototype.toString.call(expected) == '[object RegExp]') {
      return expected.test(actual);
    } else if (actual instanceof expected) {
      return true;
    } else if (expected.call({}, actual) === true) {
      return true;
    }
  
    return false;
  }
  
  function _throws(shouldThrow, block, expected, message) {
    var actual;
  
    if (util.isString(expected)) {
      message = expected;
      expected = null;
    }
  
    try {
      block();
    } catch (e) {
      actual = e;
    }
  
    message = (expected && expected.name ? ' (' + expected.name + ').' : '.') +
              (message ? ' ' + message : '.');
  
    if (shouldThrow && !actual) {
      fail(actual, expected, 'Missing expected exception' + message);
    }
  
    if (!shouldThrow && expectedException(actual, expected)) {
      fail(actual, expected, 'Got unwanted exception' + message);
    }
  
    if ((shouldThrow && actual && expected &&
        !expectedException(actual, expected)) || (!shouldThrow && actual)) {
      throw actual;
    }
  }
  
  // 11. Expected to throw an error:
  // assert.throws(block, Error_opt, message_opt);
  
  assert.throws = function(block, /*optional*/error, /*optional*/message) {
    _throws.apply(this, [true].concat(pSlice.call(arguments)));
  };
  
  // EXTENSION! This is annoying to write outside this module.
  assert.doesNotThrow = function(block, /*optional*/message) {
    _throws.apply(this, [false].concat(pSlice.call(arguments)));
  };
  
  assert.ifError = function(err) { if (err) {throw err;}};
  
  var objectKeys = Object.keys || function (obj) {
    var keys = [];
    for (var key in obj) {
      if (hasOwn.call(obj, key)) keys.push(key);
    }
    return keys;
  };
  
  },{"util/":35}],18:[function(require,module,exports){
  var Buffer = require('buffer').Buffer;
  var intSize = 4;
  var zeroBuffer = new Buffer(intSize); zeroBuffer.fill(0);
  var chrsz = 8;
  
  function toArray(buf, bigEndian) {
    if ((buf.length % intSize) !== 0) {
      var len = buf.length + (intSize - (buf.length % intSize));
      buf = Buffer.concat([buf, zeroBuffer], len);
    }
  
    var arr = [];
    var fn = bigEndian ? buf.readInt32BE : buf.readInt32LE;
    for (var i = 0; i < buf.length; i += intSize) {
      arr.push(fn.call(buf, i));
    }
    return arr;
  }
  
  function toBuffer(arr, size, bigEndian) {
    var buf = new Buffer(size);
    var fn = bigEndian ? buf.writeInt32BE : buf.writeInt32LE;
    for (var i = 0; i < arr.length; i++) {
      fn.call(buf, arr[i], i * 4, true);
    }
    return buf;
  }
  
  function hash(buf, fn, hashSize, bigEndian) {
    if (!Buffer.isBuffer(buf)) buf = new Buffer(buf);
    var arr = fn(toArray(buf, bigEndian), buf.length * chrsz);
    return toBuffer(arr, hashSize, bigEndian);
  }
  
  module.exports = { hash: hash };
  
  },{"buffer":27}],19:[function(require,module,exports){
  var Buffer = require('buffer').Buffer
  var sha = require('./sha')
  var sha256 = require('./sha256')
  var rng = require('./rng')
  var md5 = require('./md5')
  
  var algorithms = {
    sha1: sha,
    sha256: sha256,
    md5: md5
  }
  
  var blocksize = 64
  var zeroBuffer = new Buffer(blocksize); zeroBuffer.fill(0)
  function hmac(fn, key, data) {
    if(!Buffer.isBuffer(key)) key = new Buffer(key)
    if(!Buffer.isBuffer(data)) data = new Buffer(data)
  
    if(key.length > blocksize) {
      key = fn(key)
    } else if(key.length < blocksize) {
      key = Buffer.concat([key, zeroBuffer], blocksize)
    }
  
    var ipad = new Buffer(blocksize), opad = new Buffer(blocksize)
    for(var i = 0; i < blocksize; i++) {
      ipad[i] = key[i] ^ 0x36
      opad[i] = key[i] ^ 0x5C
    }
  
    var hash = fn(Buffer.concat([ipad, data]))
    return fn(Buffer.concat([opad, hash]))
  }
  
  function hash(alg, key) {
    alg = alg || 'sha1'
    var fn = algorithms[alg]
    var bufs = []
    var length = 0
    if(!fn) error('algorithm:', alg, 'is not yet supported')
    return {
      update: function (data) {
        if(!Buffer.isBuffer(data)) data = new Buffer(data)
          
        bufs.push(data)
        length += data.length
        return this
      },
      digest: function (enc) {
        var buf = Buffer.concat(bufs)
        var r = key ? hmac(fn, key, buf) : fn(buf)
        bufs = null
        return enc ? r.toString(enc) : r
      }
    }
  }
  
  function error () {
    var m = [].slice.call(arguments).join(' ')
    throw new Error([
      m,
      'we accept pull requests',
      'http://github.com/dominictarr/crypto-browserify'
      ].join('\n'))
  }
  
  exports.createHash = function (alg) { return hash(alg) }
  exports.createHmac = function (alg, key) { return hash(alg, key) }
  exports.randomBytes = function(size, callback) {
    if (callback && callback.call) {
      try {
        callback.call(this, undefined, new Buffer(rng(size)))
      } catch (err) { callback(err) }
    } else {
      return new Buffer(rng(size))
    }
  }
  
  function each(a, f) {
    for(var i in a)
      f(a[i], i)
  }
  
  // the least I can do is make error messages for the rest of the node.js/crypto api.
  each(['createCredentials'
  , 'createCipher'
  , 'createCipheriv'
  , 'createDecipher'
  , 'createDecipheriv'
  , 'createSign'
  , 'createVerify'
  , 'createDiffieHellman'
  , 'pbkdf2'], function (name) {
    exports[name] = function () {
      error('sorry,', name, 'is not implemented yet')
    }
  })
  
  },{"./md5":20,"./rng":21,"./sha":22,"./sha256":23,"buffer":27}],20:[function(require,module,exports){
  /*
   * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message
   * Digest Algorithm, as defined in RFC 1321.
   * Version 2.1 Copyright (C) Paul Johnston 1999 - 2002.
   * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
   * Distributed under the BSD License
   * See http://pajhome.org.uk/crypt/md5 for more info.
   */
  
  var helpers = require('./helpers');
  
  /*
   * Perform a simple self-test to see if the VM is working
   */
  function md5_vm_test()
  {
    return hex_md5("abc") == "900150983cd24fb0d6963f7d28e17f72";
  }
  
  /*
   * Calculate the MD5 of an array of little-endian words, and a bit length
   */
  function core_md5(x, len)
  {
    /* append padding */
    x[len >> 5] |= 0x80 << ((len) % 32);
    x[(((len + 64) >>> 9) << 4) + 14] = len;
  
    var a =  1732584193;
    var b = -271733879;
    var c = -1732584194;
    var d =  271733878;
  
    for(var i = 0; i < x.length; i += 16)
    {
      var olda = a;
      var oldb = b;
      var oldc = c;
      var oldd = d;
  
      a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);
      d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);
      c = md5_ff(c, d, a, b, x[i+ 2], 17,  606105819);
      b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);
      a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);
      d = md5_ff(d, a, b, c, x[i+ 5], 12,  1200080426);
      c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);
      b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);
      a = md5_ff(a, b, c, d, x[i+ 8], 7 ,  1770035416);
      d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);
      c = md5_ff(c, d, a, b, x[i+10], 17, -42063);
      b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);
      a = md5_ff(a, b, c, d, x[i+12], 7 ,  1804603682);
      d = md5_ff(d, a, b, c, x[i+13], 12, -40341101);
      c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);
      b = md5_ff(b, c, d, a, x[i+15], 22,  1236535329);
  
      a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);
      d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
      c = md5_gg(c, d, a, b, x[i+11], 14,  643717713);
      b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);
      a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);
      d = md5_gg(d, a, b, c, x[i+10], 9 ,  38016083);
      c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);
      b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);
      a = md5_gg(a, b, c, d, x[i+ 9], 5 ,  568446438);
      d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);
      c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);
      b = md5_gg(b, c, d, a, x[i+ 8], 20,  1163531501);
      a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);
      d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);
      c = md5_gg(c, d, a, b, x[i+ 7], 14,  1735328473);
      b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);
  
      a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);
      d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
      c = md5_hh(c, d, a, b, x[i+11], 16,  1839030562);
      b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);
      a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);
      d = md5_hh(d, a, b, c, x[i+ 4], 11,  1272893353);
      c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);
      b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);
      a = md5_hh(a, b, c, d, x[i+13], 4 ,  681279174);
      d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);
      c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);
      b = md5_hh(b, c, d, a, x[i+ 6], 23,  76029189);
      a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);
      d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);
      c = md5_hh(c, d, a, b, x[i+15], 16,  530742520);
      b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);
  
      a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);
      d = md5_ii(d, a, b, c, x[i+ 7], 10,  1126891415);
      c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);
      b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);
      a = md5_ii(a, b, c, d, x[i+12], 6 ,  1700485571);
      d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);
      c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);
      b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);
      a = md5_ii(a, b, c, d, x[i+ 8], 6 ,  1873313359);
      d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);
      c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);
      b = md5_ii(b, c, d, a, x[i+13], 21,  1309151649);
      a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);
      d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);
      c = md5_ii(c, d, a, b, x[i+ 2], 15,  718787259);
      b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);
  
      a = safe_add(a, olda);
      b = safe_add(b, oldb);
      c = safe_add(c, oldc);
      d = safe_add(d, oldd);
    }
    return Array(a, b, c, d);
  
  }
  
  /*
   * These functions implement the four basic operations the algorithm uses.
   */
  function md5_cmn(q, a, b, x, s, t)
  {
    return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b);
  }
  function md5_ff(a, b, c, d, x, s, t)
  {
    return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
  }
  function md5_gg(a, b, c, d, x, s, t)
  {
    return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
  }
  function md5_hh(a, b, c, d, x, s, t)
  {
    return md5_cmn(b ^ c ^ d, a, b, x, s, t);
  }
  function md5_ii(a, b, c, d, x, s, t)
  {
    return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
  }
  
  /*
   * Add integers, wrapping at 2^32. This uses 16-bit operations internally
   * to work around bugs in some JS interpreters.
   */
  function safe_add(x, y)
  {
    var lsw = (x & 0xFFFF) + (y & 0xFFFF);
    var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
    return (msw << 16) | (lsw & 0xFFFF);
  }
  
  /*
   * Bitwise rotate a 32-bit number to the left.
   */
  function bit_rol(num, cnt)
  {
    return (num << cnt) | (num >>> (32 - cnt));
  }
  
  module.exports = function md5(buf) {
    return helpers.hash(buf, core_md5, 16);
  };
  
  },{"./helpers":18}],21:[function(require,module,exports){
  // Original code adapted from Robert Kieffer.
  // details at https://github.com/broofa/node-uuid
  (function() {
    var _global = this;
  
    var mathRNG, whatwgRNG;
  
    // NOTE: Math.random() does not guarantee "cryptographic quality"
    mathRNG = function(size) {
      var bytes = new Array(size);
      var r;
  
      for (var i = 0, r; i < size; i++) {
        if ((i & 0x03) == 0) r = Math.random() * 0x100000000;
        bytes[i] = r >>> ((i & 0x03) << 3) & 0xff;
      }
  
      return bytes;
    }
  
    if (_global.crypto && crypto.getRandomValues) {
      whatwgRNG = function(size) {
        var bytes = new Uint8Array(size);
        crypto.getRandomValues(bytes);
        return bytes;
      }
    }
  
    module.exports = whatwgRNG || mathRNG;
  
  }())
  
  },{}],22:[function(require,module,exports){
  /*
   * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined
   * in FIPS PUB 180-1
   * Version 2.1a Copyright Paul Johnston 2000 - 2002.
   * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
   * Distributed under the BSD License
   * See http://pajhome.org.uk/crypt/md5 for details.
   */
  
  var helpers = require('./helpers');
  
  /*
   * Calculate the SHA-1 of an array of big-endian words, and a bit length
   */
  function core_sha1(x, len)
  {
    /* append padding */
    x[len >> 5] |= 0x80 << (24 - len % 32);
    x[((len + 64 >> 9) << 4) + 15] = len;
  
    var w = Array(80);
    var a =  1732584193;
    var b = -271733879;
    var c = -1732584194;
    var d =  271733878;
    var e = -1009589776;
  
    for(var i = 0; i < x.length; i += 16)
    {
      var olda = a;
      var oldb = b;
      var oldc = c;
      var oldd = d;
      var olde = e;
  
      for(var j = 0; j < 80; j++)
      {
        if(j < 16) w[j] = x[i + j];
        else w[j] = rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1);
        var t = safe_add(safe_add(rol(a, 5), sha1_ft(j, b, c, d)),
                         safe_add(safe_add(e, w[j]), sha1_kt(j)));
        e = d;
        d = c;
        c = rol(b, 30);
        b = a;
        a = t;
      }
  
      a = safe_add(a, olda);
      b = safe_add(b, oldb);
      c = safe_add(c, oldc);
      d = safe_add(d, oldd);
      e = safe_add(e, olde);
    }
    return Array(a, b, c, d, e);
  
  }
  
  /*
   * Perform the appropriate triplet combination function for the current
   * iteration
   */
  function sha1_ft(t, b, c, d)
  {
    if(t < 20) return (b & c) | ((~b) & d);
    if(t < 40) return b ^ c ^ d;
    if(t < 60) return (b & c) | (b & d) | (c & d);
    return b ^ c ^ d;
  }
  
  /*
   * Determine the appropriate additive constant for the current iteration
   */
  function sha1_kt(t)
  {
    return (t < 20) ?  1518500249 : (t < 40) ?  1859775393 :
           (t < 60) ? -1894007588 : -899497514;
  }
  
  /*
   * Add integers, wrapping at 2^32. This uses 16-bit operations internally
   * to work around bugs in some JS interpreters.
   */
  function safe_add(x, y)
  {
    var lsw = (x & 0xFFFF) + (y & 0xFFFF);
    var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
    return (msw << 16) | (lsw & 0xFFFF);
  }
  
  /*
   * Bitwise rotate a 32-bit number to the left.
   */
  function rol(num, cnt)
  {
    return (num << cnt) | (num >>> (32 - cnt));
  }
  
  module.exports = function sha1(buf) {
    return helpers.hash(buf, core_sha1, 20, true);
  };
  
  },{"./helpers":18}],23:[function(require,module,exports){
  
  /**
   * A JavaScript implementation of the Secure Hash Algorithm, SHA-256, as defined
   * in FIPS 180-2
   * Version 2.2-beta Copyright Angel Marin, Paul Johnston 2000 - 2009.
   * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet
   *
   */
  
  var helpers = require('./helpers');
  
  var safe_add = function(x, y) {
    var lsw = (x & 0xFFFF) + (y & 0xFFFF);
    var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
    return (msw << 16) | (lsw & 0xFFFF);
  };
  
  var S = function(X, n) {
    return (X >>> n) | (X << (32 - n));
  };
  
  var R = function(X, n) {
    return (X >>> n);
  };
  
  var Ch = function(x, y, z) {
    return ((x & y) ^ ((~x) & z));
  };
  
  var Maj = function(x, y, z) {
    return ((x & y) ^ (x & z) ^ (y & z));
  };
  
  var Sigma0256 = function(x) {
    return (S(x, 2) ^ S(x, 13) ^ S(x, 22));
  };
  
  var Sigma1256 = function(x) {
    return (S(x, 6) ^ S(x, 11) ^ S(x, 25));
  };
  
  var Gamma0256 = function(x) {
    return (S(x, 7) ^ S(x, 18) ^ R(x, 3));
  };
  
  var Gamma1256 = function(x) {
    return (S(x, 17) ^ S(x, 19) ^ R(x, 10));
  };
  
  var core_sha256 = function(m, l) {
    var K = new Array(0x428A2F98,0x71374491,0xB5C0FBCF,0xE9B5DBA5,0x3956C25B,0x59F111F1,0x923F82A4,0xAB1C5ED5,0xD807AA98,0x12835B01,0x243185BE,0x550C7DC3,0x72BE5D74,0x80DEB1FE,0x9BDC06A7,0xC19BF174,0xE49B69C1,0xEFBE4786,0xFC19DC6,0x240CA1CC,0x2DE92C6F,0x4A7484AA,0x5CB0A9DC,0x76F988DA,0x983E5152,0xA831C66D,0xB00327C8,0xBF597FC7,0xC6E00BF3,0xD5A79147,0x6CA6351,0x14292967,0x27B70A85,0x2E1B2138,0x4D2C6DFC,0x53380D13,0x650A7354,0x766A0ABB,0x81C2C92E,0x92722C85,0xA2BFE8A1,0xA81A664B,0xC24B8B70,0xC76C51A3,0xD192E819,0xD6990624,0xF40E3585,0x106AA070,0x19A4C116,0x1E376C08,0x2748774C,0x34B0BCB5,0x391C0CB3,0x4ED8AA4A,0x5B9CCA4F,0x682E6FF3,0x748F82EE,0x78A5636F,0x84C87814,0x8CC70208,0x90BEFFFA,0xA4506CEB,0xBEF9A3F7,0xC67178F2);
    var HASH = new Array(0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19);
      var W = new Array(64);
      var a, b, c, d, e, f, g, h, i, j;
      var T1, T2;
    /* append padding */
    m[l >> 5] |= 0x80 << (24 - l % 32);
    m[((l + 64 >> 9) << 4) + 15] = l;
    for (var i = 0; i < m.length; i += 16) {
      a = HASH[0]; b = HASH[1]; c = HASH[2]; d = HASH[3]; e = HASH[4]; f = HASH[5]; g = HASH[6]; h = HASH[7];
      for (var j = 0; j < 64; j++) {
        if (j < 16) {
          W[j] = m[j + i];
        } else {
          W[j] = safe_add(safe_add(safe_add(Gamma1256(W[j - 2]), W[j - 7]), Gamma0256(W[j - 15])), W[j - 16]);
        }
        T1 = safe_add(safe_add(safe_add(safe_add(h, Sigma1256(e)), Ch(e, f, g)), K[j]), W[j]);
        T2 = safe_add(Sigma0256(a), Maj(a, b, c));
        h = g; g = f; f = e; e = safe_add(d, T1); d = c; c = b; b = a; a = safe_add(T1, T2);
      }
      HASH[0] = safe_add(a, HASH[0]); HASH[1] = safe_add(b, HASH[1]); HASH[2] = safe_add(c, HASH[2]); HASH[3] = safe_add(d, HASH[3]);
      HASH[4] = safe_add(e, HASH[4]); HASH[5] = safe_add(f, HASH[5]); HASH[6] = safe_add(g, HASH[6]); HASH[7] = safe_add(h, HASH[7]);
    }
    return HASH;
  };
  
  module.exports = function sha256(buf) {
    return helpers.hash(buf, core_sha256, 32, true);
  };
  
  },{"./helpers":18}],24:[function(require,module,exports){
  // Copyright Joyent, Inc. and other Node contributors.
  //
  // Permission is hereby granted, free of charge, to any person obtaining a
  // copy of this software and associated documentation files (the
  // "Software"), to deal in the Software without restriction, including
  // without limitation the rights to use, copy, modify, merge, publish,
  // distribute, sublicense, and/or sell copies of the Software, and to permit
  // persons to whom the Software is furnished to do so, subject to the
  // following conditions:
  //
  // The above copyright notice and this permission notice shall be included
  // in all copies or substantial portions of the Software.
  //
  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
  // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
  // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
  // USE OR OTHER DEALINGS IN THE SOFTWARE.
  
  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;
  }
  
  },{}],25:[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
    }
  }
  
  },{}],26:[function(require,module,exports){
  // shim for using process in browser
  
  var process = module.exports = {};
  
  process.nextTick = (function () {
      var canSetImmediate = typeof window !== 'undefined'
      && window.setImmediate;
      var canPost = typeof window !== 'undefined'
      && window.postMessage && window.addEventListener
      ;
  
      if (canSetImmediate) {
          return function (f) { return window.setImmediate(f) };
      }
  
      if (canPost) {
          var queue = [];
          window.addEventListener('message', function (ev) {
              var source = ev.source;
              if ((source === window || source === null) && ev.data === 'process-tick') {
                  ev.stopPropagation();
                  if (queue.length > 0) {
                      var fn = queue.shift();
                      fn();
                  }
              }
          }, true);
  
          return function nextTick(fn) {
              queue.push(fn);
              window.postMessage('process-tick', '*');
          };
      }
  
      return function nextTick(fn) {
          setTimeout(fn, 0);
      };
  })();
  
  process.title = 'browser';
  process.browser = true;
  process.env = {};
  process.argv = [];
  
  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');
  };
  
  },{}],27:[function(require,module,exports){
  var base64 = require('base64-js')
  var ieee754 = require('ieee754')
  
  exports.Buffer = Buffer
  exports.SlowBuffer = Buffer
  exports.INSPECT_MAX_BYTES = 50
  Buffer.poolSize = 8192
  
  /**
   * If `Buffer._useTypedArrays`:
   *   === true    Use Uint8Array implementation (fastest)
   *   === false   Use Object implementation (compatible down to IE6)
   */
  Buffer._useTypedArrays = (function () {
     // Detect if browser supports Typed Arrays. Supported browsers are IE 10+,
     // Firefox 4+, Chrome 7+, Safari 5.1+, Opera 11.6+, iOS 4.2+.
     if (typeof Uint8Array === 'undefined' || typeof ArrayBuffer === 'undefined')
        return false
  
    // Does the browser support adding properties to `Uint8Array` instances? If
    // not, then that's the same as no `Uint8Array` support. We need to be able to
    // add all the node Buffer API methods.
    // Relevant Firefox bug: https://bugzilla.mozilla.org/show_bug.cgi?id=695438
    try {
      var arr = new Uint8Array(0)
      arr.foo = function () { return 42 }
      return 42 === arr.foo() &&
          typeof arr.subarray === 'function' // Chrome 9-10 lack `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
  
    // Workaround: node's base64 implementation allows for non-padded strings
    // while base64-js does not.
    if (encoding === 'base64' && type === 'string') {
      subject = stringtrim(subject)
      while (subject.length % 4 !== 0) {
        subject = subject + '='
      }
    }
  
    // Find the length
    var length
    if (type === 'number')
      length = coerce(subject)
    else if (type === 'string')
      length = Buffer.byteLength(subject, encoding)
    else if (type === 'object')
      length = coerce(subject.length) // Assume object is an array
    else
      throw new Error('First argument needs to be a number, array or string.')
  
    var buf
    if (Buffer._useTypedArrays) {
      // Preferred: Return an augmented `Uint8Array` instance for best performance
      buf = 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._useTypedArrays && typeof Uint8Array === 'function' &&
        subject instanceof Uint8Array) {
      // Speed optimization -- use set if we're copying from a Uint8Array
      buf._set(subject)
    } else if (isArrayish(subject)) {
      // Treat array-ish objects as a byte array
      for (i = 0; i < length; i++) {
        if (Buffer.isBuffer(subject))
          buf[i] = subject.readUInt8(i)
        else
          buf[i] = subject[i]
      }
    } else if (type === 'string') {
      buf.write(subject, 0, encoding)
    } else if (type === 'number' && !Buffer._useTypedArrays && !noZero) {
      for (i = 0; i < length; i++) {
        buf[i] = 0
      }
    }
  
    return buf
  }
  
  // STATIC METHODS
  // ==============
  
  Buffer.isEncoding = function (encoding) {
    switch (String(encoding).toLowerCase()) {
      case 'hex':
      case 'utf8':
      case 'utf-8':
      case 'ascii':
      case 'binary':
      case 'base64':
      case 'raw':
      case 'ucs2':
      case 'ucs-2':
      case 'utf16le':
      case 'utf-16le':
        return true
      default:
        return false
    }
  }
  
  Buffer.isBuffer = function (b) {
    return !!(b !== null && b !== undefined && b._isBuffer)
  }
  
  Buffer.byteLength = function (str, encoding) {
    var ret
    str = str + ''
    switch (encoding || 'utf8') {
      case 'hex':
        ret = str.length / 2
        break
      case 'utf8':
      case 'utf-8':
        ret = utf8ToBytes(str).length
        break
      case 'ascii':
      case 'binary':
      case 'raw':
        ret = str.length
        break
      case 'base64':
        ret = base64ToBytes(str).length
        break
      case 'ucs2':
      case 'ucs-2':
      case 'utf16le':
      case 'utf-16le':
        ret = str.length * 2
        break
      default:
        throw new Error('Unknown encoding')
    }
    return ret
  }
  
  Buffer.concat = function (list, totalLength) {
    assert(isArray(list), 'Usage: Buffer.concat(list, [totalLength])\n' +
        'list should be an Array.')
  
    if (list.length === 0) {
      return new Buffer(0)
    } else if (list.length === 1) {
      return list[0]
    }
  
    var i
    if (typeof totalLength !== 'number') {
      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 INSTANCE METHODS
  // =======================
  
  function _hexWrite (buf, string, offset, length) {
    offset = Number(offset) || 0
    var remaining = buf.length - offset
    if (!length) {
      length = remaining
    } else {
      length = Number(length)
      if (length > remaining) {
        length = remaining
      }
    }
  
    // must be an even number of digits
    var strLen = string.length
    assert(strLen % 2 === 0, 'Invalid hex string')
  
    if (length > strLen / 2) {
      length = strLen / 2
    }
    for (var i = 0; i < length; i++) {
      var byte = parseInt(string.substr(i * 2, 2), 16)
      assert(!isNaN(byte), 'Invalid hex string')
      buf[offset + i] = byte
    }
    Buffer._charsWritten = i * 2
    return i
  }
  
  function _utf8Write (buf, string, offset, length) {
    var charsWritten = Buffer._charsWritten =
      blitBuffer(utf8ToBytes(string), buf, offset, length)
    return charsWritten
  }
  
  function _asciiWrite (buf, string, offset, length) {
    var charsWritten = Buffer._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 = Buffer._charsWritten =
      blitBuffer(base64ToBytes(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()
  
    switch (encoding) {
      case 'hex':
        return _hexWrite(this, string, offset, length)
      case 'utf8':
      case 'utf-8':
      case 'ucs2': // TODO: No support for ucs2 or utf16le encodings yet
      case 'ucs-2':
      case 'utf16le':
      case 'utf-16le':
        return _utf8Write(this, string, offset, length)
      case 'ascii':
        return _asciiWrite(this, string, offset, length)
      case 'binary':
        return _binaryWrite(this, string, offset, length)
      case 'base64':
        return _base64Write(this, string, offset, length)
      default:
        throw new Error('Unknown encoding')
    }
  }
  
  Buffer.prototype.toString = function (encoding, start, end) {
    var self = this
  
    encoding = String(encoding || 'utf8').toLowerCase()
    start = Number(start) || 0
    end = (end !== undefined)
      ? Number(end)
      : end = self.length
  
    // Fastpath empty strings
    if (end === start)
      return ''
  
    switch (encoding) {
      case 'hex':
        return _hexSlice(self, start, end)
      case 'utf8':
      case 'utf-8':
      case 'ucs2': // TODO: No support for ucs2 or utf16le encodings yet
      case 'ucs-2':
      case 'utf16le':
      case 'utf-16le':
        return _utf8Slice(self, start, end)
      case 'ascii':
        return _asciiSlice(self, start, end)
      case 'binary':
        return _binarySlice(self, start, end)
      case 'base64':
        return _base64Slice(self, start, end)
      default:
        throw new Error('Unknown encoding')
    }
  }
  
  Buffer.prototype.toJSON = function () {
    return {
      type: 'Buffer',
      data: Array.prototype.slice.call(this._arr || this, 0)
    }
  }
  
  // copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length)
  Buffer.prototype.copy = function (target, target_start, start, end) {
    var source = this
  
    if (!start) start = 0
    if (!end && end !== 0) end = this.length
    if (!target_start) target_start = 0
  
    // Copy 0 bytes; we're done
    if (end === start) return
    if (target.length === 0 || source.length === 0) return
  
    // Fatal error conditions
    assert(end >= start, 'sourceEnd < sourceStart')
    assert(target_start >= 0 && target_start < target.length,
        'targetStart out of bounds')
    assert(start >= 0 && start < source.length, 'sourceStart out of bounds')
    assert(end >= 0 && end <= source.length, 'sourceEnd out of bounds')
  
    // Are we oob?
    if (end > this.length)
      end = this.length
    if (target.length - target_start < end - start)
      end = target.length - target_start + start
  
    // copy!
    for (var i = 0; i < end - start; i++)
      target[i + target_start] = this[i + start]
  }
  
  function _base64Slice (buf, start, end) {
    if (start === 0 && end === buf.length) {
      return base64.fromByteArray(buf)
    } else {
      return base64.fromByteArray(buf.slice(start, end))
    }
  }
  
  function _utf8Slice (buf, start, end) {
    var res = ''
    var tmp = ''
    end = Math.min(buf.length, end)
  
    for (var i = start; i < end; i++) {
      if (buf[i] <= 0x7F) {
        res += decodeUtf8Char(tmp) + String.fromCharCode(buf[i])
        tmp = ''
      } else {
        tmp += '%' + buf[i].toString(16)
      }
    }
  
    return res + decodeUtf8Char(tmp)
  }
  
  function _asciiSlice (buf, start, end) {
    var ret = ''
    end = Math.min(buf.length, end)
  
    for (var i = start; i < end; i++)
      ret += String.fromCharCode(buf[i])
    return ret
  }
  
  function _binarySlice (buf, start, end) {
    return _asciiSlice(buf, start, end)
  }
  
  function _hexSlice (buf, start, end) {
    var len = buf.length
  
    if (!start || start < 0) start = 0
    if (!end || end < 0 || end > len) end = len
  
    var out = ''
    for (var i = start; i < end; i++) {
      out += toHex(buf[i])
    }
    return out
  }
  
  // http://nodejs.org/api/buffer.html#buffer_buf_slice_start_end
  Buffer.prototype.slice = function (start, end) {
    var len = this.length
    start = clamp(start, len, 0)
    end = clamp(end, len, len)
  
    if (Buffer._useTypedArrays) {
      return augment(this.subarray(start, end))
    } else {
      var sliceLen = end - start
      var newBuf = new Buffer(sliceLen, undefined, true)
      for (var i = 0; i < sliceLen; i++) {
        newBuf[i] = this[i + start]
      }
      return newBuf
    }
  }
  
  // `get` will be removed in Node 0.13+
  Buffer.prototype.get = function (offset) {
    console.log('.get() is deprecated. Access using array indexes instead.')
    return this.readUInt8(offset)
  }
  
  // `set` will be removed in Node 0.13+
  Buffer.prototype.set = function (v, offset) {
    console.log('.set() is deprecated. Access using array indexes instead.')
    return this.writeUInt8(v, offset)
  }
  
  Buffer.prototype.readUInt8 = function (offset, noAssert) {
    if (!noAssert) {
      assert(offset !== undefined && offset !== null, 'missing offset')
      assert(offset < this.length, 'Trying to read beyond buffer length')
    }
  
    if (offset >= this.length)
      return
  
    return this[offset]
  }
  
  function _readUInt16 (buf, offset, littleEndian, noAssert) {
    if (!noAssert) {
      assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
      assert(offset !== undefined && offset !== null, 'missing offset')
      assert(offset + 1 < buf.length, 'Trying to read beyond buffer length')
    }
  
    var len = buf.length
    if (offset >= len)
      return
  
    var val
    if (littleEndian) {
      val = buf[offset]
      if (offset + 1 < len)
        val |= buf[offset + 1] << 8
    } else {
      val = buf[offset] << 8
      if (offset + 1 < len)
        val |= buf[offset + 1]
    }
    return val
  }
  
  Buffer.prototype.readUInt16LE = function (offset, noAssert) {
    return _readUInt16(this, offset, true, noAssert)
  }
  
  Buffer.prototype.readUInt16BE = function (offset, noAssert) {
    return _readUInt16(this, offset, false, noAssert)
  }
  
  function _readUInt32 (buf, offset, littleEndian, noAssert) {
    if (!noAssert) {
      assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
      assert(offset !== undefined && offset !== null, 'missing offset')
      assert(offset + 3 < buf.length, 'Trying to read beyond buffer length')
    }
  
    var len = buf.length
    if (offset >= len)
      return
  
    var val
    if (littleEndian) {
      if (offset + 2 < len)
        val = buf[offset + 2] << 16
      if (offset + 1 < len)
        val |= buf[offset + 1] << 8
      val |= buf[offset]
      if (offset + 3 < len)
        val = val + (buf[offset + 3] << 24 >>> 0)
    } else {
      if (offset + 1 < len)
        val = buf[offset + 1] << 16
      if (offset + 2 < len)
        val |= buf[offset + 2] << 8
      if (offset + 3 < len)
        val |= buf[offset + 3]
      val = val + (buf[offset] << 24 >>> 0)
    }
    return val
  }
  
  Buffer.prototype.readUInt32LE = function (offset, noAssert) {
    return _readUInt32(this, offset, true, noAssert)
  }
  
  Buffer.prototype.readUInt32BE = function (offset, noAssert) {
    return _readUInt32(this, offset, false, noAssert)
  }
  
  Buffer.prototype.readInt8 = function (offset, noAssert) {
    if (!noAssert) {
      assert(offset !== undefined && offset !== null,
          'missing offset')
      assert(offset < this.length, 'Trying to read beyond buffer length')
    }
  
    if (offset >= this.length)
      return
  
    var neg = this[offset] & 0x80
    if (neg)
      return (0xff - this[offset] + 1) * -1
    else
      return this[offset]
  }
  
  function _readInt16 (buf, offset, littleEndian, noAssert) {
    if (!noAssert) {
      assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
      assert(offset !== undefined && offset !== null, 'missing offset')
      assert(offset + 1 < buf.length, 'Trying to read beyond buffer length')
    }
  
    var len = buf.length
    if (offset >= len)
      return
  
    var val = _readUInt16(buf, offset, littleEndian, true)
    var neg = val & 0x8000
    if (neg)
      return (0xffff - val + 1) * -1
    else
      return val
  }
  
  Buffer.prototype.readInt16LE = function (offset, noAssert) {
    return _readInt16(this, offset, true, noAssert)
  }
  
  Buffer.prototype.readInt16BE = function (offset, noAssert) {
    return _readInt16(this, offset, false, noAssert)
  }
  
  function _readInt32 (buf, offset, littleEndian, noAssert) {
    if (!noAssert) {
      assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
      assert(offset !== undefined && offset !== null, 'missing offset')
      assert(offset + 3 < buf.length, 'Trying to read beyond buffer length')
    }
  
    var len = buf.length
    if (offset >= len)
      return
  
    var val = _readUInt32(buf, offset, littleEndian, true)
    var neg = val & 0x80000000
    if (neg)
      return (0xffffffff - val + 1) * -1
    else
      return val
  }
  
  Buffer.prototype.readInt32LE = function (offset, noAssert) {
    return _readInt32(this, offset, true, noAssert)
  }
  
  Buffer.prototype.readInt32BE = function (offset, noAssert) {
    return _readInt32(this, offset, false, noAssert)
  }
  
  function _readFloat (buf, offset, littleEndian, noAssert) {
    if (!noAssert) {
      assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
      assert(offset + 3 < buf.length, 'Trying to read beyond buffer length')
    }
  
    return ieee754.read(buf, offset, littleEndian, 23, 4)
  }
  
  Buffer.prototype.readFloatLE = function (offset, noAssert) {
    return _readFloat(this, offset, true, noAssert)
  }
  
  Buffer.prototype.readFloatBE = function (offset, noAssert) {
    return _readFloat(this, offset, false, noAssert)
  }
  
  function _readDouble (buf, offset, littleEndian, noAssert) {
    if (!noAssert) {
      assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
      assert(offset + 7 < buf.length, 'Trying to read beyond buffer length')
    }
  
    return ieee754.read(buf, offset, littleEndian, 52, 8)
  }
  
  Buffer.prototype.readDoubleLE = function (offset, noAssert) {
    return _readDouble(this, offset, true, noAssert)
  }
  
  Buffer.prototype.readDoubleBE = function (offset, noAssert) {
    return _readDouble(this, offset, false, noAssert)
  }
  
  Buffer.prototype.writeUInt8 = function (value, offset, noAssert) {
    if (!noAssert) {
      assert(value !== undefined && value !== null, 'missing value')
      assert(offset !== undefined && offset !== null, 'missing offset')
      assert(offset < this.length, 'trying to write beyond buffer length')
      verifuint(value, 0xff)
    }
  
    if (offset >= this.length) return
  
    this[offset] = value
  }
  
  function _writeUInt16 (buf, value, offset, littleEndian, noAssert) {
    if (!noAssert) {
      assert(value !== undefined && value !== null, 'missing value')
      assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
      assert(offset !== undefined && offset !== null, 'missing offset')
      assert(offset + 1 < buf.length, 'trying to write beyond buffer length')
      verifuint(value, 0xffff)
    }
  
    var len = buf.length
    if (offset >= len)
      return
  
    for (var i = 0, j = Math.min(len - offset, 2); i < j; i++) {
      buf[offset + i] =
          (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>>
              (littleEndian ? i : 1 - i) * 8
    }
  }
  
  Buffer.prototype.writeUInt16LE = function (value, offset, noAssert) {
    _writeUInt16(this, value, offset, true, noAssert)
  }
  
  Buffer.prototype.writeUInt16BE = function (value, offset, noAssert) {
    _writeUInt16(this, value, offset, false, noAssert)
  }
  
  function _writeUInt32 (buf, value, offset, littleEndian, noAssert) {
    if (!noAssert) {
      assert(value !== undefined && value !== null, 'missing value')
      assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
      assert(offset !== undefined && offset !== null, 'missing offset')
      assert(offset + 3 < buf.length, 'trying to write beyond buffer length')
      verifuint(value, 0xffffffff)
    }
  
    var len = buf.length
    if (offset >= len)
      return
  
    for (var i = 0, j = Math.min(len - offset, 4); i < j; i++) {
      buf[offset + i] =
          (value >>> (littleEndian ? i : 3 - i) * 8) & 0xff
    }
  }
  
  Buffer.prototype.writeUInt32LE = function (value, offset, noAssert) {
    _writeUInt32(this, value, offset, true, noAssert)
  }
  
  Buffer.prototype.writeUInt32BE = function (value, offset, noAssert) {
    _writeUInt32(this, value, offset, false, noAssert)
  }
  
  Buffer.prototype.writeInt8 = function (value, offset, noAssert) {
    if (!noAssert) {
      assert(value !== undefined && value !== null, 'missing value')
      assert(offset !== undefined && offset !== null, 'missing offset')
      assert(offset < this.length, 'Trying to write beyond buffer length')
      verifsint(value, 0x7f, -0x80)
    }
  
    if (offset >= this.length)
      return
  
    if (value >= 0)
      this.writeUInt8(value, offset, noAssert)
    else
      this.writeUInt8(0xff + value + 1, offset, noAssert)
  }
  
  function _writeInt16 (buf, value, offset, littleEndian, noAssert) {
    if (!noAssert) {
      assert(value !== undefined && value !== null, 'missing value')
      assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
      assert(offset !== undefined && offset !== null, 'missing offset')
      assert(offset + 1 < buf.length, 'Trying to write beyond buffer length')
      verifsint(value, 0x7fff, -0x8000)
    }
  
    var len = buf.length
    if (offset >= len)
      return
  
    if (value >= 0)
      _writeUInt16(buf, value, offset, littleEndian, noAssert)
    else
      _writeUInt16(buf, 0xffff + value + 1, offset, littleEndian, noAssert)
  }
  
  Buffer.prototype.writeInt16LE = function (value, offset, noAssert) {
    _writeInt16(this, value, offset, true, noAssert)
  }
  
  Buffer.prototype.writeInt16BE = function (value, offset, noAssert) {
    _writeInt16(this, value, offset, false, noAssert)
  }
  
  function _writeInt32 (buf, value, offset, littleEndian, noAssert) {
    if (!noAssert) {
      assert(value !== undefined && value !== null, 'missing value')
      assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
      assert(offset !== undefined && offset !== null, 'missing offset')
      assert(offset + 3 < buf.length, 'Trying to write beyond buffer length')
      verifsint(value, 0x7fffffff, -0x80000000)
    }
  
    var len = buf.length
    if (offset >= len)
      return
  
    if (value >= 0)
      _writeUInt32(buf, value, offset, littleEndian, noAssert)
    else
      _writeUInt32(buf, 0xffffffff + value + 1, offset, littleEndian, noAssert)
  }
  
  Buffer.prototype.writeInt32LE = function (value, offset, noAssert) {
    _writeInt32(this, value, offset, true, noAssert)
  }
  
  Buffer.prototype.writeInt32BE = function (value, offset, noAssert) {
    _writeInt32(this, value, offset, false, noAssert)
  }
  
  function _writeFloat (buf, value, offset, littleEndian, noAssert) {
    if (!noAssert) {
      assert(value !== undefined && value !== null, 'missing value')
      assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
      assert(offset !== undefined && offset !== null, 'missing offset')
      assert(offset + 3 < buf.length, 'Trying to write beyond buffer length')
      verifIEEE754(value, 3.4028234663852886e+38, -3.4028234663852886e+38)
    }
  
    var len = buf.length
    if (offset >= len)
      return
  
    ieee754.write(buf, value, offset, littleEndian, 23, 4)
  }
  
  Buffer.prototype.writeFloatLE = function (value, offset, noAssert) {
    _writeFloat(this, value, offset, true, noAssert)
  }
  
  Buffer.prototype.writeFloatBE = function (value, offset, noAssert) {
    _writeFloat(this, value, offset, false, noAssert)
  }
  
  function _writeDouble (buf, value, offset, littleEndian, noAssert) {
    if (!noAssert) {
      assert(value !== undefined && value !== null, 'missing value')
      assert(typeof littleEndian === 'boolean', 'missing or invalid endian')
      assert(offset !== undefined && offset !== null, 'missing offset')
      assert(offset + 7 < buf.length,
          'Trying to write beyond buffer length')
      verifIEEE754(value, 1.7976931348623157E+308, -1.7976931348623157E+308)
    }
  
    var len = buf.length
    if (offset >= len)
      return
  
    ieee754.write(buf, value, offset, littleEndian, 52, 8)
  }
  
  Buffer.prototype.writeDoubleLE = function (value, offset, noAssert) {
    _writeDouble(this, value, offset, true, noAssert)
  }
  
  Buffer.prototype.writeDoubleBE = function (value, offset, noAssert) {
    _writeDouble(this, value, offset, false, noAssert)
  }
  
  // fill(value, start=0, end=buffer.length)
  Buffer.prototype.fill = function (value, start, end) {
    if (!value) value = 0
    if (!start) start = 0
    if (!end) end = this.length
  
    if (typeof value === 'string') {
      value = value.charCodeAt(0)
    }
  
    assert(typeof value === 'number' && !isNaN(value), 'value is not a number')
    assert(end >= start, 'end < start')
  
    // Fill 0 bytes; we're done
    if (end === start) return
    if (this.length === 0) return
  
    assert(start >= 0 && start < this.length, 'start out of bounds')
    assert(end >= 0 && end <= this.length, 'end out of bounds')
  
    for (var i = start; i < end; i++) {
      this[i] = value
    }
  }
  
  Buffer.prototype.inspect = function () {
    var out = []
    var len = this.length
    for (var i = 0; i < len; i++) {
      out[i] = toHex(this[i])
      if (i === exports.INSPECT_MAX_BYTES) {
        out[i + 1] = '...'
        break
      }
    }
    return '<Buffer ' + out.join(' ') + '>'
  }
  
  /**
   * Creates a new `ArrayBuffer` with the *copied* memory of the buffer instance.
   * Added in Node 0.12. Only available in browsers that support ArrayBuffer.
   */
  Buffer.prototype.toArrayBuffer = function () {
    if (typeof Uint8Array === 'function') {
      if (Buffer._useTypedArrays) {
        return (new Buffer(this)).buffer
      } else {
        var buf = new Uint8Array(this.length)
        for (var i = 0, len = buf.length; i < len; i += 1)
          buf[i] = this[i]
        return buf.buffer
      }
    } else {
      throw new Error('Buffer.toArrayBuffer not supported in this browser')
    }
  }
  
  // HELPER FUNCTIONS
  // ================
  
  function stringtrim (str) {
    if (str.trim) return str.trim()
    return str.replace(/^\s+|\s+$/g, '')
  }
  
  var BP = Buffer.prototype
  
  /**
   * Augment the Uint8Array *instance* (not the class!) with Buffer methods
   */
  function augment (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.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
  }
  
  // slice(start, end)
  function clamp (index, len, defaultValue) {
    if (typeof index !== 'number') return defaultValue
    index = ~~index;  // Coerce to integer.
    if (index >= len) return len
    if (index >= 0) return index
    index += len
    if (index >= 0) return index
    return 0
  }
  
  function coerce (length) {
    // Coerce length to a number (possibly NaN), round up
    // in case it's fractional (e.g. 123.456) then do a
    // double negate to coerce a NaN to 0. Easy, right?
    length = ~~Math.ceil(+length)
    return length < 0 ? 0 : length
  }
  
  function isArray (subject) {
    return (Array.isArray || function (subject) {
      return Object.prototype.toString.call(subject) === '[object Array]'
    })(subject)
  }
  
  function isArrayish (subject) {
    return isArray(subject) || Buffer.isBuffer(subject) ||
        subject && typeof subject === 'object' &&
        typeof subject.length === 'number'
  }
  
  function toHex (n) {
    if (n < 16) return '0' + n.toString(16)
    return n.toString(16)
  }
  
  function utf8ToBytes (str) {
    var byteArray = []
    for (var i = 0; i < str.length; i++) {
      var b = str.charCodeAt(i)
      if (b <= 0x7F)
        byteArray.push(str.charCodeAt(i))
      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 base64ToBytes (str) {
    return base64.toByteArray(str)
  }
  
  function blitBuffer (src, dst, offset, length) {
    var pos
    for (var i = 0; i < length; i++) {
      if ((i + offset >= dst.length) || (i >= src.length))
        break
      dst[i + offset] = src[i]
    }
    return i
  }
  
  function decodeUtf8Char (str) {
    try {
      return decodeURIComponent(str)
    } catch (err) {
      return String.fromCharCode(0xFFFD) // UTF 8 invalid char
    }
  }
  
  /*
   * We have to make sure that the value is a valid integer. This means that it
   * is non-negative. It has no fractional component and that it does not
   * exceed the maximum allowed value.
   */
  function verifuint (value, max) {
    assert(typeof value == 'number', 'cannot write a non-number as a number')
    assert(value >= 0,
        'specified a negative value for writing an unsigned value')
    assert(value <= max, 'value is larger than maximum value for type')
    assert(Math.floor(value) === value, 'value has a fractional component')
  }
  
  function verifsint(value, max, min) {
    assert(typeof value == 'number', 'cannot write a non-number as a number')
    assert(value <= max, 'value larger than maximum allowed value')
    assert(value >= min, 'value smaller than minimum allowed value')
    assert(Math.floor(value) === value, 'value has a fractional component')
  }
  
  function verifIEEE754(value, max, min) {
    assert(typeof value == 'number', 'cannot write a non-number as a number')
    assert(value <= max, 'value larger than maximum allowed value')
    assert(value >= min, 'value smaller than minimum allowed value')
  }
  
  function assert (test, message) {
    if (!test) throw new Error(message || 'Failed assertion')
  }
  
  },{"base64-js":28,"ieee754":29}],28:[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))
  
  },{}],29:[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;
  };
  
  },{}],30:[function(require,module,exports){
  var process=require("__browserify_process");// Copyright Joyent, Inc. and other Node contributors.
  //
  // Permission is hereby granted, free of charge, to any person obtaining a
  // copy of this software and associated documentation files (the
  // "Software"), to deal in the Software without restriction, including
  // without limitation the rights to use, copy, modify, merge, publish,
  // distribute, sublicense, and/or sell copies of the Software, and to permit
  // persons to whom the Software is furnished to do so, subject to the
  // following conditions:
  //
  // The above copyright notice and this permission notice shall be included
  // in all copies or substantial portions of the Software.
  //
  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
  // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
  // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
  // USE OR OTHER DEALINGS IN THE SOFTWARE.
  
  // resolves . and .. elements in a path array with directory names there
  // must be no slashes, empty elements, or device names (c:\) in the array
  // (so also no leading and trailing slashes - it does not distinguish
  // relative and absolute paths)
  function normalizeArray(parts, allowAboveRoot) {
    // if the path tries to go above the root, `up` ends up > 0
    var up = 0;
    for (var i = parts.length - 1; i >= 0; i--) {
      var last = parts[i];
      if (last === '.') {
        parts.splice(i, 1);
      } else if (last === '..') {
        parts.splice(i, 1);
        up++;
      } else if (up) {
        parts.splice(i, 1);
        up--;
      }
    }
  
    // if the path is allowed to go above the root, restore leading ..s
    if (allowAboveRoot) {
      for (; up--; up) {
        parts.unshift('..');
      }
    }
  
    return parts;
  }
  
  // Split a filename into [root, dir, basename, ext], unix version
  // 'root' is just a slash, or nothing.
  var splitPathRe =
      /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;
  var splitPath = function(filename) {
    return splitPathRe.exec(filename).slice(1);
  };
  
  // path.resolve([from ...], to)
  // posix version
  exports.resolve = function() {
    var resolvedPath = '',
        resolvedAbsolute = false;
  
    for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {
      var path = (i >= 0) ? arguments[i] : process.cwd();
  
      // Skip empty and invalid entries
      if (typeof path !== 'string') {
        throw new TypeError('Arguments to path.resolve must be strings');
      } else if (!path) {
        continue;
      }
  
      resolvedPath = path + '/' + resolvedPath;
      resolvedAbsolute = path.charAt(0) === '/';
    }
  
    // At this point the path should be resolved to a full absolute path, but
    // handle relative paths to be safe (might happen when process.cwd() fails)
  
    // Normalize the path
    resolvedPath = normalizeArray(filter(resolvedPath.split('/'), function(p) {
      return !!p;
    }), !resolvedAbsolute).join('/');
  
    return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.';
  };
  
  // path.normalize(path)
  // posix version
  exports.normalize = function(path) {
    var isAbsolute = exports.isAbsolute(path),
        trailingSlash = substr(path, -1) === '/';
  
    // Normalize the path
    path = normalizeArray(filter(path.split('/'), function(p) {
      return !!p;
    }), !isAbsolute).join('/');
  
    if (!path && !isAbsolute) {
      path = '.';
    }
    if (path && trailingSlash) {
      path += '/';
    }
  
    return (isAbsolute ? '/' : '') + path;
  };
  
  // posix version
  exports.isAbsolute = function(path) {
    return path.charAt(0) === '/';
  };
  
  // posix version
  exports.join = function() {
    var paths = Array.prototype.slice.call(arguments, 0);
    return exports.normalize(filter(paths, function(p, index) {
      if (typeof p !== 'string') {
        throw new TypeError('Arguments to path.join must be strings');
      }
      return p;
    }).join('/'));
  };
  
  
  // path.relative(from, to)
  // posix version
  exports.relative = function(from, to) {
    from = exports.resolve(from).substr(1);
    to = exports.resolve(to).substr(1);
  
    function trim(arr) {
      var start = 0;
      for (; start < arr.length; start++) {
        if (arr[start] !== '') break;
      }
  
      var end = arr.length - 1;
      for (; end >= 0; end--) {
        if (arr[end] !== '') break;
      }
  
      if (start > end) return [];
      return arr.slice(start, end - start + 1);
    }
  
    var fromParts = trim(from.split('/'));
    var toParts = trim(to.split('/'));
  
    var length = Math.min(fromParts.length, toParts.length);
    var samePartsLength = length;
    for (var i = 0; i < length; i++) {
      if (fromParts[i] !== toParts[i]) {
        samePartsLength = i;
        break;
      }
    }
  
    var outputParts = [];
    for (var i = samePartsLength; i < fromParts.length; i++) {
      outputParts.push('..');
    }
  
    outputParts = outputParts.concat(toParts.slice(samePartsLength));
  
    return outputParts.join('/');
  };
  
  exports.sep = '/';
  exports.delimiter = ':';
  
  exports.dirname = function(path) {
    var result = splitPath(path),
        root = result[0],
        dir = result[1];
  
    if (!root && !dir) {
      // No dirname whatsoever
      return '.';
    }
  
    if (dir) {
      // It has a dirname, strip trailing slash
      dir = dir.substr(0, dir.length - 1);
    }
  
    return root + dir;
  };
  
  
  exports.basename = function(path, ext) {
    var f = splitPath(path)[2];
    // TODO: make this comparison case-insensitive on windows?
    if (ext && f.substr(-1 * ext.length) === ext) {
      f = f.substr(0, f.length - ext.length);
    }
    return f;
  };
  
  
  exports.extname = function(path) {
    return splitPath(path)[3];
  };
  
  function filter (xs, f) {
      if (xs.filter) return xs.filter(f);
      var res = [];
      for (var i = 0; i < xs.length; i++) {
          if (f(xs[i], i, xs)) res.push(xs[i]);
      }
      return res;
  }
  
  // String.prototype.substr - negative index don't work in IE8
  var substr = 'ab'.substr(-1) === 'b'
      ? function (str, start, len) { return str.substr(start, len) }
      : function (str, start, len) {
          if (start < 0) start = str.length + start;
          return str.substr(start, len);
      }
  ;
  
  },{"__browserify_process":26}],31:[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.
  
  'use strict';
  
  // If obj.hasOwnProperty has been overridden, then calling
  // obj.hasOwnProperty(prop) will break.
  // See: https://github.com/joyent/node/issues/1707
  function hasOwnProperty(obj, prop) {
    return Object.prototype.hasOwnProperty.call(obj, prop);
  }
  
  module.exports = function(qs, sep, eq, options) {
    sep = sep || '&';
    eq = eq || '=';
    var obj = {};
  
    if (typeof qs !== 'string' || qs.length === 0) {
      return obj;
    }
  
    var regexp = /\+/g;
    qs = qs.split(sep);
  
    var maxKeys = 1000;
    if (options && typeof options.maxKeys === 'number') {
      maxKeys = options.maxKeys;
    }
  
    var len = qs.length;
    // maxKeys <= 0 means that we should not limit keys count
    if (maxKeys > 0 && len > maxKeys) {
      len = maxKeys;
    }
  
    for (var i = 0; i < len; ++i) {
      var x = qs[i].replace(regexp, '%20'),
          idx = x.indexOf(eq),
          kstr, vstr, k, v;
  
      if (idx >= 0) {
        kstr = x.substr(0, idx);
        vstr = x.substr(idx + 1);
      } else {
        kstr = x;
        vstr = '';
      }
  
      k = decodeURIComponent(kstr);
      v = decodeURIComponent(vstr);
  
      if (!hasOwnProperty(obj, k)) {
        obj[k] = v;
      } else if (isArray(obj[k])) {
        obj[k].push(v);
      } else {
        obj[k] = [obj[k], v];
      }
    }
  
    return obj;
  };
  
  var isArray = Array.isArray || function (xs) {
    return Object.prototype.toString.call(xs) === '[object Array]';
  };
  
  },{}],32:[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.
  
  'use strict';
  
  var stringifyPrimitive = function(v) {
    switch (typeof v) {
      case 'string':
        return v;
  
      case 'boolean':
        return v ? 'true' : 'false';
  
      case 'number':
        return isFinite(v) ? v : '';
  
      default:
        return '';
    }
  };
  
  module.exports = function(obj, sep, eq, name) {
    sep = sep || '&';
    eq = eq || '=';
    if (obj === null) {
      obj = undefined;
    }
  
    if (typeof obj === 'object') {
      return map(objectKeys(obj), function(k) {
        var ks = encodeURIComponent(stringifyPrimitive(k)) + eq;
        if (isArray(obj[k])) {
          return obj[k].map(function(v) {
            return ks + encodeURIComponent(stringifyPrimitive(v));
          }).join(sep);
        } else {
          return ks + encodeURIComponent(stringifyPrimitive(obj[k]));
        }
      }).join(sep);
  
    }
  
    if (!name) return '';
    return encodeURIComponent(stringifyPrimitive(name)) + eq +
           encodeURIComponent(stringifyPrimitive(obj));
  };
  
  var isArray = Array.isArray || function (xs) {
    return Object.prototype.toString.call(xs) === '[object Array]';
  };
  
  function map (xs, f) {
    if (xs.map) return xs.map(f);
    var res = [];
    for (var i = 0; i < xs.length; i++) {
      res.push(f(xs[i], i));
    }
    return res;
  }
  
  var objectKeys = Object.keys || function (obj) {
    var res = [];
    for (var key in obj) {
      if (Object.prototype.hasOwnProperty.call(obj, key)) res.push(key);
    }
    return res;
  };
  
  },{}],33:[function(require,module,exports){
  'use strict';
  
  exports.decode = exports.parse = require('./decode');
  exports.encode = exports.stringify = require('./encode');
  
  },{"./decode":31,"./encode":32}],34:[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';
  }
  },{}],35:[function(require,module,exports){
  var process=require("__browserify_process"),global=typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {};// 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);
  }
  
  },{"./support/isBuffer":34,"__browserify_process":26,"inherits":25}],36:[function(require,module,exports){
  
  /**
   * This is the web browser implementation of `debug()`.
   *
   * Expose `debug()` as the module.
   */
  
  exports = module.exports = require('./debug');
  exports.log = log;
  exports.formatArgs = formatArgs;
  exports.save = save;
  exports.load = load;
  exports.useColors = useColors;
  
  /**
   * Colors.
   */
  
  exports.colors = [
    'lightseagreen',
    'forestgreen',
    'goldenrod',
    'dodgerblue',
    'darkorchid',
    'crimson'
  ];
  
  /**
   * Currently only WebKit-based Web Inspectors, Firefox >= v31,
   * and the Firebug extension (any Firefox version) are known
   * to support "%c" CSS customizations.
   *
   * TODO: add a `localStorage` variable to explicitly enable/disable colors
   */
  
  function useColors() {
    // is webkit? http://stackoverflow.com/a/16459606/376773
    return ('WebkitAppearance' in document.documentElement.style) ||
      // is firebug? http://stackoverflow.com/a/398120/376773
      (window.console && (console.firebug || (console.exception && console.table))) ||
      // is firefox >= v31?
      // https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages
      (navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31);
  }
  
  /**
   * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default.
   */
  
  exports.formatters.j = function(v) {
    return JSON.stringify(v);
  };
  
  
  /**
   * Colorize log arguments if enabled.
   *
   * @api public
   */
  
  function formatArgs() {
    var args = arguments;
    var useColors = this.useColors;
  
    args[0] = (useColors ? '%c' : '')
      + this.namespace
      + (useColors ? ' %c' : ' ')
      + args[0]
      + (useColors ? '%c ' : ' ')
      + '+' + exports.humanize(this.diff);
  
    if (!useColors) return args;
  
    var c = 'color: ' + this.color;
    args = [args[0], c, 'color: inherit'].concat(Array.prototype.slice.call(args, 1));
  
    // the final "%c" is somewhat tricky, because there could be other
    // arguments passed either before or after the %c, so we need to
    // figure out the correct index to insert the CSS into
    var index = 0;
    var lastC = 0;
    args[0].replace(/%[a-z%]/g, function(match) {
      if ('%%' === match) return;
      index++;
      if ('%c' === match) {
        // we only are interested in the *last* %c
        // (the user may have provided their own)
        lastC = index;
      }
    });
  
    args.splice(lastC, 0, c);
    return args;
  }
  
  /**
   * Invokes `console.log()` when available.
   * No-op when `console.log` is not a "function".
   *
   * @api public
   */
  
  function log() {
    // This hackery is required for IE8,
    // where the `console.log` function doesn't have 'apply'
    return 'object' == typeof console
      && 'function' == typeof console.log
      && Function.prototype.apply.call(console.log, console, arguments);
  }
  
  /**
   * Save `namespaces`.
   *
   * @param {String} namespaces
   * @api private
   */
  
  function save(namespaces) {
    try {
      if (null == namespaces) {
        localStorage.removeItem('debug');
      } else {
        localStorage.debug = namespaces;
      }
    } catch(e) {}
  }
  
  /**
   * Load `namespaces`.
   *
   * @return {String} returns the previously persisted debug modes
   * @api private
   */
  
  function load() {
    var r;
    try {
      r = localStorage.debug;
    } catch(e) {}
    return r;
  }
  
  /**
   * Enable namespaces listed in `localStorage.debug` initially.
   */
  
  exports.enable(load());
  
  },{"./debug":37}],37:[function(require,module,exports){
  
  /**
   * This is the common logic for both the Node.js and web browser
   * implementations of `debug()`.
   *
   * Expose `debug()` as the module.
   */
  
  exports = module.exports = debug;
  exports.coerce = coerce;
  exports.disable = disable;
  exports.enable = enable;
  exports.enabled = enabled;
  exports.humanize = require('ms');
  
  /**
   * The currently active debug mode names, and names to skip.
   */
  
  exports.names = [];
  exports.skips = [];
  
  /**
   * Map of special "%n" handling functions, for the debug "format" argument.
   *
   * Valid key names are a single, lowercased letter, i.e. "n".
   */
  
  exports.formatters = {};
  
  /**
   * Previously assigned color.
   */
  
  var prevColor = 0;
  
  /**
   * Previous log timestamp.
   */
  
  var prevTime;
  
  /**
   * Select a color.
   *
   * @return {Number}
   * @api private
   */
  
  function selectColor() {
    return exports.colors[prevColor++ % exports.colors.length];
  }
  
  /**
   * Create a debugger with the given `namespace`.
   *
   * @param {String} namespace
   * @return {Function}
   * @api public
   */
  
  function debug(namespace) {
  
    // define the `disabled` version
    function disabled() {
    }
    disabled.enabled = false;
  
    // define the `enabled` version
    function enabled() {
  
      var self = enabled;
  
      // set `diff` timestamp
      var curr = +new Date();
      var ms = curr - (prevTime || curr);
      self.diff = ms;
      self.prev = prevTime;
      self.curr = curr;
      prevTime = curr;
  
      // add the `color` if not set
      if (null == self.useColors) self.useColors = exports.useColors();
      if (null == self.color && self.useColors) self.color = selectColor();
  
      var args = Array.prototype.slice.call(arguments);
  
      args[0] = exports.coerce(args[0]);
  
      if ('string' !== typeof args[0]) {
        // anything else let's inspect with %o
        args = ['%o'].concat(args);
      }
  
      // apply any `formatters` transformations
      var index = 0;
      args[0] = args[0].replace(/%([a-z%])/g, function(match, format) {
        // if we encounter an escaped % then don't increase the array index
        if (match === '%%') return match;
        index++;
        var formatter = exports.formatters[format];
        if ('function' === typeof formatter) {
          var val = args[index];
          match = formatter.call(self, val);
  
          // now we need to remove `args[index]` since it's inlined in the `format`
          args.splice(index, 1);
          index--;
        }
        return match;
      });
  
      if ('function' === typeof exports.formatArgs) {
        args = exports.formatArgs.apply(self, args);
      }
      var logFn = enabled.log || exports.log || console.log.bind(console);
      logFn.apply(self, args);
    }
    enabled.enabled = true;
  
    var fn = exports.enabled(namespace) ? enabled : disabled;
  
    fn.namespace = namespace;
  
    return fn;
  }
  
  /**
   * Enables a debug mode by namespaces. This can include modes
   * separated by a colon and wildcards.
   *
   * @param {String} namespaces
   * @api public
   */
  
  function enable(namespaces) {
    exports.save(namespaces);
  
    var split = (namespaces || '').split(/[\s,]+/);
    var len = split.length;
  
    for (var i = 0; i < len; i++) {
      if (!split[i]) continue; // ignore empty strings
      namespaces = split[i].replace(/\*/g, '.*?');
      if (namespaces[0] === '-') {
        exports.skips.push(new RegExp('^' + namespaces.substr(1) + '$'));
      } else {
        exports.names.push(new RegExp('^' + namespaces + '$'));
      }
    }
  }
  
  /**
   * Disable debug output.
   *
   * @api public
   */
  
  function disable() {
    exports.enable('');
  }
  
  /**
   * Returns true if the given mode name is enabled, false otherwise.
   *
   * @param {String} name
   * @return {Boolean}
   * @api public
   */
  
  function enabled(name) {
    var i, len;
    for (i = 0, len = exports.skips.length; i < len; i++) {
      if (exports.skips[i].test(name)) {
        return false;
      }
    }
    for (i = 0, len = exports.names.length; i < len; i++) {
      if (exports.names[i].test(name)) {
        return true;
      }
    }
    return false;
  }
  
  /**
   * Coerce `val`.
   *
   * @param {Mixed} val
   * @return {Mixed}
   * @api private
   */
  
  function coerce(val) {
    if (val instanceof Error) return val.stack || val.message;
    return val;
  }
  
  },{"ms":38}],38:[function(require,module,exports){
  /**
   * Helpers.
   */
  
  var s = 1000;
  var m = s * 60;
  var h = m * 60;
  var d = h * 24;
  var y = d * 365.25;
  
  /**
   * Parse or format the given `val`.
   *
   * Options:
   *
   *  - `long` verbose formatting [false]
   *
   * @param {String|Number} val
   * @param {Object} options
   * @return {String|Number}
   * @api public
   */
  
  module.exports = function(val, options){
    options = options || {};
    if ('string' == typeof val) return parse(val);
    return options.long
      ? long(val)
      : short(val);
  };
  
  /**
   * Parse the given `str` and return milliseconds.
   *
   * @param {String} str
   * @return {Number}
   * @api private
   */
  
  function parse(str) {
    var match = /^((?:\d+)?\.?\d+) *(ms|seconds?|s|minutes?|m|hours?|h|days?|d|years?|y)?$/i.exec(str);
    if (!match) return;
    var n = parseFloat(match[1]);
    var type = (match[2] || 'ms').toLowerCase();
    switch (type) {
      case 'years':
      case 'year':
      case 'y':
        return n * y;
      case 'days':
      case 'day':
      case 'd':
        return n * d;
      case 'hours':
      case 'hour':
      case 'h':
        return n * h;
      case 'minutes':
      case 'minute':
      case 'm':
        return n * m;
      case 'seconds':
      case 'second':
      case 's':
        return n * s;
      case 'ms':
        return n;
    }
  }
  
  /**
   * Short format for `ms`.
   *
   * @param {Number} ms
   * @return {String}
   * @api private
   */
  
  function short(ms) {
    if (ms >= d) return Math.round(ms / d) + 'd';
    if (ms >= h) return Math.round(ms / h) + 'h';
    if (ms >= m) return Math.round(ms / m) + 'm';
    if (ms >= s) return Math.round(ms / s) + 's';
    return ms + 'ms';
  }
  
  /**
   * Long format for `ms`.
   *
   * @param {Number} ms
   * @return {String}
   * @api private
   */
  
  function long(ms) {
    return plural(ms, d, 'day')
      || plural(ms, h, 'hour')
      || plural(ms, m, 'minute')
      || plural(ms, s, 'second')
      || ms + ' ms';
  }
  
  /**
   * Pluralization helper.
   */
  
  function plural(ms, n, name) {
    if (ms < n) return;
    if (ms < n * 1.5) return Math.floor(ms / n) + ' ' + name;
    return Math.ceil(ms / n) + ' ' + name + 's';
  }
  
  },{}],39:[function(require,module,exports){
  var extend = require('util')._extend
  
  exports.Stanza = {}
  extend(exports.Stanza, require('./lib/stanza'))
  exports.JID = require('./lib/jid')
  exports.Connection = require('./lib/connection')
  exports.SRV = require('./lib/srv')
  exports.StreamParser = require('./lib/stream_parser')
  exports.ltx = require('ltx')
  },{"./lib/connection":40,"./lib/jid":41,"./lib/srv":42,"./lib/stanza":43,"./lib/stream_parser":44,"ltx":48,"util":35}],40:[function(require,module,exports){
  'use strict';
  
  var net = require('net')
    , EventEmitter = require('events').EventEmitter
    , util = require('util')
    , ltx = require('ltx')
    , reconnect = require('reconnect-core')
    , StreamParser = require('./stream_parser')
    , starttls = require('tls-connect')
    , debug = require('debug')('xmpp:connection')
    , extend = require('util')._extend
  
  var NS_XMPP_TLS = 'urn:ietf:params:xml:ns:xmpp-tls'
  var NS_STREAM = 'http://etherx.jabber.org/streams'
  var NS_XMPP_STREAMS = 'urn:ietf:params:xml:ns:xmpp-streams'
  
  var INITIAL_RECONNECT_DELAY =  1e3
  var MAX_RECONNECT_DELAY     = 30e3
  
  function defaultInjection(emitter, opts) {
      // clone opts
      var options = extend({}, opts)
  
      // add computed options
      /* jshint -W014 */
      options.initialDelay = (opts && (opts.initialReconnectDelay
                              ||  opts.reconnectDelay)) || INITIAL_RECONNECT_DELAY
      options.maxDelay = (opts &&   opts.maxReconnectDelay)  || MAX_RECONNECT_DELAY
      options.immediate = opts && opts.socket && typeof opts.socket !== 'function'
      options.type =      opts && opts.delayType
      options.emitter =   emitter
  
      // return calculated options
      return options
  }
  
  /**
   Base class for connection-based streams (TCP).
   The socket parameter is optional for incoming connections.
  */
  function Connection(opts) {
      
      EventEmitter.call(this)
  
      this.streamAttrs = (opts && opts.streamAttrs) || {}
      this.xmlns = (opts && opts.xmlns) || {}
      this.xmlns.stream = NS_STREAM
  
      this.rejectUnauthorized = (opts && opts.rejectUnauthorized) ? true : false
      this.serialized = (opts && opts.serialized) ? true : false
      this.requestCert = (opts && opts.requestCert) ? true : false
  
      this.servername = (opts && opts.servername)
  
      this._setupSocket(defaultInjection(this, opts))
      this.once('reconnect', function () {
          this.reconnect = opts && opts.reconnect
      })
  }
  
  util.inherits(Connection, EventEmitter)
  
  Connection.prototype.NS_XMPP_TLS = NS_XMPP_TLS
  Connection.NS_STREAM = NS_STREAM
  Connection.prototype.NS_XMPP_STREAMS = NS_XMPP_STREAMS
  // Defaults
  Connection.prototype.allowTLS = true
  
  Connection.prototype._setupSocket = function (options) {
      debug('setup socket')
      var previousOptions = {}
      var inject = reconnect(function (opts) {
          var previousSocket = this.socket
          /* if this opts.preserve is on
           * the previous options are stored until next time.
           * this is needed to restore from a setSecure call.
           */
          if (opts.preserve === 'on') {
              opts.preserve = previousOptions
              previousOptions = opts
          } else if (opts.preserve) {
              // switch back to the preversed options
              opts = previousOptions = opts.preserve
          } else {
              // keep some state for eg SRV.connect
              opts = previousOptions = opts || previousOptions
          }
  
          if (typeof opts.socket === 'function') {
              debug('use lazy socket')
              /* lazy evaluation
               * (can be retriggered by calling connection.connect()
               *  without arguments after a previous
               *  connection.connect({socket:function() { … }})) */
              this.socket = opts.socket.call(this)
          } else {
              debug('use standard socket')
              // only use this socket once
              this.socket = opts.socket
              opts.socket = null
              if (this.socket) {
                  this.once('connect', function () {
                      inject.options.immediate = false
                  })
              }
          }
          this.socket = this.socket || new net.Socket()
          if (previousSocket !== this.socket)
              this.setupStream()
          return this.socket
      }.bind(this))
  
      inject(inject.options = options)
  
      this.on('connection', function () {
          if (!this.parser)
              this.startParser()
      })
      this.on('end', function () {
          previousOptions = {}
      })
  }
  
  /**
   Used by both the constructor and by reinitialization in setSecure().
  */
  Connection.prototype.setupStream = function() {
      debug('setup stream')
      this.socket.on('end', this.onEnd.bind(this))
      this.socket.on('data', this.onData.bind(this))
      this.socket.on('close', this.onClose.bind(this))
      // let them sniff unparsed XML
      this.socket.on('data',  this.emit.bind(this, 'data'))
      this.socket.on('drain', this.emit.bind(this, 'drain'))
      // ignore errors after disconnect
      this.socket.on('error', function () { })
  
      if (!this.socket.serializeStanza) {
          /**
          * This is optimized for continuous TCP streams. If your "socket"
          * actually transports frames (WebSockets) and you can't have
          * stanzas split across those, use:
          *     cb(el.toString())
          */
          if (this.serialized) {
              this.socket.serializeStanza = function(el, cb) {
                  // Continuously write out
                  el.write(function(s) {
                      cb(s)
                  })
              }
          } else {
              this.socket.serializeStanza = function(el, cb) {
                  cb(el.toString())
              }
          }
      }
  }
  
  Connection.prototype.pause = function() {
      if (this.socket.pause) this.socket.pause()
  }
  
  Connection.prototype.resume = function() {
      if (this.socket.resume) this.socket.resume()
  }
  
  /** Climbs the stanza up if a child was passed,
      but you can send strings and buffers too.
  
      Returns whether the socket flushed data.
  */
  Connection.prototype.send = function(stanza) {
      var flushed = true
      if (!this.socket) {
          return // Doh!
      }
      if (!this.socket.writable) {
          this.socket.end()
          return
      }
  
      debug('send: ' + stanza.toString())
      if (stanza.root) {
          var el = this.rmXmlns(stanza.root())
          this.socket.serializeStanza(el, function(s) {
              flushed = this.write(s)
          }.bind(this.socket))
      } else {
          flushed = this.socket.write(stanza)
      }
      return flushed
  }
  
  Connection.prototype.startParser = function() {
      var self = this
      this.parser = new StreamParser.StreamParser(this.maxStanzaSize)
  
      this.parser.on('streamStart', function(attrs) {
          /* We need those xmlns often, store them extra */
          self.streamNsAttrs = {}
          for (var k in attrs) {
              if (k === 'xmlns' || (k.substr(0, 6) === 'xmlns:'))
                  self.streamNsAttrs[k] = attrs[k]
          }
  
          /* Notify in case we don't wait for <stream:features/>
             (Component or non-1.0 streams)
           */
          self.emit('streamStart', attrs)
      })
      this.parser.on('stanza', function(stanza) {
          self.onStanza(self.addStreamNs(stanza))
      })
      this.parser.on('error', function(e) {
          self.error(e.condition || 'internal-server-error', e.message)
      })
      this.parser.once('end', function() {
          self.stopParser()
          if (self.reconnect)
              self.once('reconnect', self.startParser.bind(self))
          else
              self.end()
      })
  }
  
  Connection.prototype.stopParser = function() {
      /* No more events, please (may happen however) */
      if (this.parser) {
          var parser = this.parser
          /* Get GC'ed */
          delete this.parser
          parser.end()
      }
  }
  
  Connection.prototype.startStream = function() {
      var attrs = {}
      for (var k in this.xmlns) {
          if (this.xmlns.hasOwnProperty(k)) {
              if (!k)
                  attrs.xmlns = this.xmlns[k]
              else
                  attrs['xmlns:' + k] = this.xmlns[k]
          }
      }
      for (k in this.streamAttrs) {
          if (this.streamAttrs.hasOwnProperty(k))
              attrs[k] = this.streamAttrs[k]
      }
  
      if (this.streamTo) { // in case of a component connecting
          attrs.to = this.streamTo
      }
  
      var el = new ltx.Element('stream:stream', attrs)
      // make it non-empty to cut the closing tag
      el.t(' ')
      var s = el.toString()
      this.send(s.substr(0, s.indexOf(' </stream:stream>')))
  
      this.streamOpened = true
  }
  
  Connection.prototype.onData = function(data) {
      debug('receive: ' + data.toString('utf8'))
      if (this.parser)
          this.parser.write(data)
  }
  
  Connection.prototype.setSecure = function(credentials, isServer) {
      // Remove old event listeners
      this.socket.removeAllListeners('data')
      // retain socket 'end' listeners because ssl layer doesn't support it
      this.socket.removeAllListeners('drain')
      this.socket.removeAllListeners('close')
      // remove idle_timeout
      if (this.socket.clearTimer)
          this.socket.clearTimer()
  
      var cleartext = starttls({
          socket: this.socket,
          rejectUnauthorized: this.rejectUnauthorized,
          credentials: credentials || this.credentials,
          requestCert: this.requestCert,
          isServer: !!isServer
      }, function() {
          this.isSecure = true
          this.once('disconnect', function () {
              this.isSecure = false
          })
          cleartext.emit('connect', cleartext)
      }.bind(this))
      cleartext.on('clientError', this.emit.bind(this, 'error'))
      if (!this.reconnect) {
          this.reconnect = true // need this so stopParser works properly
          this.once('reconnect', function () {this.reconnect = false})
      }
      this.stopParser()
      // if we reconnect we need to get back to the previous socket creation
      this.listen({socket:cleartext, preserve:'on'})
  }
  
  function getAllText(el) {
      return !el.children ? el : el.children.reduce(function (text, child) {
          return text + getAllText(child)
      }, '')
  }
  
  /**
   * This is not an event listener, but takes care of the TLS handshake
   * before 'stanza' events are emitted to the derived classes.
   */
  Connection.prototype.onStanza = function(stanza) {
      if (stanza.is('error', NS_STREAM)) {
          var error = new Error('' + getAllText(stanza))
          error.stanza = stanza
          this.socket.emit('error', error)
      } else if (stanza.is('features', this.NS_STREAM) &&
          this.allowTLS &&
          !this.isSecure &&
          stanza.getChild('starttls', this.NS_XMPP_TLS)) {
          /* Signal willingness to perform TLS handshake */
          this.send(new ltx.Element('starttls', { xmlns: this.NS_XMPP_TLS }))
      } else if (this.allowTLS &&
          stanza.is('proceed', this.NS_XMPP_TLS)) {
          /* Server is waiting for TLS handshake */
          this.setSecure()
      } else {
          this.emit('stanza', stanza)
      }
  }
  
  /**
   * Add stream xmlns to a stanza
   *
   * Does not add our default xmlns as it is different for
   * C2S/S2S/Component connections.
   */
  Connection.prototype.addStreamNs = function(stanza) {
      for (var attr in this.streamNsAttrs) {
          if (!stanza.attrs[attr] &&
              !((attr === 'xmlns') && (this.streamNsAttrs[attr] === this.xmlns['']))
             ) {
              stanza.attrs[attr] = this.streamNsAttrs[attr]
          }
      }
      return stanza
  }
  
  /**
   * Remove superfluous xmlns that were aleady declared in
   * our <stream:stream>
   */
  Connection.prototype.rmXmlns = function(stanza) {
      for (var prefix in this.xmlns) {
          var attr = prefix ? 'xmlns:' + prefix : 'xmlns'
          if (stanza.attrs[attr] === this.xmlns[prefix])
              delete stanza.attrs[attr]
      }
      return stanza
  }
  
  /**
   * XMPP-style end connection for user
   */
  Connection.prototype.onEnd = function() {
      if (this.socket && this.socket.writable) {
          if (this.streamOpened) {
              this.socket.write('</stream:stream>')
              delete this.streamOpened
          }
      }
      if (!this.reconnect)
          this.emit('end')
  }
  
  Connection.prototype.onClose = function() {
      if (!this.reconnect)
          this.emit('close')
  }
  
  /**
   * End connection with stream error.
   * Emits 'error' event too.
   *
   * @param {String} condition XMPP error condition, see RFC3920 4.7.3. Defined Conditions
   * @param {String} text Optional error message
   */
  Connection.prototype.error = function(condition, message) {
      this.emit('error', new Error(message))
  
      if (!this.socket || !this.socket.writable) return
  
      /* RFC 3920, 4.7.1 stream-level errors rules */
      if (!this.streamOpened) this.startStream()
  
      var error = new ltx.Element('stream:error')
      error.c(condition, { xmlns: NS_XMPP_STREAMS })
      if (message) {
          error.c( 'text', {
              xmlns: NS_XMPP_STREAMS,
              'xml:lang': 'en'
          }).t(message)
      }
  
      this.send(error)
      this.end()
  }
  
  module.exports = Connection
  
  },{"./stream_parser":44,"debug":45,"events":24,"ltx":48,"net":16,"reconnect-core":58,"tls-connect":65,"util":35}],41:[function(require,module,exports){
  var StringPrep = require('node-stringprep').StringPrep
    , toUnicode = require('node-stringprep').toUnicode
  
  
  /**
   * JID implements 
   * - Xmpp addresses according to RFC6122
   * - XEP-0106: JID Escaping
   *
   * @see http://tools.ietf.org/html/rfc6122#section-2
   * @see http://xmpp.org/extensions/xep-0106.html
   */
  function JID(a, b, c) {
      this.local = null
      this.domain = null
      this.resource = null
  
      if (a && (!b) && (!c)) {
          this.parseJID(a)
      } else if (b) {
          this.setLocal(a)
          this.setDomain(b)
          this.setResource(c)
      } else {
          throw new Error('Argument error')
      }
  }
  
  JID.prototype.parseJID = function(s) {
      if (s.indexOf('@') >= 0) {
          this.setLocal(s.substr(0, s.lastIndexOf('@')))
          s = s.substr(s.lastIndexOf('@') + 1)
      }
      if (s.indexOf('/') >= 0) {
          this.setResource(s.substr(s.indexOf('/') + 1))
          s = s.substr(0, s.indexOf('/'))
      }
      this.setDomain(s)
  }
  
  JID.prototype.toString = function(unescape) {
      var s = this.domain
      if (this.local) s = this.getLocal(unescape) + '@' + s
      if (this.resource) s = s + '/' + this.resource
      return s
  }
  
  /**
   * Convenience method to distinguish users
   **/
  JID.prototype.bare = function() {
      if (this.resource) {
          return new JID(this.local, this.domain, null)
      } else {
          return this
      }
  }
  
  /**
   * Comparison function
   **/
  JID.prototype.equals = function(other) {
      return (this.local === other.local) &&
          (this.domain === other.domain) &&
          (this.resource === other.resource)
  }
  
  /* Deprecated, use setLocal() [see RFC6122] */
  JID.prototype.setUser = function(user) {
      return this.setLocal(user)
  }
  
  /**
   * Setters that do stringprep normalization.
   **/
  JID.prototype.setLocal = function(local, escape) {
      escape = escape || this.detectEscape(local)
  
      if (escape) {
          local = this.escapeLocal(local)
      }
  
      this.local = this.user = local && this.prep('nodeprep', local)
      return this
  }
  
  /**
   * http://xmpp.org/rfcs/rfc6122.html#addressing-domain
   */
  JID.prototype.setDomain = function(domain) {
      this.domain = domain &&
          this.prep('nameprep', domain.split('.').map(toUnicode).join('.'))
      return this
  }
  
  JID.prototype.setResource = function(resource) {
      this.resource = resource && this.prep('resourceprep', resource)
      return this
  }
  
  JID.prototype.getLocal = function(unescape) {
      unescape = unescape || false
      var local = null
      
      if (unescape) {
          local = this.unescapeLocal(this.local)
      } else {
          local = this.local
      }
  
      return local;
  }
  
  JID.prototype.prep = function(operation, value) {
      var p = new StringPrep(operation)
      return p.prepare(value)
  }
  
  /* Deprecated, use getLocal() [see RFC6122] */
  JID.prototype.getUser = function() {
      return this.getLocal()
  }
  
  JID.prototype.getDomain = function() {
      return this.domain
  }
  
  JID.prototype.getResource = function() {
      return this.resource
  }
  
  JID.prototype.detectEscape = function (local) {
      if (!local) return false
  
      // remove all escaped secquences
      var tmp = local.replace(/\\20/g, '')
          .replace(/\\22/g, '')
          .replace(/\\26/g, '')
          .replace(/\\27/g, '')
          .replace(/\\2f/g, '')
          .replace(/\\3a/g, '')
          .replace(/\\3c/g, '')
          .replace(/\\3e/g, '')
          .replace(/\\40/g, '')
          .replace(/\\5c/g, '')
  
      // detect if we have unescaped sequences
      var search = tmp.search(/\\| |\"|\&|\'|\/|:|<|>|@/g);
      if (search === -1) {
          return false
      } else {
          return true
      }
  }
  
  /** 
   * Escape the local part of a JID.
   *
   * @see http://xmpp.org/extensions/xep-0106.html
   * @param String local local part of a jid
   * @return An escaped local part
   */
  JID.prototype.escapeLocal = function (local) {
      if (local === null) return null
  
      /* jshint -W044 */
      return local.replace(/^\s+|\s+$/g, '')
          .replace(/\\/g, '\\5c')
          .replace(/ /g, '\\20')
          .replace(/\"/g, '\\22')
          .replace(/\&/g, '\\26')
          .replace(/\'/g, '\\27')
          .replace(/\//g, '\\2f')
          .replace(/:/g, '\\3a')
          .replace(/</g, '\\3c')
          .replace(/>/g, '\\3e')
          .replace(/@/g, '\\40')
          .replace(/\3a/g, '\5c3a')
         
      
  }
  
  /** 
   * Unescape a local part of a JID.
   *
   * @see http://xmpp.org/extensions/xep-0106.html
   * @param String local local part of a jid
   * @return unescaped local part
   */
  JID.prototype.unescapeLocal = function (local) {
      if (local === null) return null
  
      return local.replace(/\\20/g, ' ')
          .replace(/\\22/g, '\"')
          .replace(/\\26/g, '&')
          .replace(/\\27/g, '\'')
          .replace(/\\2f/g, '/')
          .replace(/\\3a/g, ':')
          .replace(/\\3c/g, '<')
          .replace(/\\3e/g, '>')
          .replace(/\\40/g, '@')
          .replace(/\\5c/g, '\\')
  }
  
  if ((typeof exports !== 'undefined') && (exports !== null)) {
      module.exports = JID
  } else if ((typeof window !== 'undefined') && (window !== null)) {
      window.JID = JID
  }
  
  },{"node-stringprep":52}],42:[function(require,module,exports){
  'use strict';
  
  
  var dns = require('dns')
  
  function compareNumbers(a, b) {
      a = parseInt(a, 10)
      b = parseInt(b, 10)
      if (a < b)
          return -1
      if (a > b)
          return 1
      return 0
  }
  
  function groupSrvRecords(addrs) {
      var groups = {}  // by priority
      addrs.forEach(function(addr) {
          if (!groups.hasOwnProperty(addr.priority))
              groups[addr.priority] = []
  
          groups[addr.priority].push(addr)
      })
  
      var result = []
      Object.keys(groups).sort(compareNumbers).forEach(function(priority) {
          var group = groups[priority]
          var totalWeight = 0
          group.forEach(function(addr) {
              totalWeight += addr.weight
          })
          var w = Math.floor(Math.random() * totalWeight)
          totalWeight = 0
          var candidate = group[0]
          group.forEach(function(addr) {
              totalWeight += addr.weight
              if (w < totalWeight)
                  candidate = addr
          })
          if (candidate)
              result.push(candidate)
      })
      return result
  }
  
  function resolveSrv(name, cb) {
      dns.resolveSrv(name, function(err, addrs) {
          if (err) {
              /* no SRV record, try domain as A */
              cb(err)
          } else {
              var pending = 0, error, results = []
              var cb1 = function(e, addrs1) {
                  error = error || e
                  results = results.concat(addrs1)
                  pending--
                  if (pending < 1) {
                      cb(results ? null : error, results)
                  }
              }
              var gSRV = groupSrvRecords(addrs)
              pending = gSRV.length
              gSRV.forEach(function(addr) {
                  resolveHost(addr.name, function(e, a) {
                      if (a) {
                          a = a.map(function(a1) {
                              return { name: a1, port: addr.port }
                          })
                      }
                      cb1(e, a)
                  })
              })
          }
      })
  }
  
  // one of both A & AAAA, in case of broken tunnels
  function resolveHost(name, cb) {
      var error, results = []
      var cb1 = function(e, addr) {
          error = error || e
          if (addr)
              results.push(addr)
  
          cb((results.length > 0) ? null : error, results)
      }
  
      dns.lookup(name, cb1)
  }
  
  // connection attempts to multiple addresses in a row
  function tryConnect(connection, addrs) {
      connection.on('connect', cleanup)
      connection.on('disconnect', connectNext)
      return connectNext()
  
      function cleanup() {
          connection.removeListener('connect', cleanup)
          connection.removeListener('disconnect', connectNext)
      }
  
      function connectNext() {
          var addr = addrs.shift()
          if (addr)
              connection.socket.connect(addr.port, addr.name)
          else
              cleanup()
      }
  }
  
  // returns a lazy iterator which can be restarted via connection.connect()
  exports.connect = function connect(opts) {
      var services = opts.services.slice()
      // lazy evaluation to determine endpoint
      function tryServices(retry) {
          /* jshint -W040 */
          var connection = this
          if (!connection.socket && opts.socket) {
              if (typeof opts.socket === 'function') {
                  connection.socket = opts.socket.call(this)
              } else {
                  connection.socket = opts.socket
              }
              opts.socket = null
          } else if (!retry) {
              connection.socket = null
          }
          var service = services.shift()
          if (service) {
              resolveSrv(service + '.' + opts.domain, function(error, addrs) {
                  if (addrs)
                      tryConnect(connection, addrs)
                  // call tryServices again
                  else {
                      tryServices.call(connection, 'retry')
                  }
              })
          } else {
              resolveHost(opts.domain, function(error, addrs) {
                  if (addrs && addrs.length > 0) {
                      addrs = addrs.map(function(addr) {
                          return { name: addr,
                                   port: opts.defaultPort }
                      })
                      tryConnect(connection, addrs)
                  } else if (connection.reconnect)  {
                      // retry from the beginning
                      services = opts.services.slice()
                      // get a new socket
                      connection.socket = null
                  } else {
                      error = error || new Error('No addresses resolved for ' +
                                                  opts.domain)
                      connection.emit('error', error)
                  }
              })
          }
          return connection.socket
      }
      return tryServices
  }
  
  },{"dns":16}],43:[function(require,module,exports){
  'use strict';
  
  var util = require('util')
    , ltx = require('ltx')
  
  function Stanza(name, attrs) {
      ltx.Element.call(this, name, attrs)
  }
  
  util.inherits(Stanza, ltx.Element)
  
  Stanza.prototype.clone = function() {
      var clone = new Stanza(this.name, {})
      for (var k in this.attrs) {
          if (this.attrs.hasOwnProperty(k))
              clone.attrs[k] = this.attrs[k]
      }
      for (var i = 0; i < this.children.length; i++) {
          var child = this.children[i]
          clone.cnode(child.clone ? child.clone() : child)
      }
      return clone
  }
  
  /**
   * Common attribute getters/setters for all stanzas
   */
  
  Object.defineProperty(Stanza.prototype, 'from', {
      get: function() {
          return this.attrs.from
      },
  
      set: function(from) {
          this.attrs.from = from
      }
  });
  
  Object.defineProperty(Stanza.prototype, 'to', {
      get: function() {
          return this.attrs.to
      },
  
      set: function(to) {
          this.attrs.to = to
      }
  });
  
  Object.defineProperty(Stanza.prototype, 'id', {
      get: function() {
          return this.attrs.id
      },
  
      set: function(id) {
          this.attrs.id = id
      }
  });
  
  Object.defineProperty(Stanza.prototype, 'type', {
      get: function() {
          return this.attrs.type
      },
  
      set: function(type) {
          this.attrs.type = type
      }
  });
  
  /**
   * Stanza kinds
   */
  
  function Message(attrs) {
      Stanza.call(this, 'message', attrs)
  }
  
  util.inherits(Message, Stanza)
  
  function Presence(attrs) {
      Stanza.call(this, 'presence', attrs)
  }
  
  util.inherits(Presence, Stanza)
  
  function Iq(attrs) {
      Stanza.call(this, 'iq', attrs)
  }
  
  util.inherits(Iq, Stanza)
  
  exports.Element = ltx.Element
  exports.Stanza = Stanza
  exports.Message = Message
  exports.Presence = Presence
  exports.Iq = Iq
  
  },{"ltx":48,"util":35}],44:[function(require,module,exports){
  'use strict';
  
  var util = require('util')
    , EventEmitter = require('events').EventEmitter
    , ltx = require('ltx')
    , Stanza = require('./stanza').Stanza
  
  /**
   * Recognizes <stream:stream> and collects stanzas used for ordinary
   * TCP streams and Websockets.
   *
   * API: write(data) & end(data)
   * Events: streamStart, stanza, end, error
   */
  function StreamParser(maxStanzaSize) {
      EventEmitter.call(this)
  
      var self = this
      this.parser = new ltx.bestSaxParser()
  
      /* Count traffic for entire life-time */
      this.bytesParsed = 0
      this.maxStanzaSize = maxStanzaSize
      /* Will be reset upon first stanza, but enforce maxStanzaSize until it is parsed */
      this.bytesParsedOnStanzaBegin = 0
  
      this.parser.on('startElement', function(name, attrs) {
              // TODO: refuse anything but <stream:stream>
              if (!self.element && (name === 'stream:stream')) {
                  self.emit('streamStart', attrs)
              } else {
                  var child
                  if (!self.element) {
                      /* A new stanza */
                      child = new Stanza(name, attrs)
                      self.element = child
                        /* For maxStanzaSize enforcement */
                      self.bytesParsedOnStanzaBegin = self.bytesParsed
                  } else {
                      /* A child element of a stanza */
                      child = new ltx.Element(name, attrs)
                      self.element = self.element.cnode(child)
                  }
              }
          }
      )
  
      this.parser.on('endElement', function(name) {
          if (!self.element && (name === 'stream:stream')) {
              self.end()
          } else if (self.element && (name === self.element.name)) {
              if (self.element.parent) {
                  self.element = self.element.parent
              } else {
                  /* Stanza complete */
                  self.emit('stanza', self.element)
                  delete self.element
                  /* maxStanzaSize doesn't apply until next startElement */
                  delete self.bytesParsedOnStanzaBegin
              }
          } else {
              self.error('xml-not-well-formed', 'XML parse error')
          }
      })
  
      this.parser.on('text', function(str) {
          if (self.element)
              self.element.t(str)
      })
  
      this.parser.on('entityDecl', function() {
          /* Entity declarations are forbidden in XMPP. We must abort to
           * avoid a billion laughs.
           */
          self.error('xml-not-well-formed', 'No entity declarations allowed')
          self.end()
      })
  
      this.parser.on('error', this.emit.bind(this, 'error'))
  }
  
  util.inherits(StreamParser, EventEmitter)
  
  
  /* 
   * hack for most usecases, do we have a better idea?
   *   catch the following:
   *   <?xml version="1.0"?>
   *   <?xml version="1.0" encoding="UTF-8"?>
   *   <?xml version="1.0" encoding="UTF-16" standalone="yes"?>
   */
  StreamParser.prototype.checkXMLHeader = function (data) {
      // check for xml tag
      var index = data.indexOf('<?xml');
  
      if (index !== -1) {
          var end = data.indexOf('?>');
          if (index >= 0 && end >= 0 && index < end+2) {
              var search = data.substring(index,end+2);
              data = data.replace(search, '');
          }
      }
  
      return data;
  }
  
  StreamParser.prototype.write = function(data) {
      /*if (/^<stream:stream [^>]+\/>$/.test(data)) {
      data = data.replace(/\/>$/, ">")
      }*/
      if (this.parser) {
          
          data = data.toString('utf8')
          data = this.checkXMLHeader(data)
  
      /* If a maxStanzaSize is configured, the current stanza must consist only of this many bytes */
          if (this.bytesParsedOnStanzaBegin && this.maxStanzaSize &&
              this.bytesParsed > this.bytesParsedOnStanzaBegin + this.maxStanzaSize) {
  
              this.error('policy-violation', 'Maximum stanza size exceeded')
              return
          }
          this.bytesParsed += data.length
  
          this.parser.write(data)
      }
  }
  
  StreamParser.prototype.end = function(data) {
      if (data) {
          this.write(data)
      }
      /* Get GC'ed */
      delete this.parser
      this.emit('end')
  }
  
  StreamParser.prototype.error = function(condition, message) {
      var e = new Error(message)
      e.condition = condition
      this.emit('error', e)
  }
  
  exports.StreamParser = StreamParser
  },{"./stanza":43,"events":24,"ltx":48,"util":35}],45:[function(require,module,exports){
  
  /**
   * Expose `debug()` as the module.
   */
  
  module.exports = debug;
  
  /**
   * Create a debugger with the given `name`.
   *
   * @param {String} name
   * @return {Type}
   * @api public
   */
  
  function debug(name) {
    if (!debug.enabled(name)) return function(){};
  
    return function(fmt){
      fmt = coerce(fmt);
  
      var curr = new Date;
      var ms = curr - (debug[name] || curr);
      debug[name] = curr;
  
      fmt = name
        + ' '
        + fmt
        + ' +' + debug.humanize(ms);
  
      // This hackery is required for IE8
      // where `console.log` doesn't have 'apply'
      window.console
        && console.log
        && Function.prototype.apply.call(console.log, console, arguments);
    }
  }
  
  /**
   * The currently active debug mode names.
   */
  
  debug.names = [];
  debug.skips = [];
  
  /**
   * Enables a debug mode by name. This can include modes
   * separated by a colon and wildcards.
   *
   * @param {String} name
   * @api public
   */
  
  debug.enable = function(name) {
    try {
      localStorage.debug = name;
    } catch(e){}
  
    var split = (name || '').split(/[\s,]+/)
      , len = split.length;
  
    for (var i = 0; i < len; i++) {
      name = split[i].replace('*', '.*?');
      if (name[0] === '-') {
        debug.skips.push(new RegExp('^' + name.substr(1) + '$'));
      }
      else {
        debug.names.push(new RegExp('^' + name + '$'));
      }
    }
  };
  
  /**
   * Disable debug output.
   *
   * @api public
   */
  
  debug.disable = function(){
    debug.enable('');
  };
  
  /**
   * Humanize the given `ms`.
   *
   * @param {Number} m
   * @return {String}
   * @api private
   */
  
  debug.humanize = function(ms) {
    var sec = 1000
      , min = 60 * 1000
      , hour = 60 * min;
  
    if (ms >= hour) return (ms / hour).toFixed(1) + 'h';
    if (ms >= min) return (ms / min).toFixed(1) + 'm';
    if (ms >= sec) return (ms / sec | 0) + 's';
    return ms + 'ms';
  };
  
  /**
   * Returns true if the given mode name is enabled, false otherwise.
   *
   * @param {String} name
   * @return {Boolean}
   * @api public
   */
  
  debug.enabled = function(name) {
    for (var i = 0, len = debug.skips.length; i < len; i++) {
      if (debug.skips[i].test(name)) {
        return false;
      }
    }
    for (var i = 0, len = debug.names.length; i < len; i++) {
      if (debug.names[i].test(name)) {
        return true;
      }
    }
    return false;
  };
  
  /**
   * Coerce `val`.
   */
  
  function coerce(val) {
    if (val instanceof Error) return val.stack || val.message;
    return val;
  }
  
  // persist
  
  try {
    if (window.localStorage) debug.enable(localStorage.debug);
  } catch(e){}
  
  },{}],46:[function(require,module,exports){
  'use strict';
  
  var util = require('util')
    , Element = require('./element').Element
  
  function DOMElement(name, attrs) {
      Element.call(this, name, attrs)
  
      this.nodeType = 1
      this.nodeName = this.localName
  }
  
  util.inherits(DOMElement, Element)
  
  DOMElement.prototype._getElement = function(name, attrs) {
      var element = new DOMElement(name, attrs)
      return element
  }
  
  Object.defineProperty(DOMElement.prototype, 'localName', {
      get: function () {
          return this.getName()
      }
  })
  
  Object.defineProperty(DOMElement.prototype, 'namespaceURI', {
      get: function () {
          return this.getNS()
      }
  })
  
  Object.defineProperty(DOMElement.prototype, 'parentNode', {
      get: function () {
          return this.parent
      }
  })
  
  Object.defineProperty(DOMElement.prototype, 'childNodes', {
      get: function () {
          return this.children
      }
  })
  
  Object.defineProperty(DOMElement.prototype, 'textContent', {
      get: function () {
          return this.getText()
      },
      set: function (value) {
          this.children.push(value)
      }
  })
  
  DOMElement.prototype.getElementsByTagName = function (name) {
      return this.getChildren(name)
  }
  
  DOMElement.prototype.getAttribute = function (name) {
      return this.getAttr(name)
  }
  
  DOMElement.prototype.setAttribute = function (name, value) {
      this.attr(name, value)
  }
  
  DOMElement.prototype.getAttributeNS = function (ns, name) {
      if (ns === 'http://www.w3.org/XML/1998/namespace') {
          return this.getAttr(['xml', name].join(':'))
      }
      return this.getAttr(name, ns)
  }
  
  DOMElement.prototype.setAttributeNS = function (ns, name, value) {
      var prefix
      if (ns === 'http://www.w3.org/XML/1998/namespace') {
          prefix = 'xml'
      } else {
          var nss = this.getXmlns()
          prefix = nss[ns] || ''
      }
      if (prefix) {
          this.attr([prefix, name].join(':'), value)
      }
  }
  
  DOMElement.prototype.removeAttribute = function (name) {
      this.attr(name, null)
  }
  
  DOMElement.prototype.removeAttributeNS = function (ns, name) {
      var prefix
      if (ns === 'http://www.w3.org/XML/1998/namespace') {
          prefix = 'xml'
      } else {
          var nss = this.getXmlns()
          prefix = nss[ns] || ''
      }
      if (prefix) {
          this.attr([prefix, name].join(':'), null)
      }
  }
  
  DOMElement.prototype.appendChild = function (el) {
      this.cnode(el)
  }
  
  DOMElement.prototype.removeChild = function (el) {
      this.remove(el)
  }
  
  module.exports = DOMElement
  
  },{"./element":47,"util":35}],47:[function(require,module,exports){
  'use strict';
  
  /**
   * This cheap replica of DOM/Builder puts me to shame :-)
   *
   * Attributes are in the element.attrs object. Children is a list of
   * either other Elements or Strings for text content.
   **/
  function Element(name, attrs) {
      this.name = name
      this.parent = null
      this.attrs = attrs || {}
      this.children = []
  }
  
  /*** Accessors ***/
  
  /**
   * if (element.is('message', 'jabber:client')) ...
   **/
  Element.prototype.is = function(name, xmlns) {
      return (this.getName() === name) &&
          (!xmlns || (this.getNS() === xmlns))
  }
  
  /* without prefix */
  Element.prototype.getName = function() {
      if (this.name.indexOf(':') >= 0)
          return this.name.substr(this.name.indexOf(':') + 1)
      else
          return this.name
  }
  
  /**
   * retrieves the namespace of the current element, upwards recursively
   **/
  Element.prototype.getNS = function() {
      if (this.name.indexOf(':') >= 0) {
          var prefix = this.name.substr(0, this.name.indexOf(':'))
          return this.findNS(prefix)
      } else {
          return this.findNS()
      }
  }
  
  /**
   * find the namespace to the given prefix, upwards recursively
   **/
  Element.prototype.findNS = function(prefix) {
      if (!prefix) {
          /* default namespace */
          if (this.attrs.xmlns)
              return this.attrs.xmlns
          else if (this.parent)
              return this.parent.findNS()
      } else {
          /* prefixed namespace */
          var attr = 'xmlns:' + prefix
          if (this.attrs[attr])
              return this.attrs[attr]
          else if (this.parent)
              return this.parent.findNS(prefix)
      }
  }
  
  /**
   * Recursiverly gets all xmlns defined, in the form of {url:prefix}
   **/
  Element.prototype.getXmlns = function() {
      var namespaces = {}
  
      if (this.parent)
          namespaces = this.parent.getXmlns()
  
      for (var attr in this.attrs) {
          var m = attr.match('xmlns:?(.*)')
          if (this.attrs.hasOwnProperty(attr) && m) {
              namespaces[this.attrs[attr]] = m[1]
          }
      }
      return namespaces
  }
  
  
  /**
   * xmlns can be null, returns the matching attribute.
   **/
  Element.prototype.getAttr = function(name, xmlns) {
      if (!xmlns)
          return this.attrs[name]
  
      var namespaces = this.getXmlns()
  
      if (!namespaces[xmlns])
          return null
  
      return this.attrs[[namespaces[xmlns], name].join(':')]
  }
  
  /**
   * xmlns can be null
   **/
  Element.prototype.getChild = function(name, xmlns) {
      return this.getChildren(name, xmlns)[0]
  }
  
  /**
   * xmlns can be null
   **/
  Element.prototype.getChildren = function(name, xmlns) {
      var result = []
      for (var i = 0; i < this.children.length; i++) {
          var child = this.children[i]
          if (child.getName &&
              (child.getName() === name) &&
              (!xmlns || (child.getNS() === xmlns)))
              result.push(child)
      }
      return result
  }
  
  /**
   * xmlns and recursive can be null
   **/
  Element.prototype.getChildByAttr = function(attr, val, xmlns, recursive) {
      return this.getChildrenByAttr(attr, val, xmlns, recursive)[0]
  }
  
  /**
   * xmlns and recursive can be null
   **/
  Element.prototype.getChildrenByAttr = function(attr, val, xmlns, recursive) {
      var result = []
      for (var i = 0; i < this.children.length; i++) {
          var child = this.children[i]
          if (child.attrs &&
              (child.attrs[attr] === val) &&
              (!xmlns || (child.getNS() === xmlns)))
              result.push(child)
          if (recursive && child.getChildrenByAttr) {
              result.push(child.getChildrenByAttr(attr, val, xmlns, true))
          }
      }
      if (recursive) result = [].concat.apply([], result)
      return result
  }
  
  Element.prototype.getChildrenByFilter = function(filter, recursive) {
      var result = []
      for (var i = 0; i < this.children.length; i++) {
          var child = this.children[i]
          if (filter(child))
              result.push(child)
          if (recursive && child.getChildrenByFilter){
              result.push(child.getChildrenByFilter(filter, true))
          }
      }
      if (recursive) {
          result = [].concat.apply([], result)
      }
      return result
  }
  
  Element.prototype.getText = function() {
      var text = ''
      for (var i = 0; i < this.children.length; i++) {
          var child = this.children[i]
          if ((typeof child === 'string') || (typeof child === 'number')) {
              text += child
          }
      }
      return text
  }
  
  Element.prototype.getChildText = function(name, xmlns) {
      var child = this.getChild(name, xmlns)
      return child ? child.getText() : null
  }
  
  /**
   * Return all direct descendents that are Elements.
   * This differs from `getChildren` in that it will exclude text nodes,
   * processing instructions, etc.
   */
  Element.prototype.getChildElements = function() {
      return this.getChildrenByFilter(function(child) {
          return child instanceof Element
      })
  }
  
  /*** Builder ***/
  
  /** returns uppermost parent */
  Element.prototype.root = function() {
      if (this.parent)
          return this.parent.root()
      else
          return this
  }
  Element.prototype.tree = Element.prototype.root
  
  /** just parent or itself */
  Element.prototype.up = function() {
      if (this.parent)
          return this.parent
      else
          return this
  }
  
  Element.prototype._getElement = function(name, attrs) {
      var element = new Element(name, attrs)
      return element
  }
  
  /** create child node and return it */
  Element.prototype.c = function(name, attrs) {
      return this.cnode(this._getElement(name, attrs))
  }
  
  Element.prototype.cnode = function(child) {
      this.children.push(child)
      child.parent = this
      return child
  }
  
  /** add text node and return element */
  Element.prototype.t = function(text) {
      this.children.push(text)
      return this
  }
  
  /*** Manipulation ***/
  
  /**
   * Either:
   *   el.remove(childEl)
   *   el.remove('author', 'urn:...')
   */
  Element.prototype.remove = function(el, xmlns) {
      var filter
      if (typeof el === 'string') {
          /* 1st parameter is tag name */
          filter = function(child) {
              return !(child.is &&
                   child.is(el, xmlns))
          }
      } else {
          /* 1st parameter is element */
          filter = function(child) {
              return child !== el
          }
      }
  
      this.children = this.children.filter(filter)
  
      return this
  }
  
  /**
   * To use in case you want the same XML data for separate uses.
   * Please refrain from this practise unless you know what you are
   * doing. Building XML with ltx is easy!
   */
  Element.prototype.clone = function() {
      var clone = this._getElement(this.name, {})
      for (var k in this.attrs) {
          if (this.attrs.hasOwnProperty(k))
              clone.attrs[k] = this.attrs[k]
      }
      for (var i = 0; i < this.children.length; i++) {
          var child = this.children[i]
          clone.cnode(child.clone ? child.clone() : child)
      }
      return clone
  }
  
  Element.prototype.text = function(val) {
      if (val && this.children.length === 1) {
          this.children[0] = val
          return this
      }
      return this.getText()
  }
  
  Element.prototype.attr = function(attr, val) {
      if (((typeof val !== 'undefined') || (val === null))) {
          if (!this.attrs) {
              this.attrs = {}
          }
          this.attrs[attr] = val
          return this
      }
      return this.attrs[attr]
  }
  
  /*** Serialization ***/
  
  Element.prototype.toString = function() {
      var s = ''
      this.write(function(c) {
          s += c
      })
      return s
  }
  
  Element.prototype.toJSON = function() {
      return {
          name: this.name,
          attrs: this.attrs,
          children: this.children.map(function(child) {
              return child && child.toJSON ? child.toJSON() : child;
          })
      }
  }
  
  Element.prototype._addChildren = function(writer) {
      writer('>')
      for (var i = 0; i < this.children.length; i++) {
          var child = this.children[i]
          /* Skip null/undefined */
          if (child || (child === 0)) {
              if (child.write) {
                  child.write(writer)
              } else if (typeof child === 'string') {
                  writer(escapeXmlText(child))
              } else if (child.toString) {
                  writer(escapeXmlText(child.toString(10)))
              }
          }
      }
      writer('</')
      writer(this.name)
      writer('>')
  }
  
  Element.prototype.write = function(writer) {
      writer('<')
      writer(this.name)
      for (var k in this.attrs) {
          var v = this.attrs[k]
          if (v || (v === '') || (v === 0)) {
              writer(' ')
              writer(k)
              writer('="')
              if (typeof v !== 'string') {
                  v = v.toString(10)
              }
              writer(escapeXml(v))
              writer('"')
          }
      }
      if (this.children.length === 0) {
          writer('/>')
      } else {
          this._addChildren(writer)
      }
  }
  
  function escapeXml(s) {
      return s.
          replace(/\&/g, '&amp;').
          replace(/</g, '&lt;').
          replace(/>/g, '&gt;').
          replace(/"/g, '&quot;').
          replace(/"/g, '&apos;')
  }
  
  function escapeXmlText(s) {
      return s.
          replace(/\&/g, '&amp;').
          replace(/</g, '&lt;').
          replace(/>/g, '&gt;')
  }
  
  exports.Element = Element
  exports.escapeXml = escapeXml
  
  },{}],48:[function(require,module,exports){
  'use strict';
  
  /* Cause browserify to bundle SAX parsers: */
  var parse = require('./parse')
  
  parse.availableSaxParsers.push(parse.bestSaxParser = require('./sax/sax_ltx'))
  
  /* SHIM */
  module.exports = require('./index')
  },{"./index":49,"./parse":50,"./sax/sax_ltx":51}],49:[function(require,module,exports){
  'use strict';
  
  var parse = require('./parse')
  
  /**
   * The only (relevant) data structure
   */
  exports.Element = require('./dom-element')
  
  /**
   * Helper
   */
  exports.escapeXml = require('./element').escapeXml
  
  /**
   * DOM parser interface
   */
  exports.parse = parse.parse
  exports.Parser = parse.Parser
  
  /**
   * SAX parser interface
   */
  exports.availableSaxParsers = parse.availableSaxParsers
  exports.bestSaxParser = parse.bestSaxParser
  
  },{"./dom-element":46,"./element":47,"./parse":50}],50:[function(require,module,exports){
  'use strict';
  
  var events = require('events')
    , util = require('util')
    , DOMElement = require('./dom-element')
  
  
  exports.availableSaxParsers = []
  exports.bestSaxParser = null
  
  var saxParsers = [
      './sax/sax_expat.js',
      './sax/sax_ltx.js',
      /*'./sax_easysax.js', './sax_node-xml.js',*/
      './sax/sax_saxjs.js'
  ]
  
  saxParsers.forEach(function(modName) {
      var mod
      try {
          mod = require(modName)
      } catch (e) {
          /* Silently missing libraries drop for debug:
          console.error(e.stack || e)
           */
      }
      if (mod) {
          exports.availableSaxParsers.push(mod)
          if (!exports.bestSaxParser) {
              exports.bestSaxParser = mod
          }
      }
  })
  
  exports.Parser = function(saxParser) {
      events.EventEmitter.call(this)
      var self = this
  
      var ParserMod = saxParser || exports.bestSaxParser
      if (!ParserMod) {
          throw new Error('No SAX parser available')
      }
      this.parser = new ParserMod()
  
      var el
      this.parser.addListener('startElement', function(name, attrs) {
          var child = new DOMElement(name, attrs)
          if (!el) {
              el = child
          } else {
              el = el.cnode(child)
          }
      })
      this.parser.addListener('endElement', function(name) {
          /* jshint -W035 */
          if (!el) {
              /* Err */
          } else if (name === el.name) {
              if (el.parent) {
                  el = el.parent
              } else if (!self.tree) {
                  self.tree = el
                  el = undefined
              }
          }
          /* jshint +W035 */
      })
      this.parser.addListener('text', function(str) {
          if (el) {
              el.t(str)
          }
      })
      this.parser.addListener('error', function(e) {
          self.error = e
          self.emit('error', e)
      })
  }
  
  util.inherits(exports.Parser, events.EventEmitter)
  
  exports.Parser.prototype.write = function(data) {
      this.parser.write(data)
  }
  
  exports.Parser.prototype.end = function(data) {
      this.parser.end(data)
  
      if (!this.error) {
          if (this.tree) {
              this.emit('tree', this.tree)
          } else {
              this.emit('error', new Error('Incomplete document'))
          }
      }
  }
  
  exports.parse = function(data, saxParser) {
      var p = new exports.Parser(saxParser)
      var result = null
        , error = null
  
      p.on('tree', function(tree) {
          result = tree
      })
      p.on('error', function(e) {
          error = e
      })
  
      p.write(data)
      p.end()
  
      if (error) {
          throw error
      } else {
          return result
      }
  }
  
  },{"./dom-element":46,"events":24,"util":35}],51:[function(require,module,exports){
  'use strict';
  
  var util = require('util')
    , events = require('events')
  
  var STATE_TEXT = 0,
      STATE_IGNORE_TAG = 1,
      STATE_TAG_NAME = 2,
      STATE_TAG = 3,
      STATE_ATTR_NAME = 4,
      STATE_ATTR_EQ = 5,
      STATE_ATTR_QUOT = 6,
      STATE_ATTR_VALUE = 7
  
  var SaxLtx = module.exports = function SaxLtx() {
      events.EventEmitter.call(this)
  
      var state = STATE_TEXT, remainder
      var tagName, attrs, endTag, selfClosing, attrQuote
      var recordStart = 0
      var attrName
  
      this._handleTagOpening = function(endTag, tagName, attrs) {
          if (!endTag) {
              this.emit('startElement', tagName, attrs)
              if (selfClosing) {
                  this.emit('endElement', tagName)
              }
          } else {
              this.emit('endElement', tagName)
          }
      }
  
      this.write = function(data) {
          /* jshint -W071 */
          /* jshint -W074 */
          if (typeof data !== 'string') {
              data = data.toString()
          }
          var pos = 0
  
          /* Anything from previous write()? */
          if (remainder) {
              data = remainder + data
              pos += remainder.length
              remainder = null
          }
  
          function endRecording() {
              if (typeof recordStart === 'number') {
                  var recorded = data.slice(recordStart, pos)
                  recordStart = undefined
                  return recorded
              }
          }
  
          for(; pos < data.length; pos++) {
              var c = data.charCodeAt(pos)
              //console.log("state", state, "c", c, data[pos])
              switch(state) {
              case STATE_TEXT:
                  if (c === 60 /* < */) {
                      var text = endRecording()
                      if (text) {
                          this.emit('text', unescapeXml(text))
                      }
                      state = STATE_TAG_NAME
                      recordStart = pos + 1
                      attrs = {}
                  }
                  break
              case STATE_TAG_NAME:
                  if (c === 47 /* / */ && recordStart === pos) {
                      recordStart = pos + 1
                      endTag = true
                  } else if (c === 33 /* ! */ || c === 63 /* ? */) {
                      recordStart = undefined
                      state = STATE_IGNORE_TAG
                  } else if (c <= 32 || c === 47 /* / */ || c === 62 /* > */) {
                      tagName = endRecording()
                      pos--
                      state = STATE_TAG
                  }
                  break
              case STATE_IGNORE_TAG:
                  if (c === 62 /* > */) {
                      state = STATE_TEXT
                  }
                  break
              case STATE_TAG:
                  if (c === 62 /* > */) {
                      this._handleTagOpening(endTag, tagName, attrs)
                      tagName = undefined
                      attrs = undefined
                      endTag = undefined
                      selfClosing = undefined
                      state = STATE_TEXT
                      recordStart = pos + 1
                  } else if (c === 47 /* / */) {
                      selfClosing = true
                  } else if (c > 32) {
                      recordStart = pos
                      state = STATE_ATTR_NAME
                  }
                  break
              case STATE_ATTR_NAME:
                  if (c <= 32 || c === 61 /* = */) {
                      attrName = endRecording()
                      pos--
                      state = STATE_ATTR_EQ
                  }
                  break
              case STATE_ATTR_EQ:
                  if (c === 61 /* = */) {
                      state = STATE_ATTR_QUOT
                  }
                  break
              case STATE_ATTR_QUOT:
                  if (c === 34 /* " */ || c === 39 /* ' */) {
                      attrQuote = c
                      state = STATE_ATTR_VALUE
                      recordStart = pos + 1
                  }
                  break
              case STATE_ATTR_VALUE:
                  if (c === attrQuote) {
                      var value = unescapeXml(endRecording())
                      attrs[attrName] = value
                      attrName = undefined
                      state = STATE_TAG
                  }
                  break
              }
          }
  
          if (typeof recordStart === 'number' &&
              recordStart <= data.length) {
  
              remainder = data.slice(recordStart)
              recordStart = 0
          }
      }
  
      /*var origEmit = this.emit
      this.emit = function() {
      console.log('ltx', arguments)
      origEmit.apply(this, arguments)
      }*/
  }
  util.inherits(SaxLtx, events.EventEmitter)
  
  
  SaxLtx.prototype.end = function(data) {
      if (data) {
          this.write(data)
      }
  
      /* Uh, yeah */
      this.write = function() {}
  }
  
  function unescapeXml(s) {
      return s.
          replace(/\&(amp|#38);/g, '&').
          replace(/\&(lt|#60);/g, '<').
          replace(/\&(gt|#62);/g, '>').
          replace(/\&(quot|#34);/g, '"').
          replace(/\&(apos|#39);/g, '\'').
          replace(/\&(nbsp|#160);/g, '\n')
  }
  
  },{"events":24,"util":35}],52:[function(require,module,exports){
  'use strict';
  
  var log = require('debug')('node-stringprep')
  
  // from unicode/uidna.h
  var UIDNA_ALLOW_UNASSIGNED = 1
  var UIDNA_USE_STD3_RULES = 2
  
  try {
      var bindings = require('bindings')('node_stringprep.node')
  } catch (ex) {
      console.warn(
          'Cannot load StringPrep-' +
          require('./package.json').version +
          ' bindings (using fallback). You may need to ' +
          '`npm install node-stringprep`'
      )
      log(ex)
  }
  
  var toUnicode = function(value, options) {
      options = options || {}
      try {
          return bindings.toUnicode(value,
              (options.allowUnassigned && UIDNA_ALLOW_UNASSIGNED) | 0)
      } catch (e) {
          return value
      }
  }
  
  var toASCII = function(value, options) {
      options = options || {}
      try {
          return bindings.toASCII(value,
              (options.allowUnassigned && UIDNA_ALLOW_UNASSIGNED) |
              (options.useSTD3Rules && UIDNA_USE_STD3_RULES))
      } catch (e) {
          if (options.throwIfError) {
              throw e
          } else {
              return value
          }
      }
  }
  
  var StringPrep = function(operation) {
      this.operation = operation
      try {
          this.stringPrep = new bindings.StringPrep(this.operation)
      } catch (e) {
          this.stringPrep = null
          log('Operation does not exist', operation, e)
      }
  }
  
  StringPrep.prototype.UNKNOWN_PROFILE_TYPE = 'Unknown profile type'
  StringPrep.prototype.UNHANDLED_FALLBACK = 'Unhandled JS fallback'
  StringPrep.prototype.LIBICU_NOT_AVAILABLE = 'libicu unavailable'
  
  StringPrep.prototype.useJsFallbacks = true
  
  StringPrep.prototype.prepare = function(value) {
      this.value = value
      try {
          if (this.stringPrep) {
              return this.stringPrep.prepare(this.value)
          }
      } catch (e) {}
      if (false === this.useJsFallbacks) {
          throw new Error(this.LIBICU_NOT_AVAILABLE)
      }
      return this.jsFallback()
  }
  
  StringPrep.prototype.isNative = function() {
      return (null !== this.stringPrep)
  }
  
  StringPrep.prototype.jsFallback = function() {
      switch (this.operation) {
          case 'nameprep':
          case 'nodeprep':
              return this.value.toLowerCase()
          case 'resourceprep':
              return this.value
          case 'nfs4_cs_prep':
          case 'nfs4_cis_prep':
          case 'nfs4_mixed_prep prefix':
          case 'nfs4_mixed_prep suffix':
          case 'iscsi':
          case 'mib':
          case 'saslprep':
          case 'trace':
          case 'ldap':
          case 'ldapci':
              throw new Error(this.UNHANDLED_FALLBACK)
          default:
              throw new Error(this.UNKNOWN_PROFILE_TYPE)
      }
  }
  
  StringPrep.prototype.disableJsFallbacks = function() {
      this.useJsFallbacks = false
  }
  
  StringPrep.prototype.enableJsFallbacks = function() {
      this.useJsFallbacks = true
  }
  
  module.exports = {
      toUnicode: toUnicode,
      toASCII: toASCII,
      StringPrep: StringPrep
  }
  
  },{"./package.json":57,"bindings":53,"debug":54}],53:[function(require,module,exports){
  var process=require("__browserify_process"),__filename="/node_modules/node-xmpp-core/node_modules/node-stringprep/node_modules/bindings/bindings.js";
  /**
   * Module dependencies.
   */
  
  var fs = require('fs')
    , path = require('path')
    , join = path.join
    , dirname = path.dirname
    , exists = fs.existsSync || path.existsSync
    , defaults = {
          arrow: process.env.NODE_BINDINGS_ARROW || ' → '
        , compiled: process.env.NODE_BINDINGS_COMPILED_DIR || 'compiled'
        , platform: process.platform
        , arch: process.arch
        , version: process.versions.node
        , bindings: 'bindings.node'
        , try: [
            // node-gyp's linked version in the "build" dir
            [ 'module_root', 'build', 'bindings' ]
            // node-waf and gyp_addon (a.k.a node-gyp)
          , [ 'module_root', 'build', 'Debug', 'bindings' ]
          , [ 'module_root', 'build', 'Release', 'bindings' ]
            // Debug files, for development (legacy behavior, remove for node v0.9)
          , [ 'module_root', 'out', 'Debug', 'bindings' ]
          , [ 'module_root', 'Debug', 'bindings' ]
            // Release files, but manually compiled (legacy behavior, remove for node v0.9)
          , [ 'module_root', 'out', 'Release', 'bindings' ]
          , [ 'module_root', 'Release', 'bindings' ]
            // Legacy from node-waf, node <= 0.4.x
          , [ 'module_root', 'build', 'default', 'bindings' ]
            // Production "Release" buildtype binary (meh...)
          , [ 'module_root', 'compiled', 'version', 'platform', 'arch', 'bindings' ]
          ]
      }
  
  /**
   * The main `bindings()` function loads the compiled bindings for a given module.
   * It uses V8's Error API to determine the parent filename that this function is
   * being invoked from, which is then used to find the root directory.
   */
  
  function bindings (opts) {
  
    // Argument surgery
    if (typeof opts == 'string') {
      opts = { bindings: opts }
    } else if (!opts) {
      opts = {}
    }
    opts.__proto__ = defaults
  
    // Get the module root
    if (!opts.module_root) {
      opts.module_root = exports.getRoot(exports.getFileName())
    }
  
    // Ensure the given bindings name ends with .node
    if (path.extname(opts.bindings) != '.node') {
      opts.bindings += '.node'
    }
  
    var tries = []
      , i = 0
      , l = opts.try.length
      , n
      , b
      , err
  
    for (; i<l; i++) {
      n = join.apply(null, opts.try[i].map(function (p) {
        return opts[p] || p
      }))
      tries.push(n)
      try {
        b = opts.path ? require.resolve(n) : require(n)
        if (!opts.path) {
          b.path = n
        }
        return b
      } catch (e) {
        if (!/not find/i.test(e.message)) {
          throw e
        }
      }
    }
  
    err = new Error('Could not locate the bindings file. Tried:\n'
      + tries.map(function (a) { return opts.arrow + a }).join('\n'))
    err.tries = tries
    throw err
  }
  module.exports = exports = bindings
  
  
  /**
   * Gets the filename of the JavaScript file that invokes this function.
   * Used to help find the root directory of a module.
   */
  
  exports.getFileName = function getFileName () {
    var origPST = Error.prepareStackTrace
      , origSTL = Error.stackTraceLimit
      , dummy = {}
      , fileName
  
    Error.stackTraceLimit = 10
  
    Error.prepareStackTrace = function (e, st) {
      for (var i=0, l=st.length; i<l; i++) {
        fileName = st[i].getFileName()
        if (fileName !== __filename) {
          return
        }
      }
    }
  
    // run the 'prepareStackTrace' function above
    Error.captureStackTrace(dummy)
    dummy.stack
  
    // cleanup
    Error.prepareStackTrace = origPST
    Error.stackTraceLimit = origSTL
  
    return fileName
  }
  
  /**
   * Gets the root directory of a module, given an arbitrary filename
   * somewhere in the module tree. The "root directory" is the directory
   * containing the `package.json` file.
   *
   *   In:  /home/nate/node-native-module/lib/index.js
   *   Out: /home/nate/node-native-module
   */
  
  exports.getRoot = function getRoot (file) {
    var dir = dirname(file)
      , prev
    while (true) {
      if (dir === '.') {
        // Avoids an infinite loop in rare cases, like the REPL
        dir = process.cwd()
      }
      if (exists(join(dir, 'package.json')) || exists(join(dir, 'node_modules'))) {
        // Found the 'package.json' file or 'node_modules' dir; we're done
        return dir
      }
      if (prev === dir) {
        // Got to the top
        throw new Error('Could not find module root given file: "' + file
                      + '". Do you have a `package.json` file? ')
      }
      // Try the parent dir next
      prev = dir
      dir = join(dir, '..')
    }
  }
  
  },{"__browserify_process":26,"fs":16,"path":30}],54:[function(require,module,exports){
  module.exports=require(36)
  },{"./debug":55}],55:[function(require,module,exports){
  module.exports=require(37)
  },{"ms":56}],56:[function(require,module,exports){
  module.exports=require(38)
  },{}],57:[function(require,module,exports){
  module.exports={
    "name": "node-stringprep",
    "version": "0.5.4",
    "main": "index.js",
    "description": "ICU StringPrep profiles",
    "keywords": [
      "unicode",
      "stringprep",
      "icu"
    ],
    "scripts": {
      "test": "grunt test",
      "install": "node-gyp rebuild"
    },
    "dependencies": {
      "nan": "~1.2.0",
      "bindings": "~1.1.1",
      "debug": "~2.0.0"
    },
    "devDependencies": {
      "proxyquire": "~0.5.2",
      "grunt-mocha-cli": "~1.3.0",
      "grunt-contrib-jshint": "~0.7.2",
      "should": "~2.1.1",
      "grunt": "~0.4.2"
    },
    "repository": {
      "type": "git",
      "path": "git://github.com/node-xmpp/node-stringprep.git"
    },
    "homepage": "http://github.com/node-xmpp/node-stringprep",
    "bugs": {
      "url": "http://github.com/node-xmpp/node-stringprep/issues"
    },
    "author": {
      "name": "Lloyd Watkin",
      "email": "lloyd@evilprofessor.co.uk",
      "url": "http://evilprofessor.co.uk"
    },
    "licenses": [
      {
        "type": "MIT"
      }
    ],
    "engines": {
      "node": ">=0.8"
    },
    "gypfile": true,
    "_id": "node-stringprep@0.5.4",
    "dist": {
      "shasum": "dd03b3d8f6f83137754cc1ea1a55675447b0ab92",
      "tarball": "http://registry.npmjs.org/node-stringprep/-/node-stringprep-0.5.4.tgz"
    },
    "_from": "node-stringprep@>=0.5.2 <0.6.0",
    "_npmVersion": "1.4.3",
    "_npmUser": {
      "name": "lloydwatkin",
      "email": "lloyd@evilprofessor.co.uk"
    },
    "maintainers": [
      {
        "name": "astro",
        "email": "astro@spaceboyz.net"
      },
      {
        "name": "lloydwatkin",
        "email": "lloyd@evilprofessor.co.uk"
      }
    ],
    "directories": {},
    "_shasum": "dd03b3d8f6f83137754cc1ea1a55675447b0ab92",
    "_resolved": "https://registry.npmjs.org/node-stringprep/-/node-stringprep-0.5.4.tgz"
  }
  
  },{}],58:[function(require,module,exports){
  var EventEmitter = require('events').EventEmitter
  var backoff = require('backoff')
  var noop = function () {}
  
  module.exports =
  function (createConnection) {
    return function (opts, onConnect) {
      onConnect = 'function' == typeof opts ? opts : onConnect
      opts = 'object' == typeof opts ? opts : {initialDelay: 1e3, maxDelay: 30e3}
      if(!onConnect)
        onConnect = opts.onConnect
  
      var emitter = opts.emitter || new EventEmitter()
      emitter.connected = false
      emitter.reconnect = true
  
      if(onConnect)
        emitter.on('connect', onConnect)
  
      var backoffMethod = (backoff[opts.type] || backoff.fibonacci) (opts)
  
      backoffMethod.on('backoff', function (n, d) {
        emitter.emit('backoff', n, d)
      })
  
      var args
      var cleanup = noop
      backoffMethod.on('ready', attempt)
      function attempt (n, delay) {
        if(!emitter.reconnect) return
  
        cleanup()
        emitter.emit('reconnect', n, delay)
        var con = createConnection.apply(null, args)
        if (con !== emitter._connection)
          emitter.emit('connection', con)
        emitter._connection = con
  
        cleanup = onCleanup
        function onCleanup(err) {
          cleanup = noop
          con.removeListener('connect', connect)
          con.removeListener('error', onDisconnect)
          con.removeListener('close', onDisconnect)
          con.removeListener('end'  , onDisconnect)
  
          //hack to make http not crash.
          //HTTP IS THE WORST PROTOCOL.
          if(con.constructor.name == 'Request')
            con.on('error', noop)
  
        }
  
        function onDisconnect (err) {
          emitter.connected = false
          onCleanup(err)
  
          //emit disconnect before checking reconnect, so user has a chance to decide not to.
          emitter.emit('disconnect', err)
  
          if(!emitter.reconnect) return
          try { backoffMethod.backoff() } catch (_) { }
        }
  
        function connect() {
          backoffMethod.reset()
          emitter.connected = true
          if(onConnect)
            con.removeListener('connect', onConnect)
          emitter.emit('connect', con)
        }
  
        con
          .on('error', onDisconnect)
          .on('close', onDisconnect)
          .on('end'  , onDisconnect)
  
        if(opts.immediate || con.constructor.name == 'Request') {
          emitter.connected = true
          emitter.emit('connect', con)
          con.once('data', function () {
            //this is the only way to know for sure that data is coming...
            backoffMethod.reset()
          })
        } else {
          con.on('connect', connect)
        }
      }
  
      emitter.connect =
      emitter.listen = function () {
        this.reconnect = true
        backoffMethod.reset()
        args = [].slice.call(arguments)
        attempt(0, 0)
        return emitter
      }
  
      //force reconnection
  
      emitter.end =
      emitter.disconnect = function () {
        emitter.reconnect = false
  
        if(emitter._connection)
          emitter._connection.end()
  
        emitter.emit('disconnect')
        return emitter
      }
  
      return emitter
    }
  
  }
  
  },{"backoff":59,"events":24}],59:[function(require,module,exports){
  /*
   * Copyright (c) 2012 Mathieu Turcotte
   * Licensed under the MIT license.
   */
  
  var Backoff = require('./lib/backoff');
  var ExponentialBackoffStrategy = require('./lib/strategy/exponential');
  var FibonacciBackoffStrategy = require('./lib/strategy/fibonacci');
  var FunctionCall = require('./lib/function_call.js');
  
  module.exports.Backoff = Backoff;
  module.exports.FunctionCall = FunctionCall;
  module.exports.FibonacciStrategy = FibonacciBackoffStrategy;
  module.exports.ExponentialStrategy = ExponentialBackoffStrategy;
  
  /**
   * Constructs a Fibonacci backoff.
   * @param options Fibonacci backoff strategy arguments.
   * @return The fibonacci backoff.
   * @see FibonacciBackoffStrategy
   */
  module.exports.fibonacci = function(options) {
      return new Backoff(new FibonacciBackoffStrategy(options));
  };
  
  /**
   * Constructs an exponential backoff.
   * @param options Exponential strategy arguments.
   * @return The exponential backoff.
   * @see ExponentialBackoffStrategy
   */
  module.exports.exponential = function(options) {
      return new Backoff(new ExponentialBackoffStrategy(options));
  };
  
  /**
   * Constructs a FunctionCall for the given function and arguments.
   * @param fn The function to wrap in a backoff handler.
   * @param vargs The function's arguments (var args).
   * @param callback The function's callback.
   * @return The FunctionCall instance.
   */
  module.exports.call = function(fn, vargs, callback) {
      var args = Array.prototype.slice.call(arguments);
      fn = args[0];
      vargs = args.slice(1, args.length - 1);
      callback = args[args.length - 1];
      return new FunctionCall(fn, vargs, callback);
  };
  
  },{"./lib/backoff":60,"./lib/function_call.js":61,"./lib/strategy/exponential":62,"./lib/strategy/fibonacci":63}],60:[function(require,module,exports){
  /*
   * Copyright (c) 2012 Mathieu Turcotte
   * Licensed under the MIT license.
   */
  
  var events = require('events');
  var util = require('util');
  
  /**
   * Backoff driver.
   * @param backoffStrategy Backoff delay generator/strategy.
   * @constructor
   */
  function Backoff(backoffStrategy) {
      events.EventEmitter.call(this);
  
      this.backoffStrategy_ = backoffStrategy;
      this.maxNumberOfRetry_ = -1;
      this.backoffNumber_ = 0;
      this.backoffDelay_ = 0;
      this.timeoutID_ = -1;
  
      this.handlers = {
          backoff: this.onBackoff_.bind(this)
      };
  }
  util.inherits(Backoff, events.EventEmitter);
  
  /**
   * Sets a limit, greater than 0, on the maximum number of backoffs. A 'fail'
   * event will be emitted when the limit is reached.
   * @param maxNumberOfRetry The maximum number of backoffs.
   */
  Backoff.prototype.failAfter = function(maxNumberOfRetry) {
      if (maxNumberOfRetry < 1) {
          throw new Error('Maximum number of retry must be greater than 0. ' +
                          'Actual: ' + maxNumberOfRetry);
      }
  
      this.maxNumberOfRetry_ = maxNumberOfRetry;
  };
  
  /**
   * Starts a backoff operation.
   * @param err Optional paramater to let the listeners know why the backoff
   *     operation was started.
   */
  Backoff.prototype.backoff = function(err) {
      if (this.timeoutID_ !== -1) {
          throw new Error('Backoff in progress.');
      }
  
      if (this.backoffNumber_ === this.maxNumberOfRetry_) {
          this.emit('fail', err);
          this.reset();
      } else {
          this.backoffDelay_ = this.backoffStrategy_.next();
          this.timeoutID_ = setTimeout(this.handlers.backoff, this.backoffDelay_);
          this.emit('backoff', this.backoffNumber_, this.backoffDelay_, err);
      }
  };
  
  /**
   * Handles the backoff timeout completion.
   * @private
   */
  Backoff.prototype.onBackoff_ = function() {
      this.timeoutID_ = -1;
      this.emit('ready', this.backoffNumber_, this.backoffDelay_);
      this.backoffNumber_++;
  };
  
  /**
   * Stops any backoff operation and resets the backoff delay to its inital
   * value.
   */
  Backoff.prototype.reset = function() {
      this.backoffNumber_ = 0;
      this.backoffStrategy_.reset();
      clearTimeout(this.timeoutID_);
      this.timeoutID_ = -1;
  };
  
  module.exports = Backoff;
  
  },{"events":24,"util":35}],61:[function(require,module,exports){
  /*
   * Copyright (c) 2012 Mathieu Turcotte
   * Licensed under the MIT license.
   */
  
  var events = require('events');
  var util = require('util');
  
  var Backoff = require('./backoff');
  var FibonacciBackoffStrategy = require('./strategy/fibonacci');
  
  /**
   * Returns true if the specified value is a function
   * @param val Variable to test.
   * @return Whether variable is a function.
   */
  function isFunction(val) {
      return typeof val == 'function';
  }
  
  /**
   * Manages the calling of a function in a backoff loop.
   * @param fn Function to wrap in a backoff handler.
   * @param args Array of function's arguments.
   * @param callback Function's callback.
   * @constructor
   */
  function FunctionCall(fn, args, callback) {
      events.EventEmitter.call(this);
  
      if (!isFunction(fn)) {
          throw new Error('fn should be a function.' +
                          'Actual: ' + typeof fn);
      }
  
      if (!isFunction(callback)) {
          throw new Error('callback should be a function.' +
                          'Actual: ' + typeof fn);
      }
  
      this.function_ = fn;
      this.arguments_ = args;
      this.callback_ = callback;
      this.results_ = [];
  
      this.backoff_ = null;
      this.strategy_ = null;
      this.failAfter_ = -1;
  
      this.state_ = FunctionCall.State_.PENDING;
  }
  util.inherits(FunctionCall, events.EventEmitter);
  
  /**
   * Enum of states in which the FunctionCall can be.
   * @private
   */
  FunctionCall.State_ = {
      PENDING: 0,
      RUNNING: 1,
      COMPLETED: 2,
      ABORTED: 3
  };
  
  /**
   * @return Whether the call is pending.
   */
  FunctionCall.prototype.isPending = function() {
      return this.state_ == FunctionCall.State_.PENDING;
  };
  
  /**
   * @return Whether the call is in progress.
   */
  FunctionCall.prototype.isRunning = function() {
      return this.state_ == FunctionCall.State_.RUNNING;
  };
  
  /**
   * @return Whether the call is completed.
   */
  FunctionCall.prototype.isCompleted = function() {
      return this.state_ == FunctionCall.State_.COMPLETED;
  };
  
  /**
   * @return Whether the call is aborted.
   */
  FunctionCall.prototype.isAborted = function() {
      return this.state_ == FunctionCall.State_.ABORTED;
  };
  
  /**
   * Sets the backoff strategy.
   * @param strategy The backoff strategy to use.
   * @return Itself for chaining.
   */
  FunctionCall.prototype.setStrategy = function(strategy) {
      if (!this.isPending()) {
          throw new Error('FunctionCall in progress.');
      }
      this.strategy_ = strategy;
      return this;
  };
  
  /**
   * Returns all intermediary results returned by the wrapped function since
   * the initial call.
   * @return An array of intermediary results.
   */
  FunctionCall.prototype.getResults = function() {
      return this.results_.concat();
  };
  
  /**
   * Sets the backoff limit.
   * @param maxNumberOfRetry The maximum number of backoffs.
   * @return Itself for chaining.
   */
  FunctionCall.prototype.failAfter = function(maxNumberOfRetry) {
      if (!this.isPending()) {
          throw new Error('FunctionCall in progress.');
      }
      this.failAfter_ = maxNumberOfRetry;
      return this;
  };
  
  /**
   * Aborts the call.
   */
  FunctionCall.prototype.abort = function() {
      if (this.isCompleted()) {
          throw new Error('FunctionCall already completed.');
      }
  
      if (this.isRunning()) {
          this.backoff_.reset();
      }
  
      this.state_ = FunctionCall.State_.ABORTED;
  };
  
  /**
   * Initiates the call to the wrapped function.
   * @param backoffFactory Optional factory function used to create the backoff
   *     instance.
   */
  FunctionCall.prototype.start = function(backoffFactory) {
      if (this.isAborted()) {
          throw new Error('FunctionCall aborted.');
      } else if (!this.isPending()) {
          throw new Error('FunctionCall already started.');
      }
  
      var strategy = this.strategy_ || new FibonacciBackoffStrategy();
  
      this.backoff_ = backoffFactory ?
          backoffFactory(strategy) :
          new Backoff(strategy);
  
      this.backoff_.on('ready', this.doCall_.bind(this));
      this.backoff_.on('fail', this.doCallback_.bind(this));
      this.backoff_.on('backoff', this.handleBackoff_.bind(this));
  
      if (this.failAfter_ > 0) {
          this.backoff_.failAfter(this.failAfter_);
      }
  
      this.state_ = FunctionCall.State_.RUNNING;
      this.doCall_();
  };
  
  /**
   * Calls the wrapped function.
   * @private
   */
  FunctionCall.prototype.doCall_ = function() {
      var eventArgs = ['call'].concat(this.arguments_);
      events.EventEmitter.prototype.emit.apply(this, eventArgs);
      var callback = this.handleFunctionCallback_.bind(this);
      this.function_.apply(null, this.arguments_.concat(callback));
  };
  
  /**
   * Calls the wrapped function's callback with the last result returned by the
   * wrapped function.
   * @private
   */
  FunctionCall.prototype.doCallback_ = function() {
      var args = this.results_[this.results_.length - 1];
      this.callback_.apply(null, args);
  };
  
  /**
   * Handles wrapped function's completion. This method acts as a replacement
   * for the original callback function.
   * @private
   */
  FunctionCall.prototype.handleFunctionCallback_ = function() {
      if (this.isAborted()) {
          return;
      }
  
      var args = Array.prototype.slice.call(arguments);
      this.results_.push(args); // Save callback arguments.
      events.EventEmitter.prototype.emit.apply(this, ['callback'].concat(args));
  
      if (args[0]) {
          this.backoff_.backoff(args[0]);
      } else {
          this.state_ = FunctionCall.State_.COMPLETED;
          this.doCallback_();
      }
  };
  
  /**
   * Handles backoff event.
   * @param number Backoff number.
   * @param delay Backoff delay.
   * @param err The error that caused the backoff.
   * @private
   */
  FunctionCall.prototype.handleBackoff_ = function(number, delay, err) {
      this.emit('backoff', number, delay, err);
  };
  
  module.exports = FunctionCall;
  
  },{"./backoff":60,"./strategy/fibonacci":63,"events":24,"util":35}],62:[function(require,module,exports){
  /*
   * Copyright (c) 2012 Mathieu Turcotte
   * Licensed under the MIT license.
   */
  
  var util = require('util');
  
  var BackoffStrategy = require('./strategy');
  
  /**
   * Exponential backoff strategy.
   * @extends BackoffStrategy
   */
  function ExponentialBackoffStrategy(options) {
      BackoffStrategy.call(this, options);
      this.backoffDelay_ = 0;
      this.nextBackoffDelay_ = this.getInitialDelay();
  }
  util.inherits(ExponentialBackoffStrategy, BackoffStrategy);
  
  /** @inheritDoc */
  ExponentialBackoffStrategy.prototype.next_ = function() {
      this.backoffDelay_ = Math.min(this.nextBackoffDelay_, this.getMaxDelay());
      this.nextBackoffDelay_ = this.backoffDelay_ * 2;
      return this.backoffDelay_;
  };
  
  /** @inheritDoc */
  ExponentialBackoffStrategy.prototype.reset_ = function() {
      this.backoffDelay_ = 0;
      this.nextBackoffDelay_ = this.getInitialDelay();
  };
  
  module.exports = ExponentialBackoffStrategy;
  
  },{"./strategy":64,"util":35}],63:[function(require,module,exports){
  /*
   * Copyright (c) 2012 Mathieu Turcotte
   * Licensed under the MIT license.
   */
  
  var util = require('util');
  
  var BackoffStrategy = require('./strategy');
  
  /**
   * Fibonacci backoff strategy.
   * @extends BackoffStrategy
   */
  function FibonacciBackoffStrategy(options) {
      BackoffStrategy.call(this, options);
      this.backoffDelay_ = 0;
      this.nextBackoffDelay_ = this.getInitialDelay();
  }
  util.inherits(FibonacciBackoffStrategy, BackoffStrategy);
  
  /** @inheritDoc */
  FibonacciBackoffStrategy.prototype.next_ = function() {
      var backoffDelay = Math.min(this.nextBackoffDelay_, this.getMaxDelay());
      this.nextBackoffDelay_ += this.backoffDelay_;
      this.backoffDelay_ = backoffDelay;
      return backoffDelay;
  };
  
  /** @inheritDoc */
  FibonacciBackoffStrategy.prototype.reset_ = function() {
      this.nextBackoffDelay_ = this.getInitialDelay();
      this.backoffDelay_ = 0;
  };
  
  module.exports = FibonacciBackoffStrategy;
  
  },{"./strategy":64,"util":35}],64:[function(require,module,exports){
  /*
   * Copyright (c) 2012 Mathieu Turcotte
   * Licensed under the MIT license.
   */
  
  var events = require('events');
  var util = require('util');
  
  function isDef(value) {
      return value !== undefined && value !== null;
  }
  
  /**
   * Abstract class defining the skeleton for all backoff strategies.
   * @param options Backoff strategy options.
   * @param options.randomisationFactor The randomisation factor, must be between
   * 0 and 1.
   * @param options.initialDelay The backoff initial delay, in milliseconds.
   * @param options.maxDelay The backoff maximal delay, in milliseconds.
   * @constructor
   */
  function BackoffStrategy(options) {
      options = options || {};
  
      if (isDef(options.initialDelay) && options.initialDelay < 1) {
          throw new Error('The initial timeout must be greater than 0.');
      } else if (isDef(options.maxDelay) && options.maxDelay < 1) {
          throw new Error('The maximal timeout must be greater than 0.');
      }
  
      this.initialDelay_ = options.initialDelay || 100;
      this.maxDelay_ = options.maxDelay || 10000;
  
      if (this.maxDelay_ <= this.initialDelay_) {
          throw new Error('The maximal backoff delay must be ' +
                          'greater than the initial backoff delay.');
      }
  
      if (isDef(options.randomisationFactor) &&
          (options.randomisationFactor < 0 || options.randomisationFactor > 1)) {
          throw new Error('The randomisation factor must be between 0 and 1.');
      }
  
      this.randomisationFactor_ = options.randomisationFactor || 0;
  }
  
  /**
   * Retrieves the maximal backoff delay.
   * @return The maximal backoff delay, in milliseconds.
   */
  BackoffStrategy.prototype.getMaxDelay = function() {
      return this.maxDelay_;
  };
  
  /**
   * Retrieves the initial backoff delay.
   * @return The initial backoff delay, in milliseconds.
   */
  BackoffStrategy.prototype.getInitialDelay = function() {
      return this.initialDelay_;
  };
  
  /**
   * Template method that computes the next backoff delay.
   * @return The backoff delay, in milliseconds.
   */
  BackoffStrategy.prototype.next = function() {
      var backoffDelay = this.next_();
      var randomisationMultiple = 1 + Math.random() * this.randomisationFactor_;
      var randomizedDelay = Math.round(backoffDelay * randomisationMultiple);
      return randomizedDelay;
  };
  
  /**
   * Computes the next backoff delay.
   * @return The backoff delay, in milliseconds.
   * @protected
   */
  BackoffStrategy.prototype.next_ = function() {
      throw new Error('BackoffStrategy.next_() unimplemented.');
  };
  
  /**
   * Template method that resets the backoff delay to its initial value.
   */
  BackoffStrategy.prototype.reset = function() {
      this.reset_();
  };
  
  /**
   * Resets the backoff delay to its initial value.
   * @protected
   */
  BackoffStrategy.prototype.reset_ = function() {
      throw new Error('BackoffStrategy.reset_() unimplemented.');
  };
  
  module.exports = BackoffStrategy;
  
  },{"events":24,"util":35}],65:[function(require,module,exports){
  var process=require("__browserify_process");'use strict';
  
  module.exports = connect;
  connect.connect = connect;
  
  /* this whole file only exists because tls.start
   * doens't exists and tls.connect cannot start server
   * connections
   *
   * copied from _tls_wrap.js
   */
  
  // Target API:
  //
  //  var s = require('net').createStream(25, 'smtp.example.com')
  //  s.on('connect', function() {
  //   require('tls-connect')(s, {credentials:creds, isServer:false}, function() {
  //      if (!s.authorized) {
  //        s.destroy()
  //        return
  //      }
  //
  //      s.end("hello world\n")
  //    })
  //  })
  
  var net = require('net')
  var tls = require('tls')
  var util = require('util')
  var assert = require('assert')
  var crypto = require('crypto')
  
  // Returns an array [options] or [options, cb]
  // It is the same as the argument of Socket.prototype.connect().
  function __normalizeConnectArgs(args) {
    var options = {};
  
    if (typeof(args[0]) == 'object') {
      // connect(options, [cb])
      options = args[0];
    } else if (isPipeName(args[0])) {
      // connect(path, [cb]);
      options.path = args[0];
    } else {
      // connect(port, [host], [cb])
      options.port = args[0];
      if (typeof(args[1]) === 'string') {
        options.host = args[1];
      }
    }
  
    var cb = args[args.length - 1];
    return typeof(cb) === 'function' ? [options, cb] : [options];
  }
  
  function __checkServerIdentity(host, cert) {
    // Create regexp to much hostnames
    function regexpify(host, wildcards) {
      // Add trailing dot (make hostnames uniform)
      if (!/\.$/.test(host)) host += '.';
  
      // The same applies to hostname with more than one wildcard,
      // if hostname has wildcard when wildcards are not allowed,
      // or if there are less than two dots after wildcard (i.e. *.com or *d.com)
      //
      // also
      //
      // "The client SHOULD NOT attempt to match a presented identifier in
      // which the wildcard character comprises a label other than the
      // left-most label (e.g., do not match bar.*.example.net)."
      // RFC6125
      if (!wildcards && /\*/.test(host) || /[\.\*].*\*/.test(host) ||
          /\*/.test(host) && !/\*.*\..+\..+/.test(host)) {
        return /$./;
      }
  
      // Replace wildcard chars with regexp's wildcard and
      // escape all characters that have special meaning in regexps
      // (i.e. '.', '[', '{', '*', and others)
      var re = host.replace(
          /\*([a-z0-9\\-_\.])|[\.,\-\\\^\$+?*\[\]\(\):!\|{}]/g,
          function(all, sub) {
            if (sub) return '[a-z0-9\\-_]*' + (sub === '-' ? '\\-' : sub);
            return '\\' + all;
          });
  
      return new RegExp('^' + re + '$', 'i');
    }
  
    var dnsNames = [],
        uriNames = [],
        ips = [],
        matchCN = true,
        valid = false;
  
    // There're several names to perform check against:
    // CN and altnames in certificate extension
    // (DNS names, IP addresses, and URIs)
    //
    // Walk through altnames and generate lists of those names
    if (cert.subjectaltname) {
      cert.subjectaltname.split(/, /g).forEach(function(altname) {
        if (/^DNS:/.test(altname)) {
          dnsNames.push(altname.slice(4));
        } else if (/^IP Address:/.test(altname)) {
          ips.push(altname.slice(11));
        } else if (/^URI:/.test(altname)) {
          var uri = url.parse(altname.slice(4));
          if (uri) uriNames.push(uri.hostname);
        }
      });
    }
  
    // If hostname is an IP address, it should be present in the list of IP
    // addresses.
    if (net.isIP(host)) {
      valid = ips.some(function(ip) {
        return ip === host;
      });
    } else {
      // Transform hostname to canonical form
      if (!/\.$/.test(host)) host += '.';
  
      // Otherwise check all DNS/URI records from certificate
      // (with allowed wildcards)
      dnsNames = dnsNames.map(function(name) {
        return regexpify(name, true);
      });
  
      // Wildcards ain't allowed in URI names
      uriNames = uriNames.map(function(name) {
        return regexpify(name, false);
      });
  
      dnsNames = dnsNames.concat(uriNames);
  
      if (dnsNames.length > 0) matchCN = false;
  
  
      // Match against Common Name (CN) only if no supported identifiers are
      // present.
      //
      // "As noted, a client MUST NOT seek a match for a reference identifier
      //  of CN-ID if the presented identifiers include a DNS-ID, SRV-ID,
      //  URI-ID, or any application-specific identifier types supported by the
      //  client."
      // RFC6125
      if (matchCN) {
        var commonNames = cert.subject.CN;
        if (util.isArray(commonNames)) {
          for (var i = 0, k = commonNames.length; i < k; ++i) {
            dnsNames.push(regexpify(commonNames[i], true));
          }
        } else {
          dnsNames.push(regexpify(commonNames, true));
        }
      }
  
      valid = dnsNames.some(function(re) {
        return re.test(host);
      });
    }
  
    return valid;
  };
  
  // Target API:
  //
  //  var s = tls.connect({port: 8000, host: "google.com"}, function() {
  //    if (!s.authorized) {
  //      s.destroy();
  //      return;
  //    }
  //
  //    // s.socket;
  //
  //    s.end("hello world\n");
  //  });
  //
  //
  function normalizeConnectArgs(listArgs) {
    var args = __normalizeConnectArgs(listArgs);
    var options = args[0];
    var cb = args[1];
  
    if (typeof(listArgs[1]) === 'object') {
      options = util._extend(options, listArgs[1]);
    } else if (typeof(listArgs[2]) === 'object') {
      options = util._extend(options, listArgs[2]);
    }
  
    return (cb) ? [options, cb] : [options];
  }
  
  function legacyConnect(hostname, options, NPN, credentials) {
    assert(options.socket);
    var pair = tls.createSecurePair(credentials,
                                    !!options.isServer,
                                    !!options.requestCert,
                                    !!options.rejectUnauthorized,
                                    {
                                      NPNProtocols: NPN.NPNProtocols,
                                      servername: hostname
                                    });
    legacyPipe(pair, options.socket);
    pair.cleartext._controlReleased = true;
    pair.on('error', function(err) {
      pair.cleartext.emit('error', err);
    });
  
    return pair;
  }
  
  function connect(/* [port, host], options, cb */) {
    var args = normalizeConnectArgs(arguments);
    var options = args[0];
    var cb = args[1];
  
    var defaults = {
      rejectUnauthorized: '0' !== process.env.NODE_TLS_REJECT_UNAUTHORIZED,
      requestCert: true,
      isServer: false
    };
    options = util._extend(defaults, options || {});
  
    var hostname = options.servername ||
                   options.host ||
                   options.socket && options.socket._host ||
                   '127.0.0.1',
        NPN = {},
        credentials = options.credentials || crypto.createCredentials(options);
    if (tls.convertNPNProtocols)
      tls.convertNPNProtocols(options.NPNProtocols, NPN);
  
    // Wrapping TLS socket inside another TLS socket was requested -
    // create legacy secure pair
    var socket;
    var legacy;
    var result;
    if (typeof tls.TLSSocket === 'undefined') {
      legacy = true;
      socket = legacyConnect(hostname, options, NPN, credentials);
      result = socket.cleartext;
    } else {
      legacy = false;
      socket = new tls.TLSSocket(options.socket, {
        credentials: credentials,
        isServer: !!options.isServer,
        requestCert: !!options.requestCert,
        rejectUnauthorized: !!options.rejectUnauthorized,
        NPNProtocols: NPN.NPNProtocols
      });
      result = socket;
    }
  
    if (socket._handle && !socket._connecting) {
      onHandle();
    } else {
      // Not even started connecting yet (or probably resolving dns address),
      // catch socket errors and assign handle.
      if (!legacy && options.socket) {
        options.socket.once('connect', function() {
          assert(options.socket._handle);
          socket._handle = options.socket._handle;
          socket._handle.owner = socket;
  
          socket.emit('connect');
        });
      }
      socket.once('connect', onHandle);
    }
  
    if (cb)
      result.once('secureConnect', cb);
  
    if (!options.socket) {
      assert(!legacy);
      var connect_opt;
      if (options.path && !options.port) {
        connect_opt = { path: options.path };
      } else {
        connect_opt = {
          port: options.port,
          host: options.host,
          localAddress: options.localAddress
        };
      }
      socket.connect(connect_opt);
    }
  
    return result;
  
    function onHandle() {
      if (!legacy)
        socket._releaseControl();
  
      if (options.session)
        socket.setSession(options.session);
  
      if (!legacy) {
        if (options.servername)
          socket.setServername(options.servername);
  
        if (!options.isServer)
          socket._start();
      }
      socket.on('secure', function() {
        var ssl = socket._ssl || socket.ssl;
        var verifyError = ssl.verifyError();
  
        // Verify that server's identity matches it's certificate's names
        if (!verifyError) {
          var cert = result.getPeerCertificate();
          var validCert = __checkServerIdentity(hostname, cert);
          if (!validCert) {
            verifyError = new Error('Hostname/IP doesn\'t match certificate\'s ' +
                                    'altnames');
          }
        }
  
        if (verifyError) {
          result.authorized = false;
          result.authorizationError = verifyError.message;
  
          if (options.rejectUnauthorized) {
            result.emit('error', verifyError);
            result.destroy();
            return;
          } else {
            result.emit('secureConnect');
          }
        } else {
          result.authorized = true;
          result.emit('secureConnect');
        }
  
        // Uncork incoming data
        result.removeListener('end', onHangUp);
      });
  
      function onHangUp() {
        // NOTE: This logic is shared with _http_client.js
        if (!socket._hadError) {
          socket._hadError = true;
          var error = new Error('socket hang up');
          error.code = 'ECONNRESET';
          socket.destroy();
          socket.emit('error', error);
        }
      }
      result.once('end', onHangUp);
    }
  };
  
  function legacyPipe(pair, socket) {
    pair.encrypted.pipe(socket);
    socket.pipe(pair.encrypted);
  
    pair.encrypted.on('close', function() {
      process.nextTick(function() {
        // Encrypted should be unpiped from socket to prevent possible
        // write after destroy.
        if (pair.encrypted.unpipe)
          pair.encrypted.unpipe(socket);
        socket.destroySoon();
      });
    });
  
    pair.fd = socket.fd;
    pair._handle = socket._handle;
    var cleartext = pair.cleartext;
    cleartext.socket = socket;
    cleartext.encrypted = pair.encrypted;
    cleartext.authorized = false;
  
    // cycle the data whenever the socket drains, so that
    // we can pull some more into it.  normally this would
    // be handled by the fact that pipe() triggers read() calls
    // on writable.drain, but CryptoStreams are a bit more
    // complicated.  Since the encrypted side actually gets
    // its data from the cleartext side, we have to give it a
    // light kick to get in motion again.
    socket.on('drain', function() {
      if (pair.encrypted._pending && pair.encrypted._writePending)
        pair.encrypted._writePending();
      if (pair.cleartext._pending && pair.cleartext._writePending)
        pair.cleartext._writePending();
      if (pair.encrypted.read)
        pair.encrypted.read(0);
      if (pair.cleartext.read)
        pair.cleartext.read(0);
    });
  
    function onerror(e) {
      if (cleartext._controlReleased) {
        cleartext.emit('error', e);
      }
    }
  
    function onclose() {
      socket.removeListener('error', onerror);
      socket.removeListener('timeout', ontimeout);
    }
  
    function ontimeout() {
      cleartext.emit('timeout');
    }
  
    socket.on('error', onerror);
    socket.on('close', onclose);
    socket.on('timeout', ontimeout);
  
    return cleartext;
  };
  
  },{"__browserify_process":26,"assert":17,"crypto":19,"net":16,"tls":16,"util":35}]},{},[1])