videoconference/js/jssip-3.7.0.js
06fbd764
 /**
  *  Copyright (C) 2021  Double Bastion LLC
  *
  *  This file is part of Roundpin, which is licensed under the
  *  GNU Affero General Public License Version 3.0. The license terms
  *  are detailed in the "LICENSE.txt" file located in the root directory.
  *
  *  The file content from below is identical with that of the
  *  original file "jssip-3.7.0.js". The copyright notice for the
  *  original content follows:
 
  * JsSIP v3.7.0
  * the Javascript SIP library
  * Copyright: 2012-2020 José Luis Millán <jmillan@aliax.net> (https://github.com/jmillan)
  * Homepage: https://jssip.net
  * License: MIT
  */
 
 (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.JsSIP = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
 "use strict";
 
 function _createForOfIteratorHelper(o, allowArrayLike) { var it; if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
 
 function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
 
 function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
 
 var Utils = require('./Utils');
 
 var JsSIP_C = require('./Constants');
 
 var Grammar = require('./Grammar');
 
 var URI = require('./URI');
 
 var Socket = require('./Socket');
 
 var Exceptions = require('./Exceptions'); // Default settings.
 
 
 exports.settings = {
   // SIP authentication.
   authorization_user: null,
   password: null,
   realm: null,
   ha1: null,
   authorization_jwt: null,
   // SIP account.
   display_name: null,
   uri: null,
   contact_uri: null,
   // SIP instance id (GRUU).
   instance_id: null,
   // Preloaded SIP Route header field.
   use_preloaded_route: false,
   // Session parameters.
   session_timers: true,
   session_timers_refresh_method: JsSIP_C.UPDATE,
   session_timers_force_refresher: false,
   no_answer_timeout: 60,
   // Registration parameters.
   register: true,
   register_expires: 600,
   registrar_server: null,
   // Connection options.
   sockets: null,
   connection_recovery_max_interval: JsSIP_C.CONNECTION_RECOVERY_MAX_INTERVAL,
   connection_recovery_min_interval: JsSIP_C.CONNECTION_RECOVERY_MIN_INTERVAL,
 
   /*
    * Host address.
    * Value to be set in Via sent_by and host part of Contact FQDN.
   */
   via_host: "".concat(Utils.createRandomToken(12), ".invalid")
 }; // Configuration checks.
 
 var checks = {
   mandatory: {
     sockets: function sockets(_sockets2) {
       /* Allow defining sockets parameter as:
        *  Socket: socket
        *  Array of Socket: [socket1, socket2]
        *  Array of Objects: [{socket: socket1, weight:1}, {socket: Socket2, weight:0}]
        *  Array of Objects and Socket: [{socket: socket1}, socket2]
        */
       var _sockets = [];
 
       if (Socket.isSocket(_sockets2)) {
         _sockets.push({
           socket: _sockets2
         });
       } else if (Array.isArray(_sockets2) && _sockets2.length) {
         var _iterator = _createForOfIteratorHelper(_sockets2),
             _step;
 
         try {
           for (_iterator.s(); !(_step = _iterator.n()).done;) {
             var socket = _step.value;
 
             if (Object.prototype.hasOwnProperty.call(socket, 'socket') && Socket.isSocket(socket.socket)) {
               _sockets.push(socket);
             } else if (Socket.isSocket(socket)) {
               _sockets.push({
                 socket: socket
               });
             }
           }
         } catch (err) {
           _iterator.e(err);
         } finally {
           _iterator.f();
         }
       } else {
         return;
       }
 
       return _sockets;
     },
     uri: function uri(_uri) {
       if (!/^sip:/i.test(_uri)) {
         _uri = "".concat(JsSIP_C.SIP, ":").concat(_uri);
       }
 
       var parsed = URI.parse(_uri);
 
       if (!parsed) {
         return;
       } else if (!parsed.user) {
         return;
       } else {
         return parsed;
       }
     }
   },
   optional: {
     authorization_user: function authorization_user(_authorization_user) {
       if (Grammar.parse("\"".concat(_authorization_user, "\""), 'quoted_string') === -1) {
         return;
       } else {
         return _authorization_user;
       }
     },
     authorization_jwt: function authorization_jwt(_authorization_jwt) {
       if (typeof _authorization_jwt === 'string') {
         return _authorization_jwt;
       }
     },
     user_agent: function user_agent(_user_agent) {
       if (typeof _user_agent === 'string') {
         return _user_agent;
       }
     },
     connection_recovery_max_interval: function connection_recovery_max_interval(_connection_recovery_max_interval) {
       if (Utils.isDecimal(_connection_recovery_max_interval)) {
         var value = Number(_connection_recovery_max_interval);
 
         if (value > 0) {
           return value;
         }
       }
     },
     connection_recovery_min_interval: function connection_recovery_min_interval(_connection_recovery_min_interval) {
       if (Utils.isDecimal(_connection_recovery_min_interval)) {
         var value = Number(_connection_recovery_min_interval);
 
         if (value > 0) {
           return value;
         }
       }
     },
     contact_uri: function contact_uri(_contact_uri) {
       if (typeof _contact_uri === 'string') {
         var uri = Grammar.parse(_contact_uri, 'SIP_URI');
 
         if (uri !== -1) {
           return uri;
         }
       }
     },
     display_name: function display_name(_display_name) {
       return _display_name;
     },
     instance_id: function instance_id(_instance_id) {
       if (/^uuid:/i.test(_instance_id)) {
         _instance_id = _instance_id.substr(5);
       }
 
       if (Grammar.parse(_instance_id, 'uuid') === -1) {
         return;
       } else {
         return _instance_id;
       }
     },
     no_answer_timeout: function no_answer_timeout(_no_answer_timeout) {
       if (Utils.isDecimal(_no_answer_timeout)) {
         var value = Number(_no_answer_timeout);
 
         if (value > 0) {
           return value;
         }
       }
     },
     session_timers: function session_timers(_session_timers) {
       if (typeof _session_timers === 'boolean') {
         return _session_timers;
       }
     },
     session_timers_refresh_method: function session_timers_refresh_method(method) {
       if (typeof method === 'string') {
         method = method.toUpperCase();
 
         if (method === JsSIP_C.INVITE || method === JsSIP_C.UPDATE) {
           return method;
         }
       }
     },
     session_timers_force_refresher: function session_timers_force_refresher(_session_timers_force_refresher) {
       if (typeof _session_timers_force_refresher === 'boolean') {
         return _session_timers_force_refresher;
       }
     },
     password: function password(_password) {
       return String(_password);
     },
     realm: function realm(_realm) {
       return String(_realm);
     },
     ha1: function ha1(_ha) {
       return String(_ha);
     },
     register: function register(_register) {
       if (typeof _register === 'boolean') {
         return _register;
       }
     },
     register_expires: function register_expires(_register_expires) {
       if (Utils.isDecimal(_register_expires)) {
         var value = Number(_register_expires);
 
         if (value > 0) {
           return value;
         }
       }
     },
     registrar_server: function registrar_server(_registrar_server) {
       if (!/^sip:/i.test(_registrar_server)) {
         _registrar_server = "".concat(JsSIP_C.SIP, ":").concat(_registrar_server);
       }
 
       var parsed = URI.parse(_registrar_server);
 
       if (!parsed) {
         return;
       } else if (parsed.user) {
         return;
       } else {
         return parsed;
       }
     },
     use_preloaded_route: function use_preloaded_route(_use_preloaded_route) {
       if (typeof _use_preloaded_route === 'boolean') {
         return _use_preloaded_route;
       }
     }
   }
 };
 
 exports.load = function (dst, src) {
   // Check Mandatory parameters.
   for (var parameter in checks.mandatory) {
     if (!src.hasOwnProperty(parameter)) {
       throw new Exceptions.ConfigurationError(parameter);
     } else {
       var value = src[parameter];
       var checked_value = checks.mandatory[parameter](value);
 
       if (checked_value !== undefined) {
         dst[parameter] = checked_value;
       } else {
         throw new Exceptions.ConfigurationError(parameter, value);
       }
     }
   } // Check Optional parameters.
 
 
   for (var _parameter in checks.optional) {
     if (src.hasOwnProperty(_parameter)) {
       var _value = src[_parameter];
       /* If the parameter value is null, empty string, undefined, empty array
        * or it's a number with NaN value, then apply its default value.
        */
 
       if (Utils.isEmpty(_value)) {
         continue;
       }
 
       var _checked_value = checks.optional[_parameter](_value);
 
       if (_checked_value !== undefined) {
         dst[_parameter] = _checked_value;
       } else {
         throw new Exceptions.ConfigurationError(_parameter, _value);
       }
     }
   }
 };
 },{"./Constants":2,"./Exceptions":6,"./Grammar":7,"./Socket":20,"./URI":25,"./Utils":26}],2:[function(require,module,exports){
 "use strict";
 
 var pkg = require('../package.json');
 
 module.exports = {
   USER_AGENT: "".concat(pkg.title, " ").concat(pkg.version),
   // SIP scheme.
   SIP: 'sip',
   SIPS: 'sips',
   // End and Failure causes.
   causes: {
     // Generic error causes.
     CONNECTION_ERROR: 'Connection Error',
     REQUEST_TIMEOUT: 'Request Timeout',
     SIP_FAILURE_CODE: 'SIP Failure Code',
     INTERNAL_ERROR: 'Internal Error',
     // SIP error causes.
     BUSY: 'Busy',
     REJECTED: 'Rejected',
     REDIRECTED: 'Redirected',
     UNAVAILABLE: 'Unavailable',
     NOT_FOUND: 'Not Found',
     ADDRESS_INCOMPLETE: 'Address Incomplete',
     INCOMPATIBLE_SDP: 'Incompatible SDP',
     MISSING_SDP: 'Missing SDP',
     AUTHENTICATION_ERROR: 'Authentication Error',
     // Session error causes.
     BYE: 'Terminated',
     WEBRTC_ERROR: 'WebRTC Error',
     CANCELED: 'Canceled',
     NO_ANSWER: 'No Answer',
     EXPIRES: 'Expires',
     NO_ACK: 'No ACK',
     DIALOG_ERROR: 'Dialog Error',
     USER_DENIED_MEDIA_ACCESS: 'User Denied Media Access',
     BAD_MEDIA_DESCRIPTION: 'Bad Media Description',
     RTP_TIMEOUT: 'RTP Timeout'
   },
   SIP_ERROR_CAUSES: {
     REDIRECTED: [300, 301, 302, 305, 380],
     BUSY: [486, 600],
     REJECTED: [403, 603],
     NOT_FOUND: [404, 604],
     UNAVAILABLE: [480, 410, 408, 430],
     ADDRESS_INCOMPLETE: [484, 424],
     INCOMPATIBLE_SDP: [488, 606],
     AUTHENTICATION_ERROR: [401, 407]
   },
   // SIP Methods.
   ACK: 'ACK',
   BYE: 'BYE',
   CANCEL: 'CANCEL',
   INFO: 'INFO',
   INVITE: 'INVITE',
   MESSAGE: 'MESSAGE',
   NOTIFY: 'NOTIFY',
   OPTIONS: 'OPTIONS',
   REGISTER: 'REGISTER',
   REFER: 'REFER',
   UPDATE: 'UPDATE',
   SUBSCRIBE: 'SUBSCRIBE',
   // DTMF transport methods.
   DTMF_TRANSPORT: {
     INFO: 'INFO',
     RFC2833: 'RFC2833'
   },
 
   /* SIP Response Reasons
    * DOC: https://www.iana.org/assignments/sip-parameters
    * Copied from https://github.com/versatica/OverSIP/blob/master/lib/oversip/sip/constants.rb#L7
    */
   REASON_PHRASE: {
     100: 'Trying',
     180: 'Ringing',
     181: 'Call Is Being Forwarded',
     182: 'Queued',
     183: 'Session Progress',
     199: 'Early Dialog Terminated',
     // draft-ietf-sipcore-199
     200: 'OK',
     202: 'Accepted',
     // RFC 3265
     204: 'No Notification',
     // RFC 5839
     300: 'Multiple Choices',
     301: 'Moved Permanently',
     302: 'Moved Temporarily',
     305: 'Use Proxy',
     380: 'Alternative Service',
     400: 'Bad Request',
     401: 'Unauthorized',
     402: 'Payment Required',
     403: 'Forbidden',
     404: 'Not Found',
     405: 'Method Not Allowed',
     406: 'Not Acceptable',
     407: 'Proxy Authentication Required',
     408: 'Request Timeout',
     410: 'Gone',
     412: 'Conditional Request Failed',
     // RFC 3903
     413: 'Request Entity Too Large',
     414: 'Request-URI Too Long',
     415: 'Unsupported Media Type',
     416: 'Unsupported URI Scheme',
     417: 'Unknown Resource-Priority',
     // RFC 4412
     420: 'Bad Extension',
     421: 'Extension Required',
     422: 'Session Interval Too Small',
     // RFC 4028
     423: 'Interval Too Brief',
     424: 'Bad Location Information',
     // RFC 6442
     428: 'Use Identity Header',
     // RFC 4474
     429: 'Provide Referrer Identity',
     // RFC 3892
     430: 'Flow Failed',
     // RFC 5626
     433: 'Anonymity Disallowed',
     // RFC 5079
     436: 'Bad Identity-Info',
     // RFC 4474
     437: 'Unsupported Certificate',
     // RFC 4744
     438: 'Invalid Identity Header',
     // RFC 4744
     439: 'First Hop Lacks Outbound Support',
     // RFC 5626
     440: 'Max-Breadth Exceeded',
     // RFC 5393
     469: 'Bad Info Package',
     // draft-ietf-sipcore-info-events
     470: 'Consent Needed',
     // RFC 5360
     478: 'Unresolvable Destination',
     // Custom code copied from Kamailio.
     480: 'Temporarily Unavailable',
     481: 'Call/Transaction Does Not Exist',
     482: 'Loop Detected',
     483: 'Too Many Hops',
     484: 'Address Incomplete',
     485: 'Ambiguous',
     486: 'Busy Here',
     487: 'Request Terminated',
     488: 'Not Acceptable Here',
     489: 'Bad Event',
     // RFC 3265
     491: 'Request Pending',
     493: 'Undecipherable',
     494: 'Security Agreement Required',
     // RFC 3329
     500: 'JsSIP Internal Error',
     501: 'Not Implemented',
     502: 'Bad Gateway',
     503: 'Service Unavailable',
     504: 'Server Time-out',
     505: 'Version Not Supported',
     513: 'Message Too Large',
     580: 'Precondition Failure',
     // RFC 3312
     600: 'Busy Everywhere',
     603: 'Decline',
     604: 'Does Not Exist Anywhere',
     606: 'Not Acceptable'
   },
   ALLOWED_METHODS: 'INVITE,ACK,CANCEL,BYE,UPDATE,MESSAGE,OPTIONS,REFER,INFO,NOTIFY',
   ACCEPTED_BODY_TYPES: 'application/sdp, application/dtmf-relay',
   MAX_FORWARDS: 69,
   SESSION_EXPIRES: 90,
   MIN_SESSION_EXPIRES: 60,
   CONNECTION_RECOVERY_MAX_INTERVAL: 30,
   CONNECTION_RECOVERY_MIN_INTERVAL: 2
 };
 },{"../package.json":38}],3:[function(require,module,exports){
 "use strict";
 
 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
 function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
 
 function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
 
 var SIPMessage = require('./SIPMessage');
 
 var JsSIP_C = require('./Constants');
 
 var Transactions = require('./Transactions');
 
 var Dialog_RequestSender = require('./Dialog/RequestSender');
 
 var Utils = require('./Utils');
 
 var debug = require('debug')('JsSIP:Dialog');
 
 var C = {
   // Dialog states.
   STATUS_EARLY: 1,
   STATUS_CONFIRMED: 2
 }; // RFC 3261 12.1.
 
 module.exports = /*#__PURE__*/function () {
   _createClass(Dialog, null, [{
     key: "C",
     // Expose C object.
     get: function get() {
       return C;
     }
   }]);
 
   function Dialog(owner, message, type) {
     var state = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : C.STATUS_CONFIRMED;
 
     _classCallCheck(this, Dialog);
 
     this._owner = owner;
     this._ua = owner._ua;
     this._uac_pending_reply = false;
     this._uas_pending_reply = false;
 
     if (!message.hasHeader('contact')) {
       return {
         error: 'unable to create a Dialog without Contact header field'
       };
     }
 
     if (message instanceof SIPMessage.IncomingResponse) {
       state = message.status_code < 200 ? C.STATUS_EARLY : C.STATUS_CONFIRMED;
     }
 
     var contact = message.parseHeader('contact'); // RFC 3261 12.1.1.
 
     if (type === 'UAS') {
       this._id = {
         call_id: message.call_id,
         local_tag: message.to_tag,
         remote_tag: message.from_tag,
         toString: function toString() {
           return this.call_id + this.local_tag + this.remote_tag;
         }
       };
       this._state = state;
       this._remote_seqnum = message.cseq;
       this._local_uri = message.parseHeader('to').uri;
       this._remote_uri = message.parseHeader('from').uri;
       this._remote_target = contact.uri;
       this._route_set = message.getHeaders('record-route');
       this._ack_seqnum = this._remote_seqnum;
     } // RFC 3261 12.1.2.
     else if (type === 'UAC') {
         this._id = {
           call_id: message.call_id,
           local_tag: message.from_tag,
           remote_tag: message.to_tag,
           toString: function toString() {
             return this.call_id + this.local_tag + this.remote_tag;
           }
         };
         this._state = state;
         this._local_seqnum = message.cseq;
         this._local_uri = message.parseHeader('from').uri;
         this._remote_uri = message.parseHeader('to').uri;
         this._remote_target = contact.uri;
         this._route_set = message.getHeaders('record-route').reverse();
         this._ack_seqnum = null;
       }
 
     this._ua.newDialog(this);
 
     debug("new ".concat(type, " dialog created with status ").concat(this._state === C.STATUS_EARLY ? 'EARLY' : 'CONFIRMED'));
   }
 
   _createClass(Dialog, [{
     key: "update",
     value: function update(message, type) {
       this._state = C.STATUS_CONFIRMED;
       debug("dialog ".concat(this._id.toString(), "  changed to CONFIRMED state"));
 
       if (type === 'UAC') {
         // RFC 3261 13.2.2.4.
         this._route_set = message.getHeaders('record-route').reverse();
       }
     }
   }, {
     key: "terminate",
     value: function terminate() {
       debug("dialog ".concat(this._id.toString(), " deleted"));
 
       this._ua.destroyDialog(this);
     }
   }, {
     key: "sendRequest",
     value: function sendRequest(method) {
       var _this = this;
 
       var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
       var extraHeaders = Utils.cloneArray(options.extraHeaders);
       var eventHandlers = Utils.cloneObject(options.eventHandlers);
       var body = options.body || null;
 
       var request = this._createRequest(method, extraHeaders, body); // Increase the local CSeq on authentication.
 
 
       eventHandlers.onAuthenticated = function () {
         _this._local_seqnum += 1;
       };
 
       var request_sender = new Dialog_RequestSender(this, request, eventHandlers);
       request_sender.send(); // Return the instance of OutgoingRequest.
 
       return request;
     }
   }, {
     key: "receiveRequest",
     value: function receiveRequest(request) {
       // Check in-dialog request.
       if (!this._checkInDialogRequest(request)) {
         return;
       } // ACK received. Cleanup this._ack_seqnum.
 
 
       if (request.method === JsSIP_C.ACK && this._ack_seqnum !== null) {
         this._ack_seqnum = null;
       } // INVITE received. Set this._ack_seqnum.
       else if (request.method === JsSIP_C.INVITE) {
           this._ack_seqnum = request.cseq;
         }
 
       this._owner.receiveRequest(request);
     } // RFC 3261 12.2.1.1.
 
   }, {
     key: "_createRequest",
     value: function _createRequest(method, extraHeaders, body) {
       extraHeaders = Utils.cloneArray(extraHeaders);
 
       if (!this._local_seqnum) {
         this._local_seqnum = Math.floor(Math.random() * 10000);
       }
 
       var cseq = method === JsSIP_C.CANCEL || method === JsSIP_C.ACK ? this._local_seqnum : this._local_seqnum += 1;
       var request = new SIPMessage.OutgoingRequest(method, this._remote_target, this._ua, {
         'cseq': cseq,
         'call_id': this._id.call_id,
         'from_uri': this._local_uri,
         'from_tag': this._id.local_tag,
         'to_uri': this._remote_uri,
         'to_tag': this._id.remote_tag,
         'route_set': this._route_set
       }, extraHeaders, body);
       return request;
     } // RFC 3261 12.2.2.
 
   }, {
     key: "_checkInDialogRequest",
     value: function _checkInDialogRequest(request) {
       var _this2 = this;
 
       if (!this._remote_seqnum) {
         this._remote_seqnum = request.cseq;
       } else if (request.cseq < this._remote_seqnum) {
         if (request.method === JsSIP_C.ACK) {
           // We are not expecting any ACK with lower seqnum than the current one.
           // Or this is not the ACK we are waiting for.
           if (this._ack_seqnum === null || request.cseq !== this._ack_seqnum) {
             return false;
           }
         } else {
           request.reply(500);
           return false;
         }
       } else if (request.cseq > this._remote_seqnum) {
         this._remote_seqnum = request.cseq;
       } // RFC3261 14.2 Modifying an Existing Session -UAS BEHAVIOR-.
 
 
       if (request.method === JsSIP_C.INVITE || request.method === JsSIP_C.UPDATE && request.body) {
         if (this._uac_pending_reply === true) {
           request.reply(491);
         } else if (this._uas_pending_reply === true) {
           var retryAfter = (Math.random() * 10 | 0) + 1;
           request.reply(500, null, ["Retry-After:".concat(retryAfter)]);
           return false;
         } else {
           this._uas_pending_reply = true;
 
           var stateChanged = function stateChanged() {
             if (request.server_transaction.state === Transactions.C.STATUS_ACCEPTED || request.server_transaction.state === Transactions.C.STATUS_COMPLETED || request.server_transaction.state === Transactions.C.STATUS_TERMINATED) {
               request.server_transaction.removeListener('stateChanged', stateChanged);
               _this2._uas_pending_reply = false;
             }
           };
 
           request.server_transaction.on('stateChanged', stateChanged);
         } // RFC3261 12.2.2 Replace the dialog`s remote target URI if the request is accepted.
 
 
         if (request.hasHeader('contact')) {
           request.server_transaction.on('stateChanged', function () {
             if (request.server_transaction.state === Transactions.C.STATUS_ACCEPTED) {
               _this2._remote_target = request.parseHeader('contact').uri;
             }
           });
         }
       } else if (request.method === JsSIP_C.NOTIFY) {
         // RFC6665 3.2 Replace the dialog`s remote target URI if the request is accepted.
         if (request.hasHeader('contact')) {
           request.server_transaction.on('stateChanged', function () {
             if (request.server_transaction.state === Transactions.C.STATUS_COMPLETED) {
               _this2._remote_target = request.parseHeader('contact').uri;
             }
           });
         }
       }
 
       return true;
     }
   }, {
     key: "id",
     get: function get() {
       return this._id;
     }
   }, {
     key: "local_seqnum",
     get: function get() {
       return this._local_seqnum;
     },
     set: function set(num) {
       this._local_seqnum = num;
     }
   }, {
     key: "owner",
     get: function get() {
       return this._owner;
     }
   }, {
     key: "uac_pending_reply",
     get: function get() {
       return this._uac_pending_reply;
     },
     set: function set(pending) {
       this._uac_pending_reply = pending;
     }
   }, {
     key: "uas_pending_reply",
     get: function get() {
       return this._uas_pending_reply;
     }
   }]);
 
   return Dialog;
 }();
 },{"./Constants":2,"./Dialog/RequestSender":4,"./SIPMessage":19,"./Transactions":22,"./Utils":26,"debug":30}],4:[function(require,module,exports){
 "use strict";
 
 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
 function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
 
 function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
 
 var JsSIP_C = require('../Constants');
 
 var Transactions = require('../Transactions');
 
 var RTCSession = require('../RTCSession');
 
 var RequestSender = require('../RequestSender'); // Default event handlers.
 
 
 var EventHandlers = {
   onRequestTimeout: function onRequestTimeout() {},
   onTransportError: function onTransportError() {},
   onSuccessResponse: function onSuccessResponse() {},
   onErrorResponse: function onErrorResponse() {},
   onAuthenticated: function onAuthenticated() {},
   onDialogError: function onDialogError() {}
 };
 
 module.exports = /*#__PURE__*/function () {
   function DialogRequestSender(dialog, request, eventHandlers) {
     _classCallCheck(this, DialogRequestSender);
 
     this._dialog = dialog;
     this._ua = dialog._ua;
     this._request = request;
     this._eventHandlers = eventHandlers; // RFC3261 14.1 Modifying an Existing Session. UAC Behavior.
 
     this._reattempt = false;
     this._reattemptTimer = null; // Define the undefined handlers.
 
     for (var handler in EventHandlers) {
       if (Object.prototype.hasOwnProperty.call(EventHandlers, handler)) {
         if (!this._eventHandlers[handler]) {
           this._eventHandlers[handler] = EventHandlers[handler];
         }
       }
     }
   }
 
   _createClass(DialogRequestSender, [{
     key: "send",
     value: function send() {
       var _this = this;
 
       var request_sender = new RequestSender(this._ua, this._request, {
         onRequestTimeout: function onRequestTimeout() {
           _this._eventHandlers.onRequestTimeout();
         },
         onTransportError: function onTransportError() {
           _this._eventHandlers.onTransportError();
         },
         onAuthenticated: function onAuthenticated(request) {
           _this._eventHandlers.onAuthenticated(request);
         },
         onReceiveResponse: function onReceiveResponse(response) {
           _this._receiveResponse(response);
         }
       });
       request_sender.send(); // RFC3261 14.2 Modifying an Existing Session -UAC BEHAVIOR-.
 
       if ((this._request.method === JsSIP_C.INVITE || this._request.method === JsSIP_C.UPDATE && this._request.body) && request_sender.clientTransaction.state !== Transactions.C.STATUS_TERMINATED) {
         this._dialog.uac_pending_reply = true;
 
         var stateChanged = function stateChanged() {
           if (request_sender.clientTransaction.state === Transactions.C.STATUS_ACCEPTED || request_sender.clientTransaction.state === Transactions.C.STATUS_COMPLETED || request_sender.clientTransaction.state === Transactions.C.STATUS_TERMINATED) {
             request_sender.clientTransaction.removeListener('stateChanged', stateChanged);
             _this._dialog.uac_pending_reply = false;
           }
         };
 
         request_sender.clientTransaction.on('stateChanged', stateChanged);
       }
     }
   }, {
     key: "_receiveResponse",
     value: function _receiveResponse(response) {
       var _this2 = this;
 
       // RFC3261 12.2.1.2 408 or 481 is received for a request within a dialog.
       if (response.status_code === 408 || response.status_code === 481) {
         this._eventHandlers.onDialogError(response);
       } else if (response.method === JsSIP_C.INVITE && response.status_code === 491) {
         if (this._reattempt) {
           if (response.status_code >= 200 && response.status_code < 300) {
             this._eventHandlers.onSuccessResponse(response);
           } else if (response.status_code >= 300) {
             this._eventHandlers.onErrorResponse(response);
           }
         } else {
           this._request.cseq = this._dialog.local_seqnum += 1;
           this._reattemptTimer = setTimeout(function () {
             // TODO: look at dialog state instead.
             if (_this2._dialog.owner.status !== RTCSession.C.STATUS_TERMINATED) {
               _this2._reattempt = true;
 
               _this2._request_sender.send();
             }
           }, 1000);
         }
       } else if (response.status_code >= 200 && response.status_code < 300) {
         this._eventHandlers.onSuccessResponse(response);
       } else if (response.status_code >= 300) {
         this._eventHandlers.onErrorResponse(response);
       }
     }
   }, {
     key: "request",
     get: function get() {
       return this._request;
     }
   }]);
 
   return DialogRequestSender;
 }();
 },{"../Constants":2,"../RTCSession":12,"../RequestSender":18,"../Transactions":22}],5:[function(require,module,exports){
 "use strict";
 
 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
 function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
 
 function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
 
 var Utils = require('./Utils');
 
 var debug = require('debug')('JsSIP:DigestAuthentication');
 
 var debugerror = require('debug')('JsSIP:ERROR:DigestAuthentication');
 
 debugerror.log = console.warn.bind(console);
 
 module.exports = /*#__PURE__*/function () {
   function DigestAuthentication(credentials) {
     _classCallCheck(this, DigestAuthentication);
 
     this._credentials = credentials;
     this._cnonce = null;
     this._nc = 0;
     this._ncHex = '00000000';
     this._algorithm = null;
     this._realm = null;
     this._nonce = null;
     this._opaque = null;
     this._stale = null;
     this._qop = null;
     this._method = null;
     this._uri = null;
     this._ha1 = null;
     this._response = null;
   }
 
   _createClass(DigestAuthentication, [{
     key: "get",
     value: function get(parameter) {
       switch (parameter) {
         case 'realm':
           return this._realm;
 
         case 'ha1':
           return this._ha1;
 
         default:
           debugerror('get() | cannot get "%s" parameter', parameter);
           return undefined;
       }
     }
     /**
     * Performs Digest authentication given a SIP request and the challenge
     * received in a response to that request.
     * Returns true if auth was successfully generated, false otherwise.
     */
 
   }, {
     key: "authenticate",
     value: function authenticate(_ref, challenge)
     /* test interface */
     {
       var method = _ref.method,
           ruri = _ref.ruri,
           body = _ref.body;
       var cnonce = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
       this._algorithm = challenge.algorithm;
       this._realm = challenge.realm;
       this._nonce = challenge.nonce;
       this._opaque = challenge.opaque;
       this._stale = challenge.stale;
 
       if (this._algorithm) {
         if (this._algorithm !== 'MD5') {
           debugerror('authenticate() | challenge with Digest algorithm different than "MD5", authentication aborted');
           return false;
         }
       } else {
         this._algorithm = 'MD5';
       }
 
       if (!this._nonce) {
         debugerror('authenticate() | challenge without Digest nonce, authentication aborted');
         return false;
       }
 
       if (!this._realm) {
         debugerror('authenticate() | challenge without Digest realm, authentication aborted');
         return false;
       } // If no plain SIP password is provided.
 
 
       if (!this._credentials.password) {
         // If ha1 is not provided we cannot authenticate.
         if (!this._credentials.ha1) {
           debugerror('authenticate() | no plain SIP password nor ha1 provided, authentication aborted');
           return false;
         } // If the realm does not match the stored realm we cannot authenticate.
 
 
         if (this._credentials.realm !== this._realm) {
           debugerror('authenticate() | no plain SIP password, and stored `realm` does not match the given `realm`, cannot authenticate [stored:"%s", given:"%s"]', this._credentials.realm, this._realm);
           return false;
         }
       } // 'qop' can contain a list of values (Array). Let's choose just one.
 
 
       if (challenge.qop) {
         if (challenge.qop.indexOf('auth-int') > -1) {
           this._qop = 'auth-int';
         } else if (challenge.qop.indexOf('auth') > -1) {
           this._qop = 'auth';
         } else {
           // Otherwise 'qop' is present but does not contain 'auth' or 'auth-int', so abort here.
           debugerror('authenticate() | challenge without Digest qop different than "auth" or "auth-int", authentication aborted');
           return false;
         }
       } else {
         this._qop = null;
       } // Fill other attributes.
 
 
       this._method = method;
       this._uri = ruri;
       this._cnonce = cnonce || Utils.createRandomToken(12);
       this._nc += 1;
       var hex = Number(this._nc).toString(16);
       this._ncHex = '00000000'.substr(0, 8 - hex.length) + hex; // Nc-value = 8LHEX. Max value = 'FFFFFFFF'.
 
       if (this._nc === 4294967296) {
         this._nc = 1;
         this._ncHex = '00000001';
       } // Calculate the Digest "response" value.
       // If we have plain SIP password then regenerate ha1.
 
 
       if (this._credentials.password) {
         // HA1 = MD5(A1) = MD5(username:realm:password).
         this._ha1 = Utils.calculateMD5("".concat(this._credentials.username, ":").concat(this._realm, ":").concat(this._credentials.password));
       } // Otherwise reuse the stored ha1.
       else {
           this._ha1 = this._credentials.ha1;
         }
 
       var a2;
       var ha2;
 
       if (this._qop === 'auth') {
         // HA2 = MD5(A2) = MD5(method:digestURI).
         a2 = "".concat(this._method, ":").concat(this._uri);
         ha2 = Utils.calculateMD5(a2);
         debug('authenticate() | using qop=auth [a2:"%s"]', a2); // Response = MD5(HA1:nonce:nonceCount:credentialsNonce:qop:HA2).
 
         this._response = Utils.calculateMD5("".concat(this._ha1, ":").concat(this._nonce, ":").concat(this._ncHex, ":").concat(this._cnonce, ":auth:").concat(ha2));
       } else if (this._qop === 'auth-int') {
         // HA2 = MD5(A2) = MD5(method:digestURI:MD5(entityBody)).
         a2 = "".concat(this._method, ":").concat(this._uri, ":").concat(Utils.calculateMD5(body ? body : ''));
         ha2 = Utils.calculateMD5(a2);
         debug('authenticate() | using qop=auth-int [a2:"%s"]', a2); // Response = MD5(HA1:nonce:nonceCount:credentialsNonce:qop:HA2).
 
         this._response = Utils.calculateMD5("".concat(this._ha1, ":").concat(this._nonce, ":").concat(this._ncHex, ":").concat(this._cnonce, ":auth-int:").concat(ha2));
       } else if (this._qop === null) {
         // HA2 = MD5(A2) = MD5(method:digestURI).
         a2 = "".concat(this._method, ":").concat(this._uri);
         ha2 = Utils.calculateMD5(a2);
         debug('authenticate() | using qop=null [a2:"%s"]', a2); // Response = MD5(HA1:nonce:HA2).
 
         this._response = Utils.calculateMD5("".concat(this._ha1, ":").concat(this._nonce, ":").concat(ha2));
       }
 
       debug('authenticate() | response generated');
       return true;
     }
     /**
     * Return the Proxy-Authorization or WWW-Authorization header value.
     */
 
   }, {
     key: "toString",
     value: function toString() {
       var auth_params = [];
 
       if (!this._response) {
         throw new Error('response field does not exist, cannot generate Authorization header');
       }
 
       auth_params.push("algorithm=".concat(this._algorithm));
       auth_params.push("username=\"".concat(this._credentials.username, "\""));
       auth_params.push("realm=\"".concat(this._realm, "\""));
       auth_params.push("nonce=\"".concat(this._nonce, "\""));
       auth_params.push("uri=\"".concat(this._uri, "\""));
       auth_params.push("response=\"".concat(this._response, "\""));
 
       if (this._opaque) {
         auth_params.push("opaque=\"".concat(this._opaque, "\""));
       }
 
       if (this._qop) {
         auth_params.push("qop=".concat(this._qop));
         auth_params.push("cnonce=\"".concat(this._cnonce, "\""));
         auth_params.push("nc=".concat(this._ncHex));
       }
 
       return "Digest ".concat(auth_params.join(', '));
     }
   }]);
 
   return DigestAuthentication;
 }();
 },{"./Utils":26,"debug":30}],6:[function(require,module,exports){
 "use strict";
 
 function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
 
 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
 function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
 
 function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
 
 function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
 
 function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
 
 function _wrapNativeSuper(Class) { var _cache = typeof Map === "function" ? new Map() : undefined; _wrapNativeSuper = function _wrapNativeSuper(Class) { if (Class === null || !_isNativeFunction(Class)) return Class; if (typeof Class !== "function") { throw new TypeError("Super expression must either be null or a function"); } if (typeof _cache !== "undefined") { if (_cache.has(Class)) return _cache.get(Class); _cache.set(Class, Wrapper); } function Wrapper() { return _construct(Class, arguments, _getPrototypeOf(this).constructor); } Wrapper.prototype = Object.create(Class.prototype, { constructor: { value: Wrapper, enumerable: false, writable: true, configurable: true } }); return _setPrototypeOf(Wrapper, Class); }; return _wrapNativeSuper(Class); }
 
 function _construct(Parent, args, Class) { if (_isNativeReflectConstruct()) { _construct = Reflect.construct; } else { _construct = function _construct(Parent, args, Class) { var a = [null]; a.push.apply(a, args); var Constructor = Function.bind.apply(Parent, a); var instance = new Constructor(); if (Class) _setPrototypeOf(instance, Class.prototype); return instance; }; } return _construct.apply(null, arguments); }
 
 function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }
 
 function _isNativeFunction(fn) { return Function.toString.call(fn).indexOf("[native code]") !== -1; }
 
 function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
 
 function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
 
 var ConfigurationError = /*#__PURE__*/function (_Error) {
   _inherits(ConfigurationError, _Error);
 
   var _super = _createSuper(ConfigurationError);
 
   function ConfigurationError(parameter, value) {
     var _this;
 
     _classCallCheck(this, ConfigurationError);
 
     _this = _super.call(this);
     _this.code = 1;
     _this.name = 'CONFIGURATION_ERROR';
     _this.parameter = parameter;
     _this.value = value;
     _this.message = !_this.value ? "Missing parameter: ".concat(_this.parameter) : "Invalid value ".concat(JSON.stringify(_this.value), " for parameter \"").concat(_this.parameter, "\"");
     return _this;
   }
 
   return ConfigurationError;
 }( /*#__PURE__*/_wrapNativeSuper(Error));
 
 var InvalidStateError = /*#__PURE__*/function (_Error2) {
   _inherits(InvalidStateError, _Error2);
 
   var _super2 = _createSuper(InvalidStateError);
 
   function InvalidStateError(status) {
     var _this2;
 
     _classCallCheck(this, InvalidStateError);
 
     _this2 = _super2.call(this);
     _this2.code = 2;
     _this2.name = 'INVALID_STATE_ERROR';
     _this2.status = status;
     _this2.message = "Invalid status: ".concat(status);
     return _this2;
   }
 
   return InvalidStateError;
 }( /*#__PURE__*/_wrapNativeSuper(Error));
 
 var NotSupportedError = /*#__PURE__*/function (_Error3) {
   _inherits(NotSupportedError, _Error3);
 
   var _super3 = _createSuper(NotSupportedError);
 
   function NotSupportedError(message) {
     var _this3;
 
     _classCallCheck(this, NotSupportedError);
 
     _this3 = _super3.call(this);
     _this3.code = 3;
     _this3.name = 'NOT_SUPPORTED_ERROR';
     _this3.message = message;
     return _this3;
   }
 
   return NotSupportedError;
 }( /*#__PURE__*/_wrapNativeSuper(Error));
 
 var NotReadyError = /*#__PURE__*/function (_Error4) {
   _inherits(NotReadyError, _Error4);
 
   var _super4 = _createSuper(NotReadyError);
 
   function NotReadyError(message) {
     var _this4;
 
     _classCallCheck(this, NotReadyError);
 
     _this4 = _super4.call(this);
     _this4.code = 4;
     _this4.name = 'NOT_READY_ERROR';
     _this4.message = message;
     return _this4;
   }
 
   return NotReadyError;
 }( /*#__PURE__*/_wrapNativeSuper(Error));
 
 module.exports = {
   ConfigurationError: ConfigurationError,
   InvalidStateError: InvalidStateError,
   NotSupportedError: NotSupportedError,
   NotReadyError: NotReadyError
 };
 },{}],7:[function(require,module,exports){
 "use strict";
 
 module.exports = function () {
   /*
    * Generated by PEG.js 0.7.0.
    *
    * http://pegjs.majda.cz/
    */
   function quote(s) {
     /*
      * ECMA-262, 5th ed., 7.8.4: All characters may appear literally in a
      * string literal except for the closing quote character, backslash,
      * carriage return, line separator, paragraph separator, and line feed.
      * Any character may appear in the form of an escape sequence.
      *
      * For portability, we also escape escape all control and non-ASCII
      * characters. Note that "\0" and "\v" escape sequences are not used
      * because JSHint does not like the first and IE the second.
      */
     return '"' + s.replace(/\\/g, '\\\\') // backslash
     .replace(/"/g, '\\"') // closing quote character
     .replace(/\x08/g, '\\b') // backspace
     .replace(/\t/g, '\\t') // horizontal tab
     .replace(/\n/g, '\\n') // line feed
     .replace(/\f/g, '\\f') // form feed
     .replace(/\r/g, '\\r') // carriage return
     .replace(/[\x00-\x07\x0B\x0E-\x1F\x80-\uFFFF]/g, escape) + '"';
   }
 
   var result = {
     /*
      * Parses the input with a generated parser. If the parsing is successfull,
      * returns a value explicitly or implicitly specified by the grammar from
      * which the parser was generated (see |PEG.buildParser|). If the parsing is
      * unsuccessful, throws |PEG.parser.SyntaxError| describing the error.
      */
     parse: function parse(input, startRule) {
       var parseFunctions = {
         "CRLF": parse_CRLF,
         "DIGIT": parse_DIGIT,
         "ALPHA": parse_ALPHA,
         "HEXDIG": parse_HEXDIG,
         "WSP": parse_WSP,
         "OCTET": parse_OCTET,
         "DQUOTE": parse_DQUOTE,
         "SP": parse_SP,
         "HTAB": parse_HTAB,
         "alphanum": parse_alphanum,
         "reserved": parse_reserved,
         "unreserved": parse_unreserved,
         "mark": parse_mark,
         "escaped": parse_escaped,
         "LWS": parse_LWS,
         "SWS": parse_SWS,
         "HCOLON": parse_HCOLON,
         "TEXT_UTF8_TRIM": parse_TEXT_UTF8_TRIM,
         "TEXT_UTF8char": parse_TEXT_UTF8char,
         "UTF8_NONASCII": parse_UTF8_NONASCII,
         "UTF8_CONT": parse_UTF8_CONT,
         "LHEX": parse_LHEX,
         "token": parse_token,
         "token_nodot": parse_token_nodot,
         "separators": parse_separators,
         "word": parse_word,
         "STAR": parse_STAR,
         "SLASH": parse_SLASH,
         "EQUAL": parse_EQUAL,
         "LPAREN": parse_LPAREN,
         "RPAREN": parse_RPAREN,
         "RAQUOT": parse_RAQUOT,
         "LAQUOT": parse_LAQUOT,
         "COMMA": parse_COMMA,
         "SEMI": parse_SEMI,
         "COLON": parse_COLON,
         "LDQUOT": parse_LDQUOT,
         "RDQUOT": parse_RDQUOT,
         "comment": parse_comment,
         "ctext": parse_ctext,
         "quoted_string": parse_quoted_string,
         "quoted_string_clean": parse_quoted_string_clean,
         "qdtext": parse_qdtext,
         "quoted_pair": parse_quoted_pair,
         "SIP_URI_noparams": parse_SIP_URI_noparams,
         "SIP_URI": parse_SIP_URI,
         "uri_scheme": parse_uri_scheme,
         "uri_scheme_sips": parse_uri_scheme_sips,
         "uri_scheme_sip": parse_uri_scheme_sip,
         "userinfo": parse_userinfo,
         "user": parse_user,
         "user_unreserved": parse_user_unreserved,
         "password": parse_password,
         "hostport": parse_hostport,
         "host": parse_host,
         "hostname": parse_hostname,
         "domainlabel": parse_domainlabel,
         "toplabel": parse_toplabel,
         "IPv6reference": parse_IPv6reference,
         "IPv6address": parse_IPv6address,
         "h16": parse_h16,
         "ls32": parse_ls32,
         "IPv4address": parse_IPv4address,
         "dec_octet": parse_dec_octet,
         "port": parse_port,
         "uri_parameters": parse_uri_parameters,
         "uri_parameter": parse_uri_parameter,
         "transport_param": parse_transport_param,
         "user_param": parse_user_param,
         "method_param": parse_method_param,
         "ttl_param": parse_ttl_param,
         "maddr_param": parse_maddr_param,
         "lr_param": parse_lr_param,
         "other_param": parse_other_param,
         "pname": parse_pname,
         "pvalue": parse_pvalue,
         "paramchar": parse_paramchar,
         "param_unreserved": parse_param_unreserved,
         "headers": parse_headers,
         "header": parse_header,
         "hname": parse_hname,
         "hvalue": parse_hvalue,
         "hnv_unreserved": parse_hnv_unreserved,
         "Request_Response": parse_Request_Response,
         "Request_Line": parse_Request_Line,
         "Request_URI": parse_Request_URI,
         "absoluteURI": parse_absoluteURI,
         "hier_part": parse_hier_part,
         "net_path": parse_net_path,
         "abs_path": parse_abs_path,
         "opaque_part": parse_opaque_part,
         "uric": parse_uric,
         "uric_no_slash": parse_uric_no_slash,
         "path_segments": parse_path_segments,
         "segment": parse_segment,
         "param": parse_param,
         "pchar": parse_pchar,
         "scheme": parse_scheme,
         "authority": parse_authority,
         "srvr": parse_srvr,
         "reg_name": parse_reg_name,
         "query": parse_query,
         "SIP_Version": parse_SIP_Version,
         "INVITEm": parse_INVITEm,
         "ACKm": parse_ACKm,
         "OPTIONSm": parse_OPTIONSm,
         "BYEm": parse_BYEm,
         "CANCELm": parse_CANCELm,
         "REGISTERm": parse_REGISTERm,
         "SUBSCRIBEm": parse_SUBSCRIBEm,
         "NOTIFYm": parse_NOTIFYm,
         "REFERm": parse_REFERm,
         "Method": parse_Method,
         "Status_Line": parse_Status_Line,
         "Status_Code": parse_Status_Code,
         "extension_code": parse_extension_code,
         "Reason_Phrase": parse_Reason_Phrase,
         "Allow_Events": parse_Allow_Events,
         "Call_ID": parse_Call_ID,
         "Contact": parse_Contact,
         "contact_param": parse_contact_param,
         "name_addr": parse_name_addr,
         "display_name": parse_display_name,
         "contact_params": parse_contact_params,
         "c_p_q": parse_c_p_q,
         "c_p_expires": parse_c_p_expires,
         "delta_seconds": parse_delta_seconds,
         "qvalue": parse_qvalue,
         "generic_param": parse_generic_param,
         "gen_value": parse_gen_value,
         "Content_Disposition": parse_Content_Disposition,
         "disp_type": parse_disp_type,
         "disp_param": parse_disp_param,
         "handling_param": parse_handling_param,
         "Content_Encoding": parse_Content_Encoding,
         "Content_Length": parse_Content_Length,
         "Content_Type": parse_Content_Type,
         "media_type": parse_media_type,
         "m_type": parse_m_type,
         "discrete_type": parse_discrete_type,
         "composite_type": parse_composite_type,
         "extension_token": parse_extension_token,
         "x_token": parse_x_token,
         "m_subtype": parse_m_subtype,
         "m_parameter": parse_m_parameter,
         "m_value": parse_m_value,
         "CSeq": parse_CSeq,
         "CSeq_value": parse_CSeq_value,
         "Expires": parse_Expires,
         "Event": parse_Event,
         "event_type": parse_event_type,
         "From": parse_From,
         "from_param": parse_from_param,
         "tag_param": parse_tag_param,
         "Max_Forwards": parse_Max_Forwards,
         "Min_Expires": parse_Min_Expires,
         "Name_Addr_Header": parse_Name_Addr_Header,
         "Proxy_Authenticate": parse_Proxy_Authenticate,
         "challenge": parse_challenge,
         "other_challenge": parse_other_challenge,
         "auth_param": parse_auth_param,
         "digest_cln": parse_digest_cln,
         "realm": parse_realm,
         "realm_value": parse_realm_value,
         "domain": parse_domain,
         "URI": parse_URI,
         "nonce": parse_nonce,
         "nonce_value": parse_nonce_value,
         "opaque": parse_opaque,
         "stale": parse_stale,
         "algorithm": parse_algorithm,
         "qop_options": parse_qop_options,
         "qop_value": parse_qop_value,
         "Proxy_Require": parse_Proxy_Require,
         "Record_Route": parse_Record_Route,
         "rec_route": parse_rec_route,
         "Reason": parse_Reason,
         "reason_param": parse_reason_param,
         "reason_cause": parse_reason_cause,
         "Require": parse_Require,
         "Route": parse_Route,
         "route_param": parse_route_param,
         "Subscription_State": parse_Subscription_State,
         "substate_value": parse_substate_value,
         "subexp_params": parse_subexp_params,
         "event_reason_value": parse_event_reason_value,
         "Subject": parse_Subject,
         "Supported": parse_Supported,
         "To": parse_To,
         "to_param": parse_to_param,
         "Via": parse_Via,
         "via_param": parse_via_param,
         "via_params": parse_via_params,
         "via_ttl": parse_via_ttl,
         "via_maddr": parse_via_maddr,
         "via_received": parse_via_received,
         "via_branch": parse_via_branch,
         "response_port": parse_response_port,
         "rport": parse_rport,
         "sent_protocol": parse_sent_protocol,
         "protocol_name": parse_protocol_name,
         "transport": parse_transport,
         "sent_by": parse_sent_by,
         "via_host": parse_via_host,
         "via_port": parse_via_port,
         "ttl": parse_ttl,
         "WWW_Authenticate": parse_WWW_Authenticate,
         "Session_Expires": parse_Session_Expires,
         "s_e_expires": parse_s_e_expires,
         "s_e_params": parse_s_e_params,
         "s_e_refresher": parse_s_e_refresher,
         "extension_header": parse_extension_header,
         "header_value": parse_header_value,
         "message_body": parse_message_body,
         "uuid_URI": parse_uuid_URI,
         "uuid": parse_uuid,
         "hex4": parse_hex4,
         "hex8": parse_hex8,
         "hex12": parse_hex12,
         "Refer_To": parse_Refer_To,
         "Replaces": parse_Replaces,
         "call_id": parse_call_id,
         "replaces_param": parse_replaces_param,
         "to_tag": parse_to_tag,
         "from_tag": parse_from_tag,
         "early_flag": parse_early_flag
       };
 
       if (startRule !== undefined) {
         if (parseFunctions[startRule] === undefined) {
           throw new Error("Invalid rule name: " + quote(startRule) + ".");
         }
       } else {
         startRule = "CRLF";
       }
 
       var pos = 0;
       var reportFailures = 0;
       var rightmostFailuresPos = 0;
       var rightmostFailuresExpected = [];
 
       function padLeft(input, padding, length) {
         var result = input;
         var padLength = length - input.length;
 
         for (var i = 0; i < padLength; i++) {
           result = padding + result;
         }
 
         return result;
       }
 
       function escape(ch) {
         var charCode = ch.charCodeAt(0);
         var escapeChar;
         var length;
 
         if (charCode <= 0xFF) {
           escapeChar = 'x';
           length = 2;
         } else {
           escapeChar = 'u';
           length = 4;
         }
 
         return '\\' + escapeChar + padLeft(charCode.toString(16).toUpperCase(), '0', length);
       }
 
       function matchFailed(failure) {
         if (pos < rightmostFailuresPos) {
           return;
         }
 
         if (pos > rightmostFailuresPos) {
           rightmostFailuresPos = pos;
           rightmostFailuresExpected = [];
         }
 
         rightmostFailuresExpected.push(failure);
       }
 
       function parse_CRLF() {
         var result0;
 
         if (input.substr(pos, 2) === "\r\n") {
           result0 = "\r\n";
           pos += 2;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"\\r\\n\"");
           }
         }
 
         return result0;
       }
 
       function parse_DIGIT() {
         var result0;
 
         if (/^[0-9]/.test(input.charAt(pos))) {
           result0 = input.charAt(pos);
           pos++;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("[0-9]");
           }
         }
 
         return result0;
       }
 
       function parse_ALPHA() {
         var result0;
 
         if (/^[a-zA-Z]/.test(input.charAt(pos))) {
           result0 = input.charAt(pos);
           pos++;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("[a-zA-Z]");
           }
         }
 
         return result0;
       }
 
       function parse_HEXDIG() {
         var result0;
 
         if (/^[0-9a-fA-F]/.test(input.charAt(pos))) {
           result0 = input.charAt(pos);
           pos++;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("[0-9a-fA-F]");
           }
         }
 
         return result0;
       }
 
       function parse_WSP() {
         var result0;
         result0 = parse_SP();
 
         if (result0 === null) {
           result0 = parse_HTAB();
         }
 
         return result0;
       }
 
       function parse_OCTET() {
         var result0;
 
         if (/^[\0-\xFF]/.test(input.charAt(pos))) {
           result0 = input.charAt(pos);
           pos++;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("[\\0-\\xFF]");
           }
         }
 
         return result0;
       }
 
       function parse_DQUOTE() {
         var result0;
 
         if (/^["]/.test(input.charAt(pos))) {
           result0 = input.charAt(pos);
           pos++;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("[\"]");
           }
         }
 
         return result0;
       }
 
       function parse_SP() {
         var result0;
 
         if (input.charCodeAt(pos) === 32) {
           result0 = " ";
           pos++;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\" \"");
           }
         }
 
         return result0;
       }
 
       function parse_HTAB() {
         var result0;
 
         if (input.charCodeAt(pos) === 9) {
           result0 = "\t";
           pos++;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"\\t\"");
           }
         }
 
         return result0;
       }
 
       function parse_alphanum() {
         var result0;
 
         if (/^[a-zA-Z0-9]/.test(input.charAt(pos))) {
           result0 = input.charAt(pos);
           pos++;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("[a-zA-Z0-9]");
           }
         }
 
         return result0;
       }
 
       function parse_reserved() {
         var result0;
 
         if (input.charCodeAt(pos) === 59) {
           result0 = ";";
           pos++;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\";\"");
           }
         }
 
         if (result0 === null) {
           if (input.charCodeAt(pos) === 47) {
             result0 = "/";
             pos++;
           } else {
             result0 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"/\"");
             }
           }
 
           if (result0 === null) {
             if (input.charCodeAt(pos) === 63) {
               result0 = "?";
               pos++;
             } else {
               result0 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\"?\"");
               }
             }
 
             if (result0 === null) {
               if (input.charCodeAt(pos) === 58) {
                 result0 = ":";
                 pos++;
               } else {
                 result0 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\":\"");
                 }
               }
 
               if (result0 === null) {
                 if (input.charCodeAt(pos) === 64) {
                   result0 = "@";
                   pos++;
                 } else {
                   result0 = null;
 
                   if (reportFailures === 0) {
                     matchFailed("\"@\"");
                   }
                 }
 
                 if (result0 === null) {
                   if (input.charCodeAt(pos) === 38) {
                     result0 = "&";
                     pos++;
                   } else {
                     result0 = null;
 
                     if (reportFailures === 0) {
                       matchFailed("\"&\"");
                     }
                   }
 
                   if (result0 === null) {
                     if (input.charCodeAt(pos) === 61) {
                       result0 = "=";
                       pos++;
                     } else {
                       result0 = null;
 
                       if (reportFailures === 0) {
                         matchFailed("\"=\"");
                       }
                     }
 
                     if (result0 === null) {
                       if (input.charCodeAt(pos) === 43) {
                         result0 = "+";
                         pos++;
                       } else {
                         result0 = null;
 
                         if (reportFailures === 0) {
                           matchFailed("\"+\"");
                         }
                       }
 
                       if (result0 === null) {
                         if (input.charCodeAt(pos) === 36) {
                           result0 = "$";
                           pos++;
                         } else {
                           result0 = null;
 
                           if (reportFailures === 0) {
                             matchFailed("\"$\"");
                           }
                         }
 
                         if (result0 === null) {
                           if (input.charCodeAt(pos) === 44) {
                             result0 = ",";
                             pos++;
                           } else {
                             result0 = null;
 
                             if (reportFailures === 0) {
                               matchFailed("\",\"");
                             }
                           }
                         }
                       }
                     }
                   }
                 }
               }
             }
           }
         }
 
         return result0;
       }
 
       function parse_unreserved() {
         var result0;
         result0 = parse_alphanum();
 
         if (result0 === null) {
           result0 = parse_mark();
         }
 
         return result0;
       }
 
       function parse_mark() {
         var result0;
 
         if (input.charCodeAt(pos) === 45) {
           result0 = "-";
           pos++;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"-\"");
           }
         }
 
         if (result0 === null) {
           if (input.charCodeAt(pos) === 95) {
             result0 = "_";
             pos++;
           } else {
             result0 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"_\"");
             }
           }
 
           if (result0 === null) {
             if (input.charCodeAt(pos) === 46) {
               result0 = ".";
               pos++;
             } else {
               result0 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\".\"");
               }
             }
 
             if (result0 === null) {
               if (input.charCodeAt(pos) === 33) {
                 result0 = "!";
                 pos++;
               } else {
                 result0 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\"!\"");
                 }
               }
 
               if (result0 === null) {
                 if (input.charCodeAt(pos) === 126) {
                   result0 = "~";
                   pos++;
                 } else {
                   result0 = null;
 
                   if (reportFailures === 0) {
                     matchFailed("\"~\"");
                   }
                 }
 
                 if (result0 === null) {
                   if (input.charCodeAt(pos) === 42) {
                     result0 = "*";
                     pos++;
                   } else {
                     result0 = null;
 
                     if (reportFailures === 0) {
                       matchFailed("\"*\"");
                     }
                   }
 
                   if (result0 === null) {
                     if (input.charCodeAt(pos) === 39) {
                       result0 = "'";
                       pos++;
                     } else {
                       result0 = null;
 
                       if (reportFailures === 0) {
                         matchFailed("\"'\"");
                       }
                     }
 
                     if (result0 === null) {
                       if (input.charCodeAt(pos) === 40) {
                         result0 = "(";
                         pos++;
                       } else {
                         result0 = null;
 
                         if (reportFailures === 0) {
                           matchFailed("\"(\"");
                         }
                       }
 
                       if (result0 === null) {
                         if (input.charCodeAt(pos) === 41) {
                           result0 = ")";
                           pos++;
                         } else {
                           result0 = null;
 
                           if (reportFailures === 0) {
                             matchFailed("\")\"");
                           }
                         }
                       }
                     }
                   }
                 }
               }
             }
           }
         }
 
         return result0;
       }
 
       function parse_escaped() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
 
         if (input.charCodeAt(pos) === 37) {
           result0 = "%";
           pos++;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"%\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_HEXDIG();
 
           if (result1 !== null) {
             result2 = parse_HEXDIG();
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset, escaped) {
             return escaped.join('');
           }(pos0, result0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_LWS() {
         var result0, result1, result2;
         var pos0, pos1, pos2;
         pos0 = pos;
         pos1 = pos;
         pos2 = pos;
         result0 = [];
         result1 = parse_WSP();
 
         while (result1 !== null) {
           result0.push(result1);
           result1 = parse_WSP();
         }
 
         if (result0 !== null) {
           result1 = parse_CRLF();
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos2;
           }
         } else {
           result0 = null;
           pos = pos2;
         }
 
         result0 = result0 !== null ? result0 : "";
 
         if (result0 !== null) {
           result2 = parse_WSP();
 
           if (result2 !== null) {
             result1 = [];
 
             while (result2 !== null) {
               result1.push(result2);
               result2 = parse_WSP();
             }
           } else {
             result1 = null;
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             return " ";
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_SWS() {
         var result0;
         result0 = parse_LWS();
         result0 = result0 !== null ? result0 : "";
         return result0;
       }
 
       function parse_HCOLON() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
         result0 = [];
         result1 = parse_SP();
 
         if (result1 === null) {
           result1 = parse_HTAB();
         }
 
         while (result1 !== null) {
           result0.push(result1);
           result1 = parse_SP();
 
           if (result1 === null) {
             result1 = parse_HTAB();
           }
         }
 
         if (result0 !== null) {
           if (input.charCodeAt(pos) === 58) {
             result1 = ":";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\":\"");
             }
           }
 
           if (result1 !== null) {
             result2 = parse_SWS();
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             return ':';
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_TEXT_UTF8_TRIM() {
         var result0, result1, result2, result3;
         var pos0, pos1, pos2;
         pos0 = pos;
         pos1 = pos;
         result1 = parse_TEXT_UTF8char();
 
         if (result1 !== null) {
           result0 = [];
 
           while (result1 !== null) {
             result0.push(result1);
             result1 = parse_TEXT_UTF8char();
           }
         } else {
           result0 = null;
         }
 
         if (result0 !== null) {
           result1 = [];
           pos2 = pos;
           result2 = [];
           result3 = parse_LWS();
 
           while (result3 !== null) {
             result2.push(result3);
             result3 = parse_LWS();
           }
 
           if (result2 !== null) {
             result3 = parse_TEXT_UTF8char();
 
             if (result3 !== null) {
               result2 = [result2, result3];
             } else {
               result2 = null;
               pos = pos2;
             }
           } else {
             result2 = null;
             pos = pos2;
           }
 
           while (result2 !== null) {
             result1.push(result2);
             pos2 = pos;
             result2 = [];
             result3 = parse_LWS();
 
             while (result3 !== null) {
               result2.push(result3);
               result3 = parse_LWS();
             }
 
             if (result2 !== null) {
               result3 = parse_TEXT_UTF8char();
 
               if (result3 !== null) {
                 result2 = [result2, result3];
               } else {
                 result2 = null;
                 pos = pos2;
               }
             } else {
               result2 = null;
               pos = pos2;
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             return input.substring(pos, offset);
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_TEXT_UTF8char() {
         var result0;
 
         if (/^[!-~]/.test(input.charAt(pos))) {
           result0 = input.charAt(pos);
           pos++;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("[!-~]");
           }
         }
 
         if (result0 === null) {
           result0 = parse_UTF8_NONASCII();
         }
 
         return result0;
       }
 
       function parse_UTF8_NONASCII() {
         var result0;
 
         if (/^[\x80-\uFFFF]/.test(input.charAt(pos))) {
           result0 = input.charAt(pos);
           pos++;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("[\\x80-\\uFFFF]");
           }
         }
 
         return result0;
       }
 
       function parse_UTF8_CONT() {
         var result0;
 
         if (/^[\x80-\xBF]/.test(input.charAt(pos))) {
           result0 = input.charAt(pos);
           pos++;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("[\\x80-\\xBF]");
           }
         }
 
         return result0;
       }
 
       function parse_LHEX() {
         var result0;
         result0 = parse_DIGIT();
 
         if (result0 === null) {
           if (/^[a-f]/.test(input.charAt(pos))) {
             result0 = input.charAt(pos);
             pos++;
           } else {
             result0 = null;
 
             if (reportFailures === 0) {
               matchFailed("[a-f]");
             }
           }
         }
 
         return result0;
       }
 
       function parse_token() {
         var result0, result1;
         var pos0;
         pos0 = pos;
         result1 = parse_alphanum();
 
         if (result1 === null) {
           if (input.charCodeAt(pos) === 45) {
             result1 = "-";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"-\"");
             }
           }
 
           if (result1 === null) {
             if (input.charCodeAt(pos) === 46) {
               result1 = ".";
               pos++;
             } else {
               result1 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\".\"");
               }
             }
 
             if (result1 === null) {
               if (input.charCodeAt(pos) === 33) {
                 result1 = "!";
                 pos++;
               } else {
                 result1 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\"!\"");
                 }
               }
 
               if (result1 === null) {
                 if (input.charCodeAt(pos) === 37) {
                   result1 = "%";
                   pos++;
                 } else {
                   result1 = null;
 
                   if (reportFailures === 0) {
                     matchFailed("\"%\"");
                   }
                 }
 
                 if (result1 === null) {
                   if (input.charCodeAt(pos) === 42) {
                     result1 = "*";
                     pos++;
                   } else {
                     result1 = null;
 
                     if (reportFailures === 0) {
                       matchFailed("\"*\"");
                     }
                   }
 
                   if (result1 === null) {
                     if (input.charCodeAt(pos) === 95) {
                       result1 = "_";
                       pos++;
                     } else {
                       result1 = null;
 
                       if (reportFailures === 0) {
                         matchFailed("\"_\"");
                       }
                     }
 
                     if (result1 === null) {
                       if (input.charCodeAt(pos) === 43) {
                         result1 = "+";
                         pos++;
                       } else {
                         result1 = null;
 
                         if (reportFailures === 0) {
                           matchFailed("\"+\"");
                         }
                       }
 
                       if (result1 === null) {
                         if (input.charCodeAt(pos) === 96) {
                           result1 = "`";
                           pos++;
                         } else {
                           result1 = null;
 
                           if (reportFailures === 0) {
                             matchFailed("\"`\"");
                           }
                         }
 
                         if (result1 === null) {
                           if (input.charCodeAt(pos) === 39) {
                             result1 = "'";
                             pos++;
                           } else {
                             result1 = null;
 
                             if (reportFailures === 0) {
                               matchFailed("\"'\"");
                             }
                           }
 
                           if (result1 === null) {
                             if (input.charCodeAt(pos) === 126) {
                               result1 = "~";
                               pos++;
                             } else {
                               result1 = null;
 
                               if (reportFailures === 0) {
                                 matchFailed("\"~\"");
                               }
                             }
                           }
                         }
                       }
                     }
                   }
                 }
               }
             }
           }
         }
 
         if (result1 !== null) {
           result0 = [];
 
           while (result1 !== null) {
             result0.push(result1);
             result1 = parse_alphanum();
 
             if (result1 === null) {
               if (input.charCodeAt(pos) === 45) {
                 result1 = "-";
                 pos++;
               } else {
                 result1 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\"-\"");
                 }
               }
 
               if (result1 === null) {
                 if (input.charCodeAt(pos) === 46) {
                   result1 = ".";
                   pos++;
                 } else {
                   result1 = null;
 
                   if (reportFailures === 0) {
                     matchFailed("\".\"");
                   }
                 }
 
                 if (result1 === null) {
                   if (input.charCodeAt(pos) === 33) {
                     result1 = "!";
                     pos++;
                   } else {
                     result1 = null;
 
                     if (reportFailures === 0) {
                       matchFailed("\"!\"");
                     }
                   }
 
                   if (result1 === null) {
                     if (input.charCodeAt(pos) === 37) {
                       result1 = "%";
                       pos++;
                     } else {
                       result1 = null;
 
                       if (reportFailures === 0) {
                         matchFailed("\"%\"");
                       }
                     }
 
                     if (result1 === null) {
                       if (input.charCodeAt(pos) === 42) {
                         result1 = "*";
                         pos++;
                       } else {
                         result1 = null;
 
                         if (reportFailures === 0) {
                           matchFailed("\"*\"");
                         }
                       }
 
                       if (result1 === null) {
                         if (input.charCodeAt(pos) === 95) {
                           result1 = "_";
                           pos++;
                         } else {
                           result1 = null;
 
                           if (reportFailures === 0) {
                             matchFailed("\"_\"");
                           }
                         }
 
                         if (result1 === null) {
                           if (input.charCodeAt(pos) === 43) {
                             result1 = "+";
                             pos++;
                           } else {
                             result1 = null;
 
                             if (reportFailures === 0) {
                               matchFailed("\"+\"");
                             }
                           }
 
                           if (result1 === null) {
                             if (input.charCodeAt(pos) === 96) {
                               result1 = "`";
                               pos++;
                             } else {
                               result1 = null;
 
                               if (reportFailures === 0) {
                                 matchFailed("\"`\"");
                               }
                             }
 
                             if (result1 === null) {
                               if (input.charCodeAt(pos) === 39) {
                                 result1 = "'";
                                 pos++;
                               } else {
                                 result1 = null;
 
                                 if (reportFailures === 0) {
                                   matchFailed("\"'\"");
                                 }
                               }
 
                               if (result1 === null) {
                                 if (input.charCodeAt(pos) === 126) {
                                   result1 = "~";
                                   pos++;
                                 } else {
                                   result1 = null;
 
                                   if (reportFailures === 0) {
                                     matchFailed("\"~\"");
                                   }
                                 }
                               }
                             }
                           }
                         }
                       }
                     }
                   }
                 }
               }
             }
           }
         } else {
           result0 = null;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             return input.substring(pos, offset);
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_token_nodot() {
         var result0, result1;
         var pos0;
         pos0 = pos;
         result1 = parse_alphanum();
 
         if (result1 === null) {
           if (input.charCodeAt(pos) === 45) {
             result1 = "-";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"-\"");
             }
           }
 
           if (result1 === null) {
             if (input.charCodeAt(pos) === 33) {
               result1 = "!";
               pos++;
             } else {
               result1 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\"!\"");
               }
             }
 
             if (result1 === null) {
               if (input.charCodeAt(pos) === 37) {
                 result1 = "%";
                 pos++;
               } else {
                 result1 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\"%\"");
                 }
               }
 
               if (result1 === null) {
                 if (input.charCodeAt(pos) === 42) {
                   result1 = "*";
                   pos++;
                 } else {
                   result1 = null;
 
                   if (reportFailures === 0) {
                     matchFailed("\"*\"");
                   }
                 }
 
                 if (result1 === null) {
                   if (input.charCodeAt(pos) === 95) {
                     result1 = "_";
                     pos++;
                   } else {
                     result1 = null;
 
                     if (reportFailures === 0) {
                       matchFailed("\"_\"");
                     }
                   }
 
                   if (result1 === null) {
                     if (input.charCodeAt(pos) === 43) {
                       result1 = "+";
                       pos++;
                     } else {
                       result1 = null;
 
                       if (reportFailures === 0) {
                         matchFailed("\"+\"");
                       }
                     }
 
                     if (result1 === null) {
                       if (input.charCodeAt(pos) === 96) {
                         result1 = "`";
                         pos++;
                       } else {
                         result1 = null;
 
                         if (reportFailures === 0) {
                           matchFailed("\"`\"");
                         }
                       }
 
                       if (result1 === null) {
                         if (input.charCodeAt(pos) === 39) {
                           result1 = "'";
                           pos++;
                         } else {
                           result1 = null;
 
                           if (reportFailures === 0) {
                             matchFailed("\"'\"");
                           }
                         }
 
                         if (result1 === null) {
                           if (input.charCodeAt(pos) === 126) {
                             result1 = "~";
                             pos++;
                           } else {
                             result1 = null;
 
                             if (reportFailures === 0) {
                               matchFailed("\"~\"");
                             }
                           }
                         }
                       }
                     }
                   }
                 }
               }
             }
           }
         }
 
         if (result1 !== null) {
           result0 = [];
 
           while (result1 !== null) {
             result0.push(result1);
             result1 = parse_alphanum();
 
             if (result1 === null) {
               if (input.charCodeAt(pos) === 45) {
                 result1 = "-";
                 pos++;
               } else {
                 result1 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\"-\"");
                 }
               }
 
               if (result1 === null) {
                 if (input.charCodeAt(pos) === 33) {
                   result1 = "!";
                   pos++;
                 } else {
                   result1 = null;
 
                   if (reportFailures === 0) {
                     matchFailed("\"!\"");
                   }
                 }
 
                 if (result1 === null) {
                   if (input.charCodeAt(pos) === 37) {
                     result1 = "%";
                     pos++;
                   } else {
                     result1 = null;
 
                     if (reportFailures === 0) {
                       matchFailed("\"%\"");
                     }
                   }
 
                   if (result1 === null) {
                     if (input.charCodeAt(pos) === 42) {
                       result1 = "*";
                       pos++;
                     } else {
                       result1 = null;
 
                       if (reportFailures === 0) {
                         matchFailed("\"*\"");
                       }
                     }
 
                     if (result1 === null) {
                       if (input.charCodeAt(pos) === 95) {
                         result1 = "_";
                         pos++;
                       } else {
                         result1 = null;
 
                         if (reportFailures === 0) {
                           matchFailed("\"_\"");
                         }
                       }
 
                       if (result1 === null) {
                         if (input.charCodeAt(pos) === 43) {
                           result1 = "+";
                           pos++;
                         } else {
                           result1 = null;
 
                           if (reportFailures === 0) {
                             matchFailed("\"+\"");
                           }
                         }
 
                         if (result1 === null) {
                           if (input.charCodeAt(pos) === 96) {
                             result1 = "`";
                             pos++;
                           } else {
                             result1 = null;
 
                             if (reportFailures === 0) {
                               matchFailed("\"`\"");
                             }
                           }
 
                           if (result1 === null) {
                             if (input.charCodeAt(pos) === 39) {
                               result1 = "'";
                               pos++;
                             } else {
                               result1 = null;
 
                               if (reportFailures === 0) {
                                 matchFailed("\"'\"");
                               }
                             }
 
                             if (result1 === null) {
                               if (input.charCodeAt(pos) === 126) {
                                 result1 = "~";
                                 pos++;
                               } else {
                                 result1 = null;
 
                                 if (reportFailures === 0) {
                                   matchFailed("\"~\"");
                                 }
                               }
                             }
                           }
                         }
                       }
                     }
                   }
                 }
               }
             }
           }
         } else {
           result0 = null;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             return input.substring(pos, offset);
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_separators() {
         var result0;
 
         if (input.charCodeAt(pos) === 40) {
           result0 = "(";
           pos++;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"(\"");
           }
         }
 
         if (result0 === null) {
           if (input.charCodeAt(pos) === 41) {
             result0 = ")";
             pos++;
           } else {
             result0 = null;
 
             if (reportFailures === 0) {
               matchFailed("\")\"");
             }
           }
 
           if (result0 === null) {
             if (input.charCodeAt(pos) === 60) {
               result0 = "<";
               pos++;
             } else {
               result0 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\"<\"");
               }
             }
 
             if (result0 === null) {
               if (input.charCodeAt(pos) === 62) {
                 result0 = ">";
                 pos++;
               } else {
                 result0 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\">\"");
                 }
               }
 
               if (result0 === null) {
                 if (input.charCodeAt(pos) === 64) {
                   result0 = "@";
                   pos++;
                 } else {
                   result0 = null;
 
                   if (reportFailures === 0) {
                     matchFailed("\"@\"");
                   }
                 }
 
                 if (result0 === null) {
                   if (input.charCodeAt(pos) === 44) {
                     result0 = ",";
                     pos++;
                   } else {
                     result0 = null;
 
                     if (reportFailures === 0) {
                       matchFailed("\",\"");
                     }
                   }
 
                   if (result0 === null) {
                     if (input.charCodeAt(pos) === 59) {
                       result0 = ";";
                       pos++;
                     } else {
                       result0 = null;
 
                       if (reportFailures === 0) {
                         matchFailed("\";\"");
                       }
                     }
 
                     if (result0 === null) {
                       if (input.charCodeAt(pos) === 58) {
                         result0 = ":";
                         pos++;
                       } else {
                         result0 = null;
 
                         if (reportFailures === 0) {
                           matchFailed("\":\"");
                         }
                       }
 
                       if (result0 === null) {
                         if (input.charCodeAt(pos) === 92) {
                           result0 = "\\";
                           pos++;
                         } else {
                           result0 = null;
 
                           if (reportFailures === 0) {
                             matchFailed("\"\\\\\"");
                           }
                         }
 
                         if (result0 === null) {
                           result0 = parse_DQUOTE();
 
                           if (result0 === null) {
                             if (input.charCodeAt(pos) === 47) {
                               result0 = "/";
                               pos++;
                             } else {
                               result0 = null;
 
                               if (reportFailures === 0) {
                                 matchFailed("\"/\"");
                               }
                             }
 
                             if (result0 === null) {
                               if (input.charCodeAt(pos) === 91) {
                                 result0 = "[";
                                 pos++;
                               } else {
                                 result0 = null;
 
                                 if (reportFailures === 0) {
                                   matchFailed("\"[\"");
                                 }
                               }
 
                               if (result0 === null) {
                                 if (input.charCodeAt(pos) === 93) {
                                   result0 = "]";
                                   pos++;
                                 } else {
                                   result0 = null;
 
                                   if (reportFailures === 0) {
                                     matchFailed("\"]\"");
                                   }
                                 }
 
                                 if (result0 === null) {
                                   if (input.charCodeAt(pos) === 63) {
                                     result0 = "?";
                                     pos++;
                                   } else {
                                     result0 = null;
 
                                     if (reportFailures === 0) {
                                       matchFailed("\"?\"");
                                     }
                                   }
 
                                   if (result0 === null) {
                                     if (input.charCodeAt(pos) === 61) {
                                       result0 = "=";
                                       pos++;
                                     } else {
                                       result0 = null;
 
                                       if (reportFailures === 0) {
                                         matchFailed("\"=\"");
                                       }
                                     }
 
                                     if (result0 === null) {
                                       if (input.charCodeAt(pos) === 123) {
                                         result0 = "{";
                                         pos++;
                                       } else {
                                         result0 = null;
 
                                         if (reportFailures === 0) {
                                           matchFailed("\"{\"");
                                         }
                                       }
 
                                       if (result0 === null) {
                                         if (input.charCodeAt(pos) === 125) {
                                           result0 = "}";
                                           pos++;
                                         } else {
                                           result0 = null;
 
                                           if (reportFailures === 0) {
                                             matchFailed("\"}\"");
                                           }
                                         }
 
                                         if (result0 === null) {
                                           result0 = parse_SP();
 
                                           if (result0 === null) {
                                             result0 = parse_HTAB();
                                           }
                                         }
                                       }
                                     }
                                   }
                                 }
                               }
                             }
                           }
                         }
                       }
                     }
                   }
                 }
               }
             }
           }
         }
 
         return result0;
       }
 
       function parse_word() {
         var result0, result1;
         var pos0;
         pos0 = pos;
         result1 = parse_alphanum();
 
         if (result1 === null) {
           if (input.charCodeAt(pos) === 45) {
             result1 = "-";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"-\"");
             }
           }
 
           if (result1 === null) {
             if (input.charCodeAt(pos) === 46) {
               result1 = ".";
               pos++;
             } else {
               result1 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\".\"");
               }
             }
 
             if (result1 === null) {
               if (input.charCodeAt(pos) === 33) {
                 result1 = "!";
                 pos++;
               } else {
                 result1 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\"!\"");
                 }
               }
 
               if (result1 === null) {
                 if (input.charCodeAt(pos) === 37) {
                   result1 = "%";
                   pos++;
                 } else {
                   result1 = null;
 
                   if (reportFailures === 0) {
                     matchFailed("\"%\"");
                   }
                 }
 
                 if (result1 === null) {
                   if (input.charCodeAt(pos) === 42) {
                     result1 = "*";
                     pos++;
                   } else {
                     result1 = null;
 
                     if (reportFailures === 0) {
                       matchFailed("\"*\"");
                     }
                   }
 
                   if (result1 === null) {
                     if (input.charCodeAt(pos) === 95) {
                       result1 = "_";
                       pos++;
                     } else {
                       result1 = null;
 
                       if (reportFailures === 0) {
                         matchFailed("\"_\"");
                       }
                     }
 
                     if (result1 === null) {
                       if (input.charCodeAt(pos) === 43) {
                         result1 = "+";
                         pos++;
                       } else {
                         result1 = null;
 
                         if (reportFailures === 0) {
                           matchFailed("\"+\"");
                         }
                       }
 
                       if (result1 === null) {
                         if (input.charCodeAt(pos) === 96) {
                           result1 = "`";
                           pos++;
                         } else {
                           result1 = null;
 
                           if (reportFailures === 0) {
                             matchFailed("\"`\"");
                           }
                         }
 
                         if (result1 === null) {
                           if (input.charCodeAt(pos) === 39) {
                             result1 = "'";
                             pos++;
                           } else {
                             result1 = null;
 
                             if (reportFailures === 0) {
                               matchFailed("\"'\"");
                             }
                           }
 
                           if (result1 === null) {
                             if (input.charCodeAt(pos) === 126) {
                               result1 = "~";
                               pos++;
                             } else {
                               result1 = null;
 
                               if (reportFailures === 0) {
                                 matchFailed("\"~\"");
                               }
                             }
 
                             if (result1 === null) {
                               if (input.charCodeAt(pos) === 40) {
                                 result1 = "(";
                                 pos++;
                               } else {
                                 result1 = null;
 
                                 if (reportFailures === 0) {
                                   matchFailed("\"(\"");
                                 }
                               }
 
                               if (result1 === null) {
                                 if (input.charCodeAt(pos) === 41) {
                                   result1 = ")";
                                   pos++;
                                 } else {
                                   result1 = null;
 
                                   if (reportFailures === 0) {
                                     matchFailed("\")\"");
                                   }
                                 }
 
                                 if (result1 === null) {
                                   if (input.charCodeAt(pos) === 60) {
                                     result1 = "<";
                                     pos++;
                                   } else {
                                     result1 = null;
 
                                     if (reportFailures === 0) {
                                       matchFailed("\"<\"");
                                     }
                                   }
 
                                   if (result1 === null) {
                                     if (input.charCodeAt(pos) === 62) {
                                       result1 = ">";
                                       pos++;
                                     } else {
                                       result1 = null;
 
                                       if (reportFailures === 0) {
                                         matchFailed("\">\"");
                                       }
                                     }
 
                                     if (result1 === null) {
                                       if (input.charCodeAt(pos) === 58) {
                                         result1 = ":";
                                         pos++;
                                       } else {
                                         result1 = null;
 
                                         if (reportFailures === 0) {
                                           matchFailed("\":\"");
                                         }
                                       }
 
                                       if (result1 === null) {
                                         if (input.charCodeAt(pos) === 92) {
                                           result1 = "\\";
                                           pos++;
                                         } else {
                                           result1 = null;
 
                                           if (reportFailures === 0) {
                                             matchFailed("\"\\\\\"");
                                           }
                                         }
 
                                         if (result1 === null) {
                                           result1 = parse_DQUOTE();
 
                                           if (result1 === null) {
                                             if (input.charCodeAt(pos) === 47) {
                                               result1 = "/";
                                               pos++;
                                             } else {
                                               result1 = null;
 
                                               if (reportFailures === 0) {
                                                 matchFailed("\"/\"");
                                               }
                                             }
 
                                             if (result1 === null) {
                                               if (input.charCodeAt(pos) === 91) {
                                                 result1 = "[";
                                                 pos++;
                                               } else {
                                                 result1 = null;
 
                                                 if (reportFailures === 0) {
                                                   matchFailed("\"[\"");
                                                 }
                                               }
 
                                               if (result1 === null) {
                                                 if (input.charCodeAt(pos) === 93) {
                                                   result1 = "]";
                                                   pos++;
                                                 } else {
                                                   result1 = null;
 
                                                   if (reportFailures === 0) {
                                                     matchFailed("\"]\"");
                                                   }
                                                 }
 
                                                 if (result1 === null) {
                                                   if (input.charCodeAt(pos) === 63) {
                                                     result1 = "?";
                                                     pos++;
                                                   } else {
                                                     result1 = null;
 
                                                     if (reportFailures === 0) {
                                                       matchFailed("\"?\"");
                                                     }
                                                   }
 
                                                   if (result1 === null) {
                                                     if (input.charCodeAt(pos) === 123) {
                                                       result1 = "{";
                                                       pos++;
                                                     } else {
                                                       result1 = null;
 
                                                       if (reportFailures === 0) {
                                                         matchFailed("\"{\"");
                                                       }
                                                     }
 
                                                     if (result1 === null) {
                                                       if (input.charCodeAt(pos) === 125) {
                                                         result1 = "}";
                                                         pos++;
                                                       } else {
                                                         result1 = null;
 
                                                         if (reportFailures === 0) {
                                                           matchFailed("\"}\"");
                                                         }
                                                       }
                                                     }
                                                   }
                                                 }
                                               }
                                             }
                                           }
                                         }
                                       }
                                     }
                                   }
                                 }
                               }
                             }
                           }
                         }
                       }
                     }
                   }
                 }
               }
             }
           }
         }
 
         if (result1 !== null) {
           result0 = [];
 
           while (result1 !== null) {
             result0.push(result1);
             result1 = parse_alphanum();
 
             if (result1 === null) {
               if (input.charCodeAt(pos) === 45) {
                 result1 = "-";
                 pos++;
               } else {
                 result1 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\"-\"");
                 }
               }
 
               if (result1 === null) {
                 if (input.charCodeAt(pos) === 46) {
                   result1 = ".";
                   pos++;
                 } else {
                   result1 = null;
 
                   if (reportFailures === 0) {
                     matchFailed("\".\"");
                   }
                 }
 
                 if (result1 === null) {
                   if (input.charCodeAt(pos) === 33) {
                     result1 = "!";
                     pos++;
                   } else {
                     result1 = null;
 
                     if (reportFailures === 0) {
                       matchFailed("\"!\"");
                     }
                   }
 
                   if (result1 === null) {
                     if (input.charCodeAt(pos) === 37) {
                       result1 = "%";
                       pos++;
                     } else {
                       result1 = null;
 
                       if (reportFailures === 0) {
                         matchFailed("\"%\"");
                       }
                     }
 
                     if (result1 === null) {
                       if (input.charCodeAt(pos) === 42) {
                         result1 = "*";
                         pos++;
                       } else {
                         result1 = null;
 
                         if (reportFailures === 0) {
                           matchFailed("\"*\"");
                         }
                       }
 
                       if (result1 === null) {
                         if (input.charCodeAt(pos) === 95) {
                           result1 = "_";
                           pos++;
                         } else {
                           result1 = null;
 
                           if (reportFailures === 0) {
                             matchFailed("\"_\"");
                           }
                         }
 
                         if (result1 === null) {
                           if (input.charCodeAt(pos) === 43) {
                             result1 = "+";
                             pos++;
                           } else {
                             result1 = null;
 
                             if (reportFailures === 0) {
                               matchFailed("\"+\"");
                             }
                           }
 
                           if (result1 === null) {
                             if (input.charCodeAt(pos) === 96) {
                               result1 = "`";
                               pos++;
                             } else {
                               result1 = null;
 
                               if (reportFailures === 0) {
                                 matchFailed("\"`\"");
                               }
                             }
 
                             if (result1 === null) {
                               if (input.charCodeAt(pos) === 39) {
                                 result1 = "'";
                                 pos++;
                               } else {
                                 result1 = null;
 
                                 if (reportFailures === 0) {
                                   matchFailed("\"'\"");
                                 }
                               }
 
                               if (result1 === null) {
                                 if (input.charCodeAt(pos) === 126) {
                                   result1 = "~";
                                   pos++;
                                 } else {
                                   result1 = null;
 
                                   if (reportFailures === 0) {
                                     matchFailed("\"~\"");
                                   }
                                 }
 
                                 if (result1 === null) {
                                   if (input.charCodeAt(pos) === 40) {
                                     result1 = "(";
                                     pos++;
                                   } else {
                                     result1 = null;
 
                                     if (reportFailures === 0) {
                                       matchFailed("\"(\"");
                                     }
                                   }
 
                                   if (result1 === null) {
                                     if (input.charCodeAt(pos) === 41) {
                                       result1 = ")";
                                       pos++;
                                     } else {
                                       result1 = null;
 
                                       if (reportFailures === 0) {
                                         matchFailed("\")\"");
                                       }
                                     }
 
                                     if (result1 === null) {
                                       if (input.charCodeAt(pos) === 60) {
                                         result1 = "<";
                                         pos++;
                                       } else {
                                         result1 = null;
 
                                         if (reportFailures === 0) {
                                           matchFailed("\"<\"");
                                         }
                                       }
 
                                       if (result1 === null) {
                                         if (input.charCodeAt(pos) === 62) {
                                           result1 = ">";
                                           pos++;
                                         } else {
                                           result1 = null;
 
                                           if (reportFailures === 0) {
                                             matchFailed("\">\"");
                                           }
                                         }
 
                                         if (result1 === null) {
                                           if (input.charCodeAt(pos) === 58) {
                                             result1 = ":";
                                             pos++;
                                           } else {
                                             result1 = null;
 
                                             if (reportFailures === 0) {
                                               matchFailed("\":\"");
                                             }
                                           }
 
                                           if (result1 === null) {
                                             if (input.charCodeAt(pos) === 92) {
                                               result1 = "\\";
                                               pos++;
                                             } else {
                                               result1 = null;
 
                                               if (reportFailures === 0) {
                                                 matchFailed("\"\\\\\"");
                                               }
                                             }
 
                                             if (result1 === null) {
                                               result1 = parse_DQUOTE();
 
                                               if (result1 === null) {
                                                 if (input.charCodeAt(pos) === 47) {
                                                   result1 = "/";
                                                   pos++;
                                                 } else {
                                                   result1 = null;
 
                                                   if (reportFailures === 0) {
                                                     matchFailed("\"/\"");
                                                   }
                                                 }
 
                                                 if (result1 === null) {
                                                   if (input.charCodeAt(pos) === 91) {
                                                     result1 = "[";
                                                     pos++;
                                                   } else {
                                                     result1 = null;
 
                                                     if (reportFailures === 0) {
                                                       matchFailed("\"[\"");
                                                     }
                                                   }
 
                                                   if (result1 === null) {
                                                     if (input.charCodeAt(pos) === 93) {
                                                       result1 = "]";
                                                       pos++;
                                                     } else {
                                                       result1 = null;
 
                                                       if (reportFailures === 0) {
                                                         matchFailed("\"]\"");
                                                       }
                                                     }
 
                                                     if (result1 === null) {
                                                       if (input.charCodeAt(pos) === 63) {
                                                         result1 = "?";
                                                         pos++;
                                                       } else {
                                                         result1 = null;
 
                                                         if (reportFailures === 0) {
                                                           matchFailed("\"?\"");
                                                         }
                                                       }
 
                                                       if (result1 === null) {
                                                         if (input.charCodeAt(pos) === 123) {
                                                           result1 = "{";
                                                           pos++;
                                                         } else {
                                                           result1 = null;
 
                                                           if (reportFailures === 0) {
                                                             matchFailed("\"{\"");
                                                           }
                                                         }
 
                                                         if (result1 === null) {
                                                           if (input.charCodeAt(pos) === 125) {
                                                             result1 = "}";
                                                             pos++;
                                                           } else {
                                                             result1 = null;
 
                                                             if (reportFailures === 0) {
                                                               matchFailed("\"}\"");
                                                             }
                                                           }
                                                         }
                                                       }
                                                     }
                                                   }
                                                 }
                                               }
                                             }
                                           }
                                         }
                                       }
                                     }
                                   }
                                 }
                               }
                             }
                           }
                         }
                       }
                     }
                   }
                 }
               }
             }
           }
         } else {
           result0 = null;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             return input.substring(pos, offset);
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_STAR() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_SWS();
 
         if (result0 !== null) {
           if (input.charCodeAt(pos) === 42) {
             result1 = "*";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"*\"");
             }
           }
 
           if (result1 !== null) {
             result2 = parse_SWS();
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             return "*";
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_SLASH() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_SWS();
 
         if (result0 !== null) {
           if (input.charCodeAt(pos) === 47) {
             result1 = "/";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"/\"");
             }
           }
 
           if (result1 !== null) {
             result2 = parse_SWS();
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             return "/";
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_EQUAL() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_SWS();
 
         if (result0 !== null) {
           if (input.charCodeAt(pos) === 61) {
             result1 = "=";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"=\"");
             }
           }
 
           if (result1 !== null) {
             result2 = parse_SWS();
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             return "=";
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_LPAREN() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_SWS();
 
         if (result0 !== null) {
           if (input.charCodeAt(pos) === 40) {
             result1 = "(";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"(\"");
             }
           }
 
           if (result1 !== null) {
             result2 = parse_SWS();
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             return "(";
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_RPAREN() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_SWS();
 
         if (result0 !== null) {
           if (input.charCodeAt(pos) === 41) {
             result1 = ")";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\")\"");
             }
           }
 
           if (result1 !== null) {
             result2 = parse_SWS();
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             return ")";
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_RAQUOT() {
         var result0, result1;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
 
         if (input.charCodeAt(pos) === 62) {
           result0 = ">";
           pos++;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\">\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_SWS();
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             return ">";
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_LAQUOT() {
         var result0, result1;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_SWS();
 
         if (result0 !== null) {
           if (input.charCodeAt(pos) === 60) {
             result1 = "<";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"<\"");
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             return "<";
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_COMMA() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_SWS();
 
         if (result0 !== null) {
           if (input.charCodeAt(pos) === 44) {
             result1 = ",";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\",\"");
             }
           }
 
           if (result1 !== null) {
             result2 = parse_SWS();
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             return ",";
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_SEMI() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_SWS();
 
         if (result0 !== null) {
           if (input.charCodeAt(pos) === 59) {
             result1 = ";";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\";\"");
             }
           }
 
           if (result1 !== null) {
             result2 = parse_SWS();
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             return ";";
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_COLON() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_SWS();
 
         if (result0 !== null) {
           if (input.charCodeAt(pos) === 58) {
             result1 = ":";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\":\"");
             }
           }
 
           if (result1 !== null) {
             result2 = parse_SWS();
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             return ":";
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_LDQUOT() {
         var result0, result1;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_SWS();
 
         if (result0 !== null) {
           result1 = parse_DQUOTE();
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             return "\"";
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_RDQUOT() {
         var result0, result1;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_DQUOTE();
 
         if (result0 !== null) {
           result1 = parse_SWS();
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             return "\"";
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_comment() {
         var result0, result1, result2;
         var pos0;
         pos0 = pos;
         result0 = parse_LPAREN();
 
         if (result0 !== null) {
           result1 = [];
           result2 = parse_ctext();
 
           if (result2 === null) {
             result2 = parse_quoted_pair();
 
             if (result2 === null) {
               result2 = parse_comment();
             }
           }
 
           while (result2 !== null) {
             result1.push(result2);
             result2 = parse_ctext();
 
             if (result2 === null) {
               result2 = parse_quoted_pair();
 
               if (result2 === null) {
                 result2 = parse_comment();
               }
             }
           }
 
           if (result1 !== null) {
             result2 = parse_RPAREN();
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos0;
             }
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_ctext() {
         var result0;
 
         if (/^[!-']/.test(input.charAt(pos))) {
           result0 = input.charAt(pos);
           pos++;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("[!-']");
           }
         }
 
         if (result0 === null) {
           if (/^[*-[]/.test(input.charAt(pos))) {
             result0 = input.charAt(pos);
             pos++;
           } else {
             result0 = null;
 
             if (reportFailures === 0) {
               matchFailed("[*-[]");
             }
           }
 
           if (result0 === null) {
             if (/^[\]-~]/.test(input.charAt(pos))) {
               result0 = input.charAt(pos);
               pos++;
             } else {
               result0 = null;
 
               if (reportFailures === 0) {
                 matchFailed("[\\]-~]");
               }
             }
 
             if (result0 === null) {
               result0 = parse_UTF8_NONASCII();
 
               if (result0 === null) {
                 result0 = parse_LWS();
               }
             }
           }
         }
 
         return result0;
       }
 
       function parse_quoted_string() {
         var result0, result1, result2, result3;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_SWS();
 
         if (result0 !== null) {
           result1 = parse_DQUOTE();
 
           if (result1 !== null) {
             result2 = [];
             result3 = parse_qdtext();
 
             if (result3 === null) {
               result3 = parse_quoted_pair();
             }
 
             while (result3 !== null) {
               result2.push(result3);
               result3 = parse_qdtext();
 
               if (result3 === null) {
                 result3 = parse_quoted_pair();
               }
             }
 
             if (result2 !== null) {
               result3 = parse_DQUOTE();
 
               if (result3 !== null) {
                 result0 = [result0, result1, result2, result3];
               } else {
                 result0 = null;
                 pos = pos1;
               }
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             return input.substring(pos, offset);
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_quoted_string_clean() {
         var result0, result1, result2, result3;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_SWS();
 
         if (result0 !== null) {
           result1 = parse_DQUOTE();
 
           if (result1 !== null) {
             result2 = [];
             result3 = parse_qdtext();
 
             if (result3 === null) {
               result3 = parse_quoted_pair();
             }
 
             while (result3 !== null) {
               result2.push(result3);
               result3 = parse_qdtext();
 
               if (result3 === null) {
                 result3 = parse_quoted_pair();
               }
             }
 
             if (result2 !== null) {
               result3 = parse_DQUOTE();
 
               if (result3 !== null) {
                 result0 = [result0, result1, result2, result3];
               } else {
                 result0 = null;
                 pos = pos1;
               }
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             var trimmed = input.substring(pos, offset).trim();
             return trimmed.substring(1, trimmed.length - 1) // remove outer quotes
             .replace(/\\([\x00-\x09\x0b-\x0c\x0e-\x7f])/g, '$1');
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_qdtext() {
         var result0;
         result0 = parse_LWS();
 
         if (result0 === null) {
           if (input.charCodeAt(pos) === 33) {
             result0 = "!";
             pos++;
           } else {
             result0 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"!\"");
             }
           }
 
           if (result0 === null) {
             if (/^[#-[]/.test(input.charAt(pos))) {
               result0 = input.charAt(pos);
               pos++;
             } else {
               result0 = null;
 
               if (reportFailures === 0) {
                 matchFailed("[#-[]");
               }
             }
 
             if (result0 === null) {
               if (/^[\]-~]/.test(input.charAt(pos))) {
                 result0 = input.charAt(pos);
                 pos++;
               } else {
                 result0 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("[\\]-~]");
                 }
               }
 
               if (result0 === null) {
                 result0 = parse_UTF8_NONASCII();
               }
             }
           }
         }
 
         return result0;
       }
 
       function parse_quoted_pair() {
         var result0, result1;
         var pos0;
         pos0 = pos;
 
         if (input.charCodeAt(pos) === 92) {
           result0 = "\\";
           pos++;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"\\\\\"");
           }
         }
 
         if (result0 !== null) {
           if (/^[\0-\t]/.test(input.charAt(pos))) {
             result1 = input.charAt(pos);
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("[\\0-\\t]");
             }
           }
 
           if (result1 === null) {
             if (/^[\x0B-\f]/.test(input.charAt(pos))) {
               result1 = input.charAt(pos);
               pos++;
             } else {
               result1 = null;
 
               if (reportFailures === 0) {
                 matchFailed("[\\x0B-\\f]");
               }
             }
 
             if (result1 === null) {
               if (/^[\x0E-]/.test(input.charAt(pos))) {
                 result1 = input.charAt(pos);
                 pos++;
               } else {
                 result1 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("[\\x0E-]");
                 }
               }
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_SIP_URI_noparams() {
         var result0, result1, result2, result3;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_uri_scheme();
 
         if (result0 !== null) {
           if (input.charCodeAt(pos) === 58) {
             result1 = ":";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\":\"");
             }
           }
 
           if (result1 !== null) {
             result2 = parse_userinfo();
             result2 = result2 !== null ? result2 : "";
 
             if (result2 !== null) {
               result3 = parse_hostport();
 
               if (result3 !== null) {
                 result0 = [result0, result1, result2, result3];
               } else {
                 result0 = null;
                 pos = pos1;
               }
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             try {
               data.uri = new URI(data.scheme, data.user, data.host, data.port);
               delete data.scheme;
               delete data.user;
               delete data.host;
               delete data.host_type;
               delete data.port;
             } catch (e) {
               data = -1;
             }
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_SIP_URI() {
         var result0, result1, result2, result3, result4, result5;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_uri_scheme();
 
         if (result0 !== null) {
           if (input.charCodeAt(pos) === 58) {
             result1 = ":";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\":\"");
             }
           }
 
           if (result1 !== null) {
             result2 = parse_userinfo();
             result2 = result2 !== null ? result2 : "";
 
             if (result2 !== null) {
               result3 = parse_hostport();
 
               if (result3 !== null) {
                 result4 = parse_uri_parameters();
 
                 if (result4 !== null) {
                   result5 = parse_headers();
                   result5 = result5 !== null ? result5 : "";
 
                   if (result5 !== null) {
                     result0 = [result0, result1, result2, result3, result4, result5];
                   } else {
                     result0 = null;
                     pos = pos1;
                   }
                 } else {
                   result0 = null;
                   pos = pos1;
                 }
               } else {
                 result0 = null;
                 pos = pos1;
               }
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             var header;
 
             try {
               data.uri = new URI(data.scheme, data.user, data.host, data.port, data.uri_params, data.uri_headers);
               delete data.scheme;
               delete data.user;
               delete data.host;
               delete data.host_type;
               delete data.port;
               delete data.uri_params;
 
               if (startRule === 'SIP_URI') {
                 data = data.uri;
               }
             } catch (e) {
               data = -1;
             }
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_uri_scheme() {
         var result0;
         result0 = parse_uri_scheme_sips();
 
         if (result0 === null) {
           result0 = parse_uri_scheme_sip();
         }
 
         return result0;
       }
 
       function parse_uri_scheme_sips() {
         var result0;
         var pos0;
         pos0 = pos;
 
         if (input.substr(pos, 4).toLowerCase() === "sips") {
           result0 = input.substr(pos, 4);
           pos += 4;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"sips\"");
           }
         }
 
         if (result0 !== null) {
           result0 = function (offset, scheme) {
             data.scheme = scheme.toLowerCase();
           }(pos0, result0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_uri_scheme_sip() {
         var result0;
         var pos0;
         pos0 = pos;
 
         if (input.substr(pos, 3).toLowerCase() === "sip") {
           result0 = input.substr(pos, 3);
           pos += 3;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"sip\"");
           }
         }
 
         if (result0 !== null) {
           result0 = function (offset, scheme) {
             data.scheme = scheme.toLowerCase();
           }(pos0, result0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_userinfo() {
         var result0, result1, result2;
         var pos0, pos1, pos2;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_user();
 
         if (result0 !== null) {
           pos2 = pos;
 
           if (input.charCodeAt(pos) === 58) {
             result1 = ":";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\":\"");
             }
           }
 
           if (result1 !== null) {
             result2 = parse_password();
 
             if (result2 !== null) {
               result1 = [result1, result2];
             } else {
               result1 = null;
               pos = pos2;
             }
           } else {
             result1 = null;
             pos = pos2;
           }
 
           result1 = result1 !== null ? result1 : "";
 
           if (result1 !== null) {
             if (input.charCodeAt(pos) === 64) {
               result2 = "@";
               pos++;
             } else {
               result2 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\"@\"");
               }
             }
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             data.user = decodeURIComponent(input.substring(pos - 1, offset));
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_user() {
         var result0, result1;
         result1 = parse_unreserved();
 
         if (result1 === null) {
           result1 = parse_escaped();
 
           if (result1 === null) {
             result1 = parse_user_unreserved();
           }
         }
 
         if (result1 !== null) {
           result0 = [];
 
           while (result1 !== null) {
             result0.push(result1);
             result1 = parse_unreserved();
 
             if (result1 === null) {
               result1 = parse_escaped();
 
               if (result1 === null) {
                 result1 = parse_user_unreserved();
               }
             }
           }
         } else {
           result0 = null;
         }
 
         return result0;
       }
 
       function parse_user_unreserved() {
         var result0;
 
         if (input.charCodeAt(pos) === 38) {
           result0 = "&";
           pos++;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"&\"");
           }
         }
 
         if (result0 === null) {
           if (input.charCodeAt(pos) === 61) {
             result0 = "=";
             pos++;
           } else {
             result0 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"=\"");
             }
           }
 
           if (result0 === null) {
             if (input.charCodeAt(pos) === 43) {
               result0 = "+";
               pos++;
             } else {
               result0 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\"+\"");
               }
             }
 
             if (result0 === null) {
               if (input.charCodeAt(pos) === 36) {
                 result0 = "$";
                 pos++;
               } else {
                 result0 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\"$\"");
                 }
               }
 
               if (result0 === null) {
                 if (input.charCodeAt(pos) === 44) {
                   result0 = ",";
                   pos++;
                 } else {
                   result0 = null;
 
                   if (reportFailures === 0) {
                     matchFailed("\",\"");
                   }
                 }
 
                 if (result0 === null) {
                   if (input.charCodeAt(pos) === 59) {
                     result0 = ";";
                     pos++;
                   } else {
                     result0 = null;
 
                     if (reportFailures === 0) {
                       matchFailed("\";\"");
                     }
                   }
 
                   if (result0 === null) {
                     if (input.charCodeAt(pos) === 63) {
                       result0 = "?";
                       pos++;
                     } else {
                       result0 = null;
 
                       if (reportFailures === 0) {
                         matchFailed("\"?\"");
                       }
                     }
 
                     if (result0 === null) {
                       if (input.charCodeAt(pos) === 47) {
                         result0 = "/";
                         pos++;
                       } else {
                         result0 = null;
 
                         if (reportFailures === 0) {
                           matchFailed("\"/\"");
                         }
                       }
                     }
                   }
                 }
               }
             }
           }
         }
 
         return result0;
       }
 
       function parse_password() {
         var result0, result1;
         var pos0;
         pos0 = pos;
         result0 = [];
         result1 = parse_unreserved();
 
         if (result1 === null) {
           result1 = parse_escaped();
 
           if (result1 === null) {
             if (input.charCodeAt(pos) === 38) {
               result1 = "&";
               pos++;
             } else {
               result1 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\"&\"");
               }
             }
 
             if (result1 === null) {
               if (input.charCodeAt(pos) === 61) {
                 result1 = "=";
                 pos++;
               } else {
                 result1 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\"=\"");
                 }
               }
 
               if (result1 === null) {
                 if (input.charCodeAt(pos) === 43) {
                   result1 = "+";
                   pos++;
                 } else {
                   result1 = null;
 
                   if (reportFailures === 0) {
                     matchFailed("\"+\"");
                   }
                 }
 
                 if (result1 === null) {
                   if (input.charCodeAt(pos) === 36) {
                     result1 = "$";
                     pos++;
                   } else {
                     result1 = null;
 
                     if (reportFailures === 0) {
                       matchFailed("\"$\"");
                     }
                   }
 
                   if (result1 === null) {
                     if (input.charCodeAt(pos) === 44) {
                       result1 = ",";
                       pos++;
                     } else {
                       result1 = null;
 
                       if (reportFailures === 0) {
                         matchFailed("\",\"");
                       }
                     }
                   }
                 }
               }
             }
           }
         }
 
         while (result1 !== null) {
           result0.push(result1);
           result1 = parse_unreserved();
 
           if (result1 === null) {
             result1 = parse_escaped();
 
             if (result1 === null) {
               if (input.charCodeAt(pos) === 38) {
                 result1 = "&";
                 pos++;
               } else {
                 result1 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\"&\"");
                 }
               }
 
               if (result1 === null) {
                 if (input.charCodeAt(pos) === 61) {
                   result1 = "=";
                   pos++;
                 } else {
                   result1 = null;
 
                   if (reportFailures === 0) {
                     matchFailed("\"=\"");
                   }
                 }
 
                 if (result1 === null) {
                   if (input.charCodeAt(pos) === 43) {
                     result1 = "+";
                     pos++;
                   } else {
                     result1 = null;
 
                     if (reportFailures === 0) {
                       matchFailed("\"+\"");
                     }
                   }
 
                   if (result1 === null) {
                     if (input.charCodeAt(pos) === 36) {
                       result1 = "$";
                       pos++;
                     } else {
                       result1 = null;
 
                       if (reportFailures === 0) {
                         matchFailed("\"$\"");
                       }
                     }
 
                     if (result1 === null) {
                       if (input.charCodeAt(pos) === 44) {
                         result1 = ",";
                         pos++;
                       } else {
                         result1 = null;
 
                         if (reportFailures === 0) {
                           matchFailed("\",\"");
                         }
                       }
                     }
                   }
                 }
               }
             }
           }
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             data.password = input.substring(pos, offset);
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_hostport() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
         result0 = parse_host();
 
         if (result0 !== null) {
           pos1 = pos;
 
           if (input.charCodeAt(pos) === 58) {
             result1 = ":";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\":\"");
             }
           }
 
           if (result1 !== null) {
             result2 = parse_port();
 
             if (result2 !== null) {
               result1 = [result1, result2];
             } else {
               result1 = null;
               pos = pos1;
             }
           } else {
             result1 = null;
             pos = pos1;
           }
 
           result1 = result1 !== null ? result1 : "";
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_host() {
         var result0;
         var pos0;
         pos0 = pos;
         result0 = parse_hostname();
 
         if (result0 === null) {
           result0 = parse_IPv4address();
 
           if (result0 === null) {
             result0 = parse_IPv6reference();
           }
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             data.host = input.substring(pos, offset).toLowerCase();
             return data.host;
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_hostname() {
         var result0, result1, result2;
         var pos0, pos1, pos2;
         pos0 = pos;
         pos1 = pos;
         result0 = [];
         pos2 = pos;
         result1 = parse_domainlabel();
 
         if (result1 !== null) {
           if (input.charCodeAt(pos) === 46) {
             result2 = ".";
             pos++;
           } else {
             result2 = null;
 
             if (reportFailures === 0) {
               matchFailed("\".\"");
             }
           }
 
           if (result2 !== null) {
             result1 = [result1, result2];
           } else {
             result1 = null;
             pos = pos2;
           }
         } else {
           result1 = null;
           pos = pos2;
         }
 
         while (result1 !== null) {
           result0.push(result1);
           pos2 = pos;
           result1 = parse_domainlabel();
 
           if (result1 !== null) {
             if (input.charCodeAt(pos) === 46) {
               result2 = ".";
               pos++;
             } else {
               result2 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\".\"");
               }
             }
 
             if (result2 !== null) {
               result1 = [result1, result2];
             } else {
               result1 = null;
               pos = pos2;
             }
           } else {
             result1 = null;
             pos = pos2;
           }
         }
 
         if (result0 !== null) {
           result1 = parse_toplabel();
 
           if (result1 !== null) {
             if (input.charCodeAt(pos) === 46) {
               result2 = ".";
               pos++;
             } else {
               result2 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\".\"");
               }
             }
 
             result2 = result2 !== null ? result2 : "";
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             data.host_type = 'domain';
             return input.substring(pos, offset);
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_domainlabel() {
         var result0, result1, result2;
         var pos0;
         pos0 = pos;
         result0 = parse_alphanum();
 
         if (result0 !== null) {
           result1 = [];
           result2 = parse_alphanum();
 
           if (result2 === null) {
             if (input.charCodeAt(pos) === 45) {
               result2 = "-";
               pos++;
             } else {
               result2 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\"-\"");
               }
             }
 
             if (result2 === null) {
               if (input.charCodeAt(pos) === 95) {
                 result2 = "_";
                 pos++;
               } else {
                 result2 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\"_\"");
                 }
               }
             }
           }
 
           while (result2 !== null) {
             result1.push(result2);
             result2 = parse_alphanum();
 
             if (result2 === null) {
               if (input.charCodeAt(pos) === 45) {
                 result2 = "-";
                 pos++;
               } else {
                 result2 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\"-\"");
                 }
               }
 
               if (result2 === null) {
                 if (input.charCodeAt(pos) === 95) {
                   result2 = "_";
                   pos++;
                 } else {
                   result2 = null;
 
                   if (reportFailures === 0) {
                     matchFailed("\"_\"");
                   }
                 }
               }
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_toplabel() {
         var result0, result1, result2;
         var pos0;
         pos0 = pos;
         result0 = parse_ALPHA();
 
         if (result0 !== null) {
           result1 = [];
           result2 = parse_alphanum();
 
           if (result2 === null) {
             if (input.charCodeAt(pos) === 45) {
               result2 = "-";
               pos++;
             } else {
               result2 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\"-\"");
               }
             }
 
             if (result2 === null) {
               if (input.charCodeAt(pos) === 95) {
                 result2 = "_";
                 pos++;
               } else {
                 result2 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\"_\"");
                 }
               }
             }
           }
 
           while (result2 !== null) {
             result1.push(result2);
             result2 = parse_alphanum();
 
             if (result2 === null) {
               if (input.charCodeAt(pos) === 45) {
                 result2 = "-";
                 pos++;
               } else {
                 result2 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\"-\"");
                 }
               }
 
               if (result2 === null) {
                 if (input.charCodeAt(pos) === 95) {
                   result2 = "_";
                   pos++;
                 } else {
                   result2 = null;
 
                   if (reportFailures === 0) {
                     matchFailed("\"_\"");
                   }
                 }
               }
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_IPv6reference() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
 
         if (input.charCodeAt(pos) === 91) {
           result0 = "[";
           pos++;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"[\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_IPv6address();
 
           if (result1 !== null) {
             if (input.charCodeAt(pos) === 93) {
               result2 = "]";
               pos++;
             } else {
               result2 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\"]\"");
               }
             }
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             data.host_type = 'IPv6';
             return input.substring(pos, offset);
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_IPv6address() {
         var result0, result1, result2, result3, result4, result5, result6, result7, result8, result9, result10, result11, result12;
         var pos0, pos1, pos2;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_h16();
 
         if (result0 !== null) {
           if (input.charCodeAt(pos) === 58) {
             result1 = ":";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\":\"");
             }
           }
 
           if (result1 !== null) {
             result2 = parse_h16();
 
             if (result2 !== null) {
               if (input.charCodeAt(pos) === 58) {
                 result3 = ":";
                 pos++;
               } else {
                 result3 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\":\"");
                 }
               }
 
               if (result3 !== null) {
                 result4 = parse_h16();
 
                 if (result4 !== null) {
                   if (input.charCodeAt(pos) === 58) {
                     result5 = ":";
                     pos++;
                   } else {
                     result5 = null;
 
                     if (reportFailures === 0) {
                       matchFailed("\":\"");
                     }
                   }
 
                   if (result5 !== null) {
                     result6 = parse_h16();
 
                     if (result6 !== null) {
                       if (input.charCodeAt(pos) === 58) {
                         result7 = ":";
                         pos++;
                       } else {
                         result7 = null;
 
                         if (reportFailures === 0) {
                           matchFailed("\":\"");
                         }
                       }
 
                       if (result7 !== null) {
                         result8 = parse_h16();
 
                         if (result8 !== null) {
                           if (input.charCodeAt(pos) === 58) {
                             result9 = ":";
                             pos++;
                           } else {
                             result9 = null;
 
                             if (reportFailures === 0) {
                               matchFailed("\":\"");
                             }
                           }
 
                           if (result9 !== null) {
                             result10 = parse_h16();
 
                             if (result10 !== null) {
                               if (input.charCodeAt(pos) === 58) {
                                 result11 = ":";
                                 pos++;
                               } else {
                                 result11 = null;
 
                                 if (reportFailures === 0) {
                                   matchFailed("\":\"");
                                 }
                               }
 
                               if (result11 !== null) {
                                 result12 = parse_ls32();
 
                                 if (result12 !== null) {
                                   result0 = [result0, result1, result2, result3, result4, result5, result6, result7, result8, result9, result10, result11, result12];
                                 } else {
                                   result0 = null;
                                   pos = pos1;
                                 }
                               } else {
                                 result0 = null;
                                 pos = pos1;
                               }
                             } else {
                               result0 = null;
                               pos = pos1;
                             }
                           } else {
                             result0 = null;
                             pos = pos1;
                           }
                         } else {
                           result0 = null;
                           pos = pos1;
                         }
                       } else {
                         result0 = null;
                         pos = pos1;
                       }
                     } else {
                       result0 = null;
                       pos = pos1;
                     }
                   } else {
                     result0 = null;
                     pos = pos1;
                   }
                 } else {
                   result0 = null;
                   pos = pos1;
                 }
               } else {
                 result0 = null;
                 pos = pos1;
               }
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 === null) {
           pos1 = pos;
 
           if (input.substr(pos, 2) === "::") {
             result0 = "::";
             pos += 2;
           } else {
             result0 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"::\"");
             }
           }
 
           if (result0 !== null) {
             result1 = parse_h16();
 
             if (result1 !== null) {
               if (input.charCodeAt(pos) === 58) {
                 result2 = ":";
                 pos++;
               } else {
                 result2 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\":\"");
                 }
               }
 
               if (result2 !== null) {
                 result3 = parse_h16();
 
                 if (result3 !== null) {
                   if (input.charCodeAt(pos) === 58) {
                     result4 = ":";
                     pos++;
                   } else {
                     result4 = null;
 
                     if (reportFailures === 0) {
                       matchFailed("\":\"");
                     }
                   }
 
                   if (result4 !== null) {
                     result5 = parse_h16();
 
                     if (result5 !== null) {
                       if (input.charCodeAt(pos) === 58) {
                         result6 = ":";
                         pos++;
                       } else {
                         result6 = null;
 
                         if (reportFailures === 0) {
                           matchFailed("\":\"");
                         }
                       }
 
                       if (result6 !== null) {
                         result7 = parse_h16();
 
                         if (result7 !== null) {
                           if (input.charCodeAt(pos) === 58) {
                             result8 = ":";
                             pos++;
                           } else {
                             result8 = null;
 
                             if (reportFailures === 0) {
                               matchFailed("\":\"");
                             }
                           }
 
                           if (result8 !== null) {
                             result9 = parse_h16();
 
                             if (result9 !== null) {
                               if (input.charCodeAt(pos) === 58) {
                                 result10 = ":";
                                 pos++;
                               } else {
                                 result10 = null;
 
                                 if (reportFailures === 0) {
                                   matchFailed("\":\"");
                                 }
                               }
 
                               if (result10 !== null) {
                                 result11 = parse_ls32();
 
                                 if (result11 !== null) {
                                   result0 = [result0, result1, result2, result3, result4, result5, result6, result7, result8, result9, result10, result11];
                                 } else {
                                   result0 = null;
                                   pos = pos1;
                                 }
                               } else {
                                 result0 = null;
                                 pos = pos1;
                               }
                             } else {
                               result0 = null;
                               pos = pos1;
                             }
                           } else {
                             result0 = null;
                             pos = pos1;
                           }
                         } else {
                           result0 = null;
                           pos = pos1;
                         }
                       } else {
                         result0 = null;
                         pos = pos1;
                       }
                     } else {
                       result0 = null;
                       pos = pos1;
                     }
                   } else {
                     result0 = null;
                     pos = pos1;
                   }
                 } else {
                   result0 = null;
                   pos = pos1;
                 }
               } else {
                 result0 = null;
                 pos = pos1;
               }
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
 
           if (result0 === null) {
             pos1 = pos;
 
             if (input.substr(pos, 2) === "::") {
               result0 = "::";
               pos += 2;
             } else {
               result0 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\"::\"");
               }
             }
 
             if (result0 !== null) {
               result1 = parse_h16();
 
               if (result1 !== null) {
                 if (input.charCodeAt(pos) === 58) {
                   result2 = ":";
                   pos++;
                 } else {
                   result2 = null;
 
                   if (reportFailures === 0) {
                     matchFailed("\":\"");
                   }
                 }
 
                 if (result2 !== null) {
                   result3 = parse_h16();
 
                   if (result3 !== null) {
                     if (input.charCodeAt(pos) === 58) {
                       result4 = ":";
                       pos++;
                     } else {
                       result4 = null;
 
                       if (reportFailures === 0) {
                         matchFailed("\":\"");
                       }
                     }
 
                     if (result4 !== null) {
                       result5 = parse_h16();
 
                       if (result5 !== null) {
                         if (input.charCodeAt(pos) === 58) {
                           result6 = ":";
                           pos++;
                         } else {
                           result6 = null;
 
                           if (reportFailures === 0) {
                             matchFailed("\":\"");
                           }
                         }
 
                         if (result6 !== null) {
                           result7 = parse_h16();
 
                           if (result7 !== null) {
                             if (input.charCodeAt(pos) === 58) {
                               result8 = ":";
                               pos++;
                             } else {
                               result8 = null;
 
                               if (reportFailures === 0) {
                                 matchFailed("\":\"");
                               }
                             }
 
                             if (result8 !== null) {
                               result9 = parse_ls32();
 
                               if (result9 !== null) {
                                 result0 = [result0, result1, result2, result3, result4, result5, result6, result7, result8, result9];
                               } else {
                                 result0 = null;
                                 pos = pos1;
                               }
                             } else {
                               result0 = null;
                               pos = pos1;
                             }
                           } else {
                             result0 = null;
                             pos = pos1;
                           }
                         } else {
                           result0 = null;
                           pos = pos1;
                         }
                       } else {
                         result0 = null;
                         pos = pos1;
                       }
                     } else {
                       result0 = null;
                       pos = pos1;
                     }
                   } else {
                     result0 = null;
                     pos = pos1;
                   }
                 } else {
                   result0 = null;
                   pos = pos1;
                 }
               } else {
                 result0 = null;
                 pos = pos1;
               }
             } else {
               result0 = null;
               pos = pos1;
             }
 
             if (result0 === null) {
               pos1 = pos;
 
               if (input.substr(pos, 2) === "::") {
                 result0 = "::";
                 pos += 2;
               } else {
                 result0 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\"::\"");
                 }
               }
 
               if (result0 !== null) {
                 result1 = parse_h16();
 
                 if (result1 !== null) {
                   if (input.charCodeAt(pos) === 58) {
                     result2 = ":";
                     pos++;
                   } else {
                     result2 = null;
 
                     if (reportFailures === 0) {
                       matchFailed("\":\"");
                     }
                   }
 
                   if (result2 !== null) {
                     result3 = parse_h16();
 
                     if (result3 !== null) {
                       if (input.charCodeAt(pos) === 58) {
                         result4 = ":";
                         pos++;
                       } else {
                         result4 = null;
 
                         if (reportFailures === 0) {
                           matchFailed("\":\"");
                         }
                       }
 
                       if (result4 !== null) {
                         result5 = parse_h16();
 
                         if (result5 !== null) {
                           if (input.charCodeAt(pos) === 58) {
                             result6 = ":";
                             pos++;
                           } else {
                             result6 = null;
 
                             if (reportFailures === 0) {
                               matchFailed("\":\"");
                             }
                           }
 
                           if (result6 !== null) {
                             result7 = parse_ls32();
 
                             if (result7 !== null) {
                               result0 = [result0, result1, result2, result3, result4, result5, result6, result7];
                             } else {
                               result0 = null;
                               pos = pos1;
                             }
                           } else {
                             result0 = null;
                             pos = pos1;
                           }
                         } else {
                           result0 = null;
                           pos = pos1;
                         }
                       } else {
                         result0 = null;
                         pos = pos1;
                       }
                     } else {
                       result0 = null;
                       pos = pos1;
                     }
                   } else {
                     result0 = null;
                     pos = pos1;
                   }
                 } else {
                   result0 = null;
                   pos = pos1;
                 }
               } else {
                 result0 = null;
                 pos = pos1;
               }
 
               if (result0 === null) {
                 pos1 = pos;
 
                 if (input.substr(pos, 2) === "::") {
                   result0 = "::";
                   pos += 2;
                 } else {
                   result0 = null;
 
                   if (reportFailures === 0) {
                     matchFailed("\"::\"");
                   }
                 }
 
                 if (result0 !== null) {
                   result1 = parse_h16();
 
                   if (result1 !== null) {
                     if (input.charCodeAt(pos) === 58) {
                       result2 = ":";
                       pos++;
                     } else {
                       result2 = null;
 
                       if (reportFailures === 0) {
                         matchFailed("\":\"");
                       }
                     }
 
                     if (result2 !== null) {
                       result3 = parse_h16();
 
                       if (result3 !== null) {
                         if (input.charCodeAt(pos) === 58) {
                           result4 = ":";
                           pos++;
                         } else {
                           result4 = null;
 
                           if (reportFailures === 0) {
                             matchFailed("\":\"");
                           }
                         }
 
                         if (result4 !== null) {
                           result5 = parse_ls32();
 
                           if (result5 !== null) {
                             result0 = [result0, result1, result2, result3, result4, result5];
                           } else {
                             result0 = null;
                             pos = pos1;
                           }
                         } else {
                           result0 = null;
                           pos = pos1;
                         }
                       } else {
                         result0 = null;
                         pos = pos1;
                       }
                     } else {
                       result0 = null;
                       pos = pos1;
                     }
                   } else {
                     result0 = null;
                     pos = pos1;
                   }
                 } else {
                   result0 = null;
                   pos = pos1;
                 }
 
                 if (result0 === null) {
                   pos1 = pos;
 
                   if (input.substr(pos, 2) === "::") {
                     result0 = "::";
                     pos += 2;
                   } else {
                     result0 = null;
 
                     if (reportFailures === 0) {
                       matchFailed("\"::\"");
                     }
                   }
 
                   if (result0 !== null) {
                     result1 = parse_h16();
 
                     if (result1 !== null) {
                       if (input.charCodeAt(pos) === 58) {
                         result2 = ":";
                         pos++;
                       } else {
                         result2 = null;
 
                         if (reportFailures === 0) {
                           matchFailed("\":\"");
                         }
                       }
 
                       if (result2 !== null) {
                         result3 = parse_ls32();
 
                         if (result3 !== null) {
                           result0 = [result0, result1, result2, result3];
                         } else {
                           result0 = null;
                           pos = pos1;
                         }
                       } else {
                         result0 = null;
                         pos = pos1;
                       }
                     } else {
                       result0 = null;
                       pos = pos1;
                     }
                   } else {
                     result0 = null;
                     pos = pos1;
                   }
 
                   if (result0 === null) {
                     pos1 = pos;
 
                     if (input.substr(pos, 2) === "::") {
                       result0 = "::";
                       pos += 2;
                     } else {
                       result0 = null;
 
                       if (reportFailures === 0) {
                         matchFailed("\"::\"");
                       }
                     }
 
                     if (result0 !== null) {
                       result1 = parse_ls32();
 
                       if (result1 !== null) {
                         result0 = [result0, result1];
                       } else {
                         result0 = null;
                         pos = pos1;
                       }
                     } else {
                       result0 = null;
                       pos = pos1;
                     }
 
                     if (result0 === null) {
                       pos1 = pos;
 
                       if (input.substr(pos, 2) === "::") {
                         result0 = "::";
                         pos += 2;
                       } else {
                         result0 = null;
 
                         if (reportFailures === 0) {
                           matchFailed("\"::\"");
                         }
                       }
 
                       if (result0 !== null) {
                         result1 = parse_h16();
 
                         if (result1 !== null) {
                           result0 = [result0, result1];
                         } else {
                           result0 = null;
                           pos = pos1;
                         }
                       } else {
                         result0 = null;
                         pos = pos1;
                       }
 
                       if (result0 === null) {
                         pos1 = pos;
                         result0 = parse_h16();
 
                         if (result0 !== null) {
                           if (input.substr(pos, 2) === "::") {
                             result1 = "::";
                             pos += 2;
                           } else {
                             result1 = null;
 
                             if (reportFailures === 0) {
                               matchFailed("\"::\"");
                             }
                           }
 
                           if (result1 !== null) {
                             result2 = parse_h16();
 
                             if (result2 !== null) {
                               if (input.charCodeAt(pos) === 58) {
                                 result3 = ":";
                                 pos++;
                               } else {
                                 result3 = null;
 
                                 if (reportFailures === 0) {
                                   matchFailed("\":\"");
                                 }
                               }
 
                               if (result3 !== null) {
                                 result4 = parse_h16();
 
                                 if (result4 !== null) {
                                   if (input.charCodeAt(pos) === 58) {
                                     result5 = ":";
                                     pos++;
                                   } else {
                                     result5 = null;
 
                                     if (reportFailures === 0) {
                                       matchFailed("\":\"");
                                     }
                                   }
 
                                   if (result5 !== null) {
                                     result6 = parse_h16();
 
                                     if (result6 !== null) {
                                       if (input.charCodeAt(pos) === 58) {
                                         result7 = ":";
                                         pos++;
                                       } else {
                                         result7 = null;
 
                                         if (reportFailures === 0) {
                                           matchFailed("\":\"");
                                         }
                                       }
 
                                       if (result7 !== null) {
                                         result8 = parse_h16();
 
                                         if (result8 !== null) {
                                           if (input.charCodeAt(pos) === 58) {
                                             result9 = ":";
                                             pos++;
                                           } else {
                                             result9 = null;
 
                                             if (reportFailures === 0) {
                                               matchFailed("\":\"");
                                             }
                                           }
 
                                           if (result9 !== null) {
                                             result10 = parse_ls32();
 
                                             if (result10 !== null) {
                                               result0 = [result0, result1, result2, result3, result4, result5, result6, result7, result8, result9, result10];
                                             } else {
                                               result0 = null;
                                               pos = pos1;
                                             }
                                           } else {
                                             result0 = null;
                                             pos = pos1;
                                           }
                                         } else {
                                           result0 = null;
                                           pos = pos1;
                                         }
                                       } else {
                                         result0 = null;
                                         pos = pos1;
                                       }
                                     } else {
                                       result0 = null;
                                       pos = pos1;
                                     }
                                   } else {
                                     result0 = null;
                                     pos = pos1;
                                   }
                                 } else {
                                   result0 = null;
                                   pos = pos1;
                                 }
                               } else {
                                 result0 = null;
                                 pos = pos1;
                               }
                             } else {
                               result0 = null;
                               pos = pos1;
                             }
                           } else {
                             result0 = null;
                             pos = pos1;
                           }
                         } else {
                           result0 = null;
                           pos = pos1;
                         }
 
                         if (result0 === null) {
                           pos1 = pos;
                           result0 = parse_h16();
 
                           if (result0 !== null) {
                             pos2 = pos;
 
                             if (input.charCodeAt(pos) === 58) {
                               result1 = ":";
                               pos++;
                             } else {
                               result1 = null;
 
                               if (reportFailures === 0) {
                                 matchFailed("\":\"");
                               }
                             }
 
                             if (result1 !== null) {
                               result2 = parse_h16();
 
                               if (result2 !== null) {
                                 result1 = [result1, result2];
                               } else {
                                 result1 = null;
                                 pos = pos2;
                               }
                             } else {
                               result1 = null;
                               pos = pos2;
                             }
 
                             result1 = result1 !== null ? result1 : "";
 
                             if (result1 !== null) {
                               if (input.substr(pos, 2) === "::") {
                                 result2 = "::";
                                 pos += 2;
                               } else {
                                 result2 = null;
 
                                 if (reportFailures === 0) {
                                   matchFailed("\"::\"");
                                 }
                               }
 
                               if (result2 !== null) {
                                 result3 = parse_h16();
 
                                 if (result3 !== null) {
                                   if (input.charCodeAt(pos) === 58) {
                                     result4 = ":";
                                     pos++;
                                   } else {
                                     result4 = null;
 
                                     if (reportFailures === 0) {
                                       matchFailed("\":\"");
                                     }
                                   }
 
                                   if (result4 !== null) {
                                     result5 = parse_h16();
 
                                     if (result5 !== null) {
                                       if (input.charCodeAt(pos) === 58) {
                                         result6 = ":";
                                         pos++;
                                       } else {
                                         result6 = null;
 
                                         if (reportFailures === 0) {
                                           matchFailed("\":\"");
                                         }
                                       }
 
                                       if (result6 !== null) {
                                         result7 = parse_h16();
 
                                         if (result7 !== null) {
                                           if (input.charCodeAt(pos) === 58) {
                                             result8 = ":";
                                             pos++;
                                           } else {
                                             result8 = null;
 
                                             if (reportFailures === 0) {
                                               matchFailed("\":\"");
                                             }
                                           }
 
                                           if (result8 !== null) {
                                             result9 = parse_ls32();
 
                                             if (result9 !== null) {
                                               result0 = [result0, result1, result2, result3, result4, result5, result6, result7, result8, result9];
                                             } else {
                                               result0 = null;
                                               pos = pos1;
                                             }
                                           } else {
                                             result0 = null;
                                             pos = pos1;
                                           }
                                         } else {
                                           result0 = null;
                                           pos = pos1;
                                         }
                                       } else {
                                         result0 = null;
                                         pos = pos1;
                                       }
                                     } else {
                                       result0 = null;
                                       pos = pos1;
                                     }
                                   } else {
                                     result0 = null;
                                     pos = pos1;
                                   }
                                 } else {
                                   result0 = null;
                                   pos = pos1;
                                 }
                               } else {
                                 result0 = null;
                                 pos = pos1;
                               }
                             } else {
                               result0 = null;
                               pos = pos1;
                             }
                           } else {
                             result0 = null;
                             pos = pos1;
                           }
 
                           if (result0 === null) {
                             pos1 = pos;
                             result0 = parse_h16();
 
                             if (result0 !== null) {
                               pos2 = pos;
 
                               if (input.charCodeAt(pos) === 58) {
                                 result1 = ":";
                                 pos++;
                               } else {
                                 result1 = null;
 
                                 if (reportFailures === 0) {
                                   matchFailed("\":\"");
                                 }
                               }
 
                               if (result1 !== null) {
                                 result2 = parse_h16();
 
                                 if (result2 !== null) {
                                   result1 = [result1, result2];
                                 } else {
                                   result1 = null;
                                   pos = pos2;
                                 }
                               } else {
                                 result1 = null;
                                 pos = pos2;
                               }
 
                               result1 = result1 !== null ? result1 : "";
 
                               if (result1 !== null) {
                                 pos2 = pos;
 
                                 if (input.charCodeAt(pos) === 58) {
                                   result2 = ":";
                                   pos++;
                                 } else {
                                   result2 = null;
 
                                   if (reportFailures === 0) {
                                     matchFailed("\":\"");
                                   }
                                 }
 
                                 if (result2 !== null) {
                                   result3 = parse_h16();
 
                                   if (result3 !== null) {
                                     result2 = [result2, result3];
                                   } else {
                                     result2 = null;
                                     pos = pos2;
                                   }
                                 } else {
                                   result2 = null;
                                   pos = pos2;
                                 }
 
                                 result2 = result2 !== null ? result2 : "";
 
                                 if (result2 !== null) {
                                   if (input.substr(pos, 2) === "::") {
                                     result3 = "::";
                                     pos += 2;
                                   } else {
                                     result3 = null;
 
                                     if (reportFailures === 0) {
                                       matchFailed("\"::\"");
                                     }
                                   }
 
                                   if (result3 !== null) {
                                     result4 = parse_h16();
 
                                     if (result4 !== null) {
                                       if (input.charCodeAt(pos) === 58) {
                                         result5 = ":";
                                         pos++;
                                       } else {
                                         result5 = null;
 
                                         if (reportFailures === 0) {
                                           matchFailed("\":\"");
                                         }
                                       }
 
                                       if (result5 !== null) {
                                         result6 = parse_h16();
 
                                         if (result6 !== null) {
                                           if (input.charCodeAt(pos) === 58) {
                                             result7 = ":";
                                             pos++;
                                           } else {
                                             result7 = null;
 
                                             if (reportFailures === 0) {
                                               matchFailed("\":\"");
                                             }
                                           }
 
                                           if (result7 !== null) {
                                             result8 = parse_ls32();
 
                                             if (result8 !== null) {
                                               result0 = [result0, result1, result2, result3, result4, result5, result6, result7, result8];
                                             } else {
                                               result0 = null;
                                               pos = pos1;
                                             }
                                           } else {
                                             result0 = null;
                                             pos = pos1;
                                           }
                                         } else {
                                           result0 = null;
                                           pos = pos1;
                                         }
                                       } else {
                                         result0 = null;
                                         pos = pos1;
                                       }
                                     } else {
                                       result0 = null;
                                       pos = pos1;
                                     }
                                   } else {
                                     result0 = null;
                                     pos = pos1;
                                   }
                                 } else {
                                   result0 = null;
                                   pos = pos1;
                                 }
                               } else {
                                 result0 = null;
                                 pos = pos1;
                               }
                             } else {
                               result0 = null;
                               pos = pos1;
                             }
 
                             if (result0 === null) {
                               pos1 = pos;
                               result0 = parse_h16();
 
                               if (result0 !== null) {
                                 pos2 = pos;
 
                                 if (input.charCodeAt(pos) === 58) {
                                   result1 = ":";
                                   pos++;
                                 } else {
                                   result1 = null;
 
                                   if (reportFailures === 0) {
                                     matchFailed("\":\"");
                                   }
                                 }
 
                                 if (result1 !== null) {
                                   result2 = parse_h16();
 
                                   if (result2 !== null) {
                                     result1 = [result1, result2];
                                   } else {
                                     result1 = null;
                                     pos = pos2;
                                   }
                                 } else {
                                   result1 = null;
                                   pos = pos2;
                                 }
 
                                 result1 = result1 !== null ? result1 : "";
 
                                 if (result1 !== null) {
                                   pos2 = pos;
 
                                   if (input.charCodeAt(pos) === 58) {
                                     result2 = ":";
                                     pos++;
                                   } else {
                                     result2 = null;
 
                                     if (reportFailures === 0) {
                                       matchFailed("\":\"");
                                     }
                                   }
 
                                   if (result2 !== null) {
                                     result3 = parse_h16();
 
                                     if (result3 !== null) {
                                       result2 = [result2, result3];
                                     } else {
                                       result2 = null;
                                       pos = pos2;
                                     }
                                   } else {
                                     result2 = null;
                                     pos = pos2;
                                   }
 
                                   result2 = result2 !== null ? result2 : "";
 
                                   if (result2 !== null) {
                                     pos2 = pos;
 
                                     if (input.charCodeAt(pos) === 58) {
                                       result3 = ":";
                                       pos++;
                                     } else {
                                       result3 = null;
 
                                       if (reportFailures === 0) {
                                         matchFailed("\":\"");
                                       }
                                     }
 
                                     if (result3 !== null) {
                                       result4 = parse_h16();
 
                                       if (result4 !== null) {
                                         result3 = [result3, result4];
                                       } else {
                                         result3 = null;
                                         pos = pos2;
                                       }
                                     } else {
                                       result3 = null;
                                       pos = pos2;
                                     }
 
                                     result3 = result3 !== null ? result3 : "";
 
                                     if (result3 !== null) {
                                       if (input.substr(pos, 2) === "::") {
                                         result4 = "::";
                                         pos += 2;
                                       } else {
                                         result4 = null;
 
                                         if (reportFailures === 0) {
                                           matchFailed("\"::\"");
                                         }
                                       }
 
                                       if (result4 !== null) {
                                         result5 = parse_h16();
 
                                         if (result5 !== null) {
                                           if (input.charCodeAt(pos) === 58) {
                                             result6 = ":";
                                             pos++;
                                           } else {
                                             result6 = null;
 
                                             if (reportFailures === 0) {
                                               matchFailed("\":\"");
                                             }
                                           }
 
                                           if (result6 !== null) {
                                             result7 = parse_ls32();
 
                                             if (result7 !== null) {
                                               result0 = [result0, result1, result2, result3, result4, result5, result6, result7];
                                             } else {
                                               result0 = null;
                                               pos = pos1;
                                             }
                                           } else {
                                             result0 = null;
                                             pos = pos1;
                                           }
                                         } else {
                                           result0 = null;
                                           pos = pos1;
                                         }
                                       } else {
                                         result0 = null;
                                         pos = pos1;
                                       }
                                     } else {
                                       result0 = null;
                                       pos = pos1;
                                     }
                                   } else {
                                     result0 = null;
                                     pos = pos1;
                                   }
                                 } else {
                                   result0 = null;
                                   pos = pos1;
                                 }
                               } else {
                                 result0 = null;
                                 pos = pos1;
                               }
 
                               if (result0 === null) {
                                 pos1 = pos;
                                 result0 = parse_h16();
 
                                 if (result0 !== null) {
                                   pos2 = pos;
 
                                   if (input.charCodeAt(pos) === 58) {
                                     result1 = ":";
                                     pos++;
                                   } else {
                                     result1 = null;
 
                                     if (reportFailures === 0) {
                                       matchFailed("\":\"");
                                     }
                                   }
 
                                   if (result1 !== null) {
                                     result2 = parse_h16();
 
                                     if (result2 !== null) {
                                       result1 = [result1, result2];
                                     } else {
                                       result1 = null;
                                       pos = pos2;
                                     }
                                   } else {
                                     result1 = null;
                                     pos = pos2;
                                   }
 
                                   result1 = result1 !== null ? result1 : "";
 
                                   if (result1 !== null) {
                                     pos2 = pos;
 
                                     if (input.charCodeAt(pos) === 58) {
                                       result2 = ":";
                                       pos++;
                                     } else {
                                       result2 = null;
 
                                       if (reportFailures === 0) {
                                         matchFailed("\":\"");
                                       }
                                     }
 
                                     if (result2 !== null) {
                                       result3 = parse_h16();
 
                                       if (result3 !== null) {
                                         result2 = [result2, result3];
                                       } else {
                                         result2 = null;
                                         pos = pos2;
                                       }
                                     } else {
                                       result2 = null;
                                       pos = pos2;
                                     }
 
                                     result2 = result2 !== null ? result2 : "";
 
                                     if (result2 !== null) {
                                       pos2 = pos;
 
                                       if (input.charCodeAt(pos) === 58) {
                                         result3 = ":";
                                         pos++;
                                       } else {
                                         result3 = null;
 
                                         if (reportFailures === 0) {
                                           matchFailed("\":\"");
                                         }
                                       }
 
                                       if (result3 !== null) {
                                         result4 = parse_h16();
 
                                         if (result4 !== null) {
                                           result3 = [result3, result4];
                                         } else {
                                           result3 = null;
                                           pos = pos2;
                                         }
                                       } else {
                                         result3 = null;
                                         pos = pos2;
                                       }
 
                                       result3 = result3 !== null ? result3 : "";
 
                                       if (result3 !== null) {
                                         pos2 = pos;
 
                                         if (input.charCodeAt(pos) === 58) {
                                           result4 = ":";
                                           pos++;
                                         } else {
                                           result4 = null;
 
                                           if (reportFailures === 0) {
                                             matchFailed("\":\"");
                                           }
                                         }
 
                                         if (result4 !== null) {
                                           result5 = parse_h16();
 
                                           if (result5 !== null) {
                                             result4 = [result4, result5];
                                           } else {
                                             result4 = null;
                                             pos = pos2;
                                           }
                                         } else {
                                           result4 = null;
                                           pos = pos2;
                                         }
 
                                         result4 = result4 !== null ? result4 : "";
 
                                         if (result4 !== null) {
                                           if (input.substr(pos, 2) === "::") {
                                             result5 = "::";
                                             pos += 2;
                                           } else {
                                             result5 = null;
 
                                             if (reportFailures === 0) {
                                               matchFailed("\"::\"");
                                             }
                                           }
 
                                           if (result5 !== null) {
                                             result6 = parse_ls32();
 
                                             if (result6 !== null) {
                                               result0 = [result0, result1, result2, result3, result4, result5, result6];
                                             } else {
                                               result0 = null;
                                               pos = pos1;
                                             }
                                           } else {
                                             result0 = null;
                                             pos = pos1;
                                           }
                                         } else {
                                           result0 = null;
                                           pos = pos1;
                                         }
                                       } else {
                                         result0 = null;
                                         pos = pos1;
                                       }
                                     } else {
                                       result0 = null;
                                       pos = pos1;
                                     }
                                   } else {
                                     result0 = null;
                                     pos = pos1;
                                   }
                                 } else {
                                   result0 = null;
                                   pos = pos1;
                                 }
 
                                 if (result0 === null) {
                                   pos1 = pos;
                                   result0 = parse_h16();
 
                                   if (result0 !== null) {
                                     pos2 = pos;
 
                                     if (input.charCodeAt(pos) === 58) {
                                       result1 = ":";
                                       pos++;
                                     } else {
                                       result1 = null;
 
                                       if (reportFailures === 0) {
                                         matchFailed("\":\"");
                                       }
                                     }
 
                                     if (result1 !== null) {
                                       result2 = parse_h16();
 
                                       if (result2 !== null) {
                                         result1 = [result1, result2];
                                       } else {
                                         result1 = null;
                                         pos = pos2;
                                       }
                                     } else {
                                       result1 = null;
                                       pos = pos2;
                                     }
 
                                     result1 = result1 !== null ? result1 : "";
 
                                     if (result1 !== null) {
                                       pos2 = pos;
 
                                       if (input.charCodeAt(pos) === 58) {
                                         result2 = ":";
                                         pos++;
                                       } else {
                                         result2 = null;
 
                                         if (reportFailures === 0) {
                                           matchFailed("\":\"");
                                         }
                                       }
 
                                       if (result2 !== null) {
                                         result3 = parse_h16();
 
                                         if (result3 !== null) {
                                           result2 = [result2, result3];
                                         } else {
                                           result2 = null;
                                           pos = pos2;
                                         }
                                       } else {
                                         result2 = null;
                                         pos = pos2;
                                       }
 
                                       result2 = result2 !== null ? result2 : "";
 
                                       if (result2 !== null) {
                                         pos2 = pos;
 
                                         if (input.charCodeAt(pos) === 58) {
                                           result3 = ":";
                                           pos++;
                                         } else {
                                           result3 = null;
 
                                           if (reportFailures === 0) {
                                             matchFailed("\":\"");
                                           }
                                         }
 
                                         if (result3 !== null) {
                                           result4 = parse_h16();
 
                                           if (result4 !== null) {
                                             result3 = [result3, result4];
                                           } else {
                                             result3 = null;
                                             pos = pos2;
                                           }
                                         } else {
                                           result3 = null;
                                           pos = pos2;
                                         }
 
                                         result3 = result3 !== null ? result3 : "";
 
                                         if (result3 !== null) {
                                           pos2 = pos;
 
                                           if (input.charCodeAt(pos) === 58) {
                                             result4 = ":";
                                             pos++;
                                           } else {
                                             result4 = null;
 
                                             if (reportFailures === 0) {
                                               matchFailed("\":\"");
                                             }
                                           }
 
                                           if (result4 !== null) {
                                             result5 = parse_h16();
 
                                             if (result5 !== null) {
                                               result4 = [result4, result5];
                                             } else {
                                               result4 = null;
                                               pos = pos2;
                                             }
                                           } else {
                                             result4 = null;
                                             pos = pos2;
                                           }
 
                                           result4 = result4 !== null ? result4 : "";
 
                                           if (result4 !== null) {
                                             pos2 = pos;
 
                                             if (input.charCodeAt(pos) === 58) {
                                               result5 = ":";
                                               pos++;
                                             } else {
                                               result5 = null;
 
                                               if (reportFailures === 0) {
                                                 matchFailed("\":\"");
                                               }
                                             }
 
                                             if (result5 !== null) {
                                               result6 = parse_h16();
 
                                               if (result6 !== null) {
                                                 result5 = [result5, result6];
                                               } else {
                                                 result5 = null;
                                                 pos = pos2;
                                               }
                                             } else {
                                               result5 = null;
                                               pos = pos2;
                                             }
 
                                             result5 = result5 !== null ? result5 : "";
 
                                             if (result5 !== null) {
                                               if (input.substr(pos, 2) === "::") {
                                                 result6 = "::";
                                                 pos += 2;
                                               } else {
                                                 result6 = null;
 
                                                 if (reportFailures === 0) {
                                                   matchFailed("\"::\"");
                                                 }
                                               }
 
                                               if (result6 !== null) {
                                                 result7 = parse_h16();
 
                                                 if (result7 !== null) {
                                                   result0 = [result0, result1, result2, result3, result4, result5, result6, result7];
                                                 } else {
                                                   result0 = null;
                                                   pos = pos1;
                                                 }
                                               } else {
                                                 result0 = null;
                                                 pos = pos1;
                                               }
                                             } else {
                                               result0 = null;
                                               pos = pos1;
                                             }
                                           } else {
                                             result0 = null;
                                             pos = pos1;
                                           }
                                         } else {
                                           result0 = null;
                                           pos = pos1;
                                         }
                                       } else {
                                         result0 = null;
                                         pos = pos1;
                                       }
                                     } else {
                                       result0 = null;
                                       pos = pos1;
                                     }
                                   } else {
                                     result0 = null;
                                     pos = pos1;
                                   }
 
                                   if (result0 === null) {
                                     pos1 = pos;
                                     result0 = parse_h16();
 
                                     if (result0 !== null) {
                                       pos2 = pos;
 
                                       if (input.charCodeAt(pos) === 58) {
                                         result1 = ":";
                                         pos++;
                                       } else {
                                         result1 = null;
 
                                         if (reportFailures === 0) {
                                           matchFailed("\":\"");
                                         }
                                       }
 
                                       if (result1 !== null) {
                                         result2 = parse_h16();
 
                                         if (result2 !== null) {
                                           result1 = [result1, result2];
                                         } else {
                                           result1 = null;
                                           pos = pos2;
                                         }
                                       } else {
                                         result1 = null;
                                         pos = pos2;
                                       }
 
                                       result1 = result1 !== null ? result1 : "";
 
                                       if (result1 !== null) {
                                         pos2 = pos;
 
                                         if (input.charCodeAt(pos) === 58) {
                                           result2 = ":";
                                           pos++;
                                         } else {
                                           result2 = null;
 
                                           if (reportFailures === 0) {
                                             matchFailed("\":\"");
                                           }
                                         }
 
                                         if (result2 !== null) {
                                           result3 = parse_h16();
 
                                           if (result3 !== null) {
                                             result2 = [result2, result3];
                                           } else {
                                             result2 = null;
                                             pos = pos2;
                                           }
                                         } else {
                                           result2 = null;
                                           pos = pos2;
                                         }
 
                                         result2 = result2 !== null ? result2 : "";
 
                                         if (result2 !== null) {
                                           pos2 = pos;
 
                                           if (input.charCodeAt(pos) === 58) {
                                             result3 = ":";
                                             pos++;
                                           } else {
                                             result3 = null;
 
                                             if (reportFailures === 0) {
                                               matchFailed("\":\"");
                                             }
                                           }
 
                                           if (result3 !== null) {
                                             result4 = parse_h16();
 
                                             if (result4 !== null) {
                                               result3 = [result3, result4];
                                             } else {
                                               result3 = null;
                                               pos = pos2;
                                             }
                                           } else {
                                             result3 = null;
                                             pos = pos2;
                                           }
 
                                           result3 = result3 !== null ? result3 : "";
 
                                           if (result3 !== null) {
                                             pos2 = pos;
 
                                             if (input.charCodeAt(pos) === 58) {
                                               result4 = ":";
                                               pos++;
                                             } else {
                                               result4 = null;
 
                                               if (reportFailures === 0) {
                                                 matchFailed("\":\"");
                                               }
                                             }
 
                                             if (result4 !== null) {
                                               result5 = parse_h16();
 
                                               if (result5 !== null) {
                                                 result4 = [result4, result5];
                                               } else {
                                                 result4 = null;
                                                 pos = pos2;
                                               }
                                             } else {
                                               result4 = null;
                                               pos = pos2;
                                             }
 
                                             result4 = result4 !== null ? result4 : "";
 
                                             if (result4 !== null) {
                                               pos2 = pos;
 
                                               if (input.charCodeAt(pos) === 58) {
                                                 result5 = ":";
                                                 pos++;
                                               } else {
                                                 result5 = null;
 
                                                 if (reportFailures === 0) {
                                                   matchFailed("\":\"");
                                                 }
                                               }
 
                                               if (result5 !== null) {
                                                 result6 = parse_h16();
 
                                                 if (result6 !== null) {
                                                   result5 = [result5, result6];
                                                 } else {
                                                   result5 = null;
                                                   pos = pos2;
                                                 }
                                               } else {
                                                 result5 = null;
                                                 pos = pos2;
                                               }
 
                                               result5 = result5 !== null ? result5 : "";
 
                                               if (result5 !== null) {
                                                 pos2 = pos;
 
                                                 if (input.charCodeAt(pos) === 58) {
                                                   result6 = ":";
                                                   pos++;
                                                 } else {
                                                   result6 = null;
 
                                                   if (reportFailures === 0) {
                                                     matchFailed("\":\"");
                                                   }
                                                 }
 
                                                 if (result6 !== null) {
                                                   result7 = parse_h16();
 
                                                   if (result7 !== null) {
                                                     result6 = [result6, result7];
                                                   } else {
                                                     result6 = null;
                                                     pos = pos2;
                                                   }
                                                 } else {
                                                   result6 = null;
                                                   pos = pos2;
                                                 }
 
                                                 result6 = result6 !== null ? result6 : "";
 
                                                 if (result6 !== null) {
                                                   if (input.substr(pos, 2) === "::") {
                                                     result7 = "::";
                                                     pos += 2;
                                                   } else {
                                                     result7 = null;
 
                                                     if (reportFailures === 0) {
                                                       matchFailed("\"::\"");
                                                     }
                                                   }
 
                                                   if (result7 !== null) {
                                                     result0 = [result0, result1, result2, result3, result4, result5, result6, result7];
                                                   } else {
                                                     result0 = null;
                                                     pos = pos1;
                                                   }
                                                 } else {
                                                   result0 = null;
                                                   pos = pos1;
                                                 }
                                               } else {
                                                 result0 = null;
                                                 pos = pos1;
                                               }
                                             } else {
                                               result0 = null;
                                               pos = pos1;
                                             }
                                           } else {
                                             result0 = null;
                                             pos = pos1;
                                           }
                                         } else {
                                           result0 = null;
                                           pos = pos1;
                                         }
                                       } else {
                                         result0 = null;
                                         pos = pos1;
                                       }
                                     } else {
                                       result0 = null;
                                       pos = pos1;
                                     }
                                   }
                                 }
                               }
                             }
                           }
                         }
                       }
                     }
                   }
                 }
               }
             }
           }
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             data.host_type = 'IPv6';
             return input.substring(pos, offset);
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_h16() {
         var result0, result1, result2, result3;
         var pos0;
         pos0 = pos;
         result0 = parse_HEXDIG();
 
         if (result0 !== null) {
           result1 = parse_HEXDIG();
           result1 = result1 !== null ? result1 : "";
 
           if (result1 !== null) {
             result2 = parse_HEXDIG();
             result2 = result2 !== null ? result2 : "";
 
             if (result2 !== null) {
               result3 = parse_HEXDIG();
               result3 = result3 !== null ? result3 : "";
 
               if (result3 !== null) {
                 result0 = [result0, result1, result2, result3];
               } else {
                 result0 = null;
                 pos = pos0;
               }
             } else {
               result0 = null;
               pos = pos0;
             }
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_ls32() {
         var result0, result1, result2;
         var pos0;
         pos0 = pos;
         result0 = parse_h16();
 
         if (result0 !== null) {
           if (input.charCodeAt(pos) === 58) {
             result1 = ":";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\":\"");
             }
           }
 
           if (result1 !== null) {
             result2 = parse_h16();
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos0;
             }
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         if (result0 === null) {
           result0 = parse_IPv4address();
         }
 
         return result0;
       }
 
       function parse_IPv4address() {
         var result0, result1, result2, result3, result4, result5, result6;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_dec_octet();
 
         if (result0 !== null) {
           if (input.charCodeAt(pos) === 46) {
             result1 = ".";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\".\"");
             }
           }
 
           if (result1 !== null) {
             result2 = parse_dec_octet();
 
             if (result2 !== null) {
               if (input.charCodeAt(pos) === 46) {
                 result3 = ".";
                 pos++;
               } else {
                 result3 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\".\"");
                 }
               }
 
               if (result3 !== null) {
                 result4 = parse_dec_octet();
 
                 if (result4 !== null) {
                   if (input.charCodeAt(pos) === 46) {
                     result5 = ".";
                     pos++;
                   } else {
                     result5 = null;
 
                     if (reportFailures === 0) {
                       matchFailed("\".\"");
                     }
                   }
 
                   if (result5 !== null) {
                     result6 = parse_dec_octet();
 
                     if (result6 !== null) {
                       result0 = [result0, result1, result2, result3, result4, result5, result6];
                     } else {
                       result0 = null;
                       pos = pos1;
                     }
                   } else {
                     result0 = null;
                     pos = pos1;
                   }
                 } else {
                   result0 = null;
                   pos = pos1;
                 }
               } else {
                 result0 = null;
                 pos = pos1;
               }
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             data.host_type = 'IPv4';
             return input.substring(pos, offset);
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_dec_octet() {
         var result0, result1, result2;
         var pos0;
         pos0 = pos;
 
         if (input.substr(pos, 2) === "25") {
           result0 = "25";
           pos += 2;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"25\"");
           }
         }
 
         if (result0 !== null) {
           if (/^[0-5]/.test(input.charAt(pos))) {
             result1 = input.charAt(pos);
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("[0-5]");
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         if (result0 === null) {
           pos0 = pos;
 
           if (input.charCodeAt(pos) === 50) {
             result0 = "2";
             pos++;
           } else {
             result0 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"2\"");
             }
           }
 
           if (result0 !== null) {
             if (/^[0-4]/.test(input.charAt(pos))) {
               result1 = input.charAt(pos);
               pos++;
             } else {
               result1 = null;
 
               if (reportFailures === 0) {
                 matchFailed("[0-4]");
               }
             }
 
             if (result1 !== null) {
               result2 = parse_DIGIT();
 
               if (result2 !== null) {
                 result0 = [result0, result1, result2];
               } else {
                 result0 = null;
                 pos = pos0;
               }
             } else {
               result0 = null;
               pos = pos0;
             }
           } else {
             result0 = null;
             pos = pos0;
           }
 
           if (result0 === null) {
             pos0 = pos;
 
             if (input.charCodeAt(pos) === 49) {
               result0 = "1";
               pos++;
             } else {
               result0 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\"1\"");
               }
             }
 
             if (result0 !== null) {
               result1 = parse_DIGIT();
 
               if (result1 !== null) {
                 result2 = parse_DIGIT();
 
                 if (result2 !== null) {
                   result0 = [result0, result1, result2];
                 } else {
                   result0 = null;
                   pos = pos0;
                 }
               } else {
                 result0 = null;
                 pos = pos0;
               }
             } else {
               result0 = null;
               pos = pos0;
             }
 
             if (result0 === null) {
               pos0 = pos;
 
               if (/^[1-9]/.test(input.charAt(pos))) {
                 result0 = input.charAt(pos);
                 pos++;
               } else {
                 result0 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("[1-9]");
                 }
               }
 
               if (result0 !== null) {
                 result1 = parse_DIGIT();
 
                 if (result1 !== null) {
                   result0 = [result0, result1];
                 } else {
                   result0 = null;
                   pos = pos0;
                 }
               } else {
                 result0 = null;
                 pos = pos0;
               }
 
               if (result0 === null) {
                 result0 = parse_DIGIT();
               }
             }
           }
         }
 
         return result0;
       }
 
       function parse_port() {
         var result0, result1, result2, result3, result4;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_DIGIT();
         result0 = result0 !== null ? result0 : "";
 
         if (result0 !== null) {
           result1 = parse_DIGIT();
           result1 = result1 !== null ? result1 : "";
 
           if (result1 !== null) {
             result2 = parse_DIGIT();
             result2 = result2 !== null ? result2 : "";
 
             if (result2 !== null) {
               result3 = parse_DIGIT();
               result3 = result3 !== null ? result3 : "";
 
               if (result3 !== null) {
                 result4 = parse_DIGIT();
                 result4 = result4 !== null ? result4 : "";
 
                 if (result4 !== null) {
                   result0 = [result0, result1, result2, result3, result4];
                 } else {
                   result0 = null;
                   pos = pos1;
                 }
               } else {
                 result0 = null;
                 pos = pos1;
               }
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset, port) {
             port = parseInt(port.join(''));
             data.port = port;
             return port;
           }(pos0, result0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_uri_parameters() {
         var result0, result1, result2;
         var pos0;
         result0 = [];
         pos0 = pos;
 
         if (input.charCodeAt(pos) === 59) {
           result1 = ";";
           pos++;
         } else {
           result1 = null;
 
           if (reportFailures === 0) {
             matchFailed("\";\"");
           }
         }
 
         if (result1 !== null) {
           result2 = parse_uri_parameter();
 
           if (result2 !== null) {
             result1 = [result1, result2];
           } else {
             result1 = null;
             pos = pos0;
           }
         } else {
           result1 = null;
           pos = pos0;
         }
 
         while (result1 !== null) {
           result0.push(result1);
           pos0 = pos;
 
           if (input.charCodeAt(pos) === 59) {
             result1 = ";";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\";\"");
             }
           }
 
           if (result1 !== null) {
             result2 = parse_uri_parameter();
 
             if (result2 !== null) {
               result1 = [result1, result2];
             } else {
               result1 = null;
               pos = pos0;
             }
           } else {
             result1 = null;
             pos = pos0;
           }
         }
 
         return result0;
       }
 
       function parse_uri_parameter() {
         var result0;
         result0 = parse_transport_param();
 
         if (result0 === null) {
           result0 = parse_user_param();
 
           if (result0 === null) {
             result0 = parse_method_param();
 
             if (result0 === null) {
               result0 = parse_ttl_param();
 
               if (result0 === null) {
                 result0 = parse_maddr_param();
 
                 if (result0 === null) {
                   result0 = parse_lr_param();
 
                   if (result0 === null) {
                     result0 = parse_other_param();
                   }
                 }
               }
             }
           }
         }
 
         return result0;
       }
 
       function parse_transport_param() {
         var result0, result1;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
 
         if (input.substr(pos, 10).toLowerCase() === "transport=") {
           result0 = input.substr(pos, 10);
           pos += 10;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"transport=\"");
           }
         }
 
         if (result0 !== null) {
           if (input.substr(pos, 3).toLowerCase() === "udp") {
             result1 = input.substr(pos, 3);
             pos += 3;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"udp\"");
             }
           }
 
           if (result1 === null) {
             if (input.substr(pos, 3).toLowerCase() === "tcp") {
               result1 = input.substr(pos, 3);
               pos += 3;
             } else {
               result1 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\"tcp\"");
               }
             }
 
             if (result1 === null) {
               if (input.substr(pos, 4).toLowerCase() === "sctp") {
                 result1 = input.substr(pos, 4);
                 pos += 4;
               } else {
                 result1 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\"sctp\"");
                 }
               }
 
               if (result1 === null) {
                 if (input.substr(pos, 3).toLowerCase() === "tls") {
                   result1 = input.substr(pos, 3);
                   pos += 3;
                 } else {
                   result1 = null;
 
                   if (reportFailures === 0) {
                     matchFailed("\"tls\"");
                   }
                 }
 
                 if (result1 === null) {
                   result1 = parse_token();
                 }
               }
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset, transport) {
             if (!data.uri_params) data.uri_params = {};
             data.uri_params['transport'] = transport.toLowerCase();
           }(pos0, result0[1]);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_user_param() {
         var result0, result1;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
 
         if (input.substr(pos, 5).toLowerCase() === "user=") {
           result0 = input.substr(pos, 5);
           pos += 5;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"user=\"");
           }
         }
 
         if (result0 !== null) {
           if (input.substr(pos, 5).toLowerCase() === "phone") {
             result1 = input.substr(pos, 5);
             pos += 5;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"phone\"");
             }
           }
 
           if (result1 === null) {
             if (input.substr(pos, 2).toLowerCase() === "ip") {
               result1 = input.substr(pos, 2);
               pos += 2;
             } else {
               result1 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\"ip\"");
               }
             }
 
             if (result1 === null) {
               result1 = parse_token();
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset, user) {
             if (!data.uri_params) data.uri_params = {};
             data.uri_params['user'] = user.toLowerCase();
           }(pos0, result0[1]);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_method_param() {
         var result0, result1;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
 
         if (input.substr(pos, 7).toLowerCase() === "method=") {
           result0 = input.substr(pos, 7);
           pos += 7;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"method=\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_Method();
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset, method) {
             if (!data.uri_params) data.uri_params = {};
             data.uri_params['method'] = method;
           }(pos0, result0[1]);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_ttl_param() {
         var result0, result1;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
 
         if (input.substr(pos, 4).toLowerCase() === "ttl=") {
           result0 = input.substr(pos, 4);
           pos += 4;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"ttl=\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_ttl();
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset, ttl) {
             if (!data.params) data.params = {};
             data.params['ttl'] = ttl;
           }(pos0, result0[1]);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_maddr_param() {
         var result0, result1;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
 
         if (input.substr(pos, 6).toLowerCase() === "maddr=") {
           result0 = input.substr(pos, 6);
           pos += 6;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"maddr=\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_host();
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset, maddr) {
             if (!data.uri_params) data.uri_params = {};
             data.uri_params['maddr'] = maddr;
           }(pos0, result0[1]);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_lr_param() {
         var result0, result1, result2;
         var pos0, pos1, pos2;
         pos0 = pos;
         pos1 = pos;
 
         if (input.substr(pos, 2).toLowerCase() === "lr") {
           result0 = input.substr(pos, 2);
           pos += 2;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"lr\"");
           }
         }
 
         if (result0 !== null) {
           pos2 = pos;
 
           if (input.charCodeAt(pos) === 61) {
             result1 = "=";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"=\"");
             }
           }
 
           if (result1 !== null) {
             result2 = parse_token();
 
             if (result2 !== null) {
               result1 = [result1, result2];
             } else {
               result1 = null;
               pos = pos2;
             }
           } else {
             result1 = null;
             pos = pos2;
           }
 
           result1 = result1 !== null ? result1 : "";
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             if (!data.uri_params) data.uri_params = {};
             data.uri_params['lr'] = undefined;
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_other_param() {
         var result0, result1, result2;
         var pos0, pos1, pos2;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_pname();
 
         if (result0 !== null) {
           pos2 = pos;
 
           if (input.charCodeAt(pos) === 61) {
             result1 = "=";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"=\"");
             }
           }
 
           if (result1 !== null) {
             result2 = parse_pvalue();
 
             if (result2 !== null) {
               result1 = [result1, result2];
             } else {
               result1 = null;
               pos = pos2;
             }
           } else {
             result1 = null;
             pos = pos2;
           }
 
           result1 = result1 !== null ? result1 : "";
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset, param, value) {
             if (!data.uri_params) data.uri_params = {};
 
             if (typeof value === 'undefined') {
               value = undefined;
             } else {
               value = value[1];
             }
 
             data.uri_params[param.toLowerCase()] = value;
           }(pos0, result0[0], result0[1]);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_pname() {
         var result0, result1;
         var pos0;
         pos0 = pos;
         result1 = parse_paramchar();
 
         if (result1 !== null) {
           result0 = [];
 
           while (result1 !== null) {
             result0.push(result1);
             result1 = parse_paramchar();
           }
         } else {
           result0 = null;
         }
 
         if (result0 !== null) {
           result0 = function (offset, pname) {
             return pname.join('');
           }(pos0, result0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_pvalue() {
         var result0, result1;
         var pos0;
         pos0 = pos;
         result1 = parse_paramchar();
 
         if (result1 !== null) {
           result0 = [];
 
           while (result1 !== null) {
             result0.push(result1);
             result1 = parse_paramchar();
           }
         } else {
           result0 = null;
         }
 
         if (result0 !== null) {
           result0 = function (offset, pvalue) {
             return pvalue.join('');
           }(pos0, result0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_paramchar() {
         var result0;
         result0 = parse_param_unreserved();
 
         if (result0 === null) {
           result0 = parse_unreserved();
 
           if (result0 === null) {
             result0 = parse_escaped();
           }
         }
 
         return result0;
       }
 
       function parse_param_unreserved() {
         var result0;
 
         if (input.charCodeAt(pos) === 91) {
           result0 = "[";
           pos++;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"[\"");
           }
         }
 
         if (result0 === null) {
           if (input.charCodeAt(pos) === 93) {
             result0 = "]";
             pos++;
           } else {
             result0 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"]\"");
             }
           }
 
           if (result0 === null) {
             if (input.charCodeAt(pos) === 47) {
               result0 = "/";
               pos++;
             } else {
               result0 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\"/\"");
               }
             }
 
             if (result0 === null) {
               if (input.charCodeAt(pos) === 58) {
                 result0 = ":";
                 pos++;
               } else {
                 result0 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\":\"");
                 }
               }
 
               if (result0 === null) {
                 if (input.charCodeAt(pos) === 38) {
                   result0 = "&";
                   pos++;
                 } else {
                   result0 = null;
 
                   if (reportFailures === 0) {
                     matchFailed("\"&\"");
                   }
                 }
 
                 if (result0 === null) {
                   if (input.charCodeAt(pos) === 43) {
                     result0 = "+";
                     pos++;
                   } else {
                     result0 = null;
 
                     if (reportFailures === 0) {
                       matchFailed("\"+\"");
                     }
                   }
 
                   if (result0 === null) {
                     if (input.charCodeAt(pos) === 36) {
                       result0 = "$";
                       pos++;
                     } else {
                       result0 = null;
 
                       if (reportFailures === 0) {
                         matchFailed("\"$\"");
                       }
                     }
                   }
                 }
               }
             }
           }
         }
 
         return result0;
       }
 
       function parse_headers() {
         var result0, result1, result2, result3, result4;
         var pos0, pos1;
         pos0 = pos;
 
         if (input.charCodeAt(pos) === 63) {
           result0 = "?";
           pos++;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"?\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_header();
 
           if (result1 !== null) {
             result2 = [];
             pos1 = pos;
 
             if (input.charCodeAt(pos) === 38) {
               result3 = "&";
               pos++;
             } else {
               result3 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\"&\"");
               }
             }
 
             if (result3 !== null) {
               result4 = parse_header();
 
               if (result4 !== null) {
                 result3 = [result3, result4];
               } else {
                 result3 = null;
                 pos = pos1;
               }
             } else {
               result3 = null;
               pos = pos1;
             }
 
             while (result3 !== null) {
               result2.push(result3);
               pos1 = pos;
 
               if (input.charCodeAt(pos) === 38) {
                 result3 = "&";
                 pos++;
               } else {
                 result3 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\"&\"");
                 }
               }
 
               if (result3 !== null) {
                 result4 = parse_header();
 
                 if (result4 !== null) {
                   result3 = [result3, result4];
                 } else {
                   result3 = null;
                   pos = pos1;
                 }
               } else {
                 result3 = null;
                 pos = pos1;
               }
             }
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos0;
             }
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_header() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_hname();
 
         if (result0 !== null) {
           if (input.charCodeAt(pos) === 61) {
             result1 = "=";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"=\"");
             }
           }
 
           if (result1 !== null) {
             result2 = parse_hvalue();
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset, hname, hvalue) {
             hname = hname.join('').toLowerCase();
             hvalue = hvalue.join('');
             if (!data.uri_headers) data.uri_headers = {};
 
             if (!data.uri_headers[hname]) {
               data.uri_headers[hname] = [hvalue];
             } else {
               data.uri_headers[hname].push(hvalue);
             }
           }(pos0, result0[0], result0[2]);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_hname() {
         var result0, result1;
         result1 = parse_hnv_unreserved();
 
         if (result1 === null) {
           result1 = parse_unreserved();
 
           if (result1 === null) {
             result1 = parse_escaped();
           }
         }
 
         if (result1 !== null) {
           result0 = [];
 
           while (result1 !== null) {
             result0.push(result1);
             result1 = parse_hnv_unreserved();
 
             if (result1 === null) {
               result1 = parse_unreserved();
 
               if (result1 === null) {
                 result1 = parse_escaped();
               }
             }
           }
         } else {
           result0 = null;
         }
 
         return result0;
       }
 
       function parse_hvalue() {
         var result0, result1;
         result0 = [];
         result1 = parse_hnv_unreserved();
 
         if (result1 === null) {
           result1 = parse_unreserved();
 
           if (result1 === null) {
             result1 = parse_escaped();
           }
         }
 
         while (result1 !== null) {
           result0.push(result1);
           result1 = parse_hnv_unreserved();
 
           if (result1 === null) {
             result1 = parse_unreserved();
 
             if (result1 === null) {
               result1 = parse_escaped();
             }
           }
         }
 
         return result0;
       }
 
       function parse_hnv_unreserved() {
         var result0;
 
         if (input.charCodeAt(pos) === 91) {
           result0 = "[";
           pos++;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"[\"");
           }
         }
 
         if (result0 === null) {
           if (input.charCodeAt(pos) === 93) {
             result0 = "]";
             pos++;
           } else {
             result0 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"]\"");
             }
           }
 
           if (result0 === null) {
             if (input.charCodeAt(pos) === 47) {
               result0 = "/";
               pos++;
             } else {
               result0 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\"/\"");
               }
             }
 
             if (result0 === null) {
               if (input.charCodeAt(pos) === 63) {
                 result0 = "?";
                 pos++;
               } else {
                 result0 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\"?\"");
                 }
               }
 
               if (result0 === null) {
                 if (input.charCodeAt(pos) === 58) {
                   result0 = ":";
                   pos++;
                 } else {
                   result0 = null;
 
                   if (reportFailures === 0) {
                     matchFailed("\":\"");
                   }
                 }
 
                 if (result0 === null) {
                   if (input.charCodeAt(pos) === 43) {
                     result0 = "+";
                     pos++;
                   } else {
                     result0 = null;
 
                     if (reportFailures === 0) {
                       matchFailed("\"+\"");
                     }
                   }
 
                   if (result0 === null) {
                     if (input.charCodeAt(pos) === 36) {
                       result0 = "$";
                       pos++;
                     } else {
                       result0 = null;
 
                       if (reportFailures === 0) {
                         matchFailed("\"$\"");
                       }
                     }
                   }
                 }
               }
             }
           }
         }
 
         return result0;
       }
 
       function parse_Request_Response() {
         var result0;
         result0 = parse_Status_Line();
 
         if (result0 === null) {
           result0 = parse_Request_Line();
         }
 
         return result0;
       }
 
       function parse_Request_Line() {
         var result0, result1, result2, result3, result4;
         var pos0;
         pos0 = pos;
         result0 = parse_Method();
 
         if (result0 !== null) {
           result1 = parse_SP();
 
           if (result1 !== null) {
             result2 = parse_Request_URI();
 
             if (result2 !== null) {
               result3 = parse_SP();
 
               if (result3 !== null) {
                 result4 = parse_SIP_Version();
 
                 if (result4 !== null) {
                   result0 = [result0, result1, result2, result3, result4];
                 } else {
                   result0 = null;
                   pos = pos0;
                 }
               } else {
                 result0 = null;
                 pos = pos0;
               }
             } else {
               result0 = null;
               pos = pos0;
             }
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_Request_URI() {
         var result0;
         result0 = parse_SIP_URI();
 
         if (result0 === null) {
           result0 = parse_absoluteURI();
         }
 
         return result0;
       }
 
       function parse_absoluteURI() {
         var result0, result1, result2;
         var pos0;
         pos0 = pos;
         result0 = parse_scheme();
 
         if (result0 !== null) {
           if (input.charCodeAt(pos) === 58) {
             result1 = ":";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\":\"");
             }
           }
 
           if (result1 !== null) {
             result2 = parse_hier_part();
 
             if (result2 === null) {
               result2 = parse_opaque_part();
             }
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos0;
             }
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_hier_part() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
         result0 = parse_net_path();
 
         if (result0 === null) {
           result0 = parse_abs_path();
         }
 
         if (result0 !== null) {
           pos1 = pos;
 
           if (input.charCodeAt(pos) === 63) {
             result1 = "?";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"?\"");
             }
           }
 
           if (result1 !== null) {
             result2 = parse_query();
 
             if (result2 !== null) {
               result1 = [result1, result2];
             } else {
               result1 = null;
               pos = pos1;
             }
           } else {
             result1 = null;
             pos = pos1;
           }
 
           result1 = result1 !== null ? result1 : "";
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_net_path() {
         var result0, result1, result2;
         var pos0;
         pos0 = pos;
 
         if (input.substr(pos, 2) === "//") {
           result0 = "//";
           pos += 2;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"//\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_authority();
 
           if (result1 !== null) {
             result2 = parse_abs_path();
             result2 = result2 !== null ? result2 : "";
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos0;
             }
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_abs_path() {
         var result0, result1;
         var pos0;
         pos0 = pos;
 
         if (input.charCodeAt(pos) === 47) {
           result0 = "/";
           pos++;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"/\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_path_segments();
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_opaque_part() {
         var result0, result1, result2;
         var pos0;
         pos0 = pos;
         result0 = parse_uric_no_slash();
 
         if (result0 !== null) {
           result1 = [];
           result2 = parse_uric();
 
           while (result2 !== null) {
             result1.push(result2);
             result2 = parse_uric();
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_uric() {
         var result0;
         result0 = parse_reserved();
 
         if (result0 === null) {
           result0 = parse_unreserved();
 
           if (result0 === null) {
             result0 = parse_escaped();
           }
         }
 
         return result0;
       }
 
       function parse_uric_no_slash() {
         var result0;
         result0 = parse_unreserved();
 
         if (result0 === null) {
           result0 = parse_escaped();
 
           if (result0 === null) {
             if (input.charCodeAt(pos) === 59) {
               result0 = ";";
               pos++;
             } else {
               result0 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\";\"");
               }
             }
 
             if (result0 === null) {
               if (input.charCodeAt(pos) === 63) {
                 result0 = "?";
                 pos++;
               } else {
                 result0 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\"?\"");
                 }
               }
 
               if (result0 === null) {
                 if (input.charCodeAt(pos) === 58) {
                   result0 = ":";
                   pos++;
                 } else {
                   result0 = null;
 
                   if (reportFailures === 0) {
                     matchFailed("\":\"");
                   }
                 }
 
                 if (result0 === null) {
                   if (input.charCodeAt(pos) === 64) {
                     result0 = "@";
                     pos++;
                   } else {
                     result0 = null;
 
                     if (reportFailures === 0) {
                       matchFailed("\"@\"");
                     }
                   }
 
                   if (result0 === null) {
                     if (input.charCodeAt(pos) === 38) {
                       result0 = "&";
                       pos++;
                     } else {
                       result0 = null;
 
                       if (reportFailures === 0) {
                         matchFailed("\"&\"");
                       }
                     }
 
                     if (result0 === null) {
                       if (input.charCodeAt(pos) === 61) {
                         result0 = "=";
                         pos++;
                       } else {
                         result0 = null;
 
                         if (reportFailures === 0) {
                           matchFailed("\"=\"");
                         }
                       }
 
                       if (result0 === null) {
                         if (input.charCodeAt(pos) === 43) {
                           result0 = "+";
                           pos++;
                         } else {
                           result0 = null;
 
                           if (reportFailures === 0) {
                             matchFailed("\"+\"");
                           }
                         }
 
                         if (result0 === null) {
                           if (input.charCodeAt(pos) === 36) {
                             result0 = "$";
                             pos++;
                           } else {
                             result0 = null;
 
                             if (reportFailures === 0) {
                               matchFailed("\"$\"");
                             }
                           }
 
                           if (result0 === null) {
                             if (input.charCodeAt(pos) === 44) {
                               result0 = ",";
                               pos++;
                             } else {
                               result0 = null;
 
                               if (reportFailures === 0) {
                                 matchFailed("\",\"");
                               }
                             }
                           }
                         }
                       }
                     }
                   }
                 }
               }
             }
           }
         }
 
         return result0;
       }
 
       function parse_path_segments() {
         var result0, result1, result2, result3;
         var pos0, pos1;
         pos0 = pos;
         result0 = parse_segment();
 
         if (result0 !== null) {
           result1 = [];
           pos1 = pos;
 
           if (input.charCodeAt(pos) === 47) {
             result2 = "/";
             pos++;
           } else {
             result2 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"/\"");
             }
           }
 
           if (result2 !== null) {
             result3 = parse_segment();
 
             if (result3 !== null) {
               result2 = [result2, result3];
             } else {
               result2 = null;
               pos = pos1;
             }
           } else {
             result2 = null;
             pos = pos1;
           }
 
           while (result2 !== null) {
             result1.push(result2);
             pos1 = pos;
 
             if (input.charCodeAt(pos) === 47) {
               result2 = "/";
               pos++;
             } else {
               result2 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\"/\"");
               }
             }
 
             if (result2 !== null) {
               result3 = parse_segment();
 
               if (result3 !== null) {
                 result2 = [result2, result3];
               } else {
                 result2 = null;
                 pos = pos1;
               }
             } else {
               result2 = null;
               pos = pos1;
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_segment() {
         var result0, result1, result2, result3;
         var pos0, pos1;
         pos0 = pos;
         result0 = [];
         result1 = parse_pchar();
 
         while (result1 !== null) {
           result0.push(result1);
           result1 = parse_pchar();
         }
 
         if (result0 !== null) {
           result1 = [];
           pos1 = pos;
 
           if (input.charCodeAt(pos) === 59) {
             result2 = ";";
             pos++;
           } else {
             result2 = null;
 
             if (reportFailures === 0) {
               matchFailed("\";\"");
             }
           }
 
           if (result2 !== null) {
             result3 = parse_param();
 
             if (result3 !== null) {
               result2 = [result2, result3];
             } else {
               result2 = null;
               pos = pos1;
             }
           } else {
             result2 = null;
             pos = pos1;
           }
 
           while (result2 !== null) {
             result1.push(result2);
             pos1 = pos;
 
             if (input.charCodeAt(pos) === 59) {
               result2 = ";";
               pos++;
             } else {
               result2 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\";\"");
               }
             }
 
             if (result2 !== null) {
               result3 = parse_param();
 
               if (result3 !== null) {
                 result2 = [result2, result3];
               } else {
                 result2 = null;
                 pos = pos1;
               }
             } else {
               result2 = null;
               pos = pos1;
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_param() {
         var result0, result1;
         result0 = [];
         result1 = parse_pchar();
 
         while (result1 !== null) {
           result0.push(result1);
           result1 = parse_pchar();
         }
 
         return result0;
       }
 
       function parse_pchar() {
         var result0;
         result0 = parse_unreserved();
 
         if (result0 === null) {
           result0 = parse_escaped();
 
           if (result0 === null) {
             if (input.charCodeAt(pos) === 58) {
               result0 = ":";
               pos++;
             } else {
               result0 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\":\"");
               }
             }
 
             if (result0 === null) {
               if (input.charCodeAt(pos) === 64) {
                 result0 = "@";
                 pos++;
               } else {
                 result0 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\"@\"");
                 }
               }
 
               if (result0 === null) {
                 if (input.charCodeAt(pos) === 38) {
                   result0 = "&";
                   pos++;
                 } else {
                   result0 = null;
 
                   if (reportFailures === 0) {
                     matchFailed("\"&\"");
                   }
                 }
 
                 if (result0 === null) {
                   if (input.charCodeAt(pos) === 61) {
                     result0 = "=";
                     pos++;
                   } else {
                     result0 = null;
 
                     if (reportFailures === 0) {
                       matchFailed("\"=\"");
                     }
                   }
 
                   if (result0 === null) {
                     if (input.charCodeAt(pos) === 43) {
                       result0 = "+";
                       pos++;
                     } else {
                       result0 = null;
 
                       if (reportFailures === 0) {
                         matchFailed("\"+\"");
                       }
                     }
 
                     if (result0 === null) {
                       if (input.charCodeAt(pos) === 36) {
                         result0 = "$";
                         pos++;
                       } else {
                         result0 = null;
 
                         if (reportFailures === 0) {
                           matchFailed("\"$\"");
                         }
                       }
 
                       if (result0 === null) {
                         if (input.charCodeAt(pos) === 44) {
                           result0 = ",";
                           pos++;
                         } else {
                           result0 = null;
 
                           if (reportFailures === 0) {
                             matchFailed("\",\"");
                           }
                         }
                       }
                     }
                   }
                 }
               }
             }
           }
         }
 
         return result0;
       }
 
       function parse_scheme() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_ALPHA();
 
         if (result0 !== null) {
           result1 = [];
           result2 = parse_ALPHA();
 
           if (result2 === null) {
             result2 = parse_DIGIT();
 
             if (result2 === null) {
               if (input.charCodeAt(pos) === 43) {
                 result2 = "+";
                 pos++;
               } else {
                 result2 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\"+\"");
                 }
               }
 
               if (result2 === null) {
                 if (input.charCodeAt(pos) === 45) {
                   result2 = "-";
                   pos++;
                 } else {
                   result2 = null;
 
                   if (reportFailures === 0) {
                     matchFailed("\"-\"");
                   }
                 }
 
                 if (result2 === null) {
                   if (input.charCodeAt(pos) === 46) {
                     result2 = ".";
                     pos++;
                   } else {
                     result2 = null;
 
                     if (reportFailures === 0) {
                       matchFailed("\".\"");
                     }
                   }
                 }
               }
             }
           }
 
           while (result2 !== null) {
             result1.push(result2);
             result2 = parse_ALPHA();
 
             if (result2 === null) {
               result2 = parse_DIGIT();
 
               if (result2 === null) {
                 if (input.charCodeAt(pos) === 43) {
                   result2 = "+";
                   pos++;
                 } else {
                   result2 = null;
 
                   if (reportFailures === 0) {
                     matchFailed("\"+\"");
                   }
                 }
 
                 if (result2 === null) {
                   if (input.charCodeAt(pos) === 45) {
                     result2 = "-";
                     pos++;
                   } else {
                     result2 = null;
 
                     if (reportFailures === 0) {
                       matchFailed("\"-\"");
                     }
                   }
 
                   if (result2 === null) {
                     if (input.charCodeAt(pos) === 46) {
                       result2 = ".";
                       pos++;
                     } else {
                       result2 = null;
 
                       if (reportFailures === 0) {
                         matchFailed("\".\"");
                       }
                     }
                   }
                 }
               }
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             data.scheme = input.substring(pos, offset);
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_authority() {
         var result0;
         result0 = parse_srvr();
 
         if (result0 === null) {
           result0 = parse_reg_name();
         }
 
         return result0;
       }
 
       function parse_srvr() {
         var result0, result1;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_userinfo();
 
         if (result0 !== null) {
           if (input.charCodeAt(pos) === 64) {
             result1 = "@";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"@\"");
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         result0 = result0 !== null ? result0 : "";
 
         if (result0 !== null) {
           result1 = parse_hostport();
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         result0 = result0 !== null ? result0 : "";
         return result0;
       }
 
       function parse_reg_name() {
         var result0, result1;
         result1 = parse_unreserved();
 
         if (result1 === null) {
           result1 = parse_escaped();
 
           if (result1 === null) {
             if (input.charCodeAt(pos) === 36) {
               result1 = "$";
               pos++;
             } else {
               result1 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\"$\"");
               }
             }
 
             if (result1 === null) {
               if (input.charCodeAt(pos) === 44) {
                 result1 = ",";
                 pos++;
               } else {
                 result1 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\",\"");
                 }
               }
 
               if (result1 === null) {
                 if (input.charCodeAt(pos) === 59) {
                   result1 = ";";
                   pos++;
                 } else {
                   result1 = null;
 
                   if (reportFailures === 0) {
                     matchFailed("\";\"");
                   }
                 }
 
                 if (result1 === null) {
                   if (input.charCodeAt(pos) === 58) {
                     result1 = ":";
                     pos++;
                   } else {
                     result1 = null;
 
                     if (reportFailures === 0) {
                       matchFailed("\":\"");
                     }
                   }
 
                   if (result1 === null) {
                     if (input.charCodeAt(pos) === 64) {
                       result1 = "@";
                       pos++;
                     } else {
                       result1 = null;
 
                       if (reportFailures === 0) {
                         matchFailed("\"@\"");
                       }
                     }
 
                     if (result1 === null) {
                       if (input.charCodeAt(pos) === 38) {
                         result1 = "&";
                         pos++;
                       } else {
                         result1 = null;
 
                         if (reportFailures === 0) {
                           matchFailed("\"&\"");
                         }
                       }
 
                       if (result1 === null) {
                         if (input.charCodeAt(pos) === 61) {
                           result1 = "=";
                           pos++;
                         } else {
                           result1 = null;
 
                           if (reportFailures === 0) {
                             matchFailed("\"=\"");
                           }
                         }
 
                         if (result1 === null) {
                           if (input.charCodeAt(pos) === 43) {
                             result1 = "+";
                             pos++;
                           } else {
                             result1 = null;
 
                             if (reportFailures === 0) {
                               matchFailed("\"+\"");
                             }
                           }
                         }
                       }
                     }
                   }
                 }
               }
             }
           }
         }
 
         if (result1 !== null) {
           result0 = [];
 
           while (result1 !== null) {
             result0.push(result1);
             result1 = parse_unreserved();
 
             if (result1 === null) {
               result1 = parse_escaped();
 
               if (result1 === null) {
                 if (input.charCodeAt(pos) === 36) {
                   result1 = "$";
                   pos++;
                 } else {
                   result1 = null;
 
                   if (reportFailures === 0) {
                     matchFailed("\"$\"");
                   }
                 }
 
                 if (result1 === null) {
                   if (input.charCodeAt(pos) === 44) {
                     result1 = ",";
                     pos++;
                   } else {
                     result1 = null;
 
                     if (reportFailures === 0) {
                       matchFailed("\",\"");
                     }
                   }
 
                   if (result1 === null) {
                     if (input.charCodeAt(pos) === 59) {
                       result1 = ";";
                       pos++;
                     } else {
                       result1 = null;
 
                       if (reportFailures === 0) {
                         matchFailed("\";\"");
                       }
                     }
 
                     if (result1 === null) {
                       if (input.charCodeAt(pos) === 58) {
                         result1 = ":";
                         pos++;
                       } else {
                         result1 = null;
 
                         if (reportFailures === 0) {
                           matchFailed("\":\"");
                         }
                       }
 
                       if (result1 === null) {
                         if (input.charCodeAt(pos) === 64) {
                           result1 = "@";
                           pos++;
                         } else {
                           result1 = null;
 
                           if (reportFailures === 0) {
                             matchFailed("\"@\"");
                           }
                         }
 
                         if (result1 === null) {
                           if (input.charCodeAt(pos) === 38) {
                             result1 = "&";
                             pos++;
                           } else {
                             result1 = null;
 
                             if (reportFailures === 0) {
                               matchFailed("\"&\"");
                             }
                           }
 
                           if (result1 === null) {
                             if (input.charCodeAt(pos) === 61) {
                               result1 = "=";
                               pos++;
                             } else {
                               result1 = null;
 
                               if (reportFailures === 0) {
                                 matchFailed("\"=\"");
                               }
                             }
 
                             if (result1 === null) {
                               if (input.charCodeAt(pos) === 43) {
                                 result1 = "+";
                                 pos++;
                               } else {
                                 result1 = null;
 
                                 if (reportFailures === 0) {
                                   matchFailed("\"+\"");
                                 }
                               }
                             }
                           }
                         }
                       }
                     }
                   }
                 }
               }
             }
           }
         } else {
           result0 = null;
         }
 
         return result0;
       }
 
       function parse_query() {
         var result0, result1;
         result0 = [];
         result1 = parse_uric();
 
         while (result1 !== null) {
           result0.push(result1);
           result1 = parse_uric();
         }
 
         return result0;
       }
 
       function parse_SIP_Version() {
         var result0, result1, result2, result3, result4, result5;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
 
         if (input.substr(pos, 3).toLowerCase() === "sip") {
           result0 = input.substr(pos, 3);
           pos += 3;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"SIP\"");
           }
         }
 
         if (result0 !== null) {
           if (input.charCodeAt(pos) === 47) {
             result1 = "/";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"/\"");
             }
           }
 
           if (result1 !== null) {
             result3 = parse_DIGIT();
 
             if (result3 !== null) {
               result2 = [];
 
               while (result3 !== null) {
                 result2.push(result3);
                 result3 = parse_DIGIT();
               }
             } else {
               result2 = null;
             }
 
             if (result2 !== null) {
               if (input.charCodeAt(pos) === 46) {
                 result3 = ".";
                 pos++;
               } else {
                 result3 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\".\"");
                 }
               }
 
               if (result3 !== null) {
                 result5 = parse_DIGIT();
 
                 if (result5 !== null) {
                   result4 = [];
 
                   while (result5 !== null) {
                     result4.push(result5);
                     result5 = parse_DIGIT();
                   }
                 } else {
                   result4 = null;
                 }
 
                 if (result4 !== null) {
                   result0 = [result0, result1, result2, result3, result4];
                 } else {
                   result0 = null;
                   pos = pos1;
                 }
               } else {
                 result0 = null;
                 pos = pos1;
               }
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             data.sip_version = input.substring(pos, offset);
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_INVITEm() {
         var result0;
 
         if (input.substr(pos, 6) === "INVITE") {
           result0 = "INVITE";
           pos += 6;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"INVITE\"");
           }
         }
 
         return result0;
       }
 
       function parse_ACKm() {
         var result0;
 
         if (input.substr(pos, 3) === "ACK") {
           result0 = "ACK";
           pos += 3;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"ACK\"");
           }
         }
 
         return result0;
       }
 
       function parse_OPTIONSm() {
         var result0;
 
         if (input.substr(pos, 7) === "OPTIONS") {
           result0 = "OPTIONS";
           pos += 7;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"OPTIONS\"");
           }
         }
 
         return result0;
       }
 
       function parse_BYEm() {
         var result0;
 
         if (input.substr(pos, 3) === "BYE") {
           result0 = "BYE";
           pos += 3;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"BYE\"");
           }
         }
 
         return result0;
       }
 
       function parse_CANCELm() {
         var result0;
 
         if (input.substr(pos, 6) === "CANCEL") {
           result0 = "CANCEL";
           pos += 6;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"CANCEL\"");
           }
         }
 
         return result0;
       }
 
       function parse_REGISTERm() {
         var result0;
 
         if (input.substr(pos, 8) === "REGISTER") {
           result0 = "REGISTER";
           pos += 8;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"REGISTER\"");
           }
         }
 
         return result0;
       }
 
       function parse_SUBSCRIBEm() {
         var result0;
 
         if (input.substr(pos, 9) === "SUBSCRIBE") {
           result0 = "SUBSCRIBE";
           pos += 9;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"SUBSCRIBE\"");
           }
         }
 
         return result0;
       }
 
       function parse_NOTIFYm() {
         var result0;
 
         if (input.substr(pos, 6) === "NOTIFY") {
           result0 = "NOTIFY";
           pos += 6;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"NOTIFY\"");
           }
         }
 
         return result0;
       }
 
       function parse_REFERm() {
         var result0;
 
         if (input.substr(pos, 5) === "REFER") {
           result0 = "REFER";
           pos += 5;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"REFER\"");
           }
         }
 
         return result0;
       }
 
       function parse_Method() {
         var result0;
         var pos0;
         pos0 = pos;
         result0 = parse_INVITEm();
 
         if (result0 === null) {
           result0 = parse_ACKm();
 
           if (result0 === null) {
             result0 = parse_OPTIONSm();
 
             if (result0 === null) {
               result0 = parse_BYEm();
 
               if (result0 === null) {
                 result0 = parse_CANCELm();
 
                 if (result0 === null) {
                   result0 = parse_REGISTERm();
 
                   if (result0 === null) {
                     result0 = parse_SUBSCRIBEm();
 
                     if (result0 === null) {
                       result0 = parse_NOTIFYm();
 
                       if (result0 === null) {
                         result0 = parse_REFERm();
 
                         if (result0 === null) {
                           result0 = parse_token();
                         }
                       }
                     }
                   }
                 }
               }
             }
           }
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             data.method = input.substring(pos, offset);
             return data.method;
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_Status_Line() {
         var result0, result1, result2, result3, result4;
         var pos0;
         pos0 = pos;
         result0 = parse_SIP_Version();
 
         if (result0 !== null) {
           result1 = parse_SP();
 
           if (result1 !== null) {
             result2 = parse_Status_Code();
 
             if (result2 !== null) {
               result3 = parse_SP();
 
               if (result3 !== null) {
                 result4 = parse_Reason_Phrase();
 
                 if (result4 !== null) {
                   result0 = [result0, result1, result2, result3, result4];
                 } else {
                   result0 = null;
                   pos = pos0;
                 }
               } else {
                 result0 = null;
                 pos = pos0;
               }
             } else {
               result0 = null;
               pos = pos0;
             }
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_Status_Code() {
         var result0;
         var pos0;
         pos0 = pos;
         result0 = parse_extension_code();
 
         if (result0 !== null) {
           result0 = function (offset, status_code) {
             data.status_code = parseInt(status_code.join(''));
           }(pos0, result0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_extension_code() {
         var result0, result1, result2;
         var pos0;
         pos0 = pos;
         result0 = parse_DIGIT();
 
         if (result0 !== null) {
           result1 = parse_DIGIT();
 
           if (result1 !== null) {
             result2 = parse_DIGIT();
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos0;
             }
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_Reason_Phrase() {
         var result0, result1;
         var pos0;
         pos0 = pos;
         result0 = [];
         result1 = parse_reserved();
 
         if (result1 === null) {
           result1 = parse_unreserved();
 
           if (result1 === null) {
             result1 = parse_escaped();
 
             if (result1 === null) {
               result1 = parse_UTF8_NONASCII();
 
               if (result1 === null) {
                 result1 = parse_UTF8_CONT();
 
                 if (result1 === null) {
                   result1 = parse_SP();
 
                   if (result1 === null) {
                     result1 = parse_HTAB();
                   }
                 }
               }
             }
           }
         }
 
         while (result1 !== null) {
           result0.push(result1);
           result1 = parse_reserved();
 
           if (result1 === null) {
             result1 = parse_unreserved();
 
             if (result1 === null) {
               result1 = parse_escaped();
 
               if (result1 === null) {
                 result1 = parse_UTF8_NONASCII();
 
                 if (result1 === null) {
                   result1 = parse_UTF8_CONT();
 
                   if (result1 === null) {
                     result1 = parse_SP();
 
                     if (result1 === null) {
                       result1 = parse_HTAB();
                     }
                   }
                 }
               }
             }
           }
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             data.reason_phrase = input.substring(pos, offset);
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_Allow_Events() {
         var result0, result1, result2, result3;
         var pos0, pos1;
         pos0 = pos;
         result0 = parse_event_type();
 
         if (result0 !== null) {
           result1 = [];
           pos1 = pos;
           result2 = parse_COMMA();
 
           if (result2 !== null) {
             result3 = parse_event_type();
 
             if (result3 !== null) {
               result2 = [result2, result3];
             } else {
               result2 = null;
               pos = pos1;
             }
           } else {
             result2 = null;
             pos = pos1;
           }
 
           while (result2 !== null) {
             result1.push(result2);
             pos1 = pos;
             result2 = parse_COMMA();
 
             if (result2 !== null) {
               result3 = parse_event_type();
 
               if (result3 !== null) {
                 result2 = [result2, result3];
               } else {
                 result2 = null;
                 pos = pos1;
               }
             } else {
               result2 = null;
               pos = pos1;
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_Call_ID() {
         var result0, result1, result2;
         var pos0, pos1, pos2;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_word();
 
         if (result0 !== null) {
           pos2 = pos;
 
           if (input.charCodeAt(pos) === 64) {
             result1 = "@";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"@\"");
             }
           }
 
           if (result1 !== null) {
             result2 = parse_word();
 
             if (result2 !== null) {
               result1 = [result1, result2];
             } else {
               result1 = null;
               pos = pos2;
             }
           } else {
             result1 = null;
             pos = pos2;
           }
 
           result1 = result1 !== null ? result1 : "";
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             data = input.substring(pos, offset);
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_Contact() {
         var result0, result1, result2, result3;
         var pos0, pos1, pos2;
         pos0 = pos;
         result0 = parse_STAR();
 
         if (result0 === null) {
           pos1 = pos;
           result0 = parse_contact_param();
 
           if (result0 !== null) {
             result1 = [];
             pos2 = pos;
             result2 = parse_COMMA();
 
             if (result2 !== null) {
               result3 = parse_contact_param();
 
               if (result3 !== null) {
                 result2 = [result2, result3];
               } else {
                 result2 = null;
                 pos = pos2;
               }
             } else {
               result2 = null;
               pos = pos2;
             }
 
             while (result2 !== null) {
               result1.push(result2);
               pos2 = pos;
               result2 = parse_COMMA();
 
               if (result2 !== null) {
                 result3 = parse_contact_param();
 
                 if (result3 !== null) {
                   result2 = [result2, result3];
                 } else {
                   result2 = null;
                   pos = pos2;
                 }
               } else {
                 result2 = null;
                 pos = pos2;
               }
             }
 
             if (result1 !== null) {
               result0 = [result0, result1];
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             var idx, length;
             length = data.multi_header.length;
 
             for (idx = 0; idx < length; idx++) {
               if (data.multi_header[idx].parsed === null) {
                 data = null;
                 break;
               }
             }
 
             if (data !== null) {
               data = data.multi_header;
             } else {
               data = -1;
             }
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_contact_param() {
         var result0, result1, result2, result3;
         var pos0, pos1, pos2;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_SIP_URI_noparams();
 
         if (result0 === null) {
           result0 = parse_name_addr();
         }
 
         if (result0 !== null) {
           result1 = [];
           pos2 = pos;
           result2 = parse_SEMI();
 
           if (result2 !== null) {
             result3 = parse_contact_params();
 
             if (result3 !== null) {
               result2 = [result2, result3];
             } else {
               result2 = null;
               pos = pos2;
             }
           } else {
             result2 = null;
             pos = pos2;
           }
 
           while (result2 !== null) {
             result1.push(result2);
             pos2 = pos;
             result2 = parse_SEMI();
 
             if (result2 !== null) {
               result3 = parse_contact_params();
 
               if (result3 !== null) {
                 result2 = [result2, result3];
               } else {
                 result2 = null;
                 pos = pos2;
               }
             } else {
               result2 = null;
               pos = pos2;
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             var header;
             if (!data.multi_header) data.multi_header = [];
 
             try {
               header = new NameAddrHeader(data.uri, data.display_name, data.params);
               delete data.uri;
               delete data.display_name;
               delete data.params;
             } catch (e) {
               header = null;
             }
 
             data.multi_header.push({
               'possition': pos,
               'offset': offset,
               'parsed': header
             });
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_name_addr() {
         var result0, result1, result2, result3;
         var pos0;
         pos0 = pos;
         result0 = parse_display_name();
         result0 = result0 !== null ? result0 : "";
 
         if (result0 !== null) {
           result1 = parse_LAQUOT();
 
           if (result1 !== null) {
             result2 = parse_SIP_URI();
 
             if (result2 !== null) {
               result3 = parse_RAQUOT();
 
               if (result3 !== null) {
                 result0 = [result0, result1, result2, result3];
               } else {
                 result0 = null;
                 pos = pos0;
               }
             } else {
               result0 = null;
               pos = pos0;
             }
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_display_name() {
         var result0, result1, result2, result3;
         var pos0, pos1, pos2;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_token();
 
         if (result0 !== null) {
           result1 = [];
           pos2 = pos;
           result2 = parse_LWS();
 
           if (result2 !== null) {
             result3 = parse_token();
 
             if (result3 !== null) {
               result2 = [result2, result3];
             } else {
               result2 = null;
               pos = pos2;
             }
           } else {
             result2 = null;
             pos = pos2;
           }
 
           while (result2 !== null) {
             result1.push(result2);
             pos2 = pos;
             result2 = parse_LWS();
 
             if (result2 !== null) {
               result3 = parse_token();
 
               if (result3 !== null) {
                 result2 = [result2, result3];
               } else {
                 result2 = null;
                 pos = pos2;
               }
             } else {
               result2 = null;
               pos = pos2;
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 === null) {
           result0 = parse_quoted_string_clean();
         }
 
         if (result0 !== null) {
           result0 = function (offset, display_name) {
             if (typeof display_name === 'string') {
               // quoted_string_clean
               data.display_name = display_name;
             } else {
               // token ( LWS token )*
               data.display_name = display_name[1].reduce(function (acc, cur) {
                 return acc + cur[0] + cur[1];
               }, display_name[0]);
             }
           }(pos0, result0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_contact_params() {
         var result0;
         result0 = parse_c_p_q();
 
         if (result0 === null) {
           result0 = parse_c_p_expires();
 
           if (result0 === null) {
             result0 = parse_generic_param();
           }
         }
 
         return result0;
       }
 
       function parse_c_p_q() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
 
         if (input.substr(pos, 1).toLowerCase() === "q") {
           result0 = input.substr(pos, 1);
           pos++;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"q\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_EQUAL();
 
           if (result1 !== null) {
             result2 = parse_qvalue();
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset, q) {
             if (!data.params) data.params = {};
             data.params['q'] = q;
           }(pos0, result0[2]);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_c_p_expires() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
 
         if (input.substr(pos, 7).toLowerCase() === "expires") {
           result0 = input.substr(pos, 7);
           pos += 7;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"expires\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_EQUAL();
 
           if (result1 !== null) {
             result2 = parse_delta_seconds();
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset, expires) {
             if (!data.params) data.params = {};
             data.params['expires'] = expires;
           }(pos0, result0[2]);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_delta_seconds() {
         var result0, result1;
         var pos0;
         pos0 = pos;
         result1 = parse_DIGIT();
 
         if (result1 !== null) {
           result0 = [];
 
           while (result1 !== null) {
             result0.push(result1);
             result1 = parse_DIGIT();
           }
         } else {
           result0 = null;
         }
 
         if (result0 !== null) {
           result0 = function (offset, delta_seconds) {
             return parseInt(delta_seconds.join(''));
           }(pos0, result0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_qvalue() {
         var result0, result1, result2, result3, result4;
         var pos0, pos1, pos2;
         pos0 = pos;
         pos1 = pos;
 
         if (input.charCodeAt(pos) === 48) {
           result0 = "0";
           pos++;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"0\"");
           }
         }
 
         if (result0 !== null) {
           pos2 = pos;
 
           if (input.charCodeAt(pos) === 46) {
             result1 = ".";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\".\"");
             }
           }
 
           if (result1 !== null) {
             result2 = parse_DIGIT();
             result2 = result2 !== null ? result2 : "";
 
             if (result2 !== null) {
               result3 = parse_DIGIT();
               result3 = result3 !== null ? result3 : "";
 
               if (result3 !== null) {
                 result4 = parse_DIGIT();
                 result4 = result4 !== null ? result4 : "";
 
                 if (result4 !== null) {
                   result1 = [result1, result2, result3, result4];
                 } else {
                   result1 = null;
                   pos = pos2;
                 }
               } else {
                 result1 = null;
                 pos = pos2;
               }
             } else {
               result1 = null;
               pos = pos2;
             }
           } else {
             result1 = null;
             pos = pos2;
           }
 
           result1 = result1 !== null ? result1 : "";
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             return parseFloat(input.substring(pos, offset));
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_generic_param() {
         var result0, result1, result2;
         var pos0, pos1, pos2;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_token();
 
         if (result0 !== null) {
           pos2 = pos;
           result1 = parse_EQUAL();
 
           if (result1 !== null) {
             result2 = parse_gen_value();
 
             if (result2 !== null) {
               result1 = [result1, result2];
             } else {
               result1 = null;
               pos = pos2;
             }
           } else {
             result1 = null;
             pos = pos2;
           }
 
           result1 = result1 !== null ? result1 : "";
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset, param, value) {
             if (!data.params) data.params = {};
 
             if (typeof value === 'undefined') {
               value = undefined;
             } else {
               value = value[1];
             }
 
             data.params[param.toLowerCase()] = value;
           }(pos0, result0[0], result0[1]);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_gen_value() {
         var result0;
         result0 = parse_token();
 
         if (result0 === null) {
           result0 = parse_host();
 
           if (result0 === null) {
             result0 = parse_quoted_string();
           }
         }
 
         return result0;
       }
 
       function parse_Content_Disposition() {
         var result0, result1, result2, result3;
         var pos0, pos1;
         pos0 = pos;
         result0 = parse_disp_type();
 
         if (result0 !== null) {
           result1 = [];
           pos1 = pos;
           result2 = parse_SEMI();
 
           if (result2 !== null) {
             result3 = parse_disp_param();
 
             if (result3 !== null) {
               result2 = [result2, result3];
             } else {
               result2 = null;
               pos = pos1;
             }
           } else {
             result2 = null;
             pos = pos1;
           }
 
           while (result2 !== null) {
             result1.push(result2);
             pos1 = pos;
             result2 = parse_SEMI();
 
             if (result2 !== null) {
               result3 = parse_disp_param();
 
               if (result3 !== null) {
                 result2 = [result2, result3];
               } else {
                 result2 = null;
                 pos = pos1;
               }
             } else {
               result2 = null;
               pos = pos1;
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_disp_type() {
         var result0;
 
         if (input.substr(pos, 6).toLowerCase() === "render") {
           result0 = input.substr(pos, 6);
           pos += 6;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"render\"");
           }
         }
 
         if (result0 === null) {
           if (input.substr(pos, 7).toLowerCase() === "session") {
             result0 = input.substr(pos, 7);
             pos += 7;
           } else {
             result0 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"session\"");
             }
           }
 
           if (result0 === null) {
             if (input.substr(pos, 4).toLowerCase() === "icon") {
               result0 = input.substr(pos, 4);
               pos += 4;
             } else {
               result0 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\"icon\"");
               }
             }
 
             if (result0 === null) {
               if (input.substr(pos, 5).toLowerCase() === "alert") {
                 result0 = input.substr(pos, 5);
                 pos += 5;
               } else {
                 result0 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\"alert\"");
                 }
               }
 
               if (result0 === null) {
                 result0 = parse_token();
               }
             }
           }
         }
 
         return result0;
       }
 
       function parse_disp_param() {
         var result0;
         result0 = parse_handling_param();
 
         if (result0 === null) {
           result0 = parse_generic_param();
         }
 
         return result0;
       }
 
       function parse_handling_param() {
         var result0, result1, result2;
         var pos0;
         pos0 = pos;
 
         if (input.substr(pos, 8).toLowerCase() === "handling") {
           result0 = input.substr(pos, 8);
           pos += 8;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"handling\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_EQUAL();
 
           if (result1 !== null) {
             if (input.substr(pos, 8).toLowerCase() === "optional") {
               result2 = input.substr(pos, 8);
               pos += 8;
             } else {
               result2 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\"optional\"");
               }
             }
 
             if (result2 === null) {
               if (input.substr(pos, 8).toLowerCase() === "required") {
                 result2 = input.substr(pos, 8);
                 pos += 8;
               } else {
                 result2 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\"required\"");
                 }
               }
 
               if (result2 === null) {
                 result2 = parse_token();
               }
             }
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos0;
             }
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_Content_Encoding() {
         var result0, result1, result2, result3;
         var pos0, pos1;
         pos0 = pos;
         result0 = parse_token();
 
         if (result0 !== null) {
           result1 = [];
           pos1 = pos;
           result2 = parse_COMMA();
 
           if (result2 !== null) {
             result3 = parse_token();
 
             if (result3 !== null) {
               result2 = [result2, result3];
             } else {
               result2 = null;
               pos = pos1;
             }
           } else {
             result2 = null;
             pos = pos1;
           }
 
           while (result2 !== null) {
             result1.push(result2);
             pos1 = pos;
             result2 = parse_COMMA();
 
             if (result2 !== null) {
               result3 = parse_token();
 
               if (result3 !== null) {
                 result2 = [result2, result3];
               } else {
                 result2 = null;
                 pos = pos1;
               }
             } else {
               result2 = null;
               pos = pos1;
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_Content_Length() {
         var result0, result1;
         var pos0;
         pos0 = pos;
         result1 = parse_DIGIT();
 
         if (result1 !== null) {
           result0 = [];
 
           while (result1 !== null) {
             result0.push(result1);
             result1 = parse_DIGIT();
           }
         } else {
           result0 = null;
         }
 
         if (result0 !== null) {
           result0 = function (offset, length) {
             data = parseInt(length.join(''));
           }(pos0, result0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_Content_Type() {
         var result0;
         var pos0;
         pos0 = pos;
         result0 = parse_media_type();
 
         if (result0 !== null) {
           result0 = function (offset) {
             data = input.substring(pos, offset);
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_media_type() {
         var result0, result1, result2, result3, result4, result5;
         var pos0, pos1;
         pos0 = pos;
         result0 = parse_m_type();
 
         if (result0 !== null) {
           result1 = parse_SLASH();
 
           if (result1 !== null) {
             result2 = parse_m_subtype();
 
             if (result2 !== null) {
               result3 = [];
               pos1 = pos;
               result4 = parse_SEMI();
 
               if (result4 !== null) {
                 result5 = parse_m_parameter();
 
                 if (result5 !== null) {
                   result4 = [result4, result5];
                 } else {
                   result4 = null;
                   pos = pos1;
                 }
               } else {
                 result4 = null;
                 pos = pos1;
               }
 
               while (result4 !== null) {
                 result3.push(result4);
                 pos1 = pos;
                 result4 = parse_SEMI();
 
                 if (result4 !== null) {
                   result5 = parse_m_parameter();
 
                   if (result5 !== null) {
                     result4 = [result4, result5];
                   } else {
                     result4 = null;
                     pos = pos1;
                   }
                 } else {
                   result4 = null;
                   pos = pos1;
                 }
               }
 
               if (result3 !== null) {
                 result0 = [result0, result1, result2, result3];
               } else {
                 result0 = null;
                 pos = pos0;
               }
             } else {
               result0 = null;
               pos = pos0;
             }
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_m_type() {
         var result0;
         result0 = parse_discrete_type();
 
         if (result0 === null) {
           result0 = parse_composite_type();
         }
 
         return result0;
       }
 
       function parse_discrete_type() {
         var result0;
 
         if (input.substr(pos, 4).toLowerCase() === "text") {
           result0 = input.substr(pos, 4);
           pos += 4;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"text\"");
           }
         }
 
         if (result0 === null) {
           if (input.substr(pos, 5).toLowerCase() === "image") {
             result0 = input.substr(pos, 5);
             pos += 5;
           } else {
             result0 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"image\"");
             }
           }
 
           if (result0 === null) {
             if (input.substr(pos, 5).toLowerCase() === "audio") {
               result0 = input.substr(pos, 5);
               pos += 5;
             } else {
               result0 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\"audio\"");
               }
             }
 
             if (result0 === null) {
               if (input.substr(pos, 5).toLowerCase() === "video") {
                 result0 = input.substr(pos, 5);
                 pos += 5;
               } else {
                 result0 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\"video\"");
                 }
               }
 
               if (result0 === null) {
                 if (input.substr(pos, 11).toLowerCase() === "application") {
                   result0 = input.substr(pos, 11);
                   pos += 11;
                 } else {
                   result0 = null;
 
                   if (reportFailures === 0) {
                     matchFailed("\"application\"");
                   }
                 }
 
                 if (result0 === null) {
                   result0 = parse_extension_token();
                 }
               }
             }
           }
         }
 
         return result0;
       }
 
       function parse_composite_type() {
         var result0;
 
         if (input.substr(pos, 7).toLowerCase() === "message") {
           result0 = input.substr(pos, 7);
           pos += 7;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"message\"");
           }
         }
 
         if (result0 === null) {
           if (input.substr(pos, 9).toLowerCase() === "multipart") {
             result0 = input.substr(pos, 9);
             pos += 9;
           } else {
             result0 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"multipart\"");
             }
           }
 
           if (result0 === null) {
             result0 = parse_extension_token();
           }
         }
 
         return result0;
       }
 
       function parse_extension_token() {
         var result0;
         result0 = parse_token();
 
         if (result0 === null) {
           result0 = parse_x_token();
         }
 
         return result0;
       }
 
       function parse_x_token() {
         var result0, result1;
         var pos0;
         pos0 = pos;
 
         if (input.substr(pos, 2).toLowerCase() === "x-") {
           result0 = input.substr(pos, 2);
           pos += 2;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"x-\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_token();
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_m_subtype() {
         var result0;
         result0 = parse_extension_token();
 
         if (result0 === null) {
           result0 = parse_token();
         }
 
         return result0;
       }
 
       function parse_m_parameter() {
         var result0, result1, result2;
         var pos0;
         pos0 = pos;
         result0 = parse_token();
 
         if (result0 !== null) {
           result1 = parse_EQUAL();
 
           if (result1 !== null) {
             result2 = parse_m_value();
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos0;
             }
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_m_value() {
         var result0;
         result0 = parse_token();
 
         if (result0 === null) {
           result0 = parse_quoted_string();
         }
 
         return result0;
       }
 
       function parse_CSeq() {
         var result0, result1, result2;
         var pos0;
         pos0 = pos;
         result0 = parse_CSeq_value();
 
         if (result0 !== null) {
           result1 = parse_LWS();
 
           if (result1 !== null) {
             result2 = parse_Method();
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos0;
             }
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_CSeq_value() {
         var result0, result1;
         var pos0;
         pos0 = pos;
         result1 = parse_DIGIT();
 
         if (result1 !== null) {
           result0 = [];
 
           while (result1 !== null) {
             result0.push(result1);
             result1 = parse_DIGIT();
           }
         } else {
           result0 = null;
         }
 
         if (result0 !== null) {
           result0 = function (offset, cseq_value) {
             data.value = parseInt(cseq_value.join(''));
           }(pos0, result0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_Expires() {
         var result0;
         var pos0;
         pos0 = pos;
         result0 = parse_delta_seconds();
 
         if (result0 !== null) {
           result0 = function (offset, expires) {
             data = expires;
           }(pos0, result0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_Event() {
         var result0, result1, result2, result3;
         var pos0, pos1, pos2;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_event_type();
 
         if (result0 !== null) {
           result1 = [];
           pos2 = pos;
           result2 = parse_SEMI();
 
           if (result2 !== null) {
             result3 = parse_generic_param();
 
             if (result3 !== null) {
               result2 = [result2, result3];
             } else {
               result2 = null;
               pos = pos2;
             }
           } else {
             result2 = null;
             pos = pos2;
           }
 
           while (result2 !== null) {
             result1.push(result2);
             pos2 = pos;
             result2 = parse_SEMI();
 
             if (result2 !== null) {
               result3 = parse_generic_param();
 
               if (result3 !== null) {
                 result2 = [result2, result3];
               } else {
                 result2 = null;
                 pos = pos2;
               }
             } else {
               result2 = null;
               pos = pos2;
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset, event_type) {
             data.event = event_type.join('').toLowerCase();
           }(pos0, result0[0]);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_event_type() {
         var result0, result1, result2, result3;
         var pos0, pos1;
         pos0 = pos;
         result0 = parse_token_nodot();
 
         if (result0 !== null) {
           result1 = [];
           pos1 = pos;
 
           if (input.charCodeAt(pos) === 46) {
             result2 = ".";
             pos++;
           } else {
             result2 = null;
 
             if (reportFailures === 0) {
               matchFailed("\".\"");
             }
           }
 
           if (result2 !== null) {
             result3 = parse_token_nodot();
 
             if (result3 !== null) {
               result2 = [result2, result3];
             } else {
               result2 = null;
               pos = pos1;
             }
           } else {
             result2 = null;
             pos = pos1;
           }
 
           while (result2 !== null) {
             result1.push(result2);
             pos1 = pos;
 
             if (input.charCodeAt(pos) === 46) {
               result2 = ".";
               pos++;
             } else {
               result2 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\".\"");
               }
             }
 
             if (result2 !== null) {
               result3 = parse_token_nodot();
 
               if (result3 !== null) {
                 result2 = [result2, result3];
               } else {
                 result2 = null;
                 pos = pos1;
               }
             } else {
               result2 = null;
               pos = pos1;
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_From() {
         var result0, result1, result2, result3;
         var pos0, pos1, pos2;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_SIP_URI_noparams();
 
         if (result0 === null) {
           result0 = parse_name_addr();
         }
 
         if (result0 !== null) {
           result1 = [];
           pos2 = pos;
           result2 = parse_SEMI();
 
           if (result2 !== null) {
             result3 = parse_from_param();
 
             if (result3 !== null) {
               result2 = [result2, result3];
             } else {
               result2 = null;
               pos = pos2;
             }
           } else {
             result2 = null;
             pos = pos2;
           }
 
           while (result2 !== null) {
             result1.push(result2);
             pos2 = pos;
             result2 = parse_SEMI();
 
             if (result2 !== null) {
               result3 = parse_from_param();
 
               if (result3 !== null) {
                 result2 = [result2, result3];
               } else {
                 result2 = null;
                 pos = pos2;
               }
             } else {
               result2 = null;
               pos = pos2;
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             var tag = data.tag;
 
             try {
               data = new NameAddrHeader(data.uri, data.display_name, data.params);
 
               if (tag) {
                 data.setParam('tag', tag);
               }
             } catch (e) {
               data = -1;
             }
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_from_param() {
         var result0;
         result0 = parse_tag_param();
 
         if (result0 === null) {
           result0 = parse_generic_param();
         }
 
         return result0;
       }
 
       function parse_tag_param() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
 
         if (input.substr(pos, 3).toLowerCase() === "tag") {
           result0 = input.substr(pos, 3);
           pos += 3;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"tag\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_EQUAL();
 
           if (result1 !== null) {
             result2 = parse_token();
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset, tag) {
             data.tag = tag;
           }(pos0, result0[2]);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_Max_Forwards() {
         var result0, result1;
         var pos0;
         pos0 = pos;
         result1 = parse_DIGIT();
 
         if (result1 !== null) {
           result0 = [];
 
           while (result1 !== null) {
             result0.push(result1);
             result1 = parse_DIGIT();
           }
         } else {
           result0 = null;
         }
 
         if (result0 !== null) {
           result0 = function (offset, forwards) {
             data = parseInt(forwards.join(''));
           }(pos0, result0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_Min_Expires() {
         var result0;
         var pos0;
         pos0 = pos;
         result0 = parse_delta_seconds();
 
         if (result0 !== null) {
           result0 = function (offset, min_expires) {
             data = min_expires;
           }(pos0, result0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_Name_Addr_Header() {
         var result0, result1, result2, result3, result4, result5, result6;
         var pos0, pos1, pos2;
         pos0 = pos;
         pos1 = pos;
         result0 = [];
         result1 = parse_display_name();
 
         while (result1 !== null) {
           result0.push(result1);
           result1 = parse_display_name();
         }
 
         if (result0 !== null) {
           result1 = parse_LAQUOT();
 
           if (result1 !== null) {
             result2 = parse_SIP_URI();
 
             if (result2 !== null) {
               result3 = parse_RAQUOT();
 
               if (result3 !== null) {
                 result4 = [];
                 pos2 = pos;
                 result5 = parse_SEMI();
 
                 if (result5 !== null) {
                   result6 = parse_generic_param();
 
                   if (result6 !== null) {
                     result5 = [result5, result6];
                   } else {
                     result5 = null;
                     pos = pos2;
                   }
                 } else {
                   result5 = null;
                   pos = pos2;
                 }
 
                 while (result5 !== null) {
                   result4.push(result5);
                   pos2 = pos;
                   result5 = parse_SEMI();
 
                   if (result5 !== null) {
                     result6 = parse_generic_param();
 
                     if (result6 !== null) {
                       result5 = [result5, result6];
                     } else {
                       result5 = null;
                       pos = pos2;
                     }
                   } else {
                     result5 = null;
                     pos = pos2;
                   }
                 }
 
                 if (result4 !== null) {
                   result0 = [result0, result1, result2, result3, result4];
                 } else {
                   result0 = null;
                   pos = pos1;
                 }
               } else {
                 result0 = null;
                 pos = pos1;
               }
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             try {
               data = new NameAddrHeader(data.uri, data.display_name, data.params);
             } catch (e) {
               data = -1;
             }
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_Proxy_Authenticate() {
         var result0;
         result0 = parse_challenge();
         return result0;
       }
 
       function parse_challenge() {
         var result0, result1, result2, result3, result4, result5;
         var pos0, pos1;
         pos0 = pos;
 
         if (input.substr(pos, 6).toLowerCase() === "digest") {
           result0 = input.substr(pos, 6);
           pos += 6;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"Digest\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_LWS();
 
           if (result1 !== null) {
             result2 = parse_digest_cln();
 
             if (result2 !== null) {
               result3 = [];
               pos1 = pos;
               result4 = parse_COMMA();
 
               if (result4 !== null) {
                 result5 = parse_digest_cln();
 
                 if (result5 !== null) {
                   result4 = [result4, result5];
                 } else {
                   result4 = null;
                   pos = pos1;
                 }
               } else {
                 result4 = null;
                 pos = pos1;
               }
 
               while (result4 !== null) {
                 result3.push(result4);
                 pos1 = pos;
                 result4 = parse_COMMA();
 
                 if (result4 !== null) {
                   result5 = parse_digest_cln();
 
                   if (result5 !== null) {
                     result4 = [result4, result5];
                   } else {
                     result4 = null;
                     pos = pos1;
                   }
                 } else {
                   result4 = null;
                   pos = pos1;
                 }
               }
 
               if (result3 !== null) {
                 result0 = [result0, result1, result2, result3];
               } else {
                 result0 = null;
                 pos = pos0;
               }
             } else {
               result0 = null;
               pos = pos0;
             }
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         if (result0 === null) {
           result0 = parse_other_challenge();
         }
 
         return result0;
       }
 
       function parse_other_challenge() {
         var result0, result1, result2, result3, result4, result5;
         var pos0, pos1;
         pos0 = pos;
         result0 = parse_token();
 
         if (result0 !== null) {
           result1 = parse_LWS();
 
           if (result1 !== null) {
             result2 = parse_auth_param();
 
             if (result2 !== null) {
               result3 = [];
               pos1 = pos;
               result4 = parse_COMMA();
 
               if (result4 !== null) {
                 result5 = parse_auth_param();
 
                 if (result5 !== null) {
                   result4 = [result4, result5];
                 } else {
                   result4 = null;
                   pos = pos1;
                 }
               } else {
                 result4 = null;
                 pos = pos1;
               }
 
               while (result4 !== null) {
                 result3.push(result4);
                 pos1 = pos;
                 result4 = parse_COMMA();
 
                 if (result4 !== null) {
                   result5 = parse_auth_param();
 
                   if (result5 !== null) {
                     result4 = [result4, result5];
                   } else {
                     result4 = null;
                     pos = pos1;
                   }
                 } else {
                   result4 = null;
                   pos = pos1;
                 }
               }
 
               if (result3 !== null) {
                 result0 = [result0, result1, result2, result3];
               } else {
                 result0 = null;
                 pos = pos0;
               }
             } else {
               result0 = null;
               pos = pos0;
             }
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_auth_param() {
         var result0, result1, result2;
         var pos0;
         pos0 = pos;
         result0 = parse_token();
 
         if (result0 !== null) {
           result1 = parse_EQUAL();
 
           if (result1 !== null) {
             result2 = parse_token();
 
             if (result2 === null) {
               result2 = parse_quoted_string();
             }
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos0;
             }
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_digest_cln() {
         var result0;
         result0 = parse_realm();
 
         if (result0 === null) {
           result0 = parse_domain();
 
           if (result0 === null) {
             result0 = parse_nonce();
 
             if (result0 === null) {
               result0 = parse_opaque();
 
               if (result0 === null) {
                 result0 = parse_stale();
 
                 if (result0 === null) {
                   result0 = parse_algorithm();
 
                   if (result0 === null) {
                     result0 = parse_qop_options();
 
                     if (result0 === null) {
                       result0 = parse_auth_param();
                     }
                   }
                 }
               }
             }
           }
         }
 
         return result0;
       }
 
       function parse_realm() {
         var result0, result1, result2;
         var pos0;
         pos0 = pos;
 
         if (input.substr(pos, 5).toLowerCase() === "realm") {
           result0 = input.substr(pos, 5);
           pos += 5;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"realm\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_EQUAL();
 
           if (result1 !== null) {
             result2 = parse_realm_value();
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos0;
             }
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_realm_value() {
         var result0;
         var pos0;
         pos0 = pos;
         result0 = parse_quoted_string_clean();
 
         if (result0 !== null) {
           result0 = function (offset, realm) {
             data.realm = realm;
           }(pos0, result0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_domain() {
         var result0, result1, result2, result3, result4, result5, result6;
         var pos0, pos1;
         pos0 = pos;
 
         if (input.substr(pos, 6).toLowerCase() === "domain") {
           result0 = input.substr(pos, 6);
           pos += 6;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"domain\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_EQUAL();
 
           if (result1 !== null) {
             result2 = parse_LDQUOT();
 
             if (result2 !== null) {
               result3 = parse_URI();
 
               if (result3 !== null) {
                 result4 = [];
                 pos1 = pos;
                 result6 = parse_SP();
 
                 if (result6 !== null) {
                   result5 = [];
 
                   while (result6 !== null) {
                     result5.push(result6);
                     result6 = parse_SP();
                   }
                 } else {
                   result5 = null;
                 }
 
                 if (result5 !== null) {
                   result6 = parse_URI();
 
                   if (result6 !== null) {
                     result5 = [result5, result6];
                   } else {
                     result5 = null;
                     pos = pos1;
                   }
                 } else {
                   result5 = null;
                   pos = pos1;
                 }
 
                 while (result5 !== null) {
                   result4.push(result5);
                   pos1 = pos;
                   result6 = parse_SP();
 
                   if (result6 !== null) {
                     result5 = [];
 
                     while (result6 !== null) {
                       result5.push(result6);
                       result6 = parse_SP();
                     }
                   } else {
                     result5 = null;
                   }
 
                   if (result5 !== null) {
                     result6 = parse_URI();
 
                     if (result6 !== null) {
                       result5 = [result5, result6];
                     } else {
                       result5 = null;
                       pos = pos1;
                     }
                   } else {
                     result5 = null;
                     pos = pos1;
                   }
                 }
 
                 if (result4 !== null) {
                   result5 = parse_RDQUOT();
 
                   if (result5 !== null) {
                     result0 = [result0, result1, result2, result3, result4, result5];
                   } else {
                     result0 = null;
                     pos = pos0;
                   }
                 } else {
                   result0 = null;
                   pos = pos0;
                 }
               } else {
                 result0 = null;
                 pos = pos0;
               }
             } else {
               result0 = null;
               pos = pos0;
             }
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_URI() {
         var result0;
         result0 = parse_absoluteURI();
 
         if (result0 === null) {
           result0 = parse_abs_path();
         }
 
         return result0;
       }
 
       function parse_nonce() {
         var result0, result1, result2;
         var pos0;
         pos0 = pos;
 
         if (input.substr(pos, 5).toLowerCase() === "nonce") {
           result0 = input.substr(pos, 5);
           pos += 5;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"nonce\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_EQUAL();
 
           if (result1 !== null) {
             result2 = parse_nonce_value();
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos0;
             }
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_nonce_value() {
         var result0;
         var pos0;
         pos0 = pos;
         result0 = parse_quoted_string_clean();
 
         if (result0 !== null) {
           result0 = function (offset, nonce) {
             data.nonce = nonce;
           }(pos0, result0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_opaque() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
 
         if (input.substr(pos, 6).toLowerCase() === "opaque") {
           result0 = input.substr(pos, 6);
           pos += 6;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"opaque\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_EQUAL();
 
           if (result1 !== null) {
             result2 = parse_quoted_string_clean();
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset, opaque) {
             data.opaque = opaque;
           }(pos0, result0[2]);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_stale() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
 
         if (input.substr(pos, 5).toLowerCase() === "stale") {
           result0 = input.substr(pos, 5);
           pos += 5;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"stale\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_EQUAL();
 
           if (result1 !== null) {
             pos1 = pos;
 
             if (input.substr(pos, 4).toLowerCase() === "true") {
               result2 = input.substr(pos, 4);
               pos += 4;
             } else {
               result2 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\"true\"");
               }
             }
 
             if (result2 !== null) {
               result2 = function (offset) {
                 data.stale = true;
               }(pos1);
             }
 
             if (result2 === null) {
               pos = pos1;
             }
 
             if (result2 === null) {
               pos1 = pos;
 
               if (input.substr(pos, 5).toLowerCase() === "false") {
                 result2 = input.substr(pos, 5);
                 pos += 5;
               } else {
                 result2 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\"false\"");
                 }
               }
 
               if (result2 !== null) {
                 result2 = function (offset) {
                   data.stale = false;
                 }(pos1);
               }
 
               if (result2 === null) {
                 pos = pos1;
               }
             }
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos0;
             }
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_algorithm() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
 
         if (input.substr(pos, 9).toLowerCase() === "algorithm") {
           result0 = input.substr(pos, 9);
           pos += 9;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"algorithm\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_EQUAL();
 
           if (result1 !== null) {
             if (input.substr(pos, 3).toLowerCase() === "md5") {
               result2 = input.substr(pos, 3);
               pos += 3;
             } else {
               result2 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\"MD5\"");
               }
             }
 
             if (result2 === null) {
               if (input.substr(pos, 8).toLowerCase() === "md5-sess") {
                 result2 = input.substr(pos, 8);
                 pos += 8;
               } else {
                 result2 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\"MD5-sess\"");
                 }
               }
 
               if (result2 === null) {
                 result2 = parse_token();
               }
             }
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset, algorithm) {
             data.algorithm = algorithm.toUpperCase();
           }(pos0, result0[2]);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_qop_options() {
         var result0, result1, result2, result3, result4, result5, result6;
         var pos0, pos1, pos2;
         pos0 = pos;
 
         if (input.substr(pos, 3).toLowerCase() === "qop") {
           result0 = input.substr(pos, 3);
           pos += 3;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"qop\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_EQUAL();
 
           if (result1 !== null) {
             result2 = parse_LDQUOT();
 
             if (result2 !== null) {
               pos1 = pos;
               result3 = parse_qop_value();
 
               if (result3 !== null) {
                 result4 = [];
                 pos2 = pos;
 
                 if (input.charCodeAt(pos) === 44) {
                   result5 = ",";
                   pos++;
                 } else {
                   result5 = null;
 
                   if (reportFailures === 0) {
                     matchFailed("\",\"");
                   }
                 }
 
                 if (result5 !== null) {
                   result6 = parse_qop_value();
 
                   if (result6 !== null) {
                     result5 = [result5, result6];
                   } else {
                     result5 = null;
                     pos = pos2;
                   }
                 } else {
                   result5 = null;
                   pos = pos2;
                 }
 
                 while (result5 !== null) {
                   result4.push(result5);
                   pos2 = pos;
 
                   if (input.charCodeAt(pos) === 44) {
                     result5 = ",";
                     pos++;
                   } else {
                     result5 = null;
 
                     if (reportFailures === 0) {
                       matchFailed("\",\"");
                     }
                   }
 
                   if (result5 !== null) {
                     result6 = parse_qop_value();
 
                     if (result6 !== null) {
                       result5 = [result5, result6];
                     } else {
                       result5 = null;
                       pos = pos2;
                     }
                   } else {
                     result5 = null;
                     pos = pos2;
                   }
                 }
 
                 if (result4 !== null) {
                   result3 = [result3, result4];
                 } else {
                   result3 = null;
                   pos = pos1;
                 }
               } else {
                 result3 = null;
                 pos = pos1;
               }
 
               if (result3 !== null) {
                 result4 = parse_RDQUOT();
 
                 if (result4 !== null) {
                   result0 = [result0, result1, result2, result3, result4];
                 } else {
                   result0 = null;
                   pos = pos0;
                 }
               } else {
                 result0 = null;
                 pos = pos0;
               }
             } else {
               result0 = null;
               pos = pos0;
             }
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_qop_value() {
         var result0;
         var pos0;
         pos0 = pos;
 
         if (input.substr(pos, 8).toLowerCase() === "auth-int") {
           result0 = input.substr(pos, 8);
           pos += 8;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"auth-int\"");
           }
         }
 
         if (result0 === null) {
           if (input.substr(pos, 4).toLowerCase() === "auth") {
             result0 = input.substr(pos, 4);
             pos += 4;
           } else {
             result0 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"auth\"");
             }
           }
 
           if (result0 === null) {
             result0 = parse_token();
           }
         }
 
         if (result0 !== null) {
           result0 = function (offset, qop_value) {
             data.qop || (data.qop = []);
             data.qop.push(qop_value.toLowerCase());
           }(pos0, result0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_Proxy_Require() {
         var result0, result1, result2, result3;
         var pos0, pos1;
         pos0 = pos;
         result0 = parse_token();
 
         if (result0 !== null) {
           result1 = [];
           pos1 = pos;
           result2 = parse_COMMA();
 
           if (result2 !== null) {
             result3 = parse_token();
 
             if (result3 !== null) {
               result2 = [result2, result3];
             } else {
               result2 = null;
               pos = pos1;
             }
           } else {
             result2 = null;
             pos = pos1;
           }
 
           while (result2 !== null) {
             result1.push(result2);
             pos1 = pos;
             result2 = parse_COMMA();
 
             if (result2 !== null) {
               result3 = parse_token();
 
               if (result3 !== null) {
                 result2 = [result2, result3];
               } else {
                 result2 = null;
                 pos = pos1;
               }
             } else {
               result2 = null;
               pos = pos1;
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_Record_Route() {
         var result0, result1, result2, result3;
         var pos0, pos1, pos2;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_rec_route();
 
         if (result0 !== null) {
           result1 = [];
           pos2 = pos;
           result2 = parse_COMMA();
 
           if (result2 !== null) {
             result3 = parse_rec_route();
 
             if (result3 !== null) {
               result2 = [result2, result3];
             } else {
               result2 = null;
               pos = pos2;
             }
           } else {
             result2 = null;
             pos = pos2;
           }
 
           while (result2 !== null) {
             result1.push(result2);
             pos2 = pos;
             result2 = parse_COMMA();
 
             if (result2 !== null) {
               result3 = parse_rec_route();
 
               if (result3 !== null) {
                 result2 = [result2, result3];
               } else {
                 result2 = null;
                 pos = pos2;
               }
             } else {
               result2 = null;
               pos = pos2;
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             var idx, length;
             length = data.multi_header.length;
 
             for (idx = 0; idx < length; idx++) {
               if (data.multi_header[idx].parsed === null) {
                 data = null;
                 break;
               }
             }
 
             if (data !== null) {
               data = data.multi_header;
             } else {
               data = -1;
             }
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_rec_route() {
         var result0, result1, result2, result3;
         var pos0, pos1, pos2;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_name_addr();
 
         if (result0 !== null) {
           result1 = [];
           pos2 = pos;
           result2 = parse_SEMI();
 
           if (result2 !== null) {
             result3 = parse_generic_param();
 
             if (result3 !== null) {
               result2 = [result2, result3];
             } else {
               result2 = null;
               pos = pos2;
             }
           } else {
             result2 = null;
             pos = pos2;
           }
 
           while (result2 !== null) {
             result1.push(result2);
             pos2 = pos;
             result2 = parse_SEMI();
 
             if (result2 !== null) {
               result3 = parse_generic_param();
 
               if (result3 !== null) {
                 result2 = [result2, result3];
               } else {
                 result2 = null;
                 pos = pos2;
               }
             } else {
               result2 = null;
               pos = pos2;
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             var header;
             if (!data.multi_header) data.multi_header = [];
 
             try {
               header = new NameAddrHeader(data.uri, data.display_name, data.params);
               delete data.uri;
               delete data.display_name;
               delete data.params;
             } catch (e) {
               header = null;
             }
 
             data.multi_header.push({
               'possition': pos,
               'offset': offset,
               'parsed': header
             });
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_Reason() {
         var result0, result1, result2, result3;
         var pos0, pos1, pos2;
         pos0 = pos;
         pos1 = pos;
 
         if (input.substr(pos, 3).toLowerCase() === "sip") {
           result0 = input.substr(pos, 3);
           pos += 3;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"SIP\"");
           }
         }
 
         if (result0 === null) {
           result0 = parse_token();
         }
 
         if (result0 !== null) {
           result1 = [];
           pos2 = pos;
           result2 = parse_SEMI();
 
           if (result2 !== null) {
             result3 = parse_reason_param();
 
             if (result3 !== null) {
               result2 = [result2, result3];
             } else {
               result2 = null;
               pos = pos2;
             }
           } else {
             result2 = null;
             pos = pos2;
           }
 
           while (result2 !== null) {
             result1.push(result2);
             pos2 = pos;
             result2 = parse_SEMI();
 
             if (result2 !== null) {
               result3 = parse_reason_param();
 
               if (result3 !== null) {
                 result2 = [result2, result3];
               } else {
                 result2 = null;
                 pos = pos2;
               }
             } else {
               result2 = null;
               pos = pos2;
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset, protocol) {
             data.protocol = protocol.toLowerCase();
             if (!data.params) data.params = {};
 
             if (data.params.text && data.params.text[0] === '"') {
               var text = data.params.text;
               data.text = text.substring(1, text.length - 1);
               delete data.params.text;
             }
           }(pos0, result0[0]);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_reason_param() {
         var result0;
         result0 = parse_reason_cause();
 
         if (result0 === null) {
           result0 = parse_generic_param();
         }
 
         return result0;
       }
 
       function parse_reason_cause() {
         var result0, result1, result2, result3;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
 
         if (input.substr(pos, 5).toLowerCase() === "cause") {
           result0 = input.substr(pos, 5);
           pos += 5;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"cause\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_EQUAL();
 
           if (result1 !== null) {
             result3 = parse_DIGIT();
 
             if (result3 !== null) {
               result2 = [];
 
               while (result3 !== null) {
                 result2.push(result3);
                 result3 = parse_DIGIT();
               }
             } else {
               result2 = null;
             }
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset, cause) {
             data.cause = parseInt(cause.join(''));
           }(pos0, result0[2]);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_Require() {
         var result0, result1, result2, result3;
         var pos0, pos1;
         pos0 = pos;
         result0 = parse_token();
 
         if (result0 !== null) {
           result1 = [];
           pos1 = pos;
           result2 = parse_COMMA();
 
           if (result2 !== null) {
             result3 = parse_token();
 
             if (result3 !== null) {
               result2 = [result2, result3];
             } else {
               result2 = null;
               pos = pos1;
             }
           } else {
             result2 = null;
             pos = pos1;
           }
 
           while (result2 !== null) {
             result1.push(result2);
             pos1 = pos;
             result2 = parse_COMMA();
 
             if (result2 !== null) {
               result3 = parse_token();
 
               if (result3 !== null) {
                 result2 = [result2, result3];
               } else {
                 result2 = null;
                 pos = pos1;
               }
             } else {
               result2 = null;
               pos = pos1;
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_Route() {
         var result0, result1, result2, result3;
         var pos0, pos1;
         pos0 = pos;
         result0 = parse_route_param();
 
         if (result0 !== null) {
           result1 = [];
           pos1 = pos;
           result2 = parse_COMMA();
 
           if (result2 !== null) {
             result3 = parse_route_param();
 
             if (result3 !== null) {
               result2 = [result2, result3];
             } else {
               result2 = null;
               pos = pos1;
             }
           } else {
             result2 = null;
             pos = pos1;
           }
 
           while (result2 !== null) {
             result1.push(result2);
             pos1 = pos;
             result2 = parse_COMMA();
 
             if (result2 !== null) {
               result3 = parse_route_param();
 
               if (result3 !== null) {
                 result2 = [result2, result3];
               } else {
                 result2 = null;
                 pos = pos1;
               }
             } else {
               result2 = null;
               pos = pos1;
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_route_param() {
         var result0, result1, result2, result3;
         var pos0, pos1;
         pos0 = pos;
         result0 = parse_name_addr();
 
         if (result0 !== null) {
           result1 = [];
           pos1 = pos;
           result2 = parse_SEMI();
 
           if (result2 !== null) {
             result3 = parse_generic_param();
 
             if (result3 !== null) {
               result2 = [result2, result3];
             } else {
               result2 = null;
               pos = pos1;
             }
           } else {
             result2 = null;
             pos = pos1;
           }
 
           while (result2 !== null) {
             result1.push(result2);
             pos1 = pos;
             result2 = parse_SEMI();
 
             if (result2 !== null) {
               result3 = parse_generic_param();
 
               if (result3 !== null) {
                 result2 = [result2, result3];
               } else {
                 result2 = null;
                 pos = pos1;
               }
             } else {
               result2 = null;
               pos = pos1;
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_Subscription_State() {
         var result0, result1, result2, result3;
         var pos0, pos1;
         pos0 = pos;
         result0 = parse_substate_value();
 
         if (result0 !== null) {
           result1 = [];
           pos1 = pos;
           result2 = parse_SEMI();
 
           if (result2 !== null) {
             result3 = parse_subexp_params();
 
             if (result3 !== null) {
               result2 = [result2, result3];
             } else {
               result2 = null;
               pos = pos1;
             }
           } else {
             result2 = null;
             pos = pos1;
           }
 
           while (result2 !== null) {
             result1.push(result2);
             pos1 = pos;
             result2 = parse_SEMI();
 
             if (result2 !== null) {
               result3 = parse_subexp_params();
 
               if (result3 !== null) {
                 result2 = [result2, result3];
               } else {
                 result2 = null;
                 pos = pos1;
               }
             } else {
               result2 = null;
               pos = pos1;
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_substate_value() {
         var result0;
         var pos0;
         pos0 = pos;
 
         if (input.substr(pos, 6).toLowerCase() === "active") {
           result0 = input.substr(pos, 6);
           pos += 6;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"active\"");
           }
         }
 
         if (result0 === null) {
           if (input.substr(pos, 7).toLowerCase() === "pending") {
             result0 = input.substr(pos, 7);
             pos += 7;
           } else {
             result0 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"pending\"");
             }
           }
 
           if (result0 === null) {
             if (input.substr(pos, 10).toLowerCase() === "terminated") {
               result0 = input.substr(pos, 10);
               pos += 10;
             } else {
               result0 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\"terminated\"");
               }
             }
 
             if (result0 === null) {
               result0 = parse_token();
             }
           }
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             data.state = input.substring(pos, offset);
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_subexp_params() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
 
         if (input.substr(pos, 6).toLowerCase() === "reason") {
           result0 = input.substr(pos, 6);
           pos += 6;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"reason\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_EQUAL();
 
           if (result1 !== null) {
             result2 = parse_event_reason_value();
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset, reason) {
             if (typeof reason !== 'undefined') data.reason = reason;
           }(pos0, result0[2]);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         if (result0 === null) {
           pos0 = pos;
           pos1 = pos;
 
           if (input.substr(pos, 7).toLowerCase() === "expires") {
             result0 = input.substr(pos, 7);
             pos += 7;
           } else {
             result0 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"expires\"");
             }
           }
 
           if (result0 !== null) {
             result1 = parse_EQUAL();
 
             if (result1 !== null) {
               result2 = parse_delta_seconds();
 
               if (result2 !== null) {
                 result0 = [result0, result1, result2];
               } else {
                 result0 = null;
                 pos = pos1;
               }
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
 
           if (result0 !== null) {
             result0 = function (offset, expires) {
               if (typeof expires !== 'undefined') data.expires = expires;
             }(pos0, result0[2]);
           }
 
           if (result0 === null) {
             pos = pos0;
           }
 
           if (result0 === null) {
             pos0 = pos;
             pos1 = pos;
 
             if (input.substr(pos, 11).toLowerCase() === "retry_after") {
               result0 = input.substr(pos, 11);
               pos += 11;
             } else {
               result0 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\"retry_after\"");
               }
             }
 
             if (result0 !== null) {
               result1 = parse_EQUAL();
 
               if (result1 !== null) {
                 result2 = parse_delta_seconds();
 
                 if (result2 !== null) {
                   result0 = [result0, result1, result2];
                 } else {
                   result0 = null;
                   pos = pos1;
                 }
               } else {
                 result0 = null;
                 pos = pos1;
               }
             } else {
               result0 = null;
               pos = pos1;
             }
 
             if (result0 !== null) {
               result0 = function (offset, retry_after) {
                 if (typeof retry_after !== 'undefined') data.retry_after = retry_after;
               }(pos0, result0[2]);
             }
 
             if (result0 === null) {
               pos = pos0;
             }
 
             if (result0 === null) {
               result0 = parse_generic_param();
             }
           }
         }
 
         return result0;
       }
 
       function parse_event_reason_value() {
         var result0;
 
         if (input.substr(pos, 11).toLowerCase() === "deactivated") {
           result0 = input.substr(pos, 11);
           pos += 11;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"deactivated\"");
           }
         }
 
         if (result0 === null) {
           if (input.substr(pos, 9).toLowerCase() === "probation") {
             result0 = input.substr(pos, 9);
             pos += 9;
           } else {
             result0 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"probation\"");
             }
           }
 
           if (result0 === null) {
             if (input.substr(pos, 8).toLowerCase() === "rejected") {
               result0 = input.substr(pos, 8);
               pos += 8;
             } else {
               result0 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\"rejected\"");
               }
             }
 
             if (result0 === null) {
               if (input.substr(pos, 7).toLowerCase() === "timeout") {
                 result0 = input.substr(pos, 7);
                 pos += 7;
               } else {
                 result0 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\"timeout\"");
                 }
               }
 
               if (result0 === null) {
                 if (input.substr(pos, 6).toLowerCase() === "giveup") {
                   result0 = input.substr(pos, 6);
                   pos += 6;
                 } else {
                   result0 = null;
 
                   if (reportFailures === 0) {
                     matchFailed("\"giveup\"");
                   }
                 }
 
                 if (result0 === null) {
                   if (input.substr(pos, 10).toLowerCase() === "noresource") {
                     result0 = input.substr(pos, 10);
                     pos += 10;
                   } else {
                     result0 = null;
 
                     if (reportFailures === 0) {
                       matchFailed("\"noresource\"");
                     }
                   }
 
                   if (result0 === null) {
                     if (input.substr(pos, 9).toLowerCase() === "invariant") {
                       result0 = input.substr(pos, 9);
                       pos += 9;
                     } else {
                       result0 = null;
 
                       if (reportFailures === 0) {
                         matchFailed("\"invariant\"");
                       }
                     }
 
                     if (result0 === null) {
                       result0 = parse_token();
                     }
                   }
                 }
               }
             }
           }
         }
 
         return result0;
       }
 
       function parse_Subject() {
         var result0;
         result0 = parse_TEXT_UTF8_TRIM();
         result0 = result0 !== null ? result0 : "";
         return result0;
       }
 
       function parse_Supported() {
         var result0, result1, result2, result3;
         var pos0, pos1;
         pos0 = pos;
         result0 = parse_token();
 
         if (result0 !== null) {
           result1 = [];
           pos1 = pos;
           result2 = parse_COMMA();
 
           if (result2 !== null) {
             result3 = parse_token();
 
             if (result3 !== null) {
               result2 = [result2, result3];
             } else {
               result2 = null;
               pos = pos1;
             }
           } else {
             result2 = null;
             pos = pos1;
           }
 
           while (result2 !== null) {
             result1.push(result2);
             pos1 = pos;
             result2 = parse_COMMA();
 
             if (result2 !== null) {
               result3 = parse_token();
 
               if (result3 !== null) {
                 result2 = [result2, result3];
               } else {
                 result2 = null;
                 pos = pos1;
               }
             } else {
               result2 = null;
               pos = pos1;
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         result0 = result0 !== null ? result0 : "";
         return result0;
       }
 
       function parse_To() {
         var result0, result1, result2, result3;
         var pos0, pos1, pos2;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_SIP_URI_noparams();
 
         if (result0 === null) {
           result0 = parse_name_addr();
         }
 
         if (result0 !== null) {
           result1 = [];
           pos2 = pos;
           result2 = parse_SEMI();
 
           if (result2 !== null) {
             result3 = parse_to_param();
 
             if (result3 !== null) {
               result2 = [result2, result3];
             } else {
               result2 = null;
               pos = pos2;
             }
           } else {
             result2 = null;
             pos = pos2;
           }
 
           while (result2 !== null) {
             result1.push(result2);
             pos2 = pos;
             result2 = parse_SEMI();
 
             if (result2 !== null) {
               result3 = parse_to_param();
 
               if (result3 !== null) {
                 result2 = [result2, result3];
               } else {
                 result2 = null;
                 pos = pos2;
               }
             } else {
               result2 = null;
               pos = pos2;
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             var tag = data.tag;
 
             try {
               data = new NameAddrHeader(data.uri, data.display_name, data.params);
 
               if (tag) {
                 data.setParam('tag', tag);
               }
             } catch (e) {
               data = -1;
             }
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_to_param() {
         var result0;
         result0 = parse_tag_param();
 
         if (result0 === null) {
           result0 = parse_generic_param();
         }
 
         return result0;
       }
 
       function parse_Via() {
         var result0, result1, result2, result3;
         var pos0, pos1;
         pos0 = pos;
         result0 = parse_via_param();
 
         if (result0 !== null) {
           result1 = [];
           pos1 = pos;
           result2 = parse_COMMA();
 
           if (result2 !== null) {
             result3 = parse_via_param();
 
             if (result3 !== null) {
               result2 = [result2, result3];
             } else {
               result2 = null;
               pos = pos1;
             }
           } else {
             result2 = null;
             pos = pos1;
           }
 
           while (result2 !== null) {
             result1.push(result2);
             pos1 = pos;
             result2 = parse_COMMA();
 
             if (result2 !== null) {
               result3 = parse_via_param();
 
               if (result3 !== null) {
                 result2 = [result2, result3];
               } else {
                 result2 = null;
                 pos = pos1;
               }
             } else {
               result2 = null;
               pos = pos1;
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_via_param() {
         var result0, result1, result2, result3, result4, result5;
         var pos0, pos1;
         pos0 = pos;
         result0 = parse_sent_protocol();
 
         if (result0 !== null) {
           result1 = parse_LWS();
 
           if (result1 !== null) {
             result2 = parse_sent_by();
 
             if (result2 !== null) {
               result3 = [];
               pos1 = pos;
               result4 = parse_SEMI();
 
               if (result4 !== null) {
                 result5 = parse_via_params();
 
                 if (result5 !== null) {
                   result4 = [result4, result5];
                 } else {
                   result4 = null;
                   pos = pos1;
                 }
               } else {
                 result4 = null;
                 pos = pos1;
               }
 
               while (result4 !== null) {
                 result3.push(result4);
                 pos1 = pos;
                 result4 = parse_SEMI();
 
                 if (result4 !== null) {
                   result5 = parse_via_params();
 
                   if (result5 !== null) {
                     result4 = [result4, result5];
                   } else {
                     result4 = null;
                     pos = pos1;
                   }
                 } else {
                   result4 = null;
                   pos = pos1;
                 }
               }
 
               if (result3 !== null) {
                 result0 = [result0, result1, result2, result3];
               } else {
                 result0 = null;
                 pos = pos0;
               }
             } else {
               result0 = null;
               pos = pos0;
             }
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_via_params() {
         var result0;
         result0 = parse_via_ttl();
 
         if (result0 === null) {
           result0 = parse_via_maddr();
 
           if (result0 === null) {
             result0 = parse_via_received();
 
             if (result0 === null) {
               result0 = parse_via_branch();
 
               if (result0 === null) {
                 result0 = parse_response_port();
 
                 if (result0 === null) {
                   result0 = parse_generic_param();
                 }
               }
             }
           }
         }
 
         return result0;
       }
 
       function parse_via_ttl() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
 
         if (input.substr(pos, 3).toLowerCase() === "ttl") {
           result0 = input.substr(pos, 3);
           pos += 3;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"ttl\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_EQUAL();
 
           if (result1 !== null) {
             result2 = parse_ttl();
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset, via_ttl_value) {
             data.ttl = via_ttl_value;
           }(pos0, result0[2]);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_via_maddr() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
 
         if (input.substr(pos, 5).toLowerCase() === "maddr") {
           result0 = input.substr(pos, 5);
           pos += 5;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"maddr\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_EQUAL();
 
           if (result1 !== null) {
             result2 = parse_host();
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset, via_maddr) {
             data.maddr = via_maddr;
           }(pos0, result0[2]);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_via_received() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
 
         if (input.substr(pos, 8).toLowerCase() === "received") {
           result0 = input.substr(pos, 8);
           pos += 8;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"received\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_EQUAL();
 
           if (result1 !== null) {
             result2 = parse_IPv4address();
 
             if (result2 === null) {
               result2 = parse_IPv6address();
             }
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset, via_received) {
             data.received = via_received;
           }(pos0, result0[2]);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_via_branch() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
 
         if (input.substr(pos, 6).toLowerCase() === "branch") {
           result0 = input.substr(pos, 6);
           pos += 6;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"branch\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_EQUAL();
 
           if (result1 !== null) {
             result2 = parse_token();
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset, via_branch) {
             data.branch = via_branch;
           }(pos0, result0[2]);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_response_port() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
 
         if (input.substr(pos, 5).toLowerCase() === "rport") {
           result0 = input.substr(pos, 5);
           pos += 5;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"rport\"");
           }
         }
 
         if (result0 !== null) {
           pos1 = pos;
           result1 = parse_EQUAL();
 
           if (result1 !== null) {
             result2 = parse_rport();
 
             if (result2 !== null) {
               result1 = [result1, result2];
             } else {
               result1 = null;
               pos = pos1;
             }
           } else {
             result1 = null;
             pos = pos1;
           }
 
           result1 = result1 !== null ? result1 : "";
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_rport() {
         var result0, result1, result2, result3, result4;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_DIGIT();
         result0 = result0 !== null ? result0 : "";
 
         if (result0 !== null) {
           result1 = parse_DIGIT();
           result1 = result1 !== null ? result1 : "";
 
           if (result1 !== null) {
             result2 = parse_DIGIT();
             result2 = result2 !== null ? result2 : "";
 
             if (result2 !== null) {
               result3 = parse_DIGIT();
               result3 = result3 !== null ? result3 : "";
 
               if (result3 !== null) {
                 result4 = parse_DIGIT();
                 result4 = result4 !== null ? result4 : "";
 
                 if (result4 !== null) {
                   result0 = [result0, result1, result2, result3, result4];
                 } else {
                   result0 = null;
                   pos = pos1;
                 }
               } else {
                 result0 = null;
                 pos = pos1;
               }
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset, rport) {
             data.rport = parseInt(rport.join(''));
           }(pos0, result0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_sent_protocol() {
         var result0, result1, result2, result3, result4;
         var pos0;
         pos0 = pos;
         result0 = parse_protocol_name();
 
         if (result0 !== null) {
           result1 = parse_SLASH();
 
           if (result1 !== null) {
             result2 = parse_token();
 
             if (result2 !== null) {
               result3 = parse_SLASH();
 
               if (result3 !== null) {
                 result4 = parse_transport();
 
                 if (result4 !== null) {
                   result0 = [result0, result1, result2, result3, result4];
                 } else {
                   result0 = null;
                   pos = pos0;
                 }
               } else {
                 result0 = null;
                 pos = pos0;
               }
             } else {
               result0 = null;
               pos = pos0;
             }
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_protocol_name() {
         var result0;
         var pos0;
         pos0 = pos;
 
         if (input.substr(pos, 3).toLowerCase() === "sip") {
           result0 = input.substr(pos, 3);
           pos += 3;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"SIP\"");
           }
         }
 
         if (result0 === null) {
           result0 = parse_token();
         }
 
         if (result0 !== null) {
           result0 = function (offset, via_protocol) {
             data.protocol = via_protocol;
           }(pos0, result0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_transport() {
         var result0;
         var pos0;
         pos0 = pos;
 
         if (input.substr(pos, 3).toLowerCase() === "udp") {
           result0 = input.substr(pos, 3);
           pos += 3;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"UDP\"");
           }
         }
 
         if (result0 === null) {
           if (input.substr(pos, 3).toLowerCase() === "tcp") {
             result0 = input.substr(pos, 3);
             pos += 3;
           } else {
             result0 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"TCP\"");
             }
           }
 
           if (result0 === null) {
             if (input.substr(pos, 3).toLowerCase() === "tls") {
               result0 = input.substr(pos, 3);
               pos += 3;
             } else {
               result0 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\"TLS\"");
               }
             }
 
             if (result0 === null) {
               if (input.substr(pos, 4).toLowerCase() === "sctp") {
                 result0 = input.substr(pos, 4);
                 pos += 4;
               } else {
                 result0 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\"SCTP\"");
                 }
               }
 
               if (result0 === null) {
                 result0 = parse_token();
               }
             }
           }
         }
 
         if (result0 !== null) {
           result0 = function (offset, via_transport) {
             data.transport = via_transport;
           }(pos0, result0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_sent_by() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
         result0 = parse_via_host();
 
         if (result0 !== null) {
           pos1 = pos;
           result1 = parse_COLON();
 
           if (result1 !== null) {
             result2 = parse_via_port();
 
             if (result2 !== null) {
               result1 = [result1, result2];
             } else {
               result1 = null;
               pos = pos1;
             }
           } else {
             result1 = null;
             pos = pos1;
           }
 
           result1 = result1 !== null ? result1 : "";
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_via_host() {
         var result0;
         var pos0;
         pos0 = pos;
         result0 = parse_IPv4address();
 
         if (result0 === null) {
           result0 = parse_IPv6reference();
 
           if (result0 === null) {
             result0 = parse_hostname();
           }
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             data.host = input.substring(pos, offset);
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_via_port() {
         var result0, result1, result2, result3, result4;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_DIGIT();
         result0 = result0 !== null ? result0 : "";
 
         if (result0 !== null) {
           result1 = parse_DIGIT();
           result1 = result1 !== null ? result1 : "";
 
           if (result1 !== null) {
             result2 = parse_DIGIT();
             result2 = result2 !== null ? result2 : "";
 
             if (result2 !== null) {
               result3 = parse_DIGIT();
               result3 = result3 !== null ? result3 : "";
 
               if (result3 !== null) {
                 result4 = parse_DIGIT();
                 result4 = result4 !== null ? result4 : "";
 
                 if (result4 !== null) {
                   result0 = [result0, result1, result2, result3, result4];
                 } else {
                   result0 = null;
                   pos = pos1;
                 }
               } else {
                 result0 = null;
                 pos = pos1;
               }
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset, via_sent_by_port) {
             data.port = parseInt(via_sent_by_port.join(''));
           }(pos0, result0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_ttl() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_DIGIT();
 
         if (result0 !== null) {
           result1 = parse_DIGIT();
           result1 = result1 !== null ? result1 : "";
 
           if (result1 !== null) {
             result2 = parse_DIGIT();
             result2 = result2 !== null ? result2 : "";
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset, ttl) {
             return parseInt(ttl.join(''));
           }(pos0, result0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_WWW_Authenticate() {
         var result0;
         result0 = parse_challenge();
         return result0;
       }
 
       function parse_Session_Expires() {
         var result0, result1, result2, result3;
         var pos0, pos1;
         pos0 = pos;
         result0 = parse_s_e_expires();
 
         if (result0 !== null) {
           result1 = [];
           pos1 = pos;
           result2 = parse_SEMI();
 
           if (result2 !== null) {
             result3 = parse_s_e_params();
 
             if (result3 !== null) {
               result2 = [result2, result3];
             } else {
               result2 = null;
               pos = pos1;
             }
           } else {
             result2 = null;
             pos = pos1;
           }
 
           while (result2 !== null) {
             result1.push(result2);
             pos1 = pos;
             result2 = parse_SEMI();
 
             if (result2 !== null) {
               result3 = parse_s_e_params();
 
               if (result3 !== null) {
                 result2 = [result2, result3];
               } else {
                 result2 = null;
                 pos = pos1;
               }
             } else {
               result2 = null;
               pos = pos1;
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_s_e_expires() {
         var result0;
         var pos0;
         pos0 = pos;
         result0 = parse_delta_seconds();
 
         if (result0 !== null) {
           result0 = function (offset, expires) {
             data.expires = expires;
           }(pos0, result0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_s_e_params() {
         var result0;
         result0 = parse_s_e_refresher();
 
         if (result0 === null) {
           result0 = parse_generic_param();
         }
 
         return result0;
       }
 
       function parse_s_e_refresher() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
 
         if (input.substr(pos, 9).toLowerCase() === "refresher") {
           result0 = input.substr(pos, 9);
           pos += 9;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"refresher\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_EQUAL();
 
           if (result1 !== null) {
             if (input.substr(pos, 3).toLowerCase() === "uac") {
               result2 = input.substr(pos, 3);
               pos += 3;
             } else {
               result2 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\"uac\"");
               }
             }
 
             if (result2 === null) {
               if (input.substr(pos, 3).toLowerCase() === "uas") {
                 result2 = input.substr(pos, 3);
                 pos += 3;
               } else {
                 result2 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\"uas\"");
                 }
               }
             }
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset, s_e_refresher_value) {
             data.refresher = s_e_refresher_value.toLowerCase();
           }(pos0, result0[2]);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_extension_header() {
         var result0, result1, result2;
         var pos0;
         pos0 = pos;
         result0 = parse_token();
 
         if (result0 !== null) {
           result1 = parse_HCOLON();
 
           if (result1 !== null) {
             result2 = parse_header_value();
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos0;
             }
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_header_value() {
         var result0, result1;
         result0 = [];
         result1 = parse_TEXT_UTF8char();
 
         if (result1 === null) {
           result1 = parse_UTF8_CONT();
 
           if (result1 === null) {
             result1 = parse_LWS();
           }
         }
 
         while (result1 !== null) {
           result0.push(result1);
           result1 = parse_TEXT_UTF8char();
 
           if (result1 === null) {
             result1 = parse_UTF8_CONT();
 
             if (result1 === null) {
               result1 = parse_LWS();
             }
           }
         }
 
         return result0;
       }
 
       function parse_message_body() {
         var result0, result1;
         result0 = [];
         result1 = parse_OCTET();
 
         while (result1 !== null) {
           result0.push(result1);
           result1 = parse_OCTET();
         }
 
         return result0;
       }
 
       function parse_uuid_URI() {
         var result0, result1;
         var pos0;
         pos0 = pos;
 
         if (input.substr(pos, 5) === "uuid:") {
           result0 = "uuid:";
           pos += 5;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"uuid:\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_uuid();
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_uuid() {
         var result0, result1, result2, result3, result4, result5, result6, result7, result8;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_hex8();
 
         if (result0 !== null) {
           if (input.charCodeAt(pos) === 45) {
             result1 = "-";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"-\"");
             }
           }
 
           if (result1 !== null) {
             result2 = parse_hex4();
 
             if (result2 !== null) {
               if (input.charCodeAt(pos) === 45) {
                 result3 = "-";
                 pos++;
               } else {
                 result3 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\"-\"");
                 }
               }
 
               if (result3 !== null) {
                 result4 = parse_hex4();
 
                 if (result4 !== null) {
                   if (input.charCodeAt(pos) === 45) {
                     result5 = "-";
                     pos++;
                   } else {
                     result5 = null;
 
                     if (reportFailures === 0) {
                       matchFailed("\"-\"");
                     }
                   }
 
                   if (result5 !== null) {
                     result6 = parse_hex4();
 
                     if (result6 !== null) {
                       if (input.charCodeAt(pos) === 45) {
                         result7 = "-";
                         pos++;
                       } else {
                         result7 = null;
 
                         if (reportFailures === 0) {
                           matchFailed("\"-\"");
                         }
                       }
 
                       if (result7 !== null) {
                         result8 = parse_hex12();
 
                         if (result8 !== null) {
                           result0 = [result0, result1, result2, result3, result4, result5, result6, result7, result8];
                         } else {
                           result0 = null;
                           pos = pos1;
                         }
                       } else {
                         result0 = null;
                         pos = pos1;
                       }
                     } else {
                       result0 = null;
                       pos = pos1;
                     }
                   } else {
                     result0 = null;
                     pos = pos1;
                   }
                 } else {
                   result0 = null;
                   pos = pos1;
                 }
               } else {
                 result0 = null;
                 pos = pos1;
               }
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset, uuid) {
             data = input.substring(pos + 5, offset);
           }(pos0, result0[0]);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_hex4() {
         var result0, result1, result2, result3;
         var pos0;
         pos0 = pos;
         result0 = parse_HEXDIG();
 
         if (result0 !== null) {
           result1 = parse_HEXDIG();
 
           if (result1 !== null) {
             result2 = parse_HEXDIG();
 
             if (result2 !== null) {
               result3 = parse_HEXDIG();
 
               if (result3 !== null) {
                 result0 = [result0, result1, result2, result3];
               } else {
                 result0 = null;
                 pos = pos0;
               }
             } else {
               result0 = null;
               pos = pos0;
             }
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_hex8() {
         var result0, result1;
         var pos0;
         pos0 = pos;
         result0 = parse_hex4();
 
         if (result0 !== null) {
           result1 = parse_hex4();
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_hex12() {
         var result0, result1, result2;
         var pos0;
         pos0 = pos;
         result0 = parse_hex4();
 
         if (result0 !== null) {
           result1 = parse_hex4();
 
           if (result1 !== null) {
             result2 = parse_hex4();
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos0;
             }
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_Refer_To() {
         var result0, result1, result2, result3;
         var pos0, pos1, pos2;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_SIP_URI_noparams();
 
         if (result0 === null) {
           result0 = parse_name_addr();
         }
 
         if (result0 !== null) {
           result1 = [];
           pos2 = pos;
           result2 = parse_SEMI();
 
           if (result2 !== null) {
             result3 = parse_generic_param();
 
             if (result3 !== null) {
               result2 = [result2, result3];
             } else {
               result2 = null;
               pos = pos2;
             }
           } else {
             result2 = null;
             pos = pos2;
           }
 
           while (result2 !== null) {
             result1.push(result2);
             pos2 = pos;
             result2 = parse_SEMI();
 
             if (result2 !== null) {
               result3 = parse_generic_param();
 
               if (result3 !== null) {
                 result2 = [result2, result3];
               } else {
                 result2 = null;
                 pos = pos2;
               }
             } else {
               result2 = null;
               pos = pos2;
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             try {
               data = new NameAddrHeader(data.uri, data.display_name, data.params);
             } catch (e) {
               data = -1;
             }
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_Replaces() {
         var result0, result1, result2, result3;
         var pos0, pos1;
         pos0 = pos;
         result0 = parse_call_id();
 
         if (result0 !== null) {
           result1 = [];
           pos1 = pos;
           result2 = parse_SEMI();
 
           if (result2 !== null) {
             result3 = parse_replaces_param();
 
             if (result3 !== null) {
               result2 = [result2, result3];
             } else {
               result2 = null;
               pos = pos1;
             }
           } else {
             result2 = null;
             pos = pos1;
           }
 
           while (result2 !== null) {
             result1.push(result2);
             pos1 = pos;
             result2 = parse_SEMI();
 
             if (result2 !== null) {
               result3 = parse_replaces_param();
 
               if (result3 !== null) {
                 result2 = [result2, result3];
               } else {
                 result2 = null;
                 pos = pos1;
               }
             } else {
               result2 = null;
               pos = pos1;
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_call_id() {
         var result0, result1, result2;
         var pos0, pos1, pos2;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_word();
 
         if (result0 !== null) {
           pos2 = pos;
 
           if (input.charCodeAt(pos) === 64) {
             result1 = "@";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"@\"");
             }
           }
 
           if (result1 !== null) {
             result2 = parse_word();
 
             if (result2 !== null) {
               result1 = [result1, result2];
             } else {
               result1 = null;
               pos = pos2;
             }
           } else {
             result1 = null;
             pos = pos2;
           }
 
           result1 = result1 !== null ? result1 : "";
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             data.call_id = input.substring(pos, offset);
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_replaces_param() {
         var result0;
         result0 = parse_to_tag();
 
         if (result0 === null) {
           result0 = parse_from_tag();
 
           if (result0 === null) {
             result0 = parse_early_flag();
 
             if (result0 === null) {
               result0 = parse_generic_param();
             }
           }
         }
 
         return result0;
       }
 
       function parse_to_tag() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
 
         if (input.substr(pos, 6) === "to-tag") {
           result0 = "to-tag";
           pos += 6;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"to-tag\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_EQUAL();
 
           if (result1 !== null) {
             result2 = parse_token();
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset, to_tag) {
             data.to_tag = to_tag;
           }(pos0, result0[2]);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_from_tag() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
 
         if (input.substr(pos, 8) === "from-tag") {
           result0 = "from-tag";
           pos += 8;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"from-tag\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_EQUAL();
 
           if (result1 !== null) {
             result2 = parse_token();
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset, from_tag) {
             data.from_tag = from_tag;
           }(pos0, result0[2]);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_early_flag() {
         var result0;
         var pos0;
         pos0 = pos;
 
         if (input.substr(pos, 10) === "early-only") {
           result0 = "early-only";
           pos += 10;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"early-only\"");
           }
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             data.early_only = true;
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function cleanupExpected(expected) {
         expected.sort();
         var lastExpected = null;
         var cleanExpected = [];
 
         for (var i = 0; i < expected.length; i++) {
           if (expected[i] !== lastExpected) {
             cleanExpected.push(expected[i]);
             lastExpected = expected[i];
           }
         }
 
         return cleanExpected;
       }
 
       function computeErrorPosition() {
         /*
          * The first idea was to use |String.split| to break the input up to the
          * error position along newlines and derive the line and column from
          * there. However IE's |split| implementation is so broken that it was
          * enough to prevent it.
          */
         var line = 1;
         var column = 1;
         var seenCR = false;
 
         for (var i = 0; i < Math.max(pos, rightmostFailuresPos); i++) {
           var ch = input.charAt(i);
 
           if (ch === "\n") {
             if (!seenCR) {
               line++;
             }
 
             column = 1;
             seenCR = false;
           } else if (ch === "\r" || ch === "\u2028" || ch === "\u2029") {
             line++;
             column = 1;
             seenCR = true;
           } else {
             column++;
             seenCR = false;
           }
         }
 
         return {
           line: line,
           column: column
         };
       }
 
       var URI = require('./URI');
 
       var NameAddrHeader = require('./NameAddrHeader');
 
       var data = {};
       var result = parseFunctions[startRule]();
       /*
        * The parser is now in one of the following three states:
        *
        * 1. The parser successfully parsed the whole input.
        *
        *    - |result !== null|
        *    - |pos === input.length|
        *    - |rightmostFailuresExpected| may or may not contain something
        *
        * 2. The parser successfully parsed only a part of the input.
        *
        *    - |result !== null|
        *    - |pos < input.length|
        *    - |rightmostFailuresExpected| may or may not contain something
        *
        * 3. The parser did not successfully parse any part of the input.
        *
        *   - |result === null|
        *   - |pos === 0|
        *   - |rightmostFailuresExpected| contains at least one failure
        *
        * All code following this comment (including called functions) must
        * handle these states.
        */
 
       if (result === null || pos !== input.length) {
         var offset = Math.max(pos, rightmostFailuresPos);
         var found = offset < input.length ? input.charAt(offset) : null;
         var errorPosition = computeErrorPosition();
         new this.SyntaxError(cleanupExpected(rightmostFailuresExpected), found, offset, errorPosition.line, errorPosition.column);
         return -1;
       }
 
       return data;
     },
 
     /* Returns the parser source code. */
     toSource: function toSource() {
       return this._source;
     }
   };
   /* Thrown when a parser encounters a syntax error. */
 
   result.SyntaxError = function (expected, found, offset, line, column) {
     function buildMessage(expected, found) {
       var expectedHumanized, foundHumanized;
 
       switch (expected.length) {
         case 0:
           expectedHumanized = "end of input";
           break;
 
         case 1:
           expectedHumanized = expected[0];
           break;
 
         default:
           expectedHumanized = expected.slice(0, expected.length - 1).join(", ") + " or " + expected[expected.length - 1];
       }
 
       foundHumanized = found ? quote(found) : "end of input";
       return "Expected " + expectedHumanized + " but " + foundHumanized + " found.";
     }
 
     this.name = "SyntaxError";
     this.expected = expected;
     this.found = found;
     this.message = buildMessage(expected, found);
     this.offset = offset;
     this.line = line;
     this.column = column;
   };
 
   result.SyntaxError.prototype = Error.prototype;
   return result;
 }();
 },{"./NameAddrHeader":10,"./URI":25}],8:[function(require,module,exports){
 "use strict";
 
 var pkg = require('../package.json');
 
 var C = require('./Constants');
 
 var Exceptions = require('./Exceptions');
 
 var Utils = require('./Utils');
 
 var UA = require('./UA');
 
 var URI = require('./URI');
 
 var NameAddrHeader = require('./NameAddrHeader');
 
 var Grammar = require('./Grammar');
 
 var WebSocketInterface = require('./WebSocketInterface');
 
 var debug = require('debug')('JsSIP');
 
 debug('version %s', pkg.version);
 /**
  * Expose the JsSIP module.
  */
 
 module.exports = {
   C: C,
   Exceptions: Exceptions,
   Utils: Utils,
   UA: UA,
   URI: URI,
   NameAddrHeader: NameAddrHeader,
   WebSocketInterface: WebSocketInterface,
   Grammar: Grammar,
   // Expose the debug module.
   debug: require('debug'),
 
   get name() {
     return pkg.title;
   },
 
   get version() {
     return pkg.version;
   }
 
 };
 },{"../package.json":38,"./Constants":2,"./Exceptions":6,"./Grammar":7,"./NameAddrHeader":10,"./UA":24,"./URI":25,"./Utils":26,"./WebSocketInterface":27,"debug":30}],9:[function(require,module,exports){
 "use strict";
 
 function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
 
 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
 function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
 
 function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
 
 function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
 
 function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
 
 function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
 
 function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
 
 function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
 
 function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }
 
 function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
 
 var EventEmitter = require('events').EventEmitter;
 
 var JsSIP_C = require('./Constants');
 
 var SIPMessage = require('./SIPMessage');
 
 var Utils = require('./Utils');
 
 var RequestSender = require('./RequestSender');
 
 var Exceptions = require('./Exceptions');
 
 var debug = require('debug')('JsSIP:Message');
 
 module.exports = /*#__PURE__*/function (_EventEmitter) {
   _inherits(Message, _EventEmitter);
 
   var _super = _createSuper(Message);
 
   function Message(ua) {
     var _this;
 
     _classCallCheck(this, Message);
 
     _this = _super.call(this);
     _this._ua = ua;
     _this._request = null;
     _this._closed = false;
     _this._direction = null;
     _this._local_identity = null;
     _this._remote_identity = null; // Whether an incoming message has been replied.
 
     _this._is_replied = false; // Custom message empty object for high level use.
 
     _this._data = {};
     return _this;
   }
 
   _createClass(Message, [{
     key: "send",
     value: function send(target, body) {
       var _this2 = this;
 
       var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
       var originalTarget = target;
 
       if (target === undefined || body === undefined) {
         throw new TypeError('Not enough arguments');
       } // Check target validity.
 
 
       target = this._ua.normalizeTarget(target);
 
       if (!target) {
         throw new TypeError("Invalid target: ".concat(originalTarget));
       } // Get call options.
 
 
       var extraHeaders = Utils.cloneArray(options.extraHeaders);
       var eventHandlers = Utils.cloneObject(options.eventHandlers);
       var contentType = options.contentType || 'text/plain'; // Set event handlers.
 
       for (var event in eventHandlers) {
         if (Object.prototype.hasOwnProperty.call(eventHandlers, event)) {
           this.on(event, eventHandlers[event]);
         }
       }
 
       extraHeaders.push("Content-Type: ".concat(contentType));
       this._request = new SIPMessage.OutgoingRequest(JsSIP_C.MESSAGE, target, this._ua, null, extraHeaders);
 
       if (body) {
         this._request.body = body;
       }
 
       var request_sender = new RequestSender(this._ua, this._request, {
         onRequestTimeout: function onRequestTimeout() {
           _this2._onRequestTimeout();
         },
         onTransportError: function onTransportError() {
           _this2._onTransportError();
         },
         onReceiveResponse: function onReceiveResponse(response) {
           _this2._receiveResponse(response);
         }
       });
 
       this._newMessage('local', this._request);
 
       request_sender.send();
     }
   }, {
     key: "init_incoming",
     value: function init_incoming(request) {
       this._request = request;
 
       this._newMessage('remote', request); // Reply with a 200 OK if the user didn't reply.
 
 
       if (!this._is_replied) {
         this._is_replied = true;
         request.reply(200);
       }
 
       this._close();
     }
     /**
      * Accept the incoming Message
      * Only valid for incoming Messages
      */
 
   }, {
     key: "accept",
     value: function accept() {
       var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
       var extraHeaders = Utils.cloneArray(options.extraHeaders);
       var body = options.body;
 
       if (this._direction !== 'incoming') {
         throw new Exceptions.NotSupportedError('"accept" not supported for outgoing Message');
       }
 
       if (this._is_replied) {
         throw new Error('incoming Message already replied');
       }
 
       this._is_replied = true;
 
       this._request.reply(200, null, extraHeaders, body);
     }
     /**
      * Reject the incoming Message
      * Only valid for incoming Messages
      */
 
   }, {
     key: "reject",
     value: function reject() {
       var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
       var status_code = options.status_code || 480;
       var reason_phrase = options.reason_phrase;
       var extraHeaders = Utils.cloneArray(options.extraHeaders);
       var body = options.body;
 
       if (this._direction !== 'incoming') {
         throw new Exceptions.NotSupportedError('"reject" not supported for outgoing Message');
       }
 
       if (this._is_replied) {
         throw new Error('incoming Message already replied');
       }
 
       if (status_code < 300 || status_code >= 700) {
         throw new TypeError("Invalid status_code: ".concat(status_code));
       }
 
       this._is_replied = true;
 
       this._request.reply(status_code, reason_phrase, extraHeaders, body);
     }
   }, {
     key: "_receiveResponse",
     value: function _receiveResponse(response) {
       if (this._closed) {
         return;
       }
 
       switch (true) {
         case /^1[0-9]{2}$/.test(response.status_code):
           // Ignore provisional responses.
           break;
 
         case /^2[0-9]{2}$/.test(response.status_code):
           this._succeeded('remote', response);
 
           break;
 
         default:
           {
             var cause = Utils.sipErrorCause(response.status_code);
 
             this._failed('remote', response, cause);
 
             break;
           }
       }
     }
   }, {
     key: "_onRequestTimeout",
     value: function _onRequestTimeout() {
       if (this._closed) {
         return;
       }
 
       this._failed('system', null, JsSIP_C.causes.REQUEST_TIMEOUT);
     }
   }, {
     key: "_onTransportError",
     value: function _onTransportError() {
       if (this._closed) {
         return;
       }
 
       this._failed('system', null, JsSIP_C.causes.CONNECTION_ERROR);
     }
   }, {
     key: "_close",
     value: function _close() {
       this._closed = true;
 
       this._ua.destroyMessage(this);
     }
     /**
      * Internal Callbacks
      */
 
   }, {
     key: "_newMessage",
     value: function _newMessage(originator, request) {
       if (originator === 'remote') {
         this._direction = 'incoming';
         this._local_identity = request.to;
         this._remote_identity = request.from;
       } else if (originator === 'local') {
         this._direction = 'outgoing';
         this._local_identity = request.from;
         this._remote_identity = request.to;
       }
 
       this._ua.newMessage(this, {
         originator: originator,
         message: this,
         request: request
       });
     }
   }, {
     key: "_failed",
     value: function _failed(originator, response, cause) {
       debug('MESSAGE failed');
 
       this._close();
 
       debug('emit "failed"');
       this.emit('failed', {
         originator: originator,
         response: response || null,
         cause: cause
       });
     }
   }, {
     key: "_succeeded",
     value: function _succeeded(originator, response) {
       debug('MESSAGE succeeded');
 
       this._close();
 
       debug('emit "succeeded"');
       this.emit('succeeded', {
         originator: originator,
         response: response
       });
     }
   }, {
     key: "direction",
     get: function get() {
       return this._direction;
     }
   }, {
     key: "local_identity",
     get: function get() {
       return this._local_identity;
     }
   }, {
     key: "remote_identity",
     get: function get() {
       return this._remote_identity;
     }
   }]);
 
   return Message;
 }(EventEmitter);
 },{"./Constants":2,"./Exceptions":6,"./RequestSender":18,"./SIPMessage":19,"./Utils":26,"debug":30,"events":29}],10:[function(require,module,exports){
 "use strict";
 
 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
 function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
 
 function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
 
 var URI = require('./URI');
 
 var Grammar = require('./Grammar');
 
 module.exports = /*#__PURE__*/function () {
   _createClass(NameAddrHeader, null, [{
     key: "parse",
 
     /**
      * Parse the given string and returns a NameAddrHeader instance or undefined if
      * it is an invalid NameAddrHeader.
      */
     value: function parse(name_addr_header) {
       name_addr_header = Grammar.parse(name_addr_header, 'Name_Addr_Header');
 
       if (name_addr_header !== -1) {
         return name_addr_header;
       } else {
         return undefined;
       }
     }
   }]);
 
   function NameAddrHeader(uri, display_name, parameters) {
     _classCallCheck(this, NameAddrHeader);
 
     // Checks.
     if (!uri || !(uri instanceof URI)) {
       throw new TypeError('missing or invalid "uri" parameter');
     } // Initialize parameters.
 
 
     this._uri = uri;
     this._parameters = {};
     this.display_name = display_name;
 
     for (var param in parameters) {
       if (Object.prototype.hasOwnProperty.call(parameters, param)) {
         this.setParam(param, parameters[param]);
       }
     }
   }
 
   _createClass(NameAddrHeader, [{
     key: "setParam",
     value: function setParam(key, value) {
       if (key) {
         this._parameters[key.toLowerCase()] = typeof value === 'undefined' || value === null ? null : value.toString();
       }
     }
   }, {
     key: "getParam",
     value: function getParam(key) {
       if (key) {
         return this._parameters[key.toLowerCase()];
       }
     }
   }, {
     key: "hasParam",
     value: function hasParam(key) {
       if (key) {
         return this._parameters.hasOwnProperty(key.toLowerCase()) && true || false;
       }
     }
   }, {
     key: "deleteParam",
     value: function deleteParam(parameter) {
       parameter = parameter.toLowerCase();
 
       if (this._parameters.hasOwnProperty(parameter)) {
         var value = this._parameters[parameter];
         delete this._parameters[parameter];
         return value;
       }
     }
   }, {
     key: "clearParams",
     value: function clearParams() {
       this._parameters = {};
     }
   }, {
     key: "clone",
     value: function clone() {
       return new NameAddrHeader(this._uri.clone(), this._display_name, JSON.parse(JSON.stringify(this._parameters)));
     }
   }, {
     key: "_quote",
     value: function _quote(str) {
       return str.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
     }
   }, {
     key: "toString",
     value: function toString() {
       var body = this._display_name ? "\"".concat(this._quote(this._display_name), "\" ") : '';
       body += "<".concat(this._uri.toString(), ">");
 
       for (var parameter in this._parameters) {
         if (Object.prototype.hasOwnProperty.call(this._parameters, parameter)) {
           body += ";".concat(parameter);
 
           if (this._parameters[parameter] !== null) {
             body += "=".concat(this._parameters[parameter]);
           }
         }
       }
 
       return body;
     }
   }, {
     key: "uri",
     get: function get() {
       return this._uri;
     }
   }, {
     key: "display_name",
     get: function get() {
       return this._display_name;
     },
     set: function set(value) {
       this._display_name = value === 0 ? '0' : value;
     }
   }]);
 
   return NameAddrHeader;
 }();
 },{"./Grammar":7,"./URI":25}],11:[function(require,module,exports){
 "use strict";
 
 function _createForOfIteratorHelper(o, allowArrayLike) { var it; if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
 
 function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
 
 function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
 
 var Grammar = require('./Grammar');
 
 var SIPMessage = require('./SIPMessage');
 
 var debugerror = require('debug')('JsSIP:ERROR:Parser');
 
 debugerror.log = console.warn.bind(console);
 /**
  * Parse SIP Message
  */
 
 exports.parseMessage = function (data, ua) {
   var message;
   var bodyStart;
   var headerEnd = data.indexOf('\r\n');
 
   if (headerEnd === -1) {
     debugerror('parseMessage() | no CRLF found, not a SIP message');
     return;
   } // Parse first line. Check if it is a Request or a Reply.
 
 
   var firstLine = data.substring(0, headerEnd);
   var parsed = Grammar.parse(firstLine, 'Request_Response');
 
   if (parsed === -1) {
     debugerror("parseMessage() | error parsing first line of SIP message: \"".concat(firstLine, "\""));
     return;
   } else if (!parsed.status_code) {
     message = new SIPMessage.IncomingRequest(ua);
     message.method = parsed.method;
     message.ruri = parsed.uri;
   } else {
     message = new SIPMessage.IncomingResponse();
     message.status_code = parsed.status_code;
     message.reason_phrase = parsed.reason_phrase;
   }
 
   message.data = data;
   var headerStart = headerEnd + 2;
   /* Loop over every line in data. Detect the end of each header and parse
   * it or simply add to the headers collection.
   */
 
   while (true) {
     headerEnd = getHeader(data, headerStart); // The SIP message has normally finished.
 
     if (headerEnd === -2) {
       bodyStart = headerStart + 2;
       break;
     } // Data.indexOf returned -1 due to a malformed message.
     else if (headerEnd === -1) {
         debugerror('parseMessage() | malformed message');
         return;
       }
 
     parsed = parseHeader(message, data, headerStart, headerEnd);
 
     if (parsed !== true) {
       debugerror('parseMessage() |', parsed.error);
       return;
     }
 
     headerStart = headerEnd + 2;
   }
   /* RFC3261 18.3.
    * If there are additional bytes in the transport packet
    * beyond the end of the body, they MUST be discarded.
    */
 
 
   if (message.hasHeader('content-length')) {
     var contentLength = message.getHeader('content-length');
     message.body = data.substr(bodyStart, contentLength);
   } else {
     message.body = data.substring(bodyStart);
   }
 
   return message;
 };
 /**
  * Extract and parse every header of a SIP message.
  */
 
 
 function getHeader(data, headerStart) {
   // 'start' position of the header.
   var start = headerStart; // 'end' position of the header.
 
   var end = 0; // 'partial end' position of the header.
 
   var partialEnd = 0; // End of message.
 
   if (data.substring(start, start + 2).match(/(^\r\n)/)) {
     return -2;
   }
 
   while (end === 0) {
     // Partial End of Header.
     partialEnd = data.indexOf('\r\n', start); // 'indexOf' returns -1 if the value to be found never occurs.
 
     if (partialEnd === -1) {
       return partialEnd;
     }
 
     if (!data.substring(partialEnd + 2, partialEnd + 4).match(/(^\r\n)/) && data.charAt(partialEnd + 2).match(/(^\s+)/)) {
       // Not the end of the message. Continue from the next position.
       start = partialEnd + 2;
     } else {
       end = partialEnd;
     }
   }
 
   return end;
 }
 
 function parseHeader(message, data, headerStart, headerEnd) {
   var parsed;
   var hcolonIndex = data.indexOf(':', headerStart);
   var headerName = data.substring(headerStart, hcolonIndex).trim();
   var headerValue = data.substring(hcolonIndex + 1, headerEnd).trim(); // If header-field is well-known, parse it.
 
   switch (headerName.toLowerCase()) {
     case 'via':
     case 'v':
       message.addHeader('via', headerValue);
 
       if (message.getHeaders('via').length === 1) {
         parsed = message.parseHeader('Via');
 
         if (parsed) {
           message.via = parsed;
           message.via_branch = parsed.branch;
         }
       } else {
         parsed = 0;
       }
 
       break;
 
     case 'from':
     case 'f':
       message.setHeader('from', headerValue);
       parsed = message.parseHeader('from');
 
       if (parsed) {
         message.from = parsed;
         message.from_tag = parsed.getParam('tag');
       }
 
       break;
 
     case 'to':
     case 't':
       message.setHeader('to', headerValue);
       parsed = message.parseHeader('to');
 
       if (parsed) {
         message.to = parsed;
         message.to_tag = parsed.getParam('tag');
       }
 
       break;
 
     case 'record-route':
       parsed = Grammar.parse(headerValue, 'Record_Route');
 
       if (parsed === -1) {
         parsed = undefined;
       } else {
         var _iterator = _createForOfIteratorHelper(parsed),
             _step;
 
         try {
           for (_iterator.s(); !(_step = _iterator.n()).done;) {
             var header = _step.value;
             message.addHeader('record-route', headerValue.substring(header.possition, header.offset));
             message.headers['Record-Route'][message.getHeaders('record-route').length - 1].parsed = header.parsed;
           }
         } catch (err) {
           _iterator.e(err);
         } finally {
           _iterator.f();
         }
       }
 
       break;
 
     case 'call-id':
     case 'i':
       message.setHeader('call-id', headerValue);
       parsed = message.parseHeader('call-id');
 
       if (parsed) {
         message.call_id = headerValue;
       }
 
       break;
 
     case 'contact':
     case 'm':
       parsed = Grammar.parse(headerValue, 'Contact');
 
       if (parsed === -1) {
         parsed = undefined;
       } else {
         var _iterator2 = _createForOfIteratorHelper(parsed),
             _step2;
 
         try {
           for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
             var _header = _step2.value;
             message.addHeader('contact', headerValue.substring(_header.possition, _header.offset));
             message.headers.Contact[message.getHeaders('contact').length - 1].parsed = _header.parsed;
           }
         } catch (err) {
           _iterator2.e(err);
         } finally {
           _iterator2.f();
         }
       }
 
       break;
 
     case 'content-length':
     case 'l':
       message.setHeader('content-length', headerValue);
       parsed = message.parseHeader('content-length');
       break;
 
     case 'content-type':
     case 'c':
       message.setHeader('content-type', headerValue);
       parsed = message.parseHeader('content-type');
       break;
 
     case 'cseq':
       message.setHeader('cseq', headerValue);
       parsed = message.parseHeader('cseq');
 
       if (parsed) {
         message.cseq = parsed.value;
       }
 
       if (message instanceof SIPMessage.IncomingResponse) {
         message.method = parsed.method;
       }
 
       break;
 
     case 'max-forwards':
       message.setHeader('max-forwards', headerValue);
       parsed = message.parseHeader('max-forwards');
       break;
 
     case 'www-authenticate':
       message.setHeader('www-authenticate', headerValue);
       parsed = message.parseHeader('www-authenticate');
       break;
 
     case 'proxy-authenticate':
       message.setHeader('proxy-authenticate', headerValue);
       parsed = message.parseHeader('proxy-authenticate');
       break;
 
     case 'session-expires':
     case 'x':
       message.setHeader('session-expires', headerValue);
       parsed = message.parseHeader('session-expires');
 
       if (parsed) {
         message.session_expires = parsed.expires;
         message.session_expires_refresher = parsed.refresher;
       }
 
       break;
 
     case 'refer-to':
     case 'r':
       message.setHeader('refer-to', headerValue);
       parsed = message.parseHeader('refer-to');
 
       if (parsed) {
         message.refer_to = parsed;
       }
 
       break;
 
     case 'replaces':
       message.setHeader('replaces', headerValue);
       parsed = message.parseHeader('replaces');
 
       if (parsed) {
         message.replaces = parsed;
       }
 
       break;
 
     case 'event':
     case 'o':
       message.setHeader('event', headerValue);
       parsed = message.parseHeader('event');
 
       if (parsed) {
         message.event = parsed;
       }
 
       break;
 
     default:
       // Do not parse this header.
       message.addHeader(headerName, headerValue);
       parsed = 0;
   }
 
   if (parsed === undefined) {
     return {
       error: "error parsing header \"".concat(headerName, "\"")
     };
   } else {
     return true;
   }
 }
 },{"./Grammar":7,"./SIPMessage":19,"debug":30}],12:[function(require,module,exports){
 "use strict";
 
 function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
 
 function _createForOfIteratorHelper(o, allowArrayLike) { var it; if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e2) { throw _e2; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e3) { didErr = true; err = _e3; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
 
 function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
 
 function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
 
 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
 function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
 
 function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
 
 function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
 
 function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
 
 function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
 
 function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
 
 function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
 
 function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }
 
 function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
 
 /* globals RTCPeerConnection: false, RTCSessionDescription: false */
 var EventEmitter = require('events').EventEmitter;
 
 var sdp_transform = require('sdp-transform');
 
 var JsSIP_C = require('./Constants');
 
 var Exceptions = require('./Exceptions');
 
 var Transactions = require('./Transactions');
 
 var Utils = require('./Utils');
 
 var Timers = require('./Timers');
 
 var SIPMessage = require('./SIPMessage');
 
 var Dialog = require('./Dialog');
 
 var RequestSender = require('./RequestSender');
 
 var RTCSession_DTMF = require('./RTCSession/DTMF');
 
 var RTCSession_Info = require('./RTCSession/Info');
 
 var RTCSession_ReferNotifier = require('./RTCSession/ReferNotifier');
 
 var RTCSession_ReferSubscriber = require('./RTCSession/ReferSubscriber');
 
 var URI = require('./URI');
 
 var debug = require('debug')('JsSIP:RTCSession');
 
 var debugerror = require('debug')('JsSIP:ERROR:RTCSession');
 
 debugerror.log = console.warn.bind(console);
 var C = {
   // RTCSession states.
   STATUS_NULL: 0,
   STATUS_INVITE_SENT: 1,
   STATUS_1XX_RECEIVED: 2,
   STATUS_INVITE_RECEIVED: 3,
   STATUS_WAITING_FOR_ANSWER: 4,
   STATUS_ANSWERED: 5,
   STATUS_WAITING_FOR_ACK: 6,
   STATUS_CANCELED: 7,
   STATUS_TERMINATED: 8,
   STATUS_CONFIRMED: 9
 };
 /**
  * Local variables.
  */
 
 var holdMediaTypes = ['audio', 'video'];
 
 module.exports = /*#__PURE__*/function (_EventEmitter) {
   _inherits(RTCSession, _EventEmitter);
 
   var _super = _createSuper(RTCSession);
 
   _createClass(RTCSession, null, [{
     key: "C",
 
     /**
      * Expose C object.
      */
     get: function get() {
       return C;
     }
   }]);
 
   function RTCSession(ua) {
     var _this;
 
     _classCallCheck(this, RTCSession);
 
     debug('new');
     _this = _super.call(this);
     _this._id = null;
     _this._ua = ua;
     _this._status = C.STATUS_NULL;
     _this._dialog = null;
     _this._earlyDialogs = {};
     _this._contact = null;
     _this._from_tag = null;
     _this._to_tag = null; // The RTCPeerConnection instance (public attribute).
 
     _this._connection = null; // Prevent races on serial PeerConnction operations.
 
     _this._connectionPromiseQueue = Promise.resolve(); // Incoming/Outgoing request being currently processed.
 
     _this._request = null; // Cancel state for initial outgoing request.
 
     _this._is_canceled = false;
     _this._cancel_reason = ''; // RTCSession confirmation flag.
 
     _this._is_confirmed = false; // Is late SDP being negotiated.
 
     _this._late_sdp = false; // Default rtcOfferConstraints and rtcAnswerConstrainsts (passed in connect() or answer()).
 
     _this._rtcOfferConstraints = null;
     _this._rtcAnswerConstraints = null; // Local MediaStream.
 
     _this._localMediaStream = null;
     _this._localMediaStreamLocallyGenerated = false; // Flag to indicate PeerConnection ready for new actions.
 
     _this._rtcReady = true; // SIP Timers.
 
     _this._timers = {
       ackTimer: null,
       expiresTimer: null,
       invite2xxTimer: null,
       userNoAnswerTimer: null
     }; // Session info.
 
     _this._direction = null;
     _this._local_identity = null;
     _this._remote_identity = null;
     _this._start_time = null;
     _this._end_time = null;
     _this._tones = null; // Mute/Hold state.
 
     _this._audioMuted = false;
     _this._videoMuted = false;
     _this._localHold = false;
     _this._remoteHold = false; // Session Timers (RFC 4028).
 
     _this._sessionTimers = {
       enabled: _this._ua.configuration.session_timers,
       refreshMethod: _this._ua.configuration.session_timers_refresh_method,
       defaultExpires: JsSIP_C.SESSION_EXPIRES,
       currentExpires: null,
       running: false,
       refresher: false,
       timer: null // A setTimeout.
 
     }; // Map of ReferSubscriber instances indexed by the REFER's CSeq number.
 
     _this._referSubscribers = {}; // Custom session empty object for high level use.
 
     _this._data = {};
     return _this;
   }
   /**
    * User API
    */
   // Expose RTCSession constants as a property of the RTCSession instance.
 
 
   _createClass(RTCSession, [{
     key: "isInProgress",
     value: function isInProgress() {
       switch (this._status) {
         case C.STATUS_NULL:
         case C.STATUS_INVITE_SENT:
         case C.STATUS_1XX_RECEIVED:
         case C.STATUS_INVITE_RECEIVED:
         case C.STATUS_WAITING_FOR_ANSWER:
           return true;
 
         default:
           return false;
       }
     }
   }, {
     key: "isEstablished",
     value: function isEstablished() {
       switch (this._status) {
         case C.STATUS_ANSWERED:
         case C.STATUS_WAITING_FOR_ACK:
         case C.STATUS_CONFIRMED:
           return true;
 
         default:
           return false;
       }
     }
   }, {
     key: "isEnded",
     value: function isEnded() {
       switch (this._status) {
         case C.STATUS_CANCELED:
         case C.STATUS_TERMINATED:
           return true;
 
         default:
           return false;
       }
     }
   }, {
     key: "isMuted",
     value: function isMuted() {
       return {
         audio: this._audioMuted,
         video: this._videoMuted
       };
     }
   }, {
     key: "isOnHold",
     value: function isOnHold() {
       return {
         local: this._localHold,
         remote: this._remoteHold
       };
     }
   }, {
     key: "connect",
     value: function connect(target) {
       var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
       var initCallback = arguments.length > 2 ? arguments[2] : undefined;
       debug('connect()');
       var originalTarget = target;
       var eventHandlers = Utils.cloneObject(options.eventHandlers);
       var extraHeaders = Utils.cloneArray(options.extraHeaders);
       var mediaConstraints = Utils.cloneObject(options.mediaConstraints, {
         audio: true,
         video: true
       });
       var mediaStream = options.mediaStream || null;
       var pcConfig = Utils.cloneObject(options.pcConfig, {
         iceServers: []
       });
       var rtcConstraints = options.rtcConstraints || null;
       var rtcOfferConstraints = options.rtcOfferConstraints || null;
       this._rtcOfferConstraints = rtcOfferConstraints;
       this._rtcAnswerConstraints = options.rtcAnswerConstraints || null;
       this._data = options.data || this._data; // Check target.
 
       if (target === undefined) {
         throw new TypeError('Not enough arguments');
       } // Check Session Status.
 
 
       if (this._status !== C.STATUS_NULL) {
         throw new Exceptions.InvalidStateError(this._status);
       } // Check WebRTC support.
 
 
       if (!window.RTCPeerConnection) {
         throw new Exceptions.NotSupportedError('WebRTC not supported');
       } // Check target validity.
 
 
       target = this._ua.normalizeTarget(target);
 
       if (!target) {
         throw new TypeError("Invalid target: ".concat(originalTarget));
       } // Session Timers.
 
 
       if (this._sessionTimers.enabled) {
         if (Utils.isDecimal(options.sessionTimersExpires)) {
           if (options.sessionTimersExpires >= JsSIP_C.MIN_SESSION_EXPIRES) {
             this._sessionTimers.defaultExpires = options.sessionTimersExpires;
           } else {
             this._sessionTimers.defaultExpires = JsSIP_C.SESSION_EXPIRES;
           }
         }
       } // Set event handlers.
 
 
       for (var event in eventHandlers) {
         if (Object.prototype.hasOwnProperty.call(eventHandlers, event)) {
           this.on(event, eventHandlers[event]);
         }
       } // Session parameter initialization.
 
 
       this._from_tag = Utils.newTag(); // Set anonymous property.
 
       var anonymous = options.anonymous || false;
       var requestParams = {
         from_tag: this._from_tag
       };
       this._contact = this._ua.contact.toString({
         anonymous: anonymous,
         outbound: true
       });
 
       if (anonymous) {
         requestParams.from_display_name = 'Anonymous';
         requestParams.from_uri = new URI('sip', 'anonymous', 'anonymous.invalid');
         extraHeaders.push("P-Preferred-Identity: ".concat(this._ua.configuration.uri.toString()));
         extraHeaders.push('Privacy: id');
       } else if (options.fromUserName) {
         requestParams.from_uri = new URI('sip', options.fromUserName, this._ua.configuration.uri.host);
         extraHeaders.push("P-Preferred-Identity: ".concat(this._ua.configuration.uri.toString()));
       }
 
       if (options.fromDisplayName) {
         requestParams.from_display_name = options.fromDisplayName;
       }
 
       extraHeaders.push("Contact: ".concat(this._contact));
       extraHeaders.push('Content-Type: application/sdp');
 
       if (this._sessionTimers.enabled) {
         extraHeaders.push("Session-Expires: ".concat(this._sessionTimers.defaultExpires).concat(this._ua.configuration.session_timers_force_refresher ? ';refresher=uac' : ''));
       }
 
       this._request = new SIPMessage.InitialOutgoingInviteRequest(target, this._ua, requestParams, extraHeaders);
       this._id = this._request.call_id + this._from_tag; // Create a new RTCPeerConnection instance.
 
       this._createRTCConnection(pcConfig, rtcConstraints); // Set internal properties.
 
 
       this._direction = 'outgoing';
       this._local_identity = this._request.from;
       this._remote_identity = this._request.to; // User explicitly provided a newRTCSession callback for this session.
 
       if (initCallback) {
         initCallback(this);
       }
 
       this._newRTCSession('local', this._request);
 
       this._sendInitialRequest(mediaConstraints, rtcOfferConstraints, mediaStream);
     }
   }, {
     key: "init_incoming",
     value: function init_incoming(request, initCallback) {
       var _this2 = this;
 
       debug('init_incoming()');
       var expires;
       var contentType = request.hasHeader('Content-Type') ? request.getHeader('Content-Type').toLowerCase() : undefined; // Check body and content type.
 
       if (request.body && contentType !== 'application/sdp') {
         request.reply(415);
         return;
       } // Session parameter initialization.
 
 
       this._status = C.STATUS_INVITE_RECEIVED;
       this._from_tag = request.from_tag;
       this._id = request.call_id + this._from_tag;
       this._request = request;
       this._contact = this._ua.contact.toString(); // Get the Expires header value if exists.
 
       if (request.hasHeader('expires')) {
         expires = request.getHeader('expires') * 1000;
       }
       /* Set the to_tag before
        * replying a response code that will create a dialog.
        */
 
 
       request.to_tag = Utils.newTag(); // An error on dialog creation will fire 'failed' event.
 
       if (!this._createDialog(request, 'UAS', true)) {
         request.reply(500, 'Missing Contact header field');
         return;
       }
 
       if (request.body) {
         this._late_sdp = false;
       } else {
         this._late_sdp = true;
       }
 
       this._status = C.STATUS_WAITING_FOR_ANSWER; // Set userNoAnswerTimer.
 
       this._timers.userNoAnswerTimer = setTimeout(function () {
         request.reply(408);
 
         _this2._failed('local', null, JsSIP_C.causes.NO_ANSWER);
       }, this._ua.configuration.no_answer_timeout);
       /* Set expiresTimer
        * RFC3261 13.3.1
        */
 
       if (expires) {
         this._timers.expiresTimer = setTimeout(function () {
           if (_this2._status === C.STATUS_WAITING_FOR_ANSWER) {
             request.reply(487);
 
             _this2._failed('system', null, JsSIP_C.causes.EXPIRES);
           }
         }, expires);
       } // Set internal properties.
 
 
       this._direction = 'incoming';
       this._local_identity = request.to;
       this._remote_identity = request.from; // A init callback was specifically defined.
 
       if (initCallback) {
         initCallback(this);
       } // Fire 'newRTCSession' event.
 
 
       this._newRTCSession('remote', request); // The user may have rejected the call in the 'newRTCSession' event.
 
 
       if (this._status === C.STATUS_TERMINATED) {
         return;
       } // Reply 180.
 
 
       request.reply(180, null, ["Contact: ".concat(this._contact)]); // Fire 'progress' event.
       // TODO: Document that 'response' field in 'progress' event is null for incoming calls.
 
       this._progress('local', null);
     }
     /**
      * Answer the call.
      */
 
   }, {
     key: "answer",
     value: function answer() {
       var _this3 = this;
 
       var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
       debug('answer()');
       var request = this._request;
       var extraHeaders = Utils.cloneArray(options.extraHeaders);
       var mediaConstraints = Utils.cloneObject(options.mediaConstraints);
       var mediaStream = options.mediaStream || null;
       var pcConfig = Utils.cloneObject(options.pcConfig, {
         iceServers: []
       });
       var rtcConstraints = options.rtcConstraints || null;
       var rtcAnswerConstraints = options.rtcAnswerConstraints || null;
       var rtcOfferConstraints = Utils.cloneObject(options.rtcOfferConstraints);
       var tracks;
       var peerHasAudioLine = false;
       var peerHasVideoLine = false;
       var peerOffersFullAudio = false;
       var peerOffersFullVideo = false;
       this._rtcAnswerConstraints = rtcAnswerConstraints;
       this._rtcOfferConstraints = options.rtcOfferConstraints || null;
       this._data = options.data || this._data; // Check Session Direction and Status.
 
       if (this._direction !== 'incoming') {
         throw new Exceptions.NotSupportedError('"answer" not supported for outgoing RTCSession');
       } // Check Session status.
 
 
       if (this._status !== C.STATUS_WAITING_FOR_ANSWER) {
         throw new Exceptions.InvalidStateError(this._status);
       } // Session Timers.
 
 
       if (this._sessionTimers.enabled) {
         if (Utils.isDecimal(options.sessionTimersExpires)) {
           if (options.sessionTimersExpires >= JsSIP_C.MIN_SESSION_EXPIRES) {
             this._sessionTimers.defaultExpires = options.sessionTimersExpires;
           } else {
             this._sessionTimers.defaultExpires = JsSIP_C.SESSION_EXPIRES;
           }
         }
       }
 
       this._status = C.STATUS_ANSWERED; // An error on dialog creation will fire 'failed' event.
 
       if (!this._createDialog(request, 'UAS')) {
         request.reply(500, 'Error creating dialog');
         return;
       }
 
       clearTimeout(this._timers.userNoAnswerTimer);
       extraHeaders.unshift("Contact: ".concat(this._contact)); // Determine incoming media from incoming SDP offer (if any).
 
       var sdp = request.parseSDP(); // Make sure sdp.media is an array, not the case if there is only one media.
 
       if (!Array.isArray(sdp.media)) {
         sdp.media = [sdp.media];
       } // Go through all medias in SDP to find offered capabilities to answer with.
 
 
       var _iterator = _createForOfIteratorHelper(sdp.media),
           _step;
 
       try {
         for (_iterator.s(); !(_step = _iterator.n()).done;) {
           var m = _step.value;
 
           if (m.type === 'audio') {
             peerHasAudioLine = true;
 
             if (!m.direction || m.direction === 'sendrecv') {
               peerOffersFullAudio = true;
             }
           }
 
           if (m.type === 'video') {
             peerHasVideoLine = true;
 
             if (!m.direction || m.direction === 'sendrecv') {
               peerOffersFullVideo = true;
             }
           }
         } // Remove audio from mediaStream if suggested by mediaConstraints.
 
       } catch (err) {
         _iterator.e(err);
       } finally {
         _iterator.f();
       }
 
       if (mediaStream && mediaConstraints.audio === false) {
         tracks = mediaStream.getAudioTracks();
 
         var _iterator2 = _createForOfIteratorHelper(tracks),
             _step2;
 
         try {
           for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
             var track = _step2.value;
             mediaStream.removeTrack(track);
           }
         } catch (err) {
           _iterator2.e(err);
         } finally {
           _iterator2.f();
         }
       } // Remove video from mediaStream if suggested by mediaConstraints.
 
 
       if (mediaStream && mediaConstraints.video === false) {
         tracks = mediaStream.getVideoTracks();
 
         var _iterator3 = _createForOfIteratorHelper(tracks),
             _step3;
 
         try {
           for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
             var _track = _step3.value;
             mediaStream.removeTrack(_track);
           }
         } catch (err) {
           _iterator3.e(err);
         } finally {
           _iterator3.f();
         }
       } // Set audio constraints based on incoming stream if not supplied.
 
 
       if (!mediaStream && mediaConstraints.audio === undefined) {
         mediaConstraints.audio = peerOffersFullAudio;
       } // Set video constraints based on incoming stream if not supplied.
 
 
       if (!mediaStream && mediaConstraints.video === undefined) {
         mediaConstraints.video = peerOffersFullVideo;
       } // Don't ask for audio if the incoming offer has no audio section.
 
 
       if (!mediaStream && !peerHasAudioLine && !rtcOfferConstraints.offerToReceiveAudio) {
         mediaConstraints.audio = false;
       } // Don't ask for video if the incoming offer has no video section.
 
 
       if (!mediaStream && !peerHasVideoLine && !rtcOfferConstraints.offerToReceiveVideo) {
         mediaConstraints.video = false;
       } // Create a new RTCPeerConnection instance.
       // TODO: This may throw an error, should react.
 
 
       this._createRTCConnection(pcConfig, rtcConstraints);
 
       Promise.resolve() // Handle local MediaStream.
       .then(function () {
         // A local MediaStream is given, use it.
         if (mediaStream) {
           return mediaStream;
         } // Audio and/or video requested, prompt getUserMedia.
         else if (mediaConstraints.audio || mediaConstraints.video) {
             _this3._localMediaStreamLocallyGenerated = true;
             return navigator.mediaDevices.getUserMedia(mediaConstraints)["catch"](function (error) {
               if (_this3._status === C.STATUS_TERMINATED) {
                 throw new Error('terminated');
               }
 
               request.reply(480);
 
               _this3._failed('local', null, JsSIP_C.causes.USER_DENIED_MEDIA_ACCESS);
 
               debugerror('emit "getusermediafailed" [error:%o]', error);
 
               _this3.emit('getusermediafailed', error);
 
               throw new Error('getUserMedia() failed');
             });
           }
       }) // Attach MediaStream to RTCPeerconnection.
       .then(function (stream) {
         if (_this3._status === C.STATUS_TERMINATED) {
           throw new Error('terminated');
         }
 
         _this3._localMediaStream = stream;
 
         if (stream) {
           stream.getTracks().forEach(function (track) {
             _this3._connection.addTrack(track, stream);
           });
         }
       }) // Set remote description.
       .then(function () {
         if (_this3._late_sdp) {
           return;
         }
 
         var e = {
           originator: 'remote',
           type: 'offer',
           sdp: request.body
         };
         debug('emit "sdp"');
 
         _this3.emit('sdp', e);
 
         var offer = new RTCSessionDescription({
           type: 'offer',
           sdp: e.sdp
         });
         _this3._connectionPromiseQueue = _this3._connectionPromiseQueue.then(function () {
           return _this3._connection.setRemoteDescription(offer);
         })["catch"](function (error) {
           request.reply(488);
 
           _this3._failed('system', null, JsSIP_C.causes.WEBRTC_ERROR);
 
           debugerror('emit "peerconnection:setremotedescriptionfailed" [error:%o]', error);
 
           _this3.emit('peerconnection:setremotedescriptionfailed', error);
 
           throw new Error('peerconnection.setRemoteDescription() failed');
         });
         return _this3._connectionPromiseQueue;
       }) // Create local description.
       .then(function () {
         if (_this3._status === C.STATUS_TERMINATED) {
           throw new Error('terminated');
         } // TODO: Is this event already useful?
 
 
         _this3._connecting(request);
 
         if (!_this3._late_sdp) {
           return _this3._createLocalDescription('answer', rtcAnswerConstraints)["catch"](function () {
             request.reply(500);
             throw new Error('_createLocalDescription() failed');
           });
         } else {
           return _this3._createLocalDescription('offer', _this3._rtcOfferConstraints)["catch"](function () {
             request.reply(500);
             throw new Error('_createLocalDescription() failed');
           });
         }
       }) // Send reply.
       .then(function (desc) {
         if (_this3._status === C.STATUS_TERMINATED) {
           throw new Error('terminated');
         }
 
         _this3._handleSessionTimersInIncomingRequest(request, extraHeaders);
 
         request.reply(200, null, extraHeaders, desc, function () {
           _this3._status = C.STATUS_WAITING_FOR_ACK;
 
           _this3._setInvite2xxTimer(request, desc);
 
           _this3._setACKTimer();
 
           _this3._accepted('local');
         }, function () {
           _this3._failed('system', null, JsSIP_C.causes.CONNECTION_ERROR);
         });
       })["catch"](function (error) {
         if (_this3._status === C.STATUS_TERMINATED) {
           return;
         }
 
         debugerror(error);
       });
     }
     /**
      * Terminate the call.
      */
 
   }, {
     key: "terminate",
     value: function terminate() {
       var _this4 = this;
 
       var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
       debug('terminate()');
       var cause = options.cause || JsSIP_C.causes.BYE;
       var extraHeaders = Utils.cloneArray(options.extraHeaders);
       var body = options.body;
       var cancel_reason;
       var status_code = options.status_code;
       var reason_phrase = options.reason_phrase; // Check Session Status.
 
       if (this._status === C.STATUS_TERMINATED) {
         throw new Exceptions.InvalidStateError(this._status);
       }
 
       switch (this._status) {
         // - UAC -
         case C.STATUS_NULL:
         case C.STATUS_INVITE_SENT:
         case C.STATUS_1XX_RECEIVED:
           debug('canceling session');
 
           if (status_code && (status_code < 200 || status_code >= 700)) {
             throw new TypeError("Invalid status_code: ".concat(status_code));
           } else if (status_code) {
             reason_phrase = reason_phrase || JsSIP_C.REASON_PHRASE[status_code] || '';
             cancel_reason = "SIP ;cause=".concat(status_code, " ;text=\"").concat(reason_phrase, "\"");
           } // Check Session Status.
 
 
           if (this._status === C.STATUS_NULL || this._status === C.STATUS_INVITE_SENT) {
             this._is_canceled = true;
             this._cancel_reason = cancel_reason;
           } else if (this._status === C.STATUS_1XX_RECEIVED) {
             this._request.cancel(cancel_reason);
           }
 
           this._status = C.STATUS_CANCELED;
 
           this._failed('local', null, JsSIP_C.causes.CANCELED);
 
           break;
         // - UAS -
 
         case C.STATUS_WAITING_FOR_ANSWER:
         case C.STATUS_ANSWERED:
           debug('rejecting session');
           status_code = status_code || 480;
 
           if (status_code < 300 || status_code >= 700) {
             throw new TypeError("Invalid status_code: ".concat(status_code));
           }
 
           this._request.reply(status_code, reason_phrase, extraHeaders, body);
 
           this._failed('local', null, JsSIP_C.causes.REJECTED);
 
           break;
 
         case C.STATUS_WAITING_FOR_ACK:
         case C.STATUS_CONFIRMED:
           debug('terminating session');
           reason_phrase = options.reason_phrase || JsSIP_C.REASON_PHRASE[status_code] || '';
 
           if (status_code && (status_code < 200 || status_code >= 700)) {
             throw new TypeError("Invalid status_code: ".concat(status_code));
           } else if (status_code) {
             extraHeaders.push("Reason: SIP ;cause=".concat(status_code, "; text=\"").concat(reason_phrase, "\""));
           }
           /* RFC 3261 section 15 (Terminating a session):
             *
             * "...the callee's UA MUST NOT send a BYE on a confirmed dialog
             * until it has received an ACK for its 2xx response or until the server
             * transaction times out."
             */
 
 
           if (this._status === C.STATUS_WAITING_FOR_ACK && this._direction === 'incoming' && this._request.server_transaction.state !== Transactions.C.STATUS_TERMINATED) {
             // Save the dialog for later restoration.
             var dialog = this._dialog; // Send the BYE as soon as the ACK is received...
 
             this.receiveRequest = function (_ref) {
               var method = _ref.method;
 
               if (method === JsSIP_C.ACK) {
                 _this4.sendRequest(JsSIP_C.BYE, {
                   extraHeaders: extraHeaders,
                   body: body
                 });
 
                 dialog.terminate();
               }
             }; // .., or when the INVITE transaction times out
 
 
             this._request.server_transaction.on('stateChanged', function () {
               if (_this4._request.server_transaction.state === Transactions.C.STATUS_TERMINATED) {
                 _this4.sendRequest(JsSIP_C.BYE, {
                   extraHeaders: extraHeaders,
                   body: body
                 });
 
                 dialog.terminate();
               }
             });
 
             this._ended('local', null, cause); // Restore the dialog into 'this' in order to be able to send the in-dialog BYE :-).
 
 
             this._dialog = dialog; // Restore the dialog into 'ua' so the ACK can reach 'this' session.
 
             this._ua.newDialog(dialog);
           } else {
             this.sendRequest(JsSIP_C.BYE, {
               extraHeaders: extraHeaders,
               body: body
             });
 
             this._ended('local', null, cause);
           }
 
       }
     }
   }, {
     key: "sendDTMF",
     value: function sendDTMF(tones) {
       var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
       debug('sendDTMF() | tones: %s', tones);
       var position = 0;
       var duration = options.duration || null;
       var interToneGap = options.interToneGap || null;
       var transportType = options.transportType || JsSIP_C.DTMF_TRANSPORT.INFO;
 
       if (tones === undefined) {
         throw new TypeError('Not enough arguments');
       } // Check Session Status.
 
 
       if (this._status !== C.STATUS_CONFIRMED && this._status !== C.STATUS_WAITING_FOR_ACK) {
         throw new Exceptions.InvalidStateError(this._status);
       } // Check Transport type.
 
 
       if (transportType !== JsSIP_C.DTMF_TRANSPORT.INFO && transportType !== JsSIP_C.DTMF_TRANSPORT.RFC2833) {
         throw new TypeError("invalid transportType: ".concat(transportType));
       } // Convert to string.
 
 
       if (typeof tones === 'number') {
         tones = tones.toString();
       } // Check tones.
 
 
       if (!tones || typeof tones !== 'string' || !tones.match(/^[0-9A-DR#*,]+$/i)) {
         throw new TypeError("Invalid tones: ".concat(tones));
       } // Check duration.
 
 
       if (duration && !Utils.isDecimal(duration)) {
         throw new TypeError("Invalid tone duration: ".concat(duration));
       } else if (!duration) {
         duration = RTCSession_DTMF.C.DEFAULT_DURATION;
       } else if (duration < RTCSession_DTMF.C.MIN_DURATION) {
         debug("\"duration\" value is lower than the minimum allowed, setting it to ".concat(RTCSession_DTMF.C.MIN_DURATION, " milliseconds"));
         duration = RTCSession_DTMF.C.MIN_DURATION;
       } else if (duration > RTCSession_DTMF.C.MAX_DURATION) {
         debug("\"duration\" value is greater than the maximum allowed, setting it to ".concat(RTCSession_DTMF.C.MAX_DURATION, " milliseconds"));
         duration = RTCSession_DTMF.C.MAX_DURATION;
       } else {
         duration = Math.abs(duration);
       }
 
       options.duration = duration; // Check interToneGap.
 
       if (interToneGap && !Utils.isDecimal(interToneGap)) {
         throw new TypeError("Invalid interToneGap: ".concat(interToneGap));
       } else if (!interToneGap) {
         interToneGap = RTCSession_DTMF.C.DEFAULT_INTER_TONE_GAP;
       } else if (interToneGap < RTCSession_DTMF.C.MIN_INTER_TONE_GAP) {
         debug("\"interToneGap\" value is lower than the minimum allowed, setting it to ".concat(RTCSession_DTMF.C.MIN_INTER_TONE_GAP, " milliseconds"));
         interToneGap = RTCSession_DTMF.C.MIN_INTER_TONE_GAP;
       } else {
         interToneGap = Math.abs(interToneGap);
       } // RFC2833. Let RTCDTMFSender enqueue the DTMFs.
 
 
       if (transportType === JsSIP_C.DTMF_TRANSPORT.RFC2833) {
         // Send DTMF in current audio RTP stream.
         var sender = this._getDTMFRTPSender();
 
         if (sender) {
           // Add remaining buffered tones.
           tones = sender.toneBuffer + tones; // Insert tones.
 
           sender.insertDTMF(tones, duration, interToneGap);
         }
 
         return;
       }
 
       if (this._tones) {
         // Tones are already queued, just add to the queue.
         this._tones += tones;
         return;
       }
 
       this._tones = tones; // Send the first tone.
 
       _sendDTMF.call(this);
 
       function _sendDTMF() {
         var _this5 = this;
 
         var timeout;
 
         if (this._status === C.STATUS_TERMINATED || !this._tones || position >= this._tones.length) {
           // Stop sending DTMF.
           this._tones = null;
           return;
         }
 
         var tone = this._tones[position];
         position += 1;
 
         if (tone === ',') {
           timeout = 2000;
         } else {
           // Send DTMF via SIP INFO messages.
           var dtmf = new RTCSession_DTMF(this);
           options.eventHandlers = {
             onFailed: function onFailed() {
               _this5._tones = null;
             }
           };
           dtmf.send(tone, options);
           timeout = duration + interToneGap;
         } // Set timeout for the next tone.
 
 
         setTimeout(_sendDTMF.bind(this), timeout);
       }
     }
   }, {
     key: "sendInfo",
     value: function sendInfo(contentType, body) {
       var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
       debug('sendInfo()'); // Check Session Status.
 
       if (this._status !== C.STATUS_CONFIRMED && this._status !== C.STATUS_WAITING_FOR_ACK) {
         throw new Exceptions.InvalidStateError(this._status);
       }
 
       var info = new RTCSession_Info(this);
       info.send(contentType, body, options);
     }
     /**
      * Mute
      */
 
   }, {
     key: "mute",
     value: function mute() {
       var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {
         audio: true,
         video: false
       };
       debug('mute()');
       var audioMuted = false,
           videoMuted = false;
 
       if (this._audioMuted === false && options.audio) {
         audioMuted = true;
         this._audioMuted = true;
 
         this._toggleMuteAudio(true);
       }
 
       if (this._videoMuted === false && options.video) {
         videoMuted = true;
         this._videoMuted = true;
 
         this._toggleMuteVideo(true);
       }
 
       if (audioMuted === true || videoMuted === true) {
         this._onmute({
           audio: audioMuted,
           video: videoMuted
         });
       }
     }
     /**
      * Unmute
      */
 
   }, {
     key: "unmute",
     value: function unmute() {
       var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {
         audio: true,
         video: true
       };
       debug('unmute()');
       var audioUnMuted = false,
           videoUnMuted = false;
 
       if (this._audioMuted === true && options.audio) {
         audioUnMuted = true;
         this._audioMuted = false;
 
         if (this._localHold === false) {
           this._toggleMuteAudio(false);
         }
       }
 
       if (this._videoMuted === true && options.video) {
         videoUnMuted = true;
         this._videoMuted = false;
 
         if (this._localHold === false) {
           this._toggleMuteVideo(false);
         }
       }
 
       if (audioUnMuted === true || videoUnMuted === true) {
         this._onunmute({
           audio: audioUnMuted,
           video: videoUnMuted
         });
       }
     }
     /**
      * Hold
      */
 
   }, {
     key: "hold",
     value: function hold() {
       var _this6 = this;
 
       var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
       var done = arguments.length > 1 ? arguments[1] : undefined;
       debug('hold()');
 
       if (this._status !== C.STATUS_WAITING_FOR_ACK && this._status !== C.STATUS_CONFIRMED) {
         return false;
       }
 
       if (this._localHold === true) {
         return false;
       }
 
       if (!this._isReadyToReOffer()) {
         return false;
       }
 
       this._localHold = true;
 
       this._onhold('local');
 
       var eventHandlers = {
         succeeded: function succeeded() {
           if (done) {
             done();
           }
         },
         failed: function failed() {
           _this6.terminate({
             cause: JsSIP_C.causes.WEBRTC_ERROR,
             status_code: 500,
             reason_phrase: 'Hold Failed'
           });
         }
       };
 
       if (options.useUpdate) {
         this._sendUpdate({
           sdpOffer: true,
           eventHandlers: eventHandlers,
           extraHeaders: options.extraHeaders
         });
       } else {
         this._sendReinvite({
           eventHandlers: eventHandlers,
           extraHeaders: options.extraHeaders
         });
       }
 
       return true;
     }
   }, {
     key: "unhold",
     value: function unhold() {
       var _this7 = this;
 
       var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
       var done = arguments.length > 1 ? arguments[1] : undefined;
       debug('unhold()');
 
       if (this._status !== C.STATUS_WAITING_FOR_ACK && this._status !== C.STATUS_CONFIRMED) {
         return false;
       }
 
       if (this._localHold === false) {
         return false;
       }
 
       if (!this._isReadyToReOffer()) {
         return false;
       }
 
       this._localHold = false;
 
       this._onunhold('local');
 
       var eventHandlers = {
         succeeded: function succeeded() {
           if (done) {
             done();
           }
         },
         failed: function failed() {
           _this7.terminate({
             cause: JsSIP_C.causes.WEBRTC_ERROR,
             status_code: 500,
             reason_phrase: 'Unhold Failed'
           });
         }
       };
 
       if (options.useUpdate) {
         this._sendUpdate({
           sdpOffer: true,
           eventHandlers: eventHandlers,
           extraHeaders: options.extraHeaders
         });
       } else {
         this._sendReinvite({
           eventHandlers: eventHandlers,
           extraHeaders: options.extraHeaders
         });
       }
 
       return true;
     }
   }, {
     key: "renegotiate",
     value: function renegotiate() {
       var _this8 = this;
 
       var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
       var done = arguments.length > 1 ? arguments[1] : undefined;
       debug('renegotiate()');
       var rtcOfferConstraints = options.rtcOfferConstraints || null;
 
       if (this._status !== C.STATUS_WAITING_FOR_ACK && this._status !== C.STATUS_CONFIRMED) {
         return false;
       }
 
       if (!this._isReadyToReOffer()) {
         return false;
       }
 
       var eventHandlers = {
         succeeded: function succeeded() {
           if (done) {
             done();
           }
         },
         failed: function failed() {
           _this8.terminate({
             cause: JsSIP_C.causes.WEBRTC_ERROR,
             status_code: 500,
             reason_phrase: 'Media Renegotiation Failed'
           });
         }
       };
 
       this._setLocalMediaStatus();
 
       if (options.useUpdate) {
         this._sendUpdate({
           sdpOffer: true,
           eventHandlers: eventHandlers,
           rtcOfferConstraints: rtcOfferConstraints,
           extraHeaders: options.extraHeaders
         });
       } else {
         this._sendReinvite({
           eventHandlers: eventHandlers,
           rtcOfferConstraints: rtcOfferConstraints,
           extraHeaders: options.extraHeaders
         });
       }
 
       return true;
     }
     /**
      * Refer
      */
 
   }, {
     key: "refer",
     value: function refer(target, options) {
       var _this9 = this;
 
       debug('refer()');
       var originalTarget = target;
 
       if (this._status !== C.STATUS_WAITING_FOR_ACK && this._status !== C.STATUS_CONFIRMED) {
         return false;
       } // Check target validity.
 
 
       target = this._ua.normalizeTarget(target);
 
       if (!target) {
         throw new TypeError("Invalid target: ".concat(originalTarget));
       }
 
       var referSubscriber = new RTCSession_ReferSubscriber(this);
       referSubscriber.sendRefer(target, options); // Store in the map.
 
       var id = referSubscriber.id;
       this._referSubscribers[id] = referSubscriber; // Listen for ending events so we can remove it from the map.
 
       referSubscriber.on('requestFailed', function () {
         delete _this9._referSubscribers[id];
       });
       referSubscriber.on('accepted', function () {
         delete _this9._referSubscribers[id];
       });
       referSubscriber.on('failed', function () {
         delete _this9._referSubscribers[id];
       });
       return referSubscriber;
     }
     /**
      * Send a generic in-dialog Request
      */
 
   }, {
     key: "sendRequest",
     value: function sendRequest(method, options) {
       debug('sendRequest()');
       return this._dialog.sendRequest(method, options);
     }
     /**
      * In dialog Request Reception
      */
 
   }, {
     key: "receiveRequest",
     value: function receiveRequest(request) {
       var _this10 = this;
 
       debug('receiveRequest()');
 
       if (request.method === JsSIP_C.CANCEL) {
         /* RFC3261 15 States that a UAS may have accepted an invitation while a CANCEL
         * was in progress and that the UAC MAY continue with the session established by
         * any 2xx response, or MAY terminate with BYE. JsSIP does continue with the
         * established session. So the CANCEL is processed only if the session is not yet
         * established.
         */
 
         /*
         * Terminate the whole session in case the user didn't accept (or yet send the answer)
         * nor reject the request opening the session.
         */
         if (this._status === C.STATUS_WAITING_FOR_ANSWER || this._status === C.STATUS_ANSWERED) {
           this._status = C.STATUS_CANCELED;
 
           this._request.reply(487);
 
           this._failed('remote', request, JsSIP_C.causes.CANCELED);
         }
       } else {
         // Requests arriving here are in-dialog requests.
         switch (request.method) {
           case JsSIP_C.ACK:
             if (this._status !== C.STATUS_WAITING_FOR_ACK) {
               return;
             } // Update signaling status.
 
 
             this._status = C.STATUS_CONFIRMED;
             clearTimeout(this._timers.ackTimer);
             clearTimeout(this._timers.invite2xxTimer);
 
             if (this._late_sdp) {
               if (!request.body) {
                 this.terminate({
                   cause: JsSIP_C.causes.MISSING_SDP,
                   status_code: 400
                 });
                 break;
               }
 
               var e = {
                 originator: 'remote',
                 type: 'answer',
                 sdp: request.body
               };
               debug('emit "sdp"');
               this.emit('sdp', e);
               var answer = new RTCSessionDescription({
                 type: 'answer',
                 sdp: e.sdp
               });
               this._connectionPromiseQueue = this._connectionPromiseQueue.then(function () {
                 return _this10._connection.setRemoteDescription(answer);
               }).then(function () {
                 if (!_this10._is_confirmed) {
                   _this10._confirmed('remote', request);
                 }
               })["catch"](function (error) {
                 _this10.terminate({
                   cause: JsSIP_C.causes.BAD_MEDIA_DESCRIPTION,
                   status_code: 488
                 });
 
                 debugerror('emit "peerconnection:setremotedescriptionfailed" [error:%o]', error);
 
                 _this10.emit('peerconnection:setremotedescriptionfailed', error);
               });
             } else if (!this._is_confirmed) {
               this._confirmed('remote', request);
             }
 
             break;
 
           case JsSIP_C.BYE:
             if (this._status === C.STATUS_CONFIRMED || this._status === C.STATUS_WAITING_FOR_ACK) {
               request.reply(200);
 
               this._ended('remote', request, JsSIP_C.causes.BYE);
             } else if (this._status === C.STATUS_INVITE_RECEIVED || this._status === C.STATUS_WAITING_FOR_ANSWER) {
               request.reply(200);
 
               this._request.reply(487, 'BYE Received');
 
               this._ended('remote', request, JsSIP_C.causes.BYE);
             } else {
               request.reply(403, 'Wrong Status');
             }
 
             break;
 
           case JsSIP_C.INVITE:
             if (this._status === C.STATUS_CONFIRMED) {
               if (request.hasHeader('replaces')) {
                 this._receiveReplaces(request);
               } else {
                 this._receiveReinvite(request);
               }
             } else {
               request.reply(403, 'Wrong Status');
             }
 
             break;
 
           case JsSIP_C.INFO:
             if (this._status === C.STATUS_1XX_RECEIVED || this._status === C.STATUS_WAITING_FOR_ANSWER || this._status === C.STATUS_ANSWERED || this._status === C.STATUS_WAITING_FOR_ACK || this._status === C.STATUS_CONFIRMED) {
               var contentType = request.hasHeader('Content-Type') ? request.getHeader('Content-Type').toLowerCase() : undefined;
 
               if (contentType && contentType.match(/^application\/dtmf-relay/i)) {
                 new RTCSession_DTMF(this).init_incoming(request);
               } else if (contentType !== undefined) {
                 new RTCSession_Info(this).init_incoming(request);
               } else {
                 request.reply(415);
               }
             } else {
               request.reply(403, 'Wrong Status');
             }
 
             break;
 
           case JsSIP_C.UPDATE:
             if (this._status === C.STATUS_CONFIRMED) {
               this._receiveUpdate(request);
             } else {
               request.reply(403, 'Wrong Status');
             }
 
             break;
 
           case JsSIP_C.REFER:
             if (this._status === C.STATUS_CONFIRMED) {
               this._receiveRefer(request);
             } else {
               request.reply(403, 'Wrong Status');
             }
 
             break;
 
           case JsSIP_C.NOTIFY:
             if (this._status === C.STATUS_CONFIRMED) {
               this._receiveNotify(request);
             } else {
               request.reply(403, 'Wrong Status');
             }
 
             break;
 
           default:
             request.reply(501);
         }
       }
     }
     /**
      * Session Callbacks
      */
 
   }, {
     key: "onTransportError",
     value: function onTransportError() {
       debugerror('onTransportError()');
 
       if (this._status !== C.STATUS_TERMINATED) {
         this.terminate({
           status_code: 500,
           reason_phrase: JsSIP_C.causes.CONNECTION_ERROR,
           cause: JsSIP_C.causes.CONNECTION_ERROR
         });
       }
     }
   }, {
     key: "onRequestTimeout",
     value: function onRequestTimeout() {
       debugerror('onRequestTimeout()');
 
       if (this._status !== C.STATUS_TERMINATED) {
         this.terminate({
           status_code: 408,
           reason_phrase: JsSIP_C.causes.REQUEST_TIMEOUT,
           cause: JsSIP_C.causes.REQUEST_TIMEOUT
         });
       }
     }
   }, {
     key: "onDialogError",
     value: function onDialogError() {
       debugerror('onDialogError()');
 
       if (this._status !== C.STATUS_TERMINATED) {
         this.terminate({
           status_code: 500,
           reason_phrase: JsSIP_C.causes.DIALOG_ERROR,
           cause: JsSIP_C.causes.DIALOG_ERROR
         });
       }
     } // Called from DTMF handler.
 
   }, {
     key: "newDTMF",
     value: function newDTMF(data) {
       debug('newDTMF()');
       this.emit('newDTMF', data);
     } // Called from Info handler.
 
   }, {
     key: "newInfo",
     value: function newInfo(data) {
       debug('newInfo()');
       this.emit('newInfo', data);
     }
     /**
      * Check if RTCSession is ready for an outgoing re-INVITE or UPDATE with SDP.
      */
 
   }, {
     key: "_isReadyToReOffer",
     value: function _isReadyToReOffer() {
       if (!this._rtcReady) {
         debug('_isReadyToReOffer() | internal WebRTC status not ready');
         return false;
       } // No established yet.
 
 
       if (!this._dialog) {
         debug('_isReadyToReOffer() | session not established yet');
         return false;
       } // Another INVITE transaction is in progress.
 
 
       if (this._dialog.uac_pending_reply === true || this._dialog.uas_pending_reply === true) {
         debug('_isReadyToReOffer() | there is another INVITE/UPDATE transaction in progress');
         return false;
       }
 
       return true;
     }
   }, {
     key: "_close",
     value: function _close() {
       debug('close()');
 
       if (this._status === C.STATUS_TERMINATED) {
         return;
       }
 
       this._status = C.STATUS_TERMINATED; // Terminate RTC.
 
       if (this._connection) {
         try {
           this._connection.close();
         } catch (error) {
           debugerror('close() | error closing the RTCPeerConnection: %o', error);
         }
       } // Close local MediaStream if it was not given by the user.
 
 
       if (this._localMediaStream && this._localMediaStreamLocallyGenerated) {
         debug('close() | closing local MediaStream');
         Utils.closeMediaStream(this._localMediaStream);
       } // Terminate signaling.
       // Clear SIP timers.
 
 
       for (var timer in this._timers) {
         if (Object.prototype.hasOwnProperty.call(this._timers, timer)) {
           clearTimeout(this._timers[timer]);
         }
       } // Clear Session Timers.
 
 
       clearTimeout(this._sessionTimers.timer); // Terminate confirmed dialog.
 
       if (this._dialog) {
         this._dialog.terminate();
 
         delete this._dialog;
       } // Terminate early dialogs.
 
 
       for (var dialog in this._earlyDialogs) {
         if (Object.prototype.hasOwnProperty.call(this._earlyDialogs, dialog)) {
           this._earlyDialogs[dialog].terminate();
 
           delete this._earlyDialogs[dialog];
         }
       } // Terminate REFER subscribers.
 
 
       for (var subscriber in this._referSubscribers) {
         if (Object.prototype.hasOwnProperty.call(this._referSubscribers, subscriber)) {
           delete this._referSubscribers[subscriber];
         }
       }
 
       this._ua.destroyRTCSession(this);
     }
     /**
      * Private API.
      */
 
     /**
      * RFC3261 13.3.1.4
      * Response retransmissions cannot be accomplished by transaction layer
      *  since it is destroyed when receiving the first 2xx answer
      */
 
   }, {
     key: "_setInvite2xxTimer",
     value: function _setInvite2xxTimer(request, body) {
       var timeout = Timers.T1;
 
       function invite2xxRetransmission() {
         if (this._status !== C.STATUS_WAITING_FOR_ACK) {
           return;
         }
 
         request.reply(200, null, ["Contact: ".concat(this._contact)], body);
 
         if (timeout < Timers.T2) {
           timeout = timeout * 2;
 
           if (timeout > Timers.T2) {
             timeout = Timers.T2;
           }
         }
 
         this._timers.invite2xxTimer = setTimeout(invite2xxRetransmission.bind(this), timeout);
       }
 
       this._timers.invite2xxTimer = setTimeout(invite2xxRetransmission.bind(this), timeout);
     }
     /**
      * RFC3261 14.2
      * If a UAS generates a 2xx response and never receives an ACK,
      *  it SHOULD generate a BYE to terminate the dialog.
      */
 
   }, {
     key: "_setACKTimer",
     value: function _setACKTimer() {
       var _this11 = this;
 
       this._timers.ackTimer = setTimeout(function () {
         if (_this11._status === C.STATUS_WAITING_FOR_ACK) {
           debug('no ACK received, terminating the session');
           clearTimeout(_this11._timers.invite2xxTimer);
 
           _this11.sendRequest(JsSIP_C.BYE);
 
           _this11._ended('remote', null, JsSIP_C.causes.NO_ACK);
         }
       }, Timers.TIMER_H);
     }
   }, {
     key: "_createRTCConnection",
     value: function _createRTCConnection(pcConfig, rtcConstraints) {
       var _this12 = this;
 
       this._connection = new RTCPeerConnection(pcConfig, rtcConstraints);
 
       this._connection.addEventListener('iceconnectionstatechange', function () {
         var state = _this12._connection.iceConnectionState; // TODO: Do more with different states.
 
         if (state === 'failed') {
           _this12.terminate({
             cause: JsSIP_C.causes.RTP_TIMEOUT,
             status_code: 408,
             reason_phrase: JsSIP_C.causes.RTP_TIMEOUT
           });
         }
       });
 
       debug('emit "peerconnection"');
       this.emit('peerconnection', {
         peerconnection: this._connection
       });
     }
   }, {
     key: "_createLocalDescription",
     value: function _createLocalDescription(type, constraints) {
       var _this13 = this;
 
       debug('createLocalDescription()');
       if (type !== 'offer' && type !== 'answer') throw new Error("createLocalDescription() | invalid type \"".concat(type, "\""));
       var connection = this._connection;
       this._rtcReady = false;
       return Promise.resolve() // Create Offer or Answer.
       .then(function () {
         if (type === 'offer') {
           return connection.createOffer(constraints)["catch"](function (error) {
             debugerror('emit "peerconnection:createofferfailed" [error:%o]', error);
 
             _this13.emit('peerconnection:createofferfailed', error);
 
             return Promise.reject(error);
           });
         } else {
           return connection.createAnswer(constraints)["catch"](function (error) {
             debugerror('emit "peerconnection:createanswerfailed" [error:%o]', error);
 
             _this13.emit('peerconnection:createanswerfailed', error);
 
             return Promise.reject(error);
           });
         }
       }) // Set local description.
       .then(function (desc) {
         return connection.setLocalDescription(desc)["catch"](function (error) {
           _this13._rtcReady = true;
           debugerror('emit "peerconnection:setlocaldescriptionfailed" [error:%o]', error);
 
           _this13.emit('peerconnection:setlocaldescriptionfailed', error);
 
           return Promise.reject(error);
         });
       }).then(function () {
         // Resolve right away if 'pc.iceGatheringState' is 'complete'.
         if (connection.iceGatheringState === 'complete' && (!constraints || !constraints.iceRestart)) {
           _this13._rtcReady = true;
           var e = {
             originator: 'local',
             type: type,
             sdp: connection.localDescription.sdp
           };
           debug('emit "sdp"');
 
           _this13.emit('sdp', e);
 
           return Promise.resolve(e.sdp);
         } // Add 'pc.onicencandidate' event handler to resolve on last candidate.
 
 
         return new Promise(function (resolve) {
           var finished = false;
           var iceCandidateListener;
           var iceGatheringStateListener;
 
           var ready = function ready() {
             connection.removeEventListener('icecandidate', iceCandidateListener);
             connection.removeEventListener('icegatheringstatechange', iceGatheringStateListener);
             finished = true;
             _this13._rtcReady = true;
             var e = {
               originator: 'local',
               type: type,
               sdp: connection.localDescription.sdp
             };
             debug('emit "sdp"');
 
             _this13.emit('sdp', e);
 
             resolve(e.sdp);
           };
 
           connection.addEventListener('icecandidate', iceCandidateListener = function iceCandidateListener(event) {
             var candidate = event.candidate;
 
             if (candidate) {
               _this13.emit('icecandidate', {
                 candidate: candidate,
                 ready: ready
               });
             } else if (!finished) {
               ready();
             }
           });
           connection.addEventListener('icegatheringstatechange', iceGatheringStateListener = function iceGatheringStateListener() {
             if (connection.iceGatheringState === 'complete' && !finished) {
               ready();
             }
           });
         });
       });
     }
     /**
      * Dialog Management
      */
 
   }, {
     key: "_createDialog",
     value: function _createDialog(message, type, early) {
       var local_tag = type === 'UAS' ? message.to_tag : message.from_tag;
       var remote_tag = type === 'UAS' ? message.from_tag : message.to_tag;
       var id = message.call_id + local_tag + remote_tag;
       var early_dialog = this._earlyDialogs[id]; // Early Dialog.
 
       if (early) {
         if (early_dialog) {
           return true;
         } else {
           early_dialog = new Dialog(this, message, type, Dialog.C.STATUS_EARLY); // Dialog has been successfully created.
 
           if (early_dialog.error) {
             debug(early_dialog.error);
 
             this._failed('remote', message, JsSIP_C.causes.INTERNAL_ERROR);
 
             return false;
           } else {
             this._earlyDialogs[id] = early_dialog;
             return true;
           }
         }
       } // Confirmed Dialog.
       else {
           this._from_tag = message.from_tag;
           this._to_tag = message.to_tag; // In case the dialog is in _early_ state, update it.
 
           if (early_dialog) {
             early_dialog.update(message, type);
             this._dialog = early_dialog;
             delete this._earlyDialogs[id];
             return true;
           } // Otherwise, create a _confirmed_ dialog.
 
 
           var dialog = new Dialog(this, message, type);
 
           if (dialog.error) {
             debug(dialog.error);
 
             this._failed('remote', message, JsSIP_C.causes.INTERNAL_ERROR);
 
             return false;
           } else {
             this._dialog = dialog;
             return true;
           }
         }
     }
     /**
      * In dialog INVITE Reception
      */
 
   }, {
     key: "_receiveReinvite",
     value: function _receiveReinvite(request) {
       var _this14 = this;
 
       debug('receiveReinvite()');
       var contentType = request.hasHeader('Content-Type') ? request.getHeader('Content-Type').toLowerCase() : undefined;
       var data = {
         request: request,
         callback: undefined,
         reject: reject.bind(this)
       };
       var rejected = false;
 
       function reject() {
         var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
         rejected = true;
         var status_code = options.status_code || 403;
         var reason_phrase = options.reason_phrase || '';
         var extraHeaders = Utils.cloneArray(options.extraHeaders);
 
         if (this._status !== C.STATUS_CONFIRMED) {
           return false;
         }
 
         if (status_code < 300 || status_code >= 700) {
           throw new TypeError("Invalid status_code: ".concat(status_code));
         }
 
         request.reply(status_code, reason_phrase, extraHeaders);
       } // Emit 'reinvite'.
 
 
       this.emit('reinvite', data);
 
       if (rejected) {
         return;
       }
 
       this._late_sdp = false; // Request without SDP.
 
       if (!request.body) {
         this._late_sdp = true;
 
         if (this._remoteHold) {
           this._remoteHold = false;
 
           this._onunhold('remote');
         }
 
         this._connectionPromiseQueue = this._connectionPromiseQueue.then(function () {
           return _this14._createLocalDescription('offer', _this14._rtcOfferConstraints);
         }).then(function (sdp) {
           sendAnswer.call(_this14, sdp);
         })["catch"](function () {
           request.reply(500);
         });
         return;
       } // Request with SDP.
 
 
       if (contentType !== 'application/sdp') {
         debug('invalid Content-Type');
         request.reply(415);
         return;
       }
 
       this._processInDialogSdpOffer(request) // Send answer.
       .then(function (desc) {
         if (_this14._status === C.STATUS_TERMINATED) {
           return;
         }
 
         sendAnswer.call(_this14, desc);
       })["catch"](function (error) {
         debugerror(error);
       });
 
       function sendAnswer(desc) {
         var _this15 = this;
 
         var extraHeaders = ["Contact: ".concat(this._contact)];
 
         this._handleSessionTimersInIncomingRequest(request, extraHeaders);
 
         if (this._late_sdp) {
           desc = this._mangleOffer(desc);
         }
 
         request.reply(200, null, extraHeaders, desc, function () {
           _this15._status = C.STATUS_WAITING_FOR_ACK;
 
           _this15._setInvite2xxTimer(request, desc);
 
           _this15._setACKTimer();
         }); // If callback is given execute it.
 
         if (typeof data.callback === 'function') {
           data.callback();
         }
       }
     }
     /**
      * In dialog UPDATE Reception
      */
 
   }, {
     key: "_receiveUpdate",
     value: function _receiveUpdate(request) {
       var _this16 = this;
 
       debug('receiveUpdate()');
       var contentType = request.hasHeader('Content-Type') ? request.getHeader('Content-Type').toLowerCase() : undefined;
       var data = {
         request: request,
         callback: undefined,
         reject: reject.bind(this)
       };
       var rejected = false;
 
       function reject() {
         var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
         rejected = true;
         var status_code = options.status_code || 403;
         var reason_phrase = options.reason_phrase || '';
         var extraHeaders = Utils.cloneArray(options.extraHeaders);
 
         if (this._status !== C.STATUS_CONFIRMED) {
           return false;
         }
 
         if (status_code < 300 || status_code >= 700) {
           throw new TypeError("Invalid status_code: ".concat(status_code));
         }
 
         request.reply(status_code, reason_phrase, extraHeaders);
       } // Emit 'update'.
 
 
       this.emit('update', data);
 
       if (rejected) {
         return;
       }
 
       if (!request.body) {
         sendAnswer.call(this, null);
         return;
       }
 
       if (contentType !== 'application/sdp') {
         debug('invalid Content-Type');
         request.reply(415);
         return;
       }
 
       this._processInDialogSdpOffer(request) // Send answer.
       .then(function (desc) {
         if (_this16._status === C.STATUS_TERMINATED) {
           return;
         }
 
         sendAnswer.call(_this16, desc);
       })["catch"](function (error) {
         debugerror(error);
       });
 
       function sendAnswer(desc) {
         var extraHeaders = ["Contact: ".concat(this._contact)];
 
         this._handleSessionTimersInIncomingRequest(request, extraHeaders);
 
         request.reply(200, null, extraHeaders, desc); // If callback is given execute it.
 
         if (typeof data.callback === 'function') {
           data.callback();
         }
       }
     }
   }, {
     key: "_processInDialogSdpOffer",
     value: function _processInDialogSdpOffer(request) {
       var _this17 = this;
 
       debug('_processInDialogSdpOffer()');
       var sdp = request.parseSDP();
       var hold = false;
 
       var _iterator4 = _createForOfIteratorHelper(sdp.media),
           _step4;
 
       try {
         for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
           var m = _step4.value;
 
           if (holdMediaTypes.indexOf(m.type) === -1) {
             continue;
           }
 
           var direction = m.direction || sdp.direction || 'sendrecv';
 
           if (direction === 'sendonly' || direction === 'inactive') {
             hold = true;
           } // If at least one of the streams is active don't emit 'hold'.
           else {
               hold = false;
               break;
             }
         }
       } catch (err) {
         _iterator4.e(err);
       } finally {
         _iterator4.f();
       }
 
       var e = {
         originator: 'remote',
         type: 'offer',
         sdp: request.body
       };
       debug('emit "sdp"');
       this.emit('sdp', e);
       var offer = new RTCSessionDescription({
         type: 'offer',
         sdp: e.sdp
       });
       this._connectionPromiseQueue = this._connectionPromiseQueue // Set remote description.
       .then(function () {
         if (_this17._status === C.STATUS_TERMINATED) {
           throw new Error('terminated');
         }
 
         return _this17._connection.setRemoteDescription(offer)["catch"](function (error) {
           request.reply(488);
           debugerror('emit "peerconnection:setremotedescriptionfailed" [error:%o]', error);
 
           _this17.emit('peerconnection:setremotedescriptionfailed', error);
 
           throw error;
         });
       }).then(function () {
         if (_this17._status === C.STATUS_TERMINATED) {
           throw new Error('terminated');
         }
 
         if (_this17._remoteHold === true && hold === false) {
           _this17._remoteHold = false;
 
           _this17._onunhold('remote');
         } else if (_this17._remoteHold === false && hold === true) {
           _this17._remoteHold = true;
 
           _this17._onhold('remote');
         }
       }) // Create local description.
       .then(function () {
         if (_this17._status === C.STATUS_TERMINATED) {
           throw new Error('terminated');
         }
 
         return _this17._createLocalDescription('answer', _this17._rtcAnswerConstraints)["catch"](function (error) {
           request.reply(500);
           debugerror('emit "peerconnection:createtelocaldescriptionfailed" [error:%o]', error);
           throw error;
         });
       })["catch"](function (error) {
         debugerror('_processInDialogSdpOffer() failed [error: %o]', error);
       });
       return this._connectionPromiseQueue;
     }
     /**
      * In dialog Refer Reception
      */
 
   }, {
     key: "_receiveRefer",
     value: function _receiveRefer(request) {
       var _this18 = this;
 
       debug('receiveRefer()');
 
       if (!request.refer_to) {
         debug('no Refer-To header field present in REFER');
         request.reply(400);
         return;
       }
 
       if (request.refer_to.uri.scheme !== JsSIP_C.SIP) {
         debug('Refer-To header field points to a non-SIP URI scheme');
         request.reply(416);
         return;
       } // Reply before the transaction timer expires.
 
 
       request.reply(202);
       var notifier = new RTCSession_ReferNotifier(this, request.cseq);
       debug('emit "refer"'); // Emit 'refer'.
 
       this.emit('refer', {
         request: request,
         accept: function accept(initCallback, options) {
           _accept.call(_this18, initCallback, options);
         },
         reject: function reject() {
           _reject.call(_this18);
         }
       });
 
       function _accept(initCallback) {
         var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
         initCallback = typeof initCallback === 'function' ? initCallback : null;
 
         if (this._status !== C.STATUS_WAITING_FOR_ACK && this._status !== C.STATUS_CONFIRMED) {
           return false;
         }
 
         var session = new RTCSession(this._ua);
         session.on('progress', function (_ref2) {
           var response = _ref2.response;
           notifier.notify(response.status_code, response.reason_phrase);
         });
         session.on('accepted', function (_ref3) {
           var response = _ref3.response;
           notifier.notify(response.status_code, response.reason_phrase);
         });
         session.on('_failed', function (_ref4) {
           var message = _ref4.message,
               cause = _ref4.cause;
 
           if (message) {
             notifier.notify(message.status_code, message.reason_phrase);
           } else {
             notifier.notify(487, cause);
           }
         }); // Consider the Replaces header present in the Refer-To URI.
 
         if (request.refer_to.uri.hasHeader('replaces')) {
           var replaces = decodeURIComponent(request.refer_to.uri.getHeader('replaces'));
           options.extraHeaders = Utils.cloneArray(options.extraHeaders);
           options.extraHeaders.push("Replaces: ".concat(replaces));
         }
 
         session.connect(request.refer_to.uri.toAor(), options, initCallback);
       }
 
       function _reject() {
         notifier.notify(603);
       }
     }
     /**
      * In dialog Notify Reception
      */
 
   }, {
     key: "_receiveNotify",
     value: function _receiveNotify(request) {
       debug('receiveNotify()');
 
       if (!request.event) {
         request.reply(400);
       }
 
       switch (request.event.event) {
         case 'refer':
           {
             var id;
             var referSubscriber;
 
             if (request.event.params && request.event.params.id) {
               id = request.event.params.id;
               referSubscriber = this._referSubscribers[id];
             } else if (Object.keys(this._referSubscribers).length === 1) {
               referSubscriber = this._referSubscribers[Object.keys(this._referSubscribers)[0]];
             } else {
               request.reply(400, 'Missing event id parameter');
               return;
             }
 
             if (!referSubscriber) {
               request.reply(481, 'Subscription does not exist');
               return;
             }
 
             referSubscriber.receiveNotify(request);
             request.reply(200);
             break;
           }
 
         default:
           {
             request.reply(489);
           }
       }
     }
     /**
      * INVITE with Replaces Reception
      */
 
   }, {
     key: "_receiveReplaces",
     value: function _receiveReplaces(request) {
       var _this20 = this;
 
       debug('receiveReplaces()');
 
       function _accept2(initCallback) {
         var _this19 = this;
 
         if (this._status !== C.STATUS_WAITING_FOR_ACK && this._status !== C.STATUS_CONFIRMED) {
           return false;
         }
 
         var session = new RTCSession(this._ua); // Terminate the current session when the new one is confirmed.
 
         session.on('confirmed', function () {
           _this19.terminate();
         });
         session.init_incoming(request, initCallback);
       }
 
       function _reject2() {
         debug('Replaced INVITE rejected by the user');
         request.reply(486);
       } // Emit 'replace'.
 
 
       this.emit('replaces', {
         request: request,
         accept: function accept(initCallback) {
           _accept2.call(_this20, initCallback);
         },
         reject: function reject() {
           _reject2.call(_this20);
         }
       });
     }
     /**
      * Initial Request Sender
      */
 
   }, {
     key: "_sendInitialRequest",
     value: function _sendInitialRequest(mediaConstraints, rtcOfferConstraints, mediaStream) {
       var _this21 = this;
 
       var request_sender = new RequestSender(this._ua, this._request, {
         onRequestTimeout: function onRequestTimeout() {
           _this21.onRequestTimeout();
         },
         onTransportError: function onTransportError() {
           _this21.onTransportError();
         },
         // Update the request on authentication.
         onAuthenticated: function onAuthenticated(request) {
           _this21._request = request;
         },
         onReceiveResponse: function onReceiveResponse(response) {
           _this21._receiveInviteResponse(response);
         }
       }); // This Promise is resolved within the next iteration, so the app has now
       // a chance to set events such as 'peerconnection' and 'connecting'.
 
       Promise.resolve() // Get a stream if required.
       .then(function () {
         // A stream is given, let the app set events such as 'peerconnection' and 'connecting'.
         if (mediaStream) {
           return mediaStream;
         } // Request for user media access.
         else if (mediaConstraints.audio || mediaConstraints.video) {
             _this21._localMediaStreamLocallyGenerated = true;
             return navigator.mediaDevices.getUserMedia(mediaConstraints)["catch"](function (error) {
               if (_this21._status === C.STATUS_TERMINATED) {
                 throw new Error('terminated');
               }
 
               _this21._failed('local', null, JsSIP_C.causes.USER_DENIED_MEDIA_ACCESS);
 
               debugerror('emit "getusermediafailed" [error:%o]', error);
 
               _this21.emit('getusermediafailed', error);
 
               throw error;
             });
           }
       }).then(function (stream) {
         if (_this21._status === C.STATUS_TERMINATED) {
           throw new Error('terminated');
         }
 
         _this21._localMediaStream = stream;
 
         if (stream) {
           stream.getTracks().forEach(function (track) {
             _this21._connection.addTrack(track, stream);
           });
         } // TODO: should this be triggered here?
 
 
         _this21._connecting(_this21._request);
 
         return _this21._createLocalDescription('offer', rtcOfferConstraints)["catch"](function (error) {
           _this21._failed('local', null, JsSIP_C.causes.WEBRTC_ERROR);
 
           throw error;
         });
       }).then(function (desc) {
         if (_this21._is_canceled || _this21._status === C.STATUS_TERMINATED) {
           throw new Error('terminated');
         }
 
         _this21._request.body = desc;
         _this21._status = C.STATUS_INVITE_SENT;
         debug('emit "sending" [request:%o]', _this21._request); // Emit 'sending' so the app can mangle the body before the request is sent.
 
         _this21.emit('sending', {
           request: _this21._request
         });
 
         request_sender.send();
       })["catch"](function (error) {
         if (_this21._status === C.STATUS_TERMINATED) {
           return;
         }
 
         debugerror(error);
       });
     }
     /**
      * Get DTMF RTCRtpSender.
      */
 
   }, {
     key: "_getDTMFRTPSender",
     value: function _getDTMFRTPSender() {
       var sender = this._connection.getSenders().find(function (rtpSender) {
         return rtpSender.track && rtpSender.track.kind === 'audio';
       });
 
       if (!(sender && sender.dtmf)) {
         debugerror('sendDTMF() | no local audio track to send DTMF with');
         return;
       }
 
       return sender.dtmf;
     }
     /**
      * Reception of Response for Initial INVITE
      */
 
   }, {
     key: "_receiveInviteResponse",
     value: function _receiveInviteResponse(response) {
       var _this22 = this;
 
       debug('receiveInviteResponse()'); // Handle 2XX retransmissions and responses from forked requests.
 
       if (this._dialog && response.status_code >= 200 && response.status_code <= 299) {
         /*
          * If it is a retransmission from the endpoint that established
          * the dialog, send an ACK
          */
         if (this._dialog.id.call_id === response.call_id && this._dialog.id.local_tag === response.from_tag && this._dialog.id.remote_tag === response.to_tag) {
           this.sendRequest(JsSIP_C.ACK);
           return;
         } // If not, send an ACK  and terminate.
         else {
             var dialog = new Dialog(this, response, 'UAC');
 
             if (dialog.error !== undefined) {
               debug(dialog.error);
               return;
             }
 
             this.sendRequest(JsSIP_C.ACK);
             this.sendRequest(JsSIP_C.BYE);
             return;
           }
       } // Proceed to cancellation if the user requested.
 
 
       if (this._is_canceled) {
         if (response.status_code >= 100 && response.status_code < 200) {
           this._request.cancel(this._cancel_reason);
         } else if (response.status_code >= 200 && response.status_code < 299) {
           this._acceptAndTerminate(response);
         }
 
         return;
       }
 
       if (this._status !== C.STATUS_INVITE_SENT && this._status !== C.STATUS_1XX_RECEIVED) {
         return;
       }
 
       switch (true) {
         case /^100$/.test(response.status_code):
           this._status = C.STATUS_1XX_RECEIVED;
           break;
 
         case /^1[0-9]{2}$/.test(response.status_code):
           {
             // Do nothing with 1xx responses without To tag.
             if (!response.to_tag) {
               debug('1xx response received without to tag');
               break;
             } // Create Early Dialog if 1XX comes with contact.
 
 
             if (response.hasHeader('contact')) {
               // An error on dialog creation will fire 'failed' event.
               if (!this._createDialog(response, 'UAC', true)) {
                 break;
               }
             }
 
             this._status = C.STATUS_1XX_RECEIVED;
 
             if (!response.body) {
               this._progress('remote', response);
 
               break;
             }
 
             var e = {
               originator: 'remote',
               type: 'answer',
               sdp: response.body
             };
             debug('emit "sdp"');
             this.emit('sdp', e);
             var answer = new RTCSessionDescription({
               type: 'answer',
               sdp: e.sdp
             });
             this._connectionPromiseQueue = this._connectionPromiseQueue.then(function () {
               return _this22._connection.setRemoteDescription(answer);
             }).then(function () {
               return _this22._progress('remote', response);
             })["catch"](function (error) {
               debugerror('emit "peerconnection:setremotedescriptionfailed" [error:%o]', error);
 
               _this22.emit('peerconnection:setremotedescriptionfailed', error);
             });
             break;
           }
 
         case /^2[0-9]{2}$/.test(response.status_code):
           {
             this._status = C.STATUS_CONFIRMED;
 
             if (!response.body) {
               this._acceptAndTerminate(response, 400, JsSIP_C.causes.MISSING_SDP);
 
               this._failed('remote', response, JsSIP_C.causes.BAD_MEDIA_DESCRIPTION);
 
               break;
             } // An error on dialog creation will fire 'failed' event.
 
 
             if (!this._createDialog(response, 'UAC')) {
               break;
             }
 
             var _e = {
               originator: 'remote',
               type: 'answer',
               sdp: response.body
             };
             debug('emit "sdp"');
             this.emit('sdp', _e);
 
             var _answer = new RTCSessionDescription({
               type: 'answer',
               sdp: _e.sdp
             });
 
             this._connectionPromiseQueue = this._connectionPromiseQueue.then(function () {
               // Be ready for 200 with SDP after a 180/183 with SDP.
               // We created a SDP 'answer' for it, so check the current signaling state.
               if (_this22._connection.signalingState === 'stable') {
                 return _this22._connection.createOffer(_this22._rtcOfferConstraints).then(function (offer) {
                   return _this22._connection.setLocalDescription(offer);
                 })["catch"](function (error) {
                   _this22._acceptAndTerminate(response, 500, error.toString());
 
                   _this22._failed('local', response, JsSIP_C.causes.WEBRTC_ERROR);
                 });
               }
             }).then(function () {
               _this22._connection.setRemoteDescription(_answer).then(function () {
                 // Handle Session Timers.
                 _this22._handleSessionTimersInIncomingResponse(response);
 
                 _this22._accepted('remote', response);
 
                 _this22.sendRequest(JsSIP_C.ACK);
 
                 _this22._confirmed('local', null);
               })["catch"](function (error) {
                 _this22._acceptAndTerminate(response, 488, 'Not Acceptable Here');
 
                 _this22._failed('remote', response, JsSIP_C.causes.BAD_MEDIA_DESCRIPTION);
 
                 debugerror('emit "peerconnection:setremotedescriptionfailed" [error:%o]', error);
 
                 _this22.emit('peerconnection:setremotedescriptionfailed', error);
               });
             });
             break;
           }
 
         default:
           {
             var cause = Utils.sipErrorCause(response.status_code);
 
             this._failed('remote', response, cause);
           }
       }
     }
     /**
      * Send Re-INVITE
      */
 
   }, {
     key: "_sendReinvite",
     value: function _sendReinvite() {
       var _this23 = this;
 
       var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
       debug('sendReinvite()');
       var extraHeaders = Utils.cloneArray(options.extraHeaders);
       var eventHandlers = Utils.cloneObject(options.eventHandlers);
       var rtcOfferConstraints = options.rtcOfferConstraints || this._rtcOfferConstraints || null;
       var succeeded = false;
       extraHeaders.push("Contact: ".concat(this._contact));
       extraHeaders.push('Content-Type: application/sdp'); // Session Timers.
 
       if (this._sessionTimers.running) {
         extraHeaders.push("Session-Expires: ".concat(this._sessionTimers.currentExpires, ";refresher=").concat(this._sessionTimers.refresher ? 'uac' : 'uas'));
       }
 
       this._connectionPromiseQueue = this._connectionPromiseQueue.then(function () {
         return _this23._createLocalDescription('offer', rtcOfferConstraints);
       }).then(function (sdp) {
         sdp = _this23._mangleOffer(sdp);
         var e = {
           originator: 'local',
           type: 'offer',
           sdp: sdp
         };
         debug('emit "sdp"');
 
         _this23.emit('sdp', e);
 
         _this23.sendRequest(JsSIP_C.INVITE, {
           extraHeaders: extraHeaders,
           body: sdp,
           eventHandlers: {
             onSuccessResponse: function onSuccessResponse(response) {
               onSucceeded.call(_this23, response);
               succeeded = true;
             },
             onErrorResponse: function onErrorResponse(response) {
               onFailed.call(_this23, response);
             },
             onTransportError: function onTransportError() {
               _this23.onTransportError(); // Do nothing because session ends.
 
             },
             onRequestTimeout: function onRequestTimeout() {
               _this23.onRequestTimeout(); // Do nothing because session ends.
 
             },
             onDialogError: function onDialogError() {
               _this23.onDialogError(); // Do nothing because session ends.
 
             }
           }
         });
       })["catch"](function () {
         onFailed();
       });
 
       function onSucceeded(response) {
         var _this24 = this;
 
         if (this._status === C.STATUS_TERMINATED) {
           return;
         }
 
         this.sendRequest(JsSIP_C.ACK); // If it is a 2XX retransmission exit now.
 
         if (succeeded) {
           return;
         } // Handle Session Timers.
 
 
         this._handleSessionTimersInIncomingResponse(response); // Must have SDP answer.
 
 
         if (!response.body) {
           onFailed.call(this);
           return;
         } else if (!response.hasHeader('Content-Type') || response.getHeader('Content-Type').toLowerCase() !== 'application/sdp') {
           onFailed.call(this);
           return;
         }
 
         var e = {
           originator: 'remote',
           type: 'answer',
           sdp: response.body
         };
         debug('emit "sdp"');
         this.emit('sdp', e);
         var answer = new RTCSessionDescription({
           type: 'answer',
           sdp: e.sdp
         });
         this._connectionPromiseQueue = this._connectionPromiseQueue.then(function () {
           return _this24._connection.setRemoteDescription(answer);
         }).then(function () {
           if (eventHandlers.succeeded) {
             eventHandlers.succeeded(response);
           }
         })["catch"](function (error) {
           onFailed.call(_this24);
           debugerror('emit "peerconnection:setremotedescriptionfailed" [error:%o]', error);
 
           _this24.emit('peerconnection:setremotedescriptionfailed', error);
         });
       }
 
       function onFailed(response) {
         if (eventHandlers.failed) {
           eventHandlers.failed(response);
         }
       }
     }
     /**
      * Send UPDATE
      */
 
   }, {
     key: "_sendUpdate",
     value: function _sendUpdate() {
       var _this25 = this;
 
       var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
       debug('sendUpdate()');
       var extraHeaders = Utils.cloneArray(options.extraHeaders);
       var eventHandlers = Utils.cloneObject(options.eventHandlers);
       var rtcOfferConstraints = options.rtcOfferConstraints || this._rtcOfferConstraints || null;
       var sdpOffer = options.sdpOffer || false;
       var succeeded = false;
       extraHeaders.push("Contact: ".concat(this._contact)); // Session Timers.
 
       if (this._sessionTimers.running) {
         extraHeaders.push("Session-Expires: ".concat(this._sessionTimers.currentExpires, ";refresher=").concat(this._sessionTimers.refresher ? 'uac' : 'uas'));
       }
 
       if (sdpOffer) {
         extraHeaders.push('Content-Type: application/sdp');
         this._connectionPromiseQueue = this._connectionPromiseQueue.then(function () {
           return _this25._createLocalDescription('offer', rtcOfferConstraints);
         }).then(function (sdp) {
           sdp = _this25._mangleOffer(sdp);
           var e = {
             originator: 'local',
             type: 'offer',
             sdp: sdp
           };
           debug('emit "sdp"');
 
           _this25.emit('sdp', e);
 
           _this25.sendRequest(JsSIP_C.UPDATE, {
             extraHeaders: extraHeaders,
             body: sdp,
             eventHandlers: {
               onSuccessResponse: function onSuccessResponse(response) {
                 onSucceeded.call(_this25, response);
                 succeeded = true;
               },
               onErrorResponse: function onErrorResponse(response) {
                 onFailed.call(_this25, response);
               },
               onTransportError: function onTransportError() {
                 _this25.onTransportError(); // Do nothing because session ends.
 
               },
               onRequestTimeout: function onRequestTimeout() {
                 _this25.onRequestTimeout(); // Do nothing because session ends.
 
               },
               onDialogError: function onDialogError() {
                 _this25.onDialogError(); // Do nothing because session ends.
 
               }
             }
           });
         })["catch"](function () {
           onFailed.call(_this25);
         });
       } // No SDP.
       else {
           this.sendRequest(JsSIP_C.UPDATE, {
             extraHeaders: extraHeaders,
             eventHandlers: {
               onSuccessResponse: function onSuccessResponse(response) {
                 onSucceeded.call(_this25, response);
               },
               onErrorResponse: function onErrorResponse(response) {
                 onFailed.call(_this25, response);
               },
               onTransportError: function onTransportError() {
                 _this25.onTransportError(); // Do nothing because session ends.
 
               },
               onRequestTimeout: function onRequestTimeout() {
                 _this25.onRequestTimeout(); // Do nothing because session ends.
 
               },
               onDialogError: function onDialogError() {
                 _this25.onDialogError(); // Do nothing because session ends.
 
               }
             }
           });
         }
 
       function onSucceeded(response) {
         var _this26 = this;
 
         if (this._status === C.STATUS_TERMINATED) {
           return;
         } // If it is a 2XX retransmission exit now.
 
 
         if (succeeded) {
           return;
         } // Handle Session Timers.
 
 
         this._handleSessionTimersInIncomingResponse(response); // Must have SDP answer.
 
 
         if (sdpOffer) {
           if (!response.body) {
             onFailed.call(this);
             return;
           } else if (!response.hasHeader('Content-Type') || response.getHeader('Content-Type').toLowerCase() !== 'application/sdp') {
             onFailed.call(this);
             return;
           }
 
           var e = {
             originator: 'remote',
             type: 'answer',
             sdp: response.body
           };
           debug('emit "sdp"');
           this.emit('sdp', e);
           var answer = new RTCSessionDescription({
             type: 'answer',
             sdp: e.sdp
           });
           this._connectionPromiseQueue = this._connectionPromiseQueue.then(function () {
             return _this26._connection.setRemoteDescription(answer);
           }).then(function () {
             if (eventHandlers.succeeded) {
               eventHandlers.succeeded(response);
             }
           })["catch"](function (error) {
             onFailed.call(_this26);
             debugerror('emit "peerconnection:setremotedescriptionfailed" [error:%o]', error);
 
             _this26.emit('peerconnection:setremotedescriptionfailed', error);
           });
         } // No SDP answer.
         else if (eventHandlers.succeeded) {
             eventHandlers.succeeded(response);
           }
       }
 
       function onFailed(response) {
         if (eventHandlers.failed) {
           eventHandlers.failed(response);
         }
       }
     }
   }, {
     key: "_acceptAndTerminate",
     value: function _acceptAndTerminate(response, status_code, reason_phrase) {
       debug('acceptAndTerminate()');
       var extraHeaders = [];
 
       if (status_code) {
         reason_phrase = reason_phrase || JsSIP_C.REASON_PHRASE[status_code] || '';
         extraHeaders.push("Reason: SIP ;cause=".concat(status_code, "; text=\"").concat(reason_phrase, "\""));
       } // An error on dialog creation will fire 'failed' event.
 
 
       if (this._dialog || this._createDialog(response, 'UAC')) {
         this.sendRequest(JsSIP_C.ACK);
         this.sendRequest(JsSIP_C.BYE, {
           extraHeaders: extraHeaders
         });
       } // Update session status.
 
 
       this._status = C.STATUS_TERMINATED;
     }
     /**
      * Correctly set the SDP direction attributes if the call is on local hold
      */
 
   }, {
     key: "_mangleOffer",
     value: function _mangleOffer(sdp) {
       if (!this._localHold && !this._remoteHold) {
         return sdp;
       }
 
       sdp = sdp_transform.parse(sdp); // Local hold.
 
       if (this._localHold && !this._remoteHold) {
         debug('mangleOffer() | me on hold, mangling offer');
 
         var _iterator5 = _createForOfIteratorHelper(sdp.media),
             _step5;
 
         try {
           for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
             var m = _step5.value;
 
             if (holdMediaTypes.indexOf(m.type) === -1) {
               continue;
             }
 
             if (!m.direction) {
               m.direction = 'sendonly';
             } else if (m.direction === 'sendrecv') {
               m.direction = 'sendonly';
             } else if (m.direction === 'recvonly') {
               m.direction = 'inactive';
             }
           }
         } catch (err) {
           _iterator5.e(err);
         } finally {
           _iterator5.f();
         }
       } // Local and remote hold.
       else if (this._localHold && this._remoteHold) {
           debug('mangleOffer() | both on hold, mangling offer');
 
           var _iterator6 = _createForOfIteratorHelper(sdp.media),
               _step6;
 
           try {
             for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
               var _m = _step6.value;
 
               if (holdMediaTypes.indexOf(_m.type) === -1) {
                 continue;
               }
 
               _m.direction = 'inactive';
             }
           } catch (err) {
             _iterator6.e(err);
           } finally {
             _iterator6.f();
           }
         } // Remote hold.
         else if (this._remoteHold) {
             debug('mangleOffer() | remote on hold, mangling offer');
 
             var _iterator7 = _createForOfIteratorHelper(sdp.media),
                 _step7;
 
             try {
               for (_iterator7.s(); !(_step7 = _iterator7.n()).done;) {
                 var _m2 = _step7.value;
 
                 if (holdMediaTypes.indexOf(_m2.type) === -1) {
                   continue;
                 }
 
                 if (!_m2.direction) {
                   _m2.direction = 'recvonly';
                 } else if (_m2.direction === 'sendrecv') {
                   _m2.direction = 'recvonly';
                 } else if (_m2.direction === 'recvonly') {
                   _m2.direction = 'inactive';
                 }
               }
             } catch (err) {
               _iterator7.e(err);
             } finally {
               _iterator7.f();
             }
           }
 
       return sdp_transform.write(sdp);
     }
   }, {
     key: "_setLocalMediaStatus",
     value: function _setLocalMediaStatus() {
       var enableAudio = true,
           enableVideo = true;
 
       if (this._localHold || this._remoteHold) {
         enableAudio = false;
         enableVideo = false;
       }
 
       if (this._audioMuted) {
         enableAudio = false;
       }
 
       if (this._videoMuted) {
         enableVideo = false;
       }
 
       this._toggleMuteAudio(!enableAudio);
 
       this._toggleMuteVideo(!enableVideo);
     }
     /**
      * Handle SessionTimers for an incoming INVITE or UPDATE.
      * @param  {IncomingRequest} request
      * @param  {Array} responseExtraHeaders  Extra headers for the 200 response.
      */
 
   }, {
     key: "_handleSessionTimersInIncomingRequest",
     value: function _handleSessionTimersInIncomingRequest(request, responseExtraHeaders) {
       if (!this._sessionTimers.enabled) {
         return;
       }
 
       var session_expires_refresher;
 
       if (request.session_expires && request.session_expires >= JsSIP_C.MIN_SESSION_EXPIRES) {
         this._sessionTimers.currentExpires = request.session_expires;
         session_expires_refresher = request.session_expires_refresher || 'uas';
       } else {
         this._sessionTimers.currentExpires = this._sessionTimers.defaultExpires;
         session_expires_refresher = 'uas';
       }
 
       responseExtraHeaders.push("Session-Expires: ".concat(this._sessionTimers.currentExpires, ";refresher=").concat(session_expires_refresher));
       this._sessionTimers.refresher = session_expires_refresher === 'uas';
 
       this._runSessionTimer();
     }
     /**
      * Handle SessionTimers for an incoming response to INVITE or UPDATE.
      * @param  {IncomingResponse} response
      */
 
   }, {
     key: "_handleSessionTimersInIncomingResponse",
     value: function _handleSessionTimersInIncomingResponse(response) {
       if (!this._sessionTimers.enabled) {
         return;
       }
 
       var session_expires_refresher;
 
       if (response.session_expires && response.session_expires >= JsSIP_C.MIN_SESSION_EXPIRES) {
         this._sessionTimers.currentExpires = response.session_expires;
         session_expires_refresher = response.session_expires_refresher || 'uac';
       } else {
         this._sessionTimers.currentExpires = this._sessionTimers.defaultExpires;
         session_expires_refresher = 'uac';
       }
 
       this._sessionTimers.refresher = session_expires_refresher === 'uac';
 
       this._runSessionTimer();
     }
   }, {
     key: "_runSessionTimer",
     value: function _runSessionTimer() {
       var _this27 = this;
 
       var expires = this._sessionTimers.currentExpires;
       this._sessionTimers.running = true;
       clearTimeout(this._sessionTimers.timer); // I'm the refresher.
 
       if (this._sessionTimers.refresher) {
         this._sessionTimers.timer = setTimeout(function () {
           if (_this27._status === C.STATUS_TERMINATED) {
             return;
           }
 
           debug('runSessionTimer() | sending session refresh request');
 
           if (_this27._sessionTimers.refreshMethod === JsSIP_C.UPDATE) {
             _this27._sendUpdate();
           } else {
             _this27._sendReinvite();
           }
         }, expires * 500); // Half the given interval (as the RFC states).
       } // I'm not the refresher.
       else {
           this._sessionTimers.timer = setTimeout(function () {
             if (_this27._status === C.STATUS_TERMINATED) {
               return;
             }
 
             debugerror('runSessionTimer() | timer expired, terminating the session');
 
             _this27.terminate({
               cause: JsSIP_C.causes.REQUEST_TIMEOUT,
               status_code: 408,
               reason_phrase: 'Session Timer Expired'
             });
           }, expires * 1100);
         }
     }
   }, {
     key: "_toggleMuteAudio",
     value: function _toggleMuteAudio(mute) {
       var senders = this._connection.getSenders().filter(function (sender) {
         return sender.track && sender.track.kind === 'audio';
       });
 
       var _iterator8 = _createForOfIteratorHelper(senders),
           _step8;
 
       try {
         for (_iterator8.s(); !(_step8 = _iterator8.n()).done;) {
           var sender = _step8.value;
           sender.track.enabled = !mute;
         }
       } catch (err) {
         _iterator8.e(err);
       } finally {
         _iterator8.f();
       }
     }
   }, {
     key: "_toggleMuteVideo",
     value: function _toggleMuteVideo(mute) {
       var senders = this._connection.getSenders().filter(function (sender) {
         return sender.track && sender.track.kind === 'video';
       });
 
       var _iterator9 = _createForOfIteratorHelper(senders),
           _step9;
 
       try {
         for (_iterator9.s(); !(_step9 = _iterator9.n()).done;) {
           var sender = _step9.value;
           sender.track.enabled = !mute;
         }
       } catch (err) {
         _iterator9.e(err);
       } finally {
         _iterator9.f();
       }
     }
   }, {
     key: "_newRTCSession",
     value: function _newRTCSession(originator, request) {
       debug('newRTCSession()');
 
       this._ua.newRTCSession(this, {
         originator: originator,
         session: this,
         request: request
       });
     }
   }, {
     key: "_connecting",
     value: function _connecting(request) {
       debug('session connecting');
       debug('emit "connecting"');
       this.emit('connecting', {
         request: request
       });
     }
   }, {
     key: "_progress",
     value: function _progress(originator, response) {
       debug('session progress');
       debug('emit "progress"');
       this.emit('progress', {
         originator: originator,
         response: response || null
       });
     }
   }, {
     key: "_accepted",
     value: function _accepted(originator, message) {
       debug('session accepted');
       this._start_time = new Date();
       debug('emit "accepted"');
       this.emit('accepted', {
         originator: originator,
         response: message || null
       });
     }
   }, {
     key: "_confirmed",
     value: function _confirmed(originator, ack) {
       debug('session confirmed');
       this._is_confirmed = true;
       debug('emit "confirmed"');
       this.emit('confirmed', {
         originator: originator,
         ack: ack || null
       });
     }
   }, {
     key: "_ended",
     value: function _ended(originator, message, cause) {
       debug('session ended');
       this._end_time = new Date();
 
       this._close();
 
       debug('emit "ended"');
       this.emit('ended', {
         originator: originator,
         message: message || null,
         cause: cause
       });
     }
   }, {
     key: "_failed",
     value: function _failed(originator, message, cause) {
       debug('session failed'); // Emit private '_failed' event first.
 
       debug('emit "_failed"');
       this.emit('_failed', {
         originator: originator,
         message: message || null,
         cause: cause
       });
 
       this._close();
 
       debug('emit "failed"');
       this.emit('failed', {
         originator: originator,
         message: message || null,
         cause: cause
       });
     }
   }, {
     key: "_onhold",
     value: function _onhold(originator) {
       debug('session onhold');
 
       this._setLocalMediaStatus();
 
       debug('emit "hold"');
       this.emit('hold', {
         originator: originator
       });
     }
   }, {
     key: "_onunhold",
     value: function _onunhold(originator) {
       debug('session onunhold');
 
       this._setLocalMediaStatus();
 
       debug('emit "unhold"');
       this.emit('unhold', {
         originator: originator
       });
     }
   }, {
     key: "_onmute",
     value: function _onmute(_ref5) {
       var audio = _ref5.audio,
           video = _ref5.video;
       debug('session onmute');
 
       this._setLocalMediaStatus();
 
       debug('emit "muted"');
       this.emit('muted', {
         audio: audio,
         video: video
       });
     }
   }, {
     key: "_onunmute",
     value: function _onunmute(_ref6) {
       var audio = _ref6.audio,
           video = _ref6.video;
       debug('session onunmute');
 
       this._setLocalMediaStatus();
 
       debug('emit "unmuted"');
       this.emit('unmuted', {
         audio: audio,
         video: video
       });
     }
   }, {
     key: "C",
     get: function get() {
       return C;
     } // Expose session failed/ended causes as a property of the RTCSession instance.
 
   }, {
     key: "causes",
     get: function get() {
       return JsSIP_C.causes;
     }
   }, {
     key: "id",
     get: function get() {
       return this._id;
     }
   }, {
     key: "connection",
     get: function get() {
       return this._connection;
     }
   }, {
     key: "contact",
     get: function get() {
       return this._contact;
     }
   }, {
     key: "direction",
     get: function get() {
       return this._direction;
     }
   }, {
     key: "local_identity",
     get: function get() {
       return this._local_identity;
     }
   }, {
     key: "remote_identity",
     get: function get() {
       return this._remote_identity;
     }
   }, {
     key: "start_time",
     get: function get() {
       return this._start_time;
     }
   }, {
     key: "end_time",
     get: function get() {
       return this._end_time;
     }
   }, {
     key: "data",
     get: function get() {
       return this._data;
     },
     set: function set(_data) {
       this._data = _data;
     }
   }, {
     key: "status",
     get: function get() {
       return this._status;
     }
   }]);
 
   return RTCSession;
 }(EventEmitter);
 },{"./Constants":2,"./Dialog":3,"./Exceptions":6,"./RTCSession/DTMF":13,"./RTCSession/Info":14,"./RTCSession/ReferNotifier":15,"./RTCSession/ReferSubscriber":16,"./RequestSender":18,"./SIPMessage":19,"./Timers":21,"./Transactions":22,"./URI":25,"./Utils":26,"debug":30,"events":29,"sdp-transform":35}],13:[function(require,module,exports){
 "use strict";
 
 function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
 
 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
 function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
 
 function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
 
 function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
 
 function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
 
 function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
 
 function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
 
 function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
 
 function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }
 
 function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
 
 var EventEmitter = require('events').EventEmitter;
 
 var JsSIP_C = require('../Constants');
 
 var Exceptions = require('../Exceptions');
 
 var Utils = require('../Utils');
 
 var debug = require('debug')('JsSIP:RTCSession:DTMF');
 
 var debugerror = require('debug')('JsSIP:ERROR:RTCSession:DTMF');
 
 debugerror.log = console.warn.bind(console);
 var C = {
   MIN_DURATION: 70,
   MAX_DURATION: 6000,
   DEFAULT_DURATION: 100,
   MIN_INTER_TONE_GAP: 50,
   DEFAULT_INTER_TONE_GAP: 500
 };
 
 module.exports = /*#__PURE__*/function (_EventEmitter) {
   _inherits(DTMF, _EventEmitter);
 
   var _super = _createSuper(DTMF);
 
   function DTMF(session) {
     var _this;
 
     _classCallCheck(this, DTMF);
 
     _this = _super.call(this);
     _this._session = session;
     _this._direction = null;
     _this._tone = null;
     _this._duration = null;
     _this._request = null;
     return _this;
   }
 
   _createClass(DTMF, [{
     key: "send",
     value: function send(tone) {
       var _this2 = this;
 
       var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
 
       if (tone === undefined) {
         throw new TypeError('Not enough arguments');
       }
 
       this._direction = 'outgoing'; // Check RTCSession Status.
 
       if (this._session.status !== this._session.C.STATUS_CONFIRMED && this._session.status !== this._session.C.STATUS_WAITING_FOR_ACK) {
         throw new Exceptions.InvalidStateError(this._session.status);
       }
 
       var extraHeaders = Utils.cloneArray(options.extraHeaders);
       this.eventHandlers = Utils.cloneObject(options.eventHandlers); // Check tone type.
 
       if (typeof tone === 'string') {
         tone = tone.toUpperCase();
       } else if (typeof tone === 'number') {
         tone = tone.toString();
       } else {
         throw new TypeError("Invalid tone: ".concat(tone));
       } // Check tone value.
 
 
       if (!tone.match(/^[0-9A-DR#*]$/)) {
         throw new TypeError("Invalid tone: ".concat(tone));
       } else {
         this._tone = tone;
       } // Duration is checked/corrected in RTCSession.
 
 
       this._duration = options.duration;
       extraHeaders.push('Content-Type: application/dtmf-relay');
       var body = "Signal=".concat(this._tone, "\r\n");
       body += "Duration=".concat(this._duration);
 
       this._session.newDTMF({
         originator: 'local',
         dtmf: this,
         request: this._request
       });
 
       this._session.sendRequest(JsSIP_C.INFO, {
         extraHeaders: extraHeaders,
         eventHandlers: {
           onSuccessResponse: function onSuccessResponse(response) {
             _this2.emit('succeeded', {
               originator: 'remote',
               response: response
             });
           },
           onErrorResponse: function onErrorResponse(response) {
             if (_this2.eventHandlers.onFailed) {
               _this2.eventHandlers.onFailed();
             }
 
             _this2.emit('failed', {
               originator: 'remote',
               response: response
             });
           },
           onRequestTimeout: function onRequestTimeout() {
             _this2._session.onRequestTimeout();
           },
           onTransportError: function onTransportError() {
             _this2._session.onTransportError();
           },
           onDialogError: function onDialogError() {
             _this2._session.onDialogError();
           }
         },
         body: body
       });
     }
   }, {
     key: "init_incoming",
     value: function init_incoming(request) {
       var reg_tone = /^(Signal\s*?=\s*?)([0-9A-D#*]{1})(\s)?.*/;
       var reg_duration = /^(Duration\s?=\s?)([0-9]{1,4})(\s)?.*/;
       this._direction = 'incoming';
       this._request = request;
       request.reply(200);
 
       if (request.body) {
         var body = request.body.split('\n');
 
         if (body.length >= 1) {
           if (reg_tone.test(body[0])) {
             this._tone = body[0].replace(reg_tone, '$2');
           }
         }
 
         if (body.length >= 2) {
           if (reg_duration.test(body[1])) {
             this._duration = parseInt(body[1].replace(reg_duration, '$2'), 10);
           }
         }
       }
 
       if (!this._duration) {
         this._duration = C.DEFAULT_DURATION;
       }
 
       if (!this._tone) {
         debug('invalid INFO DTMF received, discarded');
       } else {
         this._session.newDTMF({
           originator: 'remote',
           dtmf: this,
           request: request
         });
       }
     }
   }, {
     key: "tone",
     get: function get() {
       return this._tone;
     }
   }, {
     key: "duration",
     get: function get() {
       return this._duration;
     }
   }]);
 
   return DTMF;
 }(EventEmitter);
 /**
  * Expose C object.
  */
 
 
 module.exports.C = C;
 },{"../Constants":2,"../Exceptions":6,"../Utils":26,"debug":30,"events":29}],14:[function(require,module,exports){
 "use strict";
 
 function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
 
 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
 function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
 
 function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
 
 function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
 
 function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
 
 function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
 
 function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
 
 function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
 
 function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }
 
 function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
 
 var EventEmitter = require('events').EventEmitter;
 
 var debugerror = require('debug')('JsSIP:ERROR:RTCSession:Info');
 
 debugerror.log = console.warn.bind(console);
 
 var JsSIP_C = require('../Constants');
 
 var Exceptions = require('../Exceptions');
 
 var Utils = require('../Utils');
 
 module.exports = /*#__PURE__*/function (_EventEmitter) {
   _inherits(Info, _EventEmitter);
 
   var _super = _createSuper(Info);
 
   function Info(session) {
     var _this;
 
     _classCallCheck(this, Info);
 
     _this = _super.call(this);
     _this._session = session;
     _this._direction = null;
     _this._contentType = null;
     _this._body = null;
     return _this;
   }
 
   _createClass(Info, [{
     key: "send",
     value: function send(contentType, body) {
       var _this2 = this;
 
       var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
       this._direction = 'outgoing';
 
       if (contentType === undefined) {
         throw new TypeError('Not enough arguments');
       } // Check RTCSession Status.
 
 
       if (this._session.status !== this._session.C.STATUS_CONFIRMED && this._session.status !== this._session.C.STATUS_WAITING_FOR_ACK) {
         throw new Exceptions.InvalidStateError(this._session.status);
       }
 
       this._contentType = contentType;
       this._body = body;
       var extraHeaders = Utils.cloneArray(options.extraHeaders);
       extraHeaders.push("Content-Type: ".concat(contentType));
 
       this._session.newInfo({
         originator: 'local',
         info: this,
         request: this.request
       });
 
       this._session.sendRequest(JsSIP_C.INFO, {
         extraHeaders: extraHeaders,
         eventHandlers: {
           onSuccessResponse: function onSuccessResponse(response) {
             _this2.emit('succeeded', {
               originator: 'remote',
               response: response
             });
           },
           onErrorResponse: function onErrorResponse(response) {
             _this2.emit('failed', {
               originator: 'remote',
               response: response
             });
           },
           onTransportError: function onTransportError() {
             _this2._session.onTransportError();
           },
           onRequestTimeout: function onRequestTimeout() {
             _this2._session.onRequestTimeout();
           },
           onDialogError: function onDialogError() {
             _this2._session.onDialogError();
           }
         },
         body: body
       });
     }
   }, {
     key: "init_incoming",
     value: function init_incoming(request) {
       this._direction = 'incoming';
       this.request = request;
       request.reply(200);
       this._contentType = request.hasHeader('Content-Type') ? request.getHeader('Content-Type').toLowerCase() : undefined;
       this._body = request.body;
 
       this._session.newInfo({
         originator: 'remote',
         info: this,
         request: request
       });
     }
   }, {
     key: "contentType",
     get: function get() {
       return this._contentType;
     }
   }, {
     key: "body",
     get: function get() {
       return this._body;
     }
   }]);
 
   return Info;
 }(EventEmitter);
 },{"../Constants":2,"../Exceptions":6,"../Utils":26,"debug":30,"events":29}],15:[function(require,module,exports){
 "use strict";
 
 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
 function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
 
 function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
 
 var JsSIP_C = require('../Constants');
 
 var debug = require('debug')('JsSIP:RTCSession:ReferNotifier');
 
 var C = {
   event_type: 'refer',
   body_type: 'message/sipfrag;version=2.0',
   expires: 300
 };
 
 module.exports = /*#__PURE__*/function () {
   function ReferNotifier(session, id, expires) {
     _classCallCheck(this, ReferNotifier);
 
     this._session = session;
     this._id = id;
     this._expires = expires || C.expires;
     this._active = true; // The creation of a Notifier results in an immediate NOTIFY.
 
     this.notify(100);
   }
 
   _createClass(ReferNotifier, [{
     key: "notify",
     value: function notify(code, reason) {
       debug('notify()');
 
       if (this._active === false) {
         return;
       }
 
       reason = reason || JsSIP_C.REASON_PHRASE[code] || '';
       var state;
 
       if (code >= 200) {
         state = 'terminated;reason=noresource';
       } else {
         state = "active;expires=".concat(this._expires);
       } // Put this in a try/catch block.
 
 
       this._session.sendRequest(JsSIP_C.NOTIFY, {
         extraHeaders: ["Event: ".concat(C.event_type, ";id=").concat(this._id), "Subscription-State: ".concat(state), "Content-Type: ".concat(C.body_type)],
         body: "SIP/2.0 ".concat(code, " ").concat(reason),
         eventHandlers: {
           // If a negative response is received, subscription is canceled.
           onErrorResponse: function onErrorResponse() {
             this._active = false;
           }
         }
       });
     }
   }]);
 
   return ReferNotifier;
 }();
 },{"../Constants":2,"debug":30}],16:[function(require,module,exports){
 "use strict";
 
 function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
 
 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
 function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
 
 function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
 
 function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
 
 function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
 
 function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
 
 function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
 
 function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
 
 function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }
 
 function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
 
 var EventEmitter = require('events').EventEmitter;
 
 var JsSIP_C = require('../Constants');
 
 var Grammar = require('../Grammar');
 
 var Utils = require('../Utils');
 
 var debug = require('debug')('JsSIP:RTCSession:ReferSubscriber');
 
 module.exports = /*#__PURE__*/function (_EventEmitter) {
   _inherits(ReferSubscriber, _EventEmitter);
 
   var _super = _createSuper(ReferSubscriber);
 
   function ReferSubscriber(session) {
     var _this;
 
     _classCallCheck(this, ReferSubscriber);
 
     _this = _super.call(this);
     _this._id = null;
     _this._session = session;
     return _this;
   }
 
   _createClass(ReferSubscriber, [{
     key: "sendRefer",
     value: function sendRefer(target) {
       var _this2 = this;
 
       var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
       debug('sendRefer()');
       var extraHeaders = Utils.cloneArray(options.extraHeaders);
       var eventHandlers = Utils.cloneObject(options.eventHandlers); // Set event handlers.
 
       for (var event in eventHandlers) {
         if (Object.prototype.hasOwnProperty.call(eventHandlers, event)) {
           this.on(event, eventHandlers[event]);
         }
       } // Replaces URI header field.
 
 
       var replaces = null;
 
       if (options.replaces) {
         replaces = options.replaces._request.call_id;
         replaces += ";to-tag=".concat(options.replaces._to_tag);
         replaces += ";from-tag=".concat(options.replaces._from_tag);
         replaces = encodeURIComponent(replaces);
       } // Refer-To header field.
 
 
       var referTo = "Refer-To: <".concat(target).concat(replaces ? "?Replaces=".concat(replaces) : '', ">");
       extraHeaders.push(referTo); // Referred-By header field.
 
       var referredBy = "Referred-By: <".concat(this._session._ua._configuration.uri._scheme, ":").concat(this._session._ua._configuration.uri._user, "@").concat(this._session._ua._configuration.uri._host, ">");
       extraHeaders.push(referredBy);
       extraHeaders.push("Contact: ".concat(this._session.contact));
 
       var request = this._session.sendRequest(JsSIP_C.REFER, {
         extraHeaders: extraHeaders,
         eventHandlers: {
           onSuccessResponse: function onSuccessResponse(response) {
             _this2._requestSucceeded(response);
           },
           onErrorResponse: function onErrorResponse(response) {
             _this2._requestFailed(response, JsSIP_C.causes.REJECTED);
           },
           onTransportError: function onTransportError() {
             _this2._requestFailed(null, JsSIP_C.causes.CONNECTION_ERROR);
           },
           onRequestTimeout: function onRequestTimeout() {
             _this2._requestFailed(null, JsSIP_C.causes.REQUEST_TIMEOUT);
           },
           onDialogError: function onDialogError() {
             _this2._requestFailed(null, JsSIP_C.causes.DIALOG_ERROR);
           }
         }
       });
 
       this._id = request.cseq;
     }
   }, {
     key: "receiveNotify",
     value: function receiveNotify(request) {
       debug('receiveNotify()');
 
       if (!request.body) {
         return;
       }
 
       var status_line = Grammar.parse(request.body.trim(), 'Status_Line');
 
       if (status_line === -1) {
         debug("receiveNotify() | error parsing NOTIFY body: \"".concat(request.body, "\""));
         return;
       }
 
       switch (true) {
         case /^100$/.test(status_line.status_code):
           this.emit('trying', {
             request: request,
             status_line: status_line
           });
           break;
 
         case /^1[0-9]{2}$/.test(status_line.status_code):
           this.emit('progress', {
             request: request,
             status_line: status_line
           });
           break;
 
         case /^2[0-9]{2}$/.test(status_line.status_code):
           this.emit('accepted', {
             request: request,
             status_line: status_line
           });
           break;
 
         default:
           this.emit('failed', {
             request: request,
             status_line: status_line
           });
           break;
       }
     }
   }, {
     key: "_requestSucceeded",
     value: function _requestSucceeded(response) {
       debug('REFER succeeded');
       debug('emit "requestSucceeded"');
       this.emit('requestSucceeded', {
         response: response
       });
     }
   }, {
     key: "_requestFailed",
     value: function _requestFailed(response, cause) {
       debug('REFER failed');
       debug('emit "requestFailed"');
       this.emit('requestFailed', {
         response: response || null,
         cause: cause
       });
     }
   }, {
     key: "id",
     get: function get() {
       return this._id;
     }
   }]);
 
   return ReferSubscriber;
 }(EventEmitter);
 },{"../Constants":2,"../Grammar":7,"../Utils":26,"debug":30,"events":29}],17:[function(require,module,exports){
 "use strict";
 
 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
 function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
 
 function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
 
 var Utils = require('./Utils');
 
 var JsSIP_C = require('./Constants');
 
 var SIPMessage = require('./SIPMessage');
 
 var RequestSender = require('./RequestSender');
 
 var debug = require('debug')('JsSIP:Registrator');
 
 var MIN_REGISTER_EXPIRES = 10; // In seconds.
 
 module.exports = /*#__PURE__*/function () {
   function Registrator(ua, transport) {
     _classCallCheck(this, Registrator);
 
     var reg_id = 1; // Force reg_id to 1.
 
     this._ua = ua;
     this._transport = transport;
     this._registrar = ua.configuration.registrar_server;
     this._expires = ua.configuration.register_expires; // Call-ID and CSeq values RFC3261 10.2.
 
     this._call_id = Utils.createRandomToken(22);
     this._cseq = 0;
     this._to_uri = ua.configuration.uri;
     this._registrationTimer = null; // Ongoing Register request.
 
     this._registering = false; // Set status.
 
     this._registered = false; // Contact header.
 
     this._contact = this._ua.contact.toString(); // Sip.ice media feature tag (RFC 5768).
 
     this._contact += ';+sip.ice'; // Custom headers for REGISTER and un-REGISTER.
 
     this._extraHeaders = []; // Custom Contact header params for REGISTER and un-REGISTER.
 
     this._extraContactParams = '';
 
     if (reg_id) {
       this._contact += ";reg-id=".concat(reg_id);
       this._contact += ";+sip.instance=\"<urn:uuid:".concat(this._ua.configuration.instance_id, ">\"");
     }
   }
 
   _createClass(Registrator, [{
     key: "setExtraHeaders",
     value: function setExtraHeaders(extraHeaders) {
       if (!Array.isArray(extraHeaders)) {
         extraHeaders = [];
       }
 
       this._extraHeaders = extraHeaders.slice();
     }
   }, {
     key: "setExtraContactParams",
     value: function setExtraContactParams(extraContactParams) {
       if (!(extraContactParams instanceof Object)) {
         extraContactParams = {};
       } // Reset it.
 
 
       this._extraContactParams = '';
 
       for (var param_key in extraContactParams) {
         if (Object.prototype.hasOwnProperty.call(extraContactParams, param_key)) {
           var param_value = extraContactParams[param_key];
           this._extraContactParams += ";".concat(param_key);
 
           if (param_value) {
             this._extraContactParams += "=".concat(param_value);
           }
         }
       }
     }
   }, {
     key: "register",
     value: function register() {
       var _this = this;
 
       if (this._registering) {
         debug('Register request in progress...');
         return;
       }
 
       var extraHeaders = this._extraHeaders.slice();
 
       extraHeaders.push("Contact: ".concat(this._contact, ";expires=").concat(this._expires).concat(this._extraContactParams));
       extraHeaders.push("Expires: ".concat(this._expires));
       var request = new SIPMessage.OutgoingRequest(JsSIP_C.REGISTER, this._registrar, this._ua, {
         'to_uri': this._to_uri,
         'call_id': this._call_id,
         'cseq': this._cseq += 1
       }, extraHeaders);
       var request_sender = new RequestSender(this._ua, request, {
         onRequestTimeout: function onRequestTimeout() {
           _this._registrationFailure(null, JsSIP_C.causes.REQUEST_TIMEOUT);
         },
         onTransportError: function onTransportError() {
           _this._registrationFailure(null, JsSIP_C.causes.CONNECTION_ERROR);
         },
         // Increase the CSeq on authentication.
         onAuthenticated: function onAuthenticated() {
           _this._cseq += 1;
         },
         onReceiveResponse: function onReceiveResponse(response) {
           // Discard responses to older REGISTER/un-REGISTER requests.
           if (response.cseq !== _this._cseq) {
             return;
           } // Clear registration timer.
 
 
           if (_this._registrationTimer !== null) {
             clearTimeout(_this._registrationTimer);
             _this._registrationTimer = null;
           }
 
           switch (true) {
             case /^1[0-9]{2}$/.test(response.status_code):
               {
                 // Ignore provisional responses.
                 break;
               }
 
             case /^2[0-9]{2}$/.test(response.status_code):
               {
                 _this._registering = false;
 
                 if (!response.hasHeader('Contact')) {
                   debug('no Contact header in response to REGISTER, response ignored');
                   break;
                 }
 
                 var contacts = response.headers['Contact'].reduce(function (a, b) {
                   return a.concat(b.parsed);
                 }, []); // Get the Contact pointing to us and update the expires value accordingly.
 
                 var contact = contacts.find(function (element) {
                   return element.uri.user === _this._ua.contact.uri.user;
                 });
 
                 if (!contact) {
                   debug('no Contact header pointing to us, response ignored');
                   break;
                 }
 
                 var expires = contact.getParam('expires');
 
                 if (!expires && response.hasHeader('expires')) {
                   expires = response.getHeader('expires');
                 }
 
                 if (!expires) {
                   expires = _this._expires;
                 }
 
                 expires = Number(expires);
                 if (expires < MIN_REGISTER_EXPIRES) expires = MIN_REGISTER_EXPIRES;
                 var timeout = expires > 64 ? expires * 1000 / 2 + Math.floor((expires / 2 - 32) * 1000 * Math.random()) : expires * 1000 - 5000; // Re-Register or emit an event before the expiration interval has elapsed.
                 // For that, decrease the expires value. ie: 3 seconds.
 
                 _this._registrationTimer = setTimeout(function () {
                   _this._registrationTimer = null; // If there are no listeners for registrationExpiring, renew registration.
                   // If there are listeners, let the function listening do the register call.
 
                   if (_this._ua.listeners('registrationExpiring').length === 0) {
                     _this.register();
                   } else {
                     _this._ua.emit('registrationExpiring');
                   }
                 }, timeout); // Save gruu values.
 
                 if (contact.hasParam('temp-gruu')) {
                   _this._ua.contact.temp_gruu = contact.getParam('temp-gruu').replace(/"/g, '');
                 }
 
                 if (contact.hasParam('pub-gruu')) {
                   _this._ua.contact.pub_gruu = contact.getParam('pub-gruu').replace(/"/g, '');
                 }
 
                 if (!_this._registered) {
                   _this._registered = true;
 
                   _this._ua.registered({
                     response: response
                   });
                 }
 
                 break;
               }
             // Interval too brief RFC3261 10.2.8.
 
             case /^423$/.test(response.status_code):
               {
                 if (response.hasHeader('min-expires')) {
                   // Increase our registration interval to the suggested minimum.
                   _this._expires = Number(response.getHeader('min-expires'));
                   if (_this._expires < MIN_REGISTER_EXPIRES) _this._expires = MIN_REGISTER_EXPIRES; // Attempt the registration again immediately.
 
                   _this.register();
                 } else {
                   // This response MUST contain a Min-Expires header field.
                   debug('423 response received for REGISTER without Min-Expires');
 
                   _this._registrationFailure(response, JsSIP_C.causes.SIP_FAILURE_CODE);
                 }
 
                 break;
               }
 
             default:
               {
                 var cause = Utils.sipErrorCause(response.status_code);
 
                 _this._registrationFailure(response, cause);
               }
           }
         }
       });
       this._registering = true;
       request_sender.send();
     }
   }, {
     key: "unregister",
     value: function unregister() {
       var _this2 = this;
 
       var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
 
       if (!this._registered) {
         debug('already unregistered');
         return;
       }
 
       this._registered = false; // Clear the registration timer.
 
       if (this._registrationTimer !== null) {
         clearTimeout(this._registrationTimer);
         this._registrationTimer = null;
       }
 
       var extraHeaders = this._extraHeaders.slice();
 
       if (options.all) {
         extraHeaders.push("Contact: *".concat(this._extraContactParams));
       } else {
         extraHeaders.push("Contact: ".concat(this._contact, ";expires=0").concat(this._extraContactParams));
       }
 
       extraHeaders.push('Expires: 0');
       var request = new SIPMessage.OutgoingRequest(JsSIP_C.REGISTER, this._registrar, this._ua, {
         'to_uri': this._to_uri,
         'call_id': this._call_id,
         'cseq': this._cseq += 1
       }, extraHeaders);
       var request_sender = new RequestSender(this._ua, request, {
         onRequestTimeout: function onRequestTimeout() {
           _this2._unregistered(null, JsSIP_C.causes.REQUEST_TIMEOUT);
         },
         onTransportError: function onTransportError() {
           _this2._unregistered(null, JsSIP_C.causes.CONNECTION_ERROR);
         },
         // Increase the CSeq on authentication.
         onAuthenticated: function onAuthenticated() {
           _this2._cseq += 1;
         },
         onReceiveResponse: function onReceiveResponse(response) {
           switch (true) {
             case /^1[0-9]{2}$/.test(response.status_code):
               // Ignore provisional responses.
               break;
 
             case /^2[0-9]{2}$/.test(response.status_code):
               _this2._unregistered(response);
 
               break;
 
             default:
               {
                 var cause = Utils.sipErrorCause(response.status_code);
 
                 _this2._unregistered(response, cause);
               }
           }
         }
       });
       request_sender.send();
     }
   }, {
     key: "close",
     value: function close() {
       if (this._registered) {
         this.unregister();
       }
     }
   }, {
     key: "onTransportClosed",
     value: function onTransportClosed() {
       this._registering = false;
 
       if (this._registrationTimer !== null) {
         clearTimeout(this._registrationTimer);
         this._registrationTimer = null;
       }
 
       if (this._registered) {
         this._registered = false;
 
         this._ua.unregistered({});
       }
     }
   }, {
     key: "_registrationFailure",
     value: function _registrationFailure(response, cause) {
       this._registering = false;
 
       this._ua.registrationFailed({
         response: response || null,
         cause: cause
       });
 
       if (this._registered) {
         this._registered = false;
 
         this._ua.unregistered({
           response: response || null,
           cause: cause
         });
       }
     }
   }, {
     key: "_unregistered",
     value: function _unregistered(response, cause) {
       this._registering = false;
       this._registered = false;
 
       this._ua.unregistered({
         response: response || null,
         cause: cause || null
       });
     }
   }, {
     key: "registered",
     get: function get() {
       return this._registered;
     }
   }]);
 
   return Registrator;
 }();
 },{"./Constants":2,"./RequestSender":18,"./SIPMessage":19,"./Utils":26,"debug":30}],18:[function(require,module,exports){
 "use strict";
 
 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
 function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
 
 function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
 
 var JsSIP_C = require('./Constants');
 
 var DigestAuthentication = require('./DigestAuthentication');
 
 var Transactions = require('./Transactions');
 
 var debug = require('debug')('JsSIP:RequestSender'); // Default event handlers.
 
 
 var EventHandlers = {
   onRequestTimeout: function onRequestTimeout() {},
   onTransportError: function onTransportError() {},
   onReceiveResponse: function onReceiveResponse() {},
   onAuthenticated: function onAuthenticated() {}
 };
 
 module.exports = /*#__PURE__*/function () {
   function RequestSender(ua, request, eventHandlers) {
     _classCallCheck(this, RequestSender);
 
     this._ua = ua;
     this._eventHandlers = eventHandlers;
     this._method = request.method;
     this._request = request;
     this._auth = null;
     this._challenged = false;
     this._staled = false; // Define the undefined handlers.
 
     for (var handler in EventHandlers) {
       if (Object.prototype.hasOwnProperty.call(EventHandlers, handler)) {
         if (!this._eventHandlers[handler]) {
           this._eventHandlers[handler] = EventHandlers[handler];
         }
       }
     } // If ua is in closing process or even closed just allow sending Bye and ACK.
 
 
     if (ua.status === ua.C.STATUS_USER_CLOSED && (this._method !== JsSIP_C.BYE || this._method !== JsSIP_C.ACK)) {
       this._eventHandlers.onTransportError();
     }
   }
   /**
   * Create the client transaction and send the message.
   */
 
 
   _createClass(RequestSender, [{
     key: "send",
     value: function send() {
       var _this = this;
 
       var eventHandlers = {
         onRequestTimeout: function onRequestTimeout() {
           _this._eventHandlers.onRequestTimeout();
         },
         onTransportError: function onTransportError() {
           _this._eventHandlers.onTransportError();
         },
         onReceiveResponse: function onReceiveResponse(response) {
           _this._receiveResponse(response);
         }
       };
 
       switch (this._method) {
         case 'INVITE':
           this.clientTransaction = new Transactions.InviteClientTransaction(this._ua, this._ua.transport, this._request, eventHandlers);
           break;
 
         case 'ACK':
           this.clientTransaction = new Transactions.AckClientTransaction(this._ua, this._ua.transport, this._request, eventHandlers);
           break;
 
         default:
           this.clientTransaction = new Transactions.NonInviteClientTransaction(this._ua, this._ua.transport, this._request, eventHandlers);
       } // If authorization JWT is present, use it.
 
 
       if (this._ua._configuration.authorization_jwt) {
         this._request.setHeader('Authorization', this._ua._configuration.authorization_jwt);
       }
 
       this.clientTransaction.send();
     }
     /**
     * Called from client transaction when receiving a correct response to the request.
     * Authenticate request if needed or pass the response back to the applicant.
     */
 
   }, {
     key: "_receiveResponse",
     value: function _receiveResponse(response) {
       var challenge;
       var authorization_header_name;
       var status_code = response.status_code;
       /*
       * Authentication
       * Authenticate once. _challenged_ flag used to avoid infinite authentications.
       */
 
       if ((status_code === 401 || status_code === 407) && (this._ua.configuration.password !== null || this._ua.configuration.ha1 !== null)) {
         // Get and parse the appropriate WWW-Authenticate or Proxy-Authenticate header.
         if (response.status_code === 401) {
           challenge = response.parseHeader('www-authenticate');
           authorization_header_name = 'authorization';
         } else {
           challenge = response.parseHeader('proxy-authenticate');
           authorization_header_name = 'proxy-authorization';
         } // Verify it seems a valid challenge.
 
 
         if (!challenge) {
           debug("".concat(response.status_code, " with wrong or missing challenge, cannot authenticate"));
 
           this._eventHandlers.onReceiveResponse(response);
 
           return;
         }
 
         if (!this._challenged || !this._staled && challenge.stale === true) {
           if (!this._auth) {
             this._auth = new DigestAuthentication({
               username: this._ua.configuration.authorization_user,
               password: this._ua.configuration.password,
               realm: this._ua.configuration.realm,
               ha1: this._ua.configuration.ha1
             });
           } // Verify that the challenge is really valid.
 
 
           if (!this._auth.authenticate(this._request, challenge)) {
             this._eventHandlers.onReceiveResponse(response);
 
             return;
           }
 
           this._challenged = true; // Update ha1 and realm in the UA.
 
           this._ua.set('realm', this._auth.get('realm'));
 
           this._ua.set('ha1', this._auth.get('ha1'));
 
           if (challenge.stale) {
             this._staled = true;
           }
 
           this._request = this._request.clone();
           this._request.cseq += 1;
 
           this._request.setHeader('cseq', "".concat(this._request.cseq, " ").concat(this._method));
 
           this._request.setHeader(authorization_header_name, this._auth.toString());
 
           this._eventHandlers.onAuthenticated(this._request);
 
           this.send();
         } else {
           this._eventHandlers.onReceiveResponse(response);
         }
       } else {
         this._eventHandlers.onReceiveResponse(response);
       }
     }
   }]);
 
   return RequestSender;
 }();
 },{"./Constants":2,"./DigestAuthentication":5,"./Transactions":22,"debug":30}],19:[function(require,module,exports){
 "use strict";
 
 function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
 
 function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
 
 function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
 
 function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
 
 function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
 
 function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
 
 function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }
 
 function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
 
 function _createForOfIteratorHelper(o, allowArrayLike) { var it; if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
 
 function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
 
 function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
 
 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
 function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
 
 function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
 
 var sdp_transform = require('sdp-transform');
 
 var JsSIP_C = require('./Constants');
 
 var Utils = require('./Utils');
 
 var NameAddrHeader = require('./NameAddrHeader');
 
 var Grammar = require('./Grammar');
 
 var debug = require('debug')('JsSIP:SIPMessage');
 /**
  * -param {String} method request method
  * -param {String} ruri request uri
  * -param {UA} ua
  * -param {Object} params parameters that will have priority over ua.configuration parameters:
  * <br>
  *  - cseq, call_id, from_tag, from_uri, from_display_name, to_uri, to_tag, route_set
  * -param {Object} [headers] extra headers
  * -param {String} [body]
  */
 
 
 var OutgoingRequest = /*#__PURE__*/function () {
   function OutgoingRequest(method, ruri, ua, params, extraHeaders, body) {
     _classCallCheck(this, OutgoingRequest);
 
     // Mandatory parameters check.
     if (!method || !ruri || !ua) {
       return null;
     }
 
     params = params || {};
     this.ua = ua;
     this.headers = {};
     this.method = method;
     this.ruri = ruri;
     this.body = body;
     this.extraHeaders = Utils.cloneArray(extraHeaders); // Fill the Common SIP Request Headers.
     // Route.
 
     if (params.route_set) {
       this.setHeader('route', params.route_set);
     } else if (ua.configuration.use_preloaded_route) {
       this.setHeader('route', "<".concat(ua.transport.sip_uri, ";lr>"));
     } // Via.
     // Empty Via header. Will be filled by the client transaction.
 
 
     this.setHeader('via', ''); // Max-Forwards.
 
     this.setHeader('max-forwards', JsSIP_C.MAX_FORWARDS); // To
 
     var to_uri = params.to_uri || ruri;
     var to_params = params.to_tag ? {
       tag: params.to_tag
     } : null;
     var to_display_name = typeof params.to_display_name !== 'undefined' ? params.to_display_name : null;
     this.to = new NameAddrHeader(to_uri, to_display_name, to_params);
     this.setHeader('to', this.to.toString()); // From.
 
     var from_uri = params.from_uri || ua.configuration.uri;
     var from_params = {
       tag: params.from_tag || Utils.newTag()
     };
     var display_name;
 
     if (typeof params.from_display_name !== 'undefined') {
       display_name = params.from_display_name;
     } else if (ua.configuration.display_name) {
       display_name = ua.configuration.display_name;
     } else {
       display_name = null;
     }
 
     this.from = new NameAddrHeader(from_uri, display_name, from_params);
     this.setHeader('from', this.from.toString()); // Call-ID.
 
     var call_id = params.call_id || ua.configuration.jssip_id + Utils.createRandomToken(15);
     this.call_id = call_id;
     this.setHeader('call-id', call_id); // CSeq.
 
     var cseq = params.cseq || Math.floor(Math.random() * 10000);
     this.cseq = cseq;
     this.setHeader('cseq', "".concat(cseq, " ").concat(method));
   }
   /**
    * Replace the the given header by the given value.
    * -param {String} name header name
    * -param {String | Array} value header value
    */
 
 
   _createClass(OutgoingRequest, [{
     key: "setHeader",
     value: function setHeader(name, value) {
       // Remove the header from extraHeaders if present.
       var regexp = new RegExp("^\\s*".concat(name, "\\s*:"), 'i');
 
       for (var idx = 0; idx < this.extraHeaders.length; idx++) {
         if (regexp.test(this.extraHeaders[idx])) {
           this.extraHeaders.splice(idx, 1);
         }
       }
 
       this.headers[Utils.headerize(name)] = Array.isArray(value) ? value : [value];
     }
     /**
      * Get the value of the given header name at the given position.
      * -param {String} name header name
      * -returns {String|undefined} Returns the specified header, null if header doesn't exist.
      */
 
   }, {
     key: "getHeader",
     value: function getHeader(name) {
       var headers = this.headers[Utils.headerize(name)];
 
       if (headers) {
         if (headers[0]) {
           return headers[0];
         }
       } else {
         var regexp = new RegExp("^\\s*".concat(name, "\\s*:"), 'i');
 
         var _iterator = _createForOfIteratorHelper(this.extraHeaders),
             _step;
 
         try {
           for (_iterator.s(); !(_step = _iterator.n()).done;) {
             var header = _step.value;
 
             if (regexp.test(header)) {
               return header.substring(header.indexOf(':') + 1).trim();
             }
           }
         } catch (err) {
           _iterator.e(err);
         } finally {
           _iterator.f();
         }
       }
 
       return;
     }
     /**
      * Get the header/s of the given name.
      * -param {String} name header name
      * -returns {Array} Array with all the headers of the specified name.
      */
 
   }, {
     key: "getHeaders",
     value: function getHeaders(name) {
       var headers = this.headers[Utils.headerize(name)];
       var result = [];
 
       if (headers) {
         var _iterator2 = _createForOfIteratorHelper(headers),
             _step2;
 
         try {
           for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
             var header = _step2.value;
             result.push(header);
           }
         } catch (err) {
           _iterator2.e(err);
         } finally {
           _iterator2.f();
         }
 
         return result;
       } else {
         var regexp = new RegExp("^\\s*".concat(name, "\\s*:"), 'i');
 
         var _iterator3 = _createForOfIteratorHelper(this.extraHeaders),
             _step3;
 
         try {
           for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
             var _header = _step3.value;
 
             if (regexp.test(_header)) {
               result.push(_header.substring(_header.indexOf(':') + 1).trim());
             }
           }
         } catch (err) {
           _iterator3.e(err);
         } finally {
           _iterator3.f();
         }
 
         return result;
       }
     }
     /**
      * Verify the existence of the given header.
      * -param {String} name header name
      * -returns {boolean} true if header with given name exists, false otherwise
      */
 
   }, {
     key: "hasHeader",
     value: function hasHeader(name) {
       if (this.headers[Utils.headerize(name)]) {
         return true;
       } else {
         var regexp = new RegExp("^\\s*".concat(name, "\\s*:"), 'i');
 
         var _iterator4 = _createForOfIteratorHelper(this.extraHeaders),
             _step4;
 
         try {
           for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
             var header = _step4.value;
 
             if (regexp.test(header)) {
               return true;
             }
           }
         } catch (err) {
           _iterator4.e(err);
         } finally {
           _iterator4.f();
         }
       }
 
       return false;
     }
     /**
      * Parse the current body as a SDP and store the resulting object
      * into this.sdp.
      * -param {Boolean} force: Parse even if this.sdp already exists.
      *
      * Returns this.sdp.
      */
 
   }, {
     key: "parseSDP",
     value: function parseSDP(force) {
       if (!force && this.sdp) {
         return this.sdp;
       } else {
         this.sdp = sdp_transform.parse(this.body || '');
         return this.sdp;
       }
     }
   }, {
     key: "toString",
     value: function toString() {
       var msg = "".concat(this.method, " ").concat(this.ruri, " SIP/2.0\r\n");
 
       for (var headerName in this.headers) {
         if (Object.prototype.hasOwnProperty.call(this.headers, headerName)) {
           var _iterator5 = _createForOfIteratorHelper(this.headers[headerName]),
               _step5;
 
           try {
             for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
               var headerValue = _step5.value;
               msg += "".concat(headerName, ": ").concat(headerValue, "\r\n");
             }
           } catch (err) {
             _iterator5.e(err);
           } finally {
             _iterator5.f();
           }
         }
       }
 
       var _iterator6 = _createForOfIteratorHelper(this.extraHeaders),
           _step6;
 
       try {
         for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
           var header = _step6.value;
           msg += "".concat(header.trim(), "\r\n");
         } // Supported.
 
       } catch (err) {
         _iterator6.e(err);
       } finally {
         _iterator6.f();
       }
 
       var supported = [];
 
       switch (this.method) {
         case JsSIP_C.REGISTER:
           supported.push('path', 'gruu');
           break;
 
         case JsSIP_C.INVITE:
           if (this.ua.configuration.session_timers) {
             supported.push('timer');
           }
 
           if (this.ua.contact.pub_gruu || this.ua.contact.temp_gruu) {
             supported.push('gruu');
           }
 
           supported.push('ice', 'replaces');
           break;
 
         case JsSIP_C.UPDATE:
           if (this.ua.configuration.session_timers) {
             supported.push('timer');
           }
 
           supported.push('ice');
           break;
       }
 
       supported.push('outbound');
       var userAgent = this.ua.configuration.user_agent || JsSIP_C.USER_AGENT; // Allow.
 
       msg += "Allow: ".concat(JsSIP_C.ALLOWED_METHODS, "\r\n");
       msg += "Supported: ".concat(supported, "\r\n");
       msg += "User-Agent: ".concat(userAgent, "\r\n");
 
       if (this.body) {
         var length = Utils.str_utf8_length(this.body);
         msg += "Content-Length: ".concat(length, "\r\n\r\n");
         msg += this.body;
       } else {
         msg += 'Content-Length: 0\r\n\r\n';
       }
 
       return msg;
     }
   }, {
     key: "clone",
     value: function clone() {
       var request = new OutgoingRequest(this.method, this.ruri, this.ua);
       Object.keys(this.headers).forEach(function (name) {
         request.headers[name] = this.headers[name].slice();
       }, this);
       request.body = this.body;
       request.extraHeaders = Utils.cloneArray(this.extraHeaders);
       request.to = this.to;
       request.from = this.from;
       request.call_id = this.call_id;
       request.cseq = this.cseq;
       return request;
     }
   }]);
 
   return OutgoingRequest;
 }();
 
 var InitialOutgoingInviteRequest = /*#__PURE__*/function (_OutgoingRequest) {
   _inherits(InitialOutgoingInviteRequest, _OutgoingRequest);
 
   var _super = _createSuper(InitialOutgoingInviteRequest);
 
   function InitialOutgoingInviteRequest(ruri, ua, params, extraHeaders, body) {
     var _this;
 
     _classCallCheck(this, InitialOutgoingInviteRequest);
 
     _this = _super.call(this, JsSIP_C.INVITE, ruri, ua, params, extraHeaders, body);
     _this.transaction = null;
     return _this;
   }
 
   _createClass(InitialOutgoingInviteRequest, [{
     key: "cancel",
     value: function cancel(reason) {
       this.transaction.cancel(reason);
     }
   }, {
     key: "clone",
     value: function clone() {
       var request = new InitialOutgoingInviteRequest(this.ruri, this.ua);
       Object.keys(this.headers).forEach(function (name) {
         request.headers[name] = this.headers[name].slice();
       }, this);
       request.body = this.body;
       request.extraHeaders = Utils.cloneArray(this.extraHeaders);
       request.to = this.to;
       request.from = this.from;
       request.call_id = this.call_id;
       request.cseq = this.cseq;
       request.transaction = this.transaction;
       return request;
     }
   }]);
 
   return InitialOutgoingInviteRequest;
 }(OutgoingRequest);
 
 var IncomingMessage = /*#__PURE__*/function () {
   function IncomingMessage() {
     _classCallCheck(this, IncomingMessage);
 
     this.data = null;
     this.headers = null;
     this.method = null;
     this.via = null;
     this.via_branch = null;
     this.call_id = null;
     this.cseq = null;
     this.from = null;
     this.from_tag = null;
     this.to = null;
     this.to_tag = null;
     this.body = null;
     this.sdp = null;
   }
   /**
   * Insert a header of the given name and value into the last position of the
   * header array.
   */
 
 
   _createClass(IncomingMessage, [{
     key: "addHeader",
     value: function addHeader(name, value) {
       var header = {
         raw: value
       };
       name = Utils.headerize(name);
 
       if (this.headers[name]) {
         this.headers[name].push(header);
       } else {
         this.headers[name] = [header];
       }
     }
     /**
      * Get the value of the given header name at the given position.
      */
 
   }, {
     key: "getHeader",
     value: function getHeader(name) {
       var header = this.headers[Utils.headerize(name)];
 
       if (header) {
         if (header[0]) {
           return header[0].raw;
         }
       } else {
         return;
       }
     }
     /**
      * Get the header/s of the given name.
      */
 
   }, {
     key: "getHeaders",
     value: function getHeaders(name) {
       var headers = this.headers[Utils.headerize(name)];
       var result = [];
 
       if (!headers) {
         return [];
       }
 
       var _iterator7 = _createForOfIteratorHelper(headers),
           _step7;
 
       try {
         for (_iterator7.s(); !(_step7 = _iterator7.n()).done;) {
           var header = _step7.value;
           result.push(header.raw);
         }
       } catch (err) {
         _iterator7.e(err);
       } finally {
         _iterator7.f();
       }
 
       return result;
     }
     /**
      * Verify the existence of the given header.
      */
 
   }, {
     key: "hasHeader",
     value: function hasHeader(name) {
       return this.headers[Utils.headerize(name)] ? true : false;
     }
     /**
     * Parse the given header on the given index.
     * -param {String} name header name
     * -param {Number} [idx=0] header index
     * -returns {Object|undefined} Parsed header object, undefined if the header
     *  is not present or in case of a parsing error.
     */
 
   }, {
     key: "parseHeader",
     value: function parseHeader(name) {
       var idx = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
       name = Utils.headerize(name);
 
       if (!this.headers[name]) {
         debug("header \"".concat(name, "\" not present"));
         return;
       } else if (idx >= this.headers[name].length) {
         debug("not so many \"".concat(name, "\" headers present"));
         return;
       }
 
       var header = this.headers[name][idx];
       var value = header.raw;
 
       if (header.parsed) {
         return header.parsed;
       } // Substitute '-' by '_' for grammar rule matching.
 
 
       var parsed = Grammar.parse(value, name.replace(/-/g, '_'));
 
       if (parsed === -1) {
         this.headers[name].splice(idx, 1); // delete from headers
 
         debug("error parsing \"".concat(name, "\" header field with value \"").concat(value, "\""));
         return;
       } else {
         header.parsed = parsed;
         return parsed;
       }
     }
     /**
      * Message Header attribute selector. Alias of parseHeader.
      * -param {String} name header name
      * -param {Number} [idx=0] header index
      * -returns {Object|undefined} Parsed header object, undefined if the header
      *  is not present or in case of a parsing error.
      *
      * -example
      * message.s('via',3).port
      */
 
   }, {
     key: "s",
     value: function s(name, idx) {
       return this.parseHeader(name, idx);
     }
     /**
     * Replace the value of the given header by the value.
     * -param {String} name header name
     * -param {String} value header value
     */
 
   }, {
     key: "setHeader",
     value: function setHeader(name, value) {
       var header = {
         raw: value
       };
       this.headers[Utils.headerize(name)] = [header];
     }
     /**
      * Parse the current body as a SDP and store the resulting object
      * into this.sdp.
      * -param {Boolean} force: Parse even if this.sdp already exists.
      *
      * Returns this.sdp.
      */
 
   }, {
     key: "parseSDP",
     value: function parseSDP(force) {
       if (!force && this.sdp) {
         return this.sdp;
       } else {
         this.sdp = sdp_transform.parse(this.body || '');
         return this.sdp;
       }
     }
   }, {
     key: "toString",
     value: function toString() {
       return this.data;
     }
   }]);
 
   return IncomingMessage;
 }();
 
 var IncomingRequest = /*#__PURE__*/function (_IncomingMessage) {
   _inherits(IncomingRequest, _IncomingMessage);
 
   var _super2 = _createSuper(IncomingRequest);
 
   function IncomingRequest(ua) {
     var _this2;
 
     _classCallCheck(this, IncomingRequest);
 
     _this2 = _super2.call(this);
     _this2.ua = ua;
     _this2.headers = {};
     _this2.ruri = null;
     _this2.transport = null;
     _this2.server_transaction = null;
     return _this2;
   }
   /**
   * Stateful reply.
   * -param {Number} code status code
   * -param {String} reason reason phrase
   * -param {Object} headers extra headers
   * -param {String} body body
   * -param {Function} [onSuccess] onSuccess callback
   * -param {Function} [onFailure] onFailure callback
   */
 
 
   _createClass(IncomingRequest, [{
     key: "reply",
     value: function reply(code, reason, extraHeaders, body, onSuccess, onFailure) {
       var supported = [];
       var to = this.getHeader('To');
       code = code || null;
       reason = reason || null; // Validate code and reason values.
 
       if (!code || code < 100 || code > 699) {
         throw new TypeError("Invalid status_code: ".concat(code));
       } else if (reason && typeof reason !== 'string' && !(reason instanceof String)) {
         throw new TypeError("Invalid reason_phrase: ".concat(reason));
       }
 
       reason = reason || JsSIP_C.REASON_PHRASE[code] || '';
       extraHeaders = Utils.cloneArray(extraHeaders);
       var response = "SIP/2.0 ".concat(code, " ").concat(reason, "\r\n");
 
       if (this.method === JsSIP_C.INVITE && code > 100 && code <= 200) {
         var headers = this.getHeaders('record-route');
 
         var _iterator8 = _createForOfIteratorHelper(headers),
             _step8;
 
         try {
           for (_iterator8.s(); !(_step8 = _iterator8.n()).done;) {
             var header = _step8.value;
             response += "Record-Route: ".concat(header, "\r\n");
           }
         } catch (err) {
           _iterator8.e(err);
         } finally {
           _iterator8.f();
         }
       }
 
       var vias = this.getHeaders('via');
 
       var _iterator9 = _createForOfIteratorHelper(vias),
           _step9;
 
       try {
         for (_iterator9.s(); !(_step9 = _iterator9.n()).done;) {
           var via = _step9.value;
           response += "Via: ".concat(via, "\r\n");
         }
       } catch (err) {
         _iterator9.e(err);
       } finally {
         _iterator9.f();
       }
 
       if (!this.to_tag && code > 100) {
         to += ";tag=".concat(Utils.newTag());
       } else if (this.to_tag && !this.s('to').hasParam('tag')) {
         to += ";tag=".concat(this.to_tag);
       }
 
       response += "To: ".concat(to, "\r\n");
       response += "From: ".concat(this.getHeader('From'), "\r\n");
       response += "Call-ID: ".concat(this.call_id, "\r\n");
       response += "CSeq: ".concat(this.cseq, " ").concat(this.method, "\r\n");
 
       var _iterator10 = _createForOfIteratorHelper(extraHeaders),
           _step10;
 
       try {
         for (_iterator10.s(); !(_step10 = _iterator10.n()).done;) {
           var _header2 = _step10.value;
           response += "".concat(_header2.trim(), "\r\n");
         } // Supported.
 
       } catch (err) {
         _iterator10.e(err);
       } finally {
         _iterator10.f();
       }
 
       switch (this.method) {
         case JsSIP_C.INVITE:
           if (this.ua.configuration.session_timers) {
             supported.push('timer');
           }
 
           if (this.ua.contact.pub_gruu || this.ua.contact.temp_gruu) {
             supported.push('gruu');
           }
 
           supported.push('ice', 'replaces');
           break;
 
         case JsSIP_C.UPDATE:
           if (this.ua.configuration.session_timers) {
             supported.push('timer');
           }
 
           if (body) {
             supported.push('ice');
           }
 
           supported.push('replaces');
       }
 
       supported.push('outbound'); // Allow and Accept.
 
       if (this.method === JsSIP_C.OPTIONS) {
         response += "Allow: ".concat(JsSIP_C.ALLOWED_METHODS, "\r\n");
         response += "Accept: ".concat(JsSIP_C.ACCEPTED_BODY_TYPES, "\r\n");
       } else if (code === 405) {
         response += "Allow: ".concat(JsSIP_C.ALLOWED_METHODS, "\r\n");
       } else if (code === 415) {
         response += "Accept: ".concat(JsSIP_C.ACCEPTED_BODY_TYPES, "\r\n");
       }
 
       response += "Supported: ".concat(supported, "\r\n");
 
       if (body) {
         var length = Utils.str_utf8_length(body);
         response += 'Content-Type: application/sdp\r\n';
         response += "Content-Length: ".concat(length, "\r\n\r\n");
         response += body;
       } else {
         response += "Content-Length: ".concat(0, "\r\n\r\n");
       }
 
       this.server_transaction.receiveResponse(code, response, onSuccess, onFailure);
     }
     /**
     * Stateless reply.
     * -param {Number} code status code
     * -param {String} reason reason phrase
     */
 
   }, {
     key: "reply_sl",
     value: function reply_sl() {
       var code = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
       var reason = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
       var vias = this.getHeaders('via'); // Validate code and reason values.
 
       if (!code || code < 100 || code > 699) {
         throw new TypeError("Invalid status_code: ".concat(code));
       } else if (reason && typeof reason !== 'string' && !(reason instanceof String)) {
         throw new TypeError("Invalid reason_phrase: ".concat(reason));
       }
 
       reason = reason || JsSIP_C.REASON_PHRASE[code] || '';
       var response = "SIP/2.0 ".concat(code, " ").concat(reason, "\r\n");
 
       var _iterator11 = _createForOfIteratorHelper(vias),
           _step11;
 
       try {
         for (_iterator11.s(); !(_step11 = _iterator11.n()).done;) {
           var via = _step11.value;
           response += "Via: ".concat(via, "\r\n");
         }
       } catch (err) {
         _iterator11.e(err);
       } finally {
         _iterator11.f();
       }
 
       var to = this.getHeader('To');
 
       if (!this.to_tag && code > 100) {
         to += ";tag=".concat(Utils.newTag());
       } else if (this.to_tag && !this.s('to').hasParam('tag')) {
         to += ";tag=".concat(this.to_tag);
       }
 
       response += "To: ".concat(to, "\r\n");
       response += "From: ".concat(this.getHeader('From'), "\r\n");
       response += "Call-ID: ".concat(this.call_id, "\r\n");
       response += "CSeq: ".concat(this.cseq, " ").concat(this.method, "\r\n");
       response += "Content-Length: ".concat(0, "\r\n\r\n");
       this.transport.send(response);
     }
   }]);
 
   return IncomingRequest;
 }(IncomingMessage);
 
 var IncomingResponse = /*#__PURE__*/function (_IncomingMessage2) {
   _inherits(IncomingResponse, _IncomingMessage2);
 
   var _super3 = _createSuper(IncomingResponse);
 
   function IncomingResponse() {
     var _this3;
 
     _classCallCheck(this, IncomingResponse);
 
     _this3 = _super3.call(this);
     _this3.headers = {};
     _this3.status_code = null;
     _this3.reason_phrase = null;
     return _this3;
   }
 
   return IncomingResponse;
 }(IncomingMessage);
 
 module.exports = {
   OutgoingRequest: OutgoingRequest,
   InitialOutgoingInviteRequest: InitialOutgoingInviteRequest,
   IncomingRequest: IncomingRequest,
   IncomingResponse: IncomingResponse
 };
 },{"./Constants":2,"./Grammar":7,"./NameAddrHeader":10,"./Utils":26,"debug":30,"sdp-transform":35}],20:[function(require,module,exports){
 "use strict";
 
 var Utils = require('./Utils');
 
 var Grammar = require('./Grammar');
 
 var debugerror = require('debug')('JsSIP:ERROR:Socket');
 
 debugerror.log = console.warn.bind(console);
 /**
  * Interface documentation: https://jssip.net/documentation/$last_version/api/socket/
  *
  * interface Socket {
  *  attribute String via_transport
  *  attribute String url
  *  attribute String sip_uri
  *
  *  method connect();
  *  method disconnect();
  *  method send(data);
  *
  *  attribute EventHandler onconnect
  *  attribute EventHandler ondisconnect
  *  attribute EventHandler ondata
  * }
  *
  */
 
 exports.isSocket = function (socket) {
   // Ignore if an array is given.
   if (Array.isArray(socket)) {
     return false;
   }
 
   if (typeof socket === 'undefined') {
     debugerror('undefined JsSIP.Socket instance');
     return false;
   } // Check Properties.
 
 
   try {
     if (!Utils.isString(socket.url)) {
       debugerror('missing or invalid JsSIP.Socket url property');
       throw new Error();
     }
 
     if (!Utils.isString(socket.via_transport)) {
       debugerror('missing or invalid JsSIP.Socket via_transport property');
       throw new Error();
     }
 
     if (Grammar.parse(socket.sip_uri, 'SIP_URI') === -1) {
       debugerror('missing or invalid JsSIP.Socket sip_uri property');
       throw new Error();
     }
   } catch (e) {
     return false;
   } // Check Methods.
 
 
   try {
     ['connect', 'disconnect', 'send'].forEach(function (method) {
       if (!Utils.isFunction(socket[method])) {
         debugerror("missing or invalid JsSIP.Socket method: ".concat(method));
         throw new Error();
       }
     });
   } catch (e) {
     return false;
   }
 
   return true;
 };
 },{"./Grammar":7,"./Utils":26,"debug":30}],21:[function(require,module,exports){
 "use strict";
 
 var T1 = 500,
     T2 = 4000,
     T4 = 5000;
 module.exports = {
   T1: T1,
   T2: T2,
   T4: T4,
   TIMER_B: 64 * T1,
   TIMER_D: 0 * T1,
   TIMER_F: 64 * T1,
   TIMER_H: 64 * T1,
   TIMER_I: 0 * T1,
   TIMER_J: 0 * T1,
   TIMER_K: 0 * T4,
   TIMER_L: 64 * T1,
   TIMER_M: 64 * T1,
   PROVISIONAL_RESPONSE_INTERVAL: 60000 // See RFC 3261 Section 13.3.1.1
 
 };
 },{}],22:[function(require,module,exports){
 "use strict";
 
 function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
 
 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
 function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
 
 function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
 
 function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
 
 function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
 
 function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
 
 function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
 
 function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
 
 function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }
 
 function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
 
 var EventEmitter = require('events').EventEmitter;
 
 var JsSIP_C = require('./Constants');
 
 var SIPMessage = require('./SIPMessage');
 
 var Timers = require('./Timers');
 
 var debugnict = require('debug')('JsSIP:NonInviteClientTransaction');
 
 var debugict = require('debug')('JsSIP:InviteClientTransaction');
 
 var debugact = require('debug')('JsSIP:AckClientTransaction');
 
 var debugnist = require('debug')('JsSIP:NonInviteServerTransaction');
 
 var debugist = require('debug')('JsSIP:InviteServerTransaction');
 
 var C = {
   // Transaction states.
   STATUS_TRYING: 1,
   STATUS_PROCEEDING: 2,
   STATUS_CALLING: 3,
   STATUS_ACCEPTED: 4,
   STATUS_COMPLETED: 5,
   STATUS_TERMINATED: 6,
   STATUS_CONFIRMED: 7,
   // Transaction types.
   NON_INVITE_CLIENT: 'nict',
   NON_INVITE_SERVER: 'nist',
   INVITE_CLIENT: 'ict',
   INVITE_SERVER: 'ist'
 };
 
 var NonInviteClientTransaction = /*#__PURE__*/function (_EventEmitter) {
   _inherits(NonInviteClientTransaction, _EventEmitter);
 
   var _super = _createSuper(NonInviteClientTransaction);
 
   function NonInviteClientTransaction(ua, transport, request, eventHandlers) {
     var _this;
 
     _classCallCheck(this, NonInviteClientTransaction);
 
     _this = _super.call(this);
     _this.type = C.NON_INVITE_CLIENT;
     _this.id = "z9hG4bK".concat(Math.floor(Math.random() * 10000000));
     _this.ua = ua;
     _this.transport = transport;
     _this.request = request;
     _this.eventHandlers = eventHandlers;
     var via = "SIP/2.0/".concat(transport.via_transport);
     via += " ".concat(ua.configuration.via_host, ";branch=").concat(_this.id);
 
     _this.request.setHeader('via', via);
 
     _this.ua.newTransaction(_assertThisInitialized(_this));
 
     return _this;
   }
 
   _createClass(NonInviteClientTransaction, [{
     key: "stateChanged",
     value: function stateChanged(state) {
       this.state = state;
       this.emit('stateChanged');
     }
   }, {
     key: "send",
     value: function send() {
       var _this2 = this;
 
       this.stateChanged(C.STATUS_TRYING);
       this.F = setTimeout(function () {
         _this2.timer_F();
       }, Timers.TIMER_F);
 
       if (!this.transport.send(this.request)) {
         this.onTransportError();
       }
     }
   }, {
     key: "onTransportError",
     value: function onTransportError() {
       debugnict("transport error occurred, deleting transaction ".concat(this.id));
       clearTimeout(this.F);
       clearTimeout(this.K);
       this.stateChanged(C.STATUS_TERMINATED);
       this.ua.destroyTransaction(this);
       this.eventHandlers.onTransportError();
     }
   }, {
     key: "timer_F",
     value: function timer_F() {
       debugnict("Timer F expired for transaction ".concat(this.id));
       this.stateChanged(C.STATUS_TERMINATED);
       this.ua.destroyTransaction(this);
       this.eventHandlers.onRequestTimeout();
     }
   }, {
     key: "timer_K",
     value: function timer_K() {
       this.stateChanged(C.STATUS_TERMINATED);
       this.ua.destroyTransaction(this);
     }
   }, {
     key: "receiveResponse",
     value: function receiveResponse(response) {
       var _this3 = this;
 
       var status_code = response.status_code;
 
       if (status_code < 200) {
         switch (this.state) {
           case C.STATUS_TRYING:
           case C.STATUS_PROCEEDING:
             this.stateChanged(C.STATUS_PROCEEDING);
             this.eventHandlers.onReceiveResponse(response);
             break;
         }
       } else {
         switch (this.state) {
           case C.STATUS_TRYING:
           case C.STATUS_PROCEEDING:
             this.stateChanged(C.STATUS_COMPLETED);
             clearTimeout(this.F);
 
             if (status_code === 408) {
               this.eventHandlers.onRequestTimeout();
             } else {
               this.eventHandlers.onReceiveResponse(response);
             }
 
             this.K = setTimeout(function () {
               _this3.timer_K();
             }, Timers.TIMER_K);
             break;
 
           case C.STATUS_COMPLETED:
             break;
         }
       }
     }
   }, {
     key: "C",
     get: function get() {
       return C;
     }
   }]);
 
   return NonInviteClientTransaction;
 }(EventEmitter);
 
 var InviteClientTransaction = /*#__PURE__*/function (_EventEmitter2) {
   _inherits(InviteClientTransaction, _EventEmitter2);
 
   var _super2 = _createSuper(InviteClientTransaction);
 
   function InviteClientTransaction(ua, transport, request, eventHandlers) {
     var _this4;
 
     _classCallCheck(this, InviteClientTransaction);
 
     _this4 = _super2.call(this);
     _this4.type = C.INVITE_CLIENT;
     _this4.id = "z9hG4bK".concat(Math.floor(Math.random() * 10000000));
     _this4.ua = ua;
     _this4.transport = transport;
     _this4.request = request;
     _this4.eventHandlers = eventHandlers;
     request.transaction = _assertThisInitialized(_this4);
     var via = "SIP/2.0/".concat(transport.via_transport);
     via += " ".concat(ua.configuration.via_host, ";branch=").concat(_this4.id);
 
     _this4.request.setHeader('via', via);
 
     _this4.ua.newTransaction(_assertThisInitialized(_this4));
 
     return _this4;
   }
 
   _createClass(InviteClientTransaction, [{
     key: "stateChanged",
     value: function stateChanged(state) {
       this.state = state;
       this.emit('stateChanged');
     }
   }, {
     key: "send",
     value: function send() {
       var _this5 = this;
 
       this.stateChanged(C.STATUS_CALLING);
       this.B = setTimeout(function () {
         _this5.timer_B();
       }, Timers.TIMER_B);
 
       if (!this.transport.send(this.request)) {
         this.onTransportError();
       }
     }
   }, {
     key: "onTransportError",
     value: function onTransportError() {
       clearTimeout(this.B);
       clearTimeout(this.D);
       clearTimeout(this.M);
 
       if (this.state !== C.STATUS_ACCEPTED) {
         debugict("transport error occurred, deleting transaction ".concat(this.id));
         this.eventHandlers.onTransportError();
       }
 
       this.stateChanged(C.STATUS_TERMINATED);
       this.ua.destroyTransaction(this);
     } // RFC 6026 7.2.
 
   }, {
     key: "timer_M",
     value: function timer_M() {
       debugict("Timer M expired for transaction ".concat(this.id));
 
       if (this.state === C.STATUS_ACCEPTED) {
         clearTimeout(this.B);
         this.stateChanged(C.STATUS_TERMINATED);
         this.ua.destroyTransaction(this);
       }
     } // RFC 3261 17.1.1.
 
   }, {
     key: "timer_B",
     value: function timer_B() {
       debugict("Timer B expired for transaction ".concat(this.id));
 
       if (this.state === C.STATUS_CALLING) {
         this.stateChanged(C.STATUS_TERMINATED);
         this.ua.destroyTransaction(this);
         this.eventHandlers.onRequestTimeout();
       }
     }
   }, {
     key: "timer_D",
     value: function timer_D() {
       debugict("Timer D expired for transaction ".concat(this.id));
       clearTimeout(this.B);
       this.stateChanged(C.STATUS_TERMINATED);
       this.ua.destroyTransaction(this);
     }
   }, {
     key: "sendACK",
     value: function sendACK(response) {
       var _this6 = this;
 
       var ack = new SIPMessage.OutgoingRequest(JsSIP_C.ACK, this.request.ruri, this.ua, {
         'route_set': this.request.getHeaders('route'),
         'call_id': this.request.getHeader('call-id'),
         'cseq': this.request.cseq
       });
       ack.setHeader('from', this.request.getHeader('from'));
       ack.setHeader('via', this.request.getHeader('via'));
       ack.setHeader('to', response.getHeader('to'));
       this.D = setTimeout(function () {
         _this6.timer_D();
       }, Timers.TIMER_D);
       this.transport.send(ack);
     }
   }, {
     key: "cancel",
     value: function cancel(reason) {
       // Send only if a provisional response (>100) has been received.
       if (this.state !== C.STATUS_PROCEEDING) {
         return;
       }
 
       var cancel = new SIPMessage.OutgoingRequest(JsSIP_C.CANCEL, this.request.ruri, this.ua, {
         'route_set': this.request.getHeaders('route'),
         'call_id': this.request.getHeader('call-id'),
         'cseq': this.request.cseq
       });
       cancel.setHeader('from', this.request.getHeader('from'));
       cancel.setHeader('via', this.request.getHeader('via'));
       cancel.setHeader('to', this.request.getHeader('to'));
 
       if (reason) {
         cancel.setHeader('reason', reason);
       }
 
       this.transport.send(cancel);
     }
   }, {
     key: "receiveResponse",
     value: function receiveResponse(response) {
       var _this7 = this;
 
       var status_code = response.status_code;
 
       if (status_code >= 100 && status_code <= 199) {
         switch (this.state) {
           case C.STATUS_CALLING:
             this.stateChanged(C.STATUS_PROCEEDING);
             this.eventHandlers.onReceiveResponse(response);
             break;
 
           case C.STATUS_PROCEEDING:
             this.eventHandlers.onReceiveResponse(response);
             break;
         }
       } else if (status_code >= 200 && status_code <= 299) {
         switch (this.state) {
           case C.STATUS_CALLING:
           case C.STATUS_PROCEEDING:
             this.stateChanged(C.STATUS_ACCEPTED);
             this.M = setTimeout(function () {
               _this7.timer_M();
             }, Timers.TIMER_M);
             this.eventHandlers.onReceiveResponse(response);
             break;
 
           case C.STATUS_ACCEPTED:
             this.eventHandlers.onReceiveResponse(response);
             break;
         }
       } else if (status_code >= 300 && status_code <= 699) {
         switch (this.state) {
           case C.STATUS_CALLING:
           case C.STATUS_PROCEEDING:
             this.stateChanged(C.STATUS_COMPLETED);
             this.sendACK(response);
             this.eventHandlers.onReceiveResponse(response);
             break;
 
           case C.STATUS_COMPLETED:
             this.sendACK(response);
             break;
         }
       }
     }
   }, {
     key: "C",
     get: function get() {
       return C;
     }
   }]);
 
   return InviteClientTransaction;
 }(EventEmitter);
 
 var AckClientTransaction = /*#__PURE__*/function (_EventEmitter3) {
   _inherits(AckClientTransaction, _EventEmitter3);
 
   var _super3 = _createSuper(AckClientTransaction);
 
   function AckClientTransaction(ua, transport, request, eventHandlers) {
     var _this8;
 
     _classCallCheck(this, AckClientTransaction);
 
     _this8 = _super3.call(this);
     _this8.id = "z9hG4bK".concat(Math.floor(Math.random() * 10000000));
     _this8.transport = transport;
     _this8.request = request;
     _this8.eventHandlers = eventHandlers;
     var via = "SIP/2.0/".concat(transport.via_transport);
     via += " ".concat(ua.configuration.via_host, ";branch=").concat(_this8.id);
 
     _this8.request.setHeader('via', via);
 
     return _this8;
   }
 
   _createClass(AckClientTransaction, [{
     key: "send",
     value: function send() {
       if (!this.transport.send(this.request)) {
         this.onTransportError();
       }
     }
   }, {
     key: "onTransportError",
     value: function onTransportError() {
       debugact("transport error occurred for transaction ".concat(this.id));
       this.eventHandlers.onTransportError();
     }
   }, {
     key: "C",
     get: function get() {
       return C;
     }
   }]);
 
   return AckClientTransaction;
 }(EventEmitter);
 
 var NonInviteServerTransaction = /*#__PURE__*/function (_EventEmitter4) {
   _inherits(NonInviteServerTransaction, _EventEmitter4);
 
   var _super4 = _createSuper(NonInviteServerTransaction);
 
   function NonInviteServerTransaction(ua, transport, request) {
     var _this9;
 
     _classCallCheck(this, NonInviteServerTransaction);
 
     _this9 = _super4.call(this);
     _this9.type = C.NON_INVITE_SERVER;
     _this9.id = request.via_branch;
     _this9.ua = ua;
     _this9.transport = transport;
     _this9.request = request;
     _this9.last_response = '';
     request.server_transaction = _assertThisInitialized(_this9);
     _this9.state = C.STATUS_TRYING;
     ua.newTransaction(_assertThisInitialized(_this9));
     return _this9;
   }
 
   _createClass(NonInviteServerTransaction, [{
     key: "stateChanged",
     value: function stateChanged(state) {
       this.state = state;
       this.emit('stateChanged');
     }
   }, {
     key: "timer_J",
     value: function timer_J() {
       debugnist("Timer J expired for transaction ".concat(this.id));
       this.stateChanged(C.STATUS_TERMINATED);
       this.ua.destroyTransaction(this);
     }
   }, {
     key: "onTransportError",
     value: function onTransportError() {
       if (!this.transportError) {
         this.transportError = true;
         debugnist("transport error occurred, deleting transaction ".concat(this.id));
         clearTimeout(this.J);
         this.stateChanged(C.STATUS_TERMINATED);
         this.ua.destroyTransaction(this);
       }
     }
   }, {
     key: "receiveResponse",
     value: function receiveResponse(status_code, response, onSuccess, onFailure) {
       var _this10 = this;
 
       if (status_code === 100) {
         /* RFC 4320 4.1
          * 'A SIP element MUST NOT
          * send any provisional response with a
          * Status-Code other than 100 to a non-INVITE request.'
          */
         switch (this.state) {
           case C.STATUS_TRYING:
             this.stateChanged(C.STATUS_PROCEEDING);
 
             if (!this.transport.send(response)) {
               this.onTransportError();
             }
 
             break;
 
           case C.STATUS_PROCEEDING:
             this.last_response = response;
 
             if (!this.transport.send(response)) {
               this.onTransportError();
 
               if (onFailure) {
                 onFailure();
               }
             } else if (onSuccess) {
               onSuccess();
             }
 
             break;
         }
       } else if (status_code >= 200 && status_code <= 699) {
         switch (this.state) {
           case C.STATUS_TRYING:
           case C.STATUS_PROCEEDING:
             this.stateChanged(C.STATUS_COMPLETED);
             this.last_response = response;
             this.J = setTimeout(function () {
               _this10.timer_J();
             }, Timers.TIMER_J);
 
             if (!this.transport.send(response)) {
               this.onTransportError();
 
               if (onFailure) {
                 onFailure();
               }
             } else if (onSuccess) {
               onSuccess();
             }
 
             break;
 
           case C.STATUS_COMPLETED:
             break;
         }
       }
     }
   }, {
     key: "C",
     get: function get() {
       return C;
     }
   }]);
 
   return NonInviteServerTransaction;
 }(EventEmitter);
 
 var InviteServerTransaction = /*#__PURE__*/function (_EventEmitter5) {
   _inherits(InviteServerTransaction, _EventEmitter5);
 
   var _super5 = _createSuper(InviteServerTransaction);
 
   function InviteServerTransaction(ua, transport, request) {
     var _this11;
 
     _classCallCheck(this, InviteServerTransaction);
 
     _this11 = _super5.call(this);
     _this11.type = C.INVITE_SERVER;
     _this11.id = request.via_branch;
     _this11.ua = ua;
     _this11.transport = transport;
     _this11.request = request;
     _this11.last_response = '';
     request.server_transaction = _assertThisInitialized(_this11);
     _this11.state = C.STATUS_PROCEEDING;
     ua.newTransaction(_assertThisInitialized(_this11));
     _this11.resendProvisionalTimer = null;
     request.reply(100);
     return _this11;
   }
 
   _createClass(InviteServerTransaction, [{
     key: "stateChanged",
     value: function stateChanged(state) {
       this.state = state;
       this.emit('stateChanged');
     }
   }, {
     key: "timer_H",
     value: function timer_H() {
       debugist("Timer H expired for transaction ".concat(this.id));
 
       if (this.state === C.STATUS_COMPLETED) {
         debugist('ACK not received, dialog will be terminated');
       }
 
       this.stateChanged(C.STATUS_TERMINATED);
       this.ua.destroyTransaction(this);
     }
   }, {
     key: "timer_I",
     value: function timer_I() {
       this.stateChanged(C.STATUS_TERMINATED);
       this.ua.destroyTransaction(this);
     } // RFC 6026 7.1.
 
   }, {
     key: "timer_L",
     value: function timer_L() {
       debugist("Timer L expired for transaction ".concat(this.id));
 
       if (this.state === C.STATUS_ACCEPTED) {
         this.stateChanged(C.STATUS_TERMINATED);
         this.ua.destroyTransaction(this);
       }
     }
   }, {
     key: "onTransportError",
     value: function onTransportError() {
       if (!this.transportError) {
         this.transportError = true;
         debugist("transport error occurred, deleting transaction ".concat(this.id));
 
         if (this.resendProvisionalTimer !== null) {
           clearInterval(this.resendProvisionalTimer);
           this.resendProvisionalTimer = null;
         }
 
         clearTimeout(this.L);
         clearTimeout(this.H);
         clearTimeout(this.I);
         this.stateChanged(C.STATUS_TERMINATED);
         this.ua.destroyTransaction(this);
       }
     }
   }, {
     key: "resend_provisional",
     value: function resend_provisional() {
       if (!this.transport.send(this.last_response)) {
         this.onTransportError();
       }
     } // INVITE Server Transaction RFC 3261 17.2.1.
 
   }, {
     key: "receiveResponse",
     value: function receiveResponse(status_code, response, onSuccess, onFailure) {
       var _this12 = this;
 
       if (status_code >= 100 && status_code <= 199) {
         switch (this.state) {
           case C.STATUS_PROCEEDING:
             if (!this.transport.send(response)) {
               this.onTransportError();
             }
 
             this.last_response = response;
             break;
         }
       }
 
       if (status_code > 100 && status_code <= 199 && this.state === C.STATUS_PROCEEDING) {
         // Trigger the resendProvisionalTimer only for the first non 100 provisional response.
         if (this.resendProvisionalTimer === null) {
           this.resendProvisionalTimer = setInterval(function () {
             _this12.resend_provisional();
           }, Timers.PROVISIONAL_RESPONSE_INTERVAL);
         }
       } else if (status_code >= 200 && status_code <= 299) {
         switch (this.state) {
           case C.STATUS_PROCEEDING:
             this.stateChanged(C.STATUS_ACCEPTED);
             this.last_response = response;
             this.L = setTimeout(function () {
               _this12.timer_L();
             }, Timers.TIMER_L);
 
             if (this.resendProvisionalTimer !== null) {
               clearInterval(this.resendProvisionalTimer);
               this.resendProvisionalTimer = null;
             }
 
           /* falls through */
 
           case C.STATUS_ACCEPTED:
             // Note that this point will be reached for proceeding this.state also.
             if (!this.transport.send(response)) {
               this.onTransportError();
 
               if (onFailure) {
                 onFailure();
               }
             } else if (onSuccess) {
               onSuccess();
             }
 
             break;
         }
       } else if (status_code >= 300 && status_code <= 699) {
         switch (this.state) {
           case C.STATUS_PROCEEDING:
             if (this.resendProvisionalTimer !== null) {
               clearInterval(this.resendProvisionalTimer);
               this.resendProvisionalTimer = null;
             }
 
             if (!this.transport.send(response)) {
               this.onTransportError();
 
               if (onFailure) {
                 onFailure();
               }
             } else {
               this.stateChanged(C.STATUS_COMPLETED);
               this.H = setTimeout(function () {
                 _this12.timer_H();
               }, Timers.TIMER_H);
 
               if (onSuccess) {
                 onSuccess();
               }
             }
 
             break;
         }
       }
     }
   }, {
     key: "C",
     get: function get() {
       return C;
     }
   }]);
 
   return InviteServerTransaction;
 }(EventEmitter);
 /**
  * INVITE:
  *  _true_ if retransmission
  *  _false_ new request
  *
  * ACK:
  *  _true_  ACK to non2xx response
  *  _false_ ACK must be passed to TU (accepted state)
  *          ACK to 2xx response
  *
  * CANCEL:
  *  _true_  no matching invite transaction
  *  _false_ matching invite transaction and no final response sent
  *
  * OTHER:
  *  _true_  retransmission
  *  _false_ new request
  */
 
 
 function checkTransaction(_ref, request) {
   var _transactions = _ref._transactions;
   var tr;
 
   switch (request.method) {
     case JsSIP_C.INVITE:
       tr = _transactions.ist[request.via_branch];
 
       if (tr) {
         switch (tr.state) {
           case C.STATUS_PROCEEDING:
             tr.transport.send(tr.last_response);
             break;
           // RFC 6026 7.1 Invite retransmission.
           // Received while in C.STATUS_ACCEPTED state. Absorb it.
 
           case C.STATUS_ACCEPTED:
             break;
         }
 
         return true;
       }
 
       break;
 
     case JsSIP_C.ACK:
       tr = _transactions.ist[request.via_branch]; // RFC 6026 7.1.
 
       if (tr) {
         if (tr.state === C.STATUS_ACCEPTED) {
           return false;
         } else if (tr.state === C.STATUS_COMPLETED) {
           tr.state = C.STATUS_CONFIRMED;
           tr.I = setTimeout(function () {
             tr.timer_I();
           }, Timers.TIMER_I);
           return true;
         }
       } // ACK to 2XX Response.
       else {
           return false;
         }
 
       break;
 
     case JsSIP_C.CANCEL:
       tr = _transactions.ist[request.via_branch];
 
       if (tr) {
         request.reply_sl(200);
 
         if (tr.state === C.STATUS_PROCEEDING) {
           return false;
         } else {
           return true;
         }
       } else {
         request.reply_sl(481);
         return true;
       }
 
     default:
       // Non-INVITE Server Transaction RFC 3261 17.2.2.
       tr = _transactions.nist[request.via_branch];
 
       if (tr) {
         switch (tr.state) {
           case C.STATUS_TRYING:
             break;
 
           case C.STATUS_PROCEEDING:
           case C.STATUS_COMPLETED:
             tr.transport.send(tr.last_response);
             break;
         }
 
         return true;
       }
 
       break;
   }
 }
 
 module.exports = {
   C: C,
   NonInviteClientTransaction: NonInviteClientTransaction,
   InviteClientTransaction: InviteClientTransaction,
   AckClientTransaction: AckClientTransaction,
   NonInviteServerTransaction: NonInviteServerTransaction,
   InviteServerTransaction: InviteServerTransaction,
   checkTransaction: checkTransaction
 };
 },{"./Constants":2,"./SIPMessage":19,"./Timers":21,"debug":30,"events":29}],23:[function(require,module,exports){
 "use strict";
 
 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
 function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
 
 function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
 
 var Socket = require('./Socket');
 
 var debug = require('debug')('JsSIP:Transport');
 
 var debugerror = require('debug')('JsSIP:ERROR:Transport');
 
 var JsSIP_C = require('./Constants');
 
 debugerror.log = console.warn.bind(console);
 /**
  * Constants
  */
 
 var C = {
   // Transport status.
   STATUS_CONNECTED: 0,
   STATUS_CONNECTING: 1,
   STATUS_DISCONNECTED: 2,
   // Socket status.
   SOCKET_STATUS_READY: 0,
   SOCKET_STATUS_ERROR: 1,
   // Recovery options.
   recovery_options: {
     // minimum interval in seconds between recover attempts.
     min_interval: JsSIP_C.CONNECTION_RECOVERY_MIN_INTERVAL,
     // maximum interval in seconds between recover attempts.
     max_interval: JsSIP_C.CONNECTION_RECOVERY_MAX_INTERVAL
   }
 };
 /*
  * Manages one or multiple JsSIP.Socket instances.
  * Is reponsible for transport recovery logic among all socket instances.
  *
  * @socket JsSIP::Socket instance
  */
 
 module.exports = /*#__PURE__*/function () {
   function Transport(sockets) {
     var recovery_options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : C.recovery_options;
 
     _classCallCheck(this, Transport);
 
     debug('new()');
     this.status = C.STATUS_DISCONNECTED; // Current socket.
 
     this.socket = null; // Socket collection.
 
     this.sockets = [];
     this.recovery_options = recovery_options;
     this.recover_attempts = 0;
     this.recovery_timer = null;
     this.close_requested = false;
 
     if (typeof sockets === 'undefined') {
       throw new TypeError('Invalid argument.' + ' undefined \'sockets\' argument');
     }
 
     if (!(sockets instanceof Array)) {
       sockets = [sockets];
     }
 
     sockets.forEach(function (socket) {
       if (!Socket.isSocket(socket.socket)) {
         throw new TypeError('Invalid argument.' + ' invalid \'JsSIP.Socket\' instance');
       }
 
       if (socket.weight && !Number(socket.weight)) {
         throw new TypeError('Invalid argument.' + ' \'weight\' attribute is not a number');
       }
 
       this.sockets.push({
         socket: socket.socket,
         weight: socket.weight || 0,
         status: C.SOCKET_STATUS_READY
       });
     }, this); // Get the socket with higher weight.
 
     this._getSocket();
   }
   /**
    * Instance Methods
    */
 
 
   _createClass(Transport, [{
     key: "connect",
     value: function connect() {
       debug('connect()');
 
       if (this.isConnected()) {
         debug('Transport is already connected');
         return;
       } else if (this.isConnecting()) {
         debug('Transport is connecting');
         return;
       }
 
       this.close_requested = false;
       this.status = C.STATUS_CONNECTING;
       this.onconnecting({
         socket: this.socket,
         attempts: this.recover_attempts
       });
 
       if (!this.close_requested) {
         // Bind socket event callbacks.
         this.socket.onconnect = this._onConnect.bind(this);
         this.socket.ondisconnect = this._onDisconnect.bind(this);
         this.socket.ondata = this._onData.bind(this);
         this.socket.connect();
       }
 
       return;
     }
   }, {
     key: "disconnect",
     value: function disconnect() {
       debug('close()');
       this.close_requested = true;
       this.recover_attempts = 0;
       this.status = C.STATUS_DISCONNECTED; // Clear recovery_timer.
 
       if (this.recovery_timer !== null) {
         clearTimeout(this.recovery_timer);
         this.recovery_timer = null;
       } // Unbind socket event callbacks.
 
 
       this.socket.onconnect = function () {};
 
       this.socket.ondisconnect = function () {};
 
       this.socket.ondata = function () {};
 
       this.socket.disconnect();
       this.ondisconnect({
         socket: this.socket,
         error: false
       });
     }
   }, {
     key: "send",
     value: function send(data) {
       debug('send()');
 
       if (!this.isConnected()) {
         debugerror('unable to send message, transport is not connected');
         return false;
       }
 
       var message = data.toString();
       debug("sending message:\n\n".concat(message, "\n"));
       return this.socket.send(message);
     }
   }, {
     key: "isConnected",
     value: function isConnected() {
       return this.status === C.STATUS_CONNECTED;
     }
   }, {
     key: "isConnecting",
     value: function isConnecting() {
       return this.status === C.STATUS_CONNECTING;
     }
     /**
      * Private API.
      */
 
   }, {
     key: "_reconnect",
     value: function _reconnect() {
       var _this = this;
 
       this.recover_attempts += 1;
       var k = Math.floor(Math.random() * Math.pow(2, this.recover_attempts) + 1);
 
       if (k < this.recovery_options.min_interval) {
         k = this.recovery_options.min_interval;
       } else if (k > this.recovery_options.max_interval) {
         k = this.recovery_options.max_interval;
       }
 
       debug("reconnection attempt: ".concat(this.recover_attempts, ". next connection attempt in ").concat(k, " seconds"));
       this.recovery_timer = setTimeout(function () {
         if (!_this.close_requested && !(_this.isConnected() || _this.isConnecting())) {
           // Get the next available socket with higher weight.
           _this._getSocket(); // Connect the socket.
 
 
           _this.connect();
         }
       }, k * 1000);
     }
     /**
      * get the next available socket with higher weight
      */
 
   }, {
     key: "_getSocket",
     value: function _getSocket() {
       var candidates = [];
       this.sockets.forEach(function (socket) {
         if (socket.status === C.SOCKET_STATUS_ERROR) {
           return; // continue the array iteration
         } else if (candidates.length === 0) {
           candidates.push(socket);
         } else if (socket.weight > candidates[0].weight) {
           candidates = [socket];
         } else if (socket.weight === candidates[0].weight) {
           candidates.push(socket);
         }
       });
 
       if (candidates.length === 0) {
         // All sockets have failed. reset sockets status.
         this.sockets.forEach(function (socket) {
           socket.status = C.SOCKET_STATUS_READY;
         }); // Get next available socket.
 
         this._getSocket();
 
         return;
       }
 
       var idx = Math.floor(Math.random() * candidates.length);
       this.socket = candidates[idx].socket;
     }
     /**
      * Socket Event Handlers
      */
 
   }, {
     key: "_onConnect",
     value: function _onConnect() {
       this.recover_attempts = 0;
       this.status = C.STATUS_CONNECTED; // Clear recovery_timer.
 
       if (this.recovery_timer !== null) {
         clearTimeout(this.recovery_timer);
         this.recovery_timer = null;
       }
 
       this.onconnect({
         socket: this
       });
     }
   }, {
     key: "_onDisconnect",
     value: function _onDisconnect(error, code, reason) {
       this.status = C.STATUS_DISCONNECTED;
       this.ondisconnect({
         socket: this.socket,
         error: error,
         code: code,
         reason: reason
       });
 
       if (this.close_requested) {
         return;
       } // Update socket status.
       else {
           this.sockets.forEach(function (socket) {
             if (this.socket === socket.socket) {
               socket.status = C.SOCKET_STATUS_ERROR;
             }
           }, this);
         }
 
       this._reconnect(error);
     }
   }, {
     key: "_onData",
     value: function _onData(data) {
       // CRLF Keep Alive response from server. Ignore it.
       if (data === '\r\n') {
         debug('received message with CRLF Keep Alive response');
         return;
       } // Binary message.
       else if (typeof data !== 'string') {
           try {
             data = String.fromCharCode.apply(null, new Uint8Array(data));
           } catch (evt) {
             debug('received binary message failed to be converted into string,' + ' message discarded');
             return;
           }
 
           debug("received binary message:\n\n".concat(data, "\n"));
         } // Text message.
         else {
             debug("received text message:\n\n".concat(data, "\n"));
           }
 
       this.ondata({
         transport: this,
         message: data
       });
     }
   }, {
     key: "via_transport",
     get: function get() {
       return this.socket.via_transport;
     }
   }, {
     key: "url",
     get: function get() {
       return this.socket.url;
     }
   }, {
     key: "sip_uri",
     get: function get() {
       return this.socket.sip_uri;
     }
   }]);
 
   return Transport;
 }();
 },{"./Constants":2,"./Socket":20,"debug":30}],24:[function(require,module,exports){
 "use strict";
 
 function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
 
 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
 function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
 
 function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
 
 function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
 
 function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
 
 function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
 
 function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
 
 function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
 
 function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }
 
 function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
 
 var EventEmitter = require('events').EventEmitter;
 
 var JsSIP_C = require('./Constants');
 
 var Registrator = require('./Registrator');
 
 var RTCSession = require('./RTCSession');
 
 var Message = require('./Message');
 
 var Transactions = require('./Transactions');
 
 var Transport = require('./Transport');
 
 var Utils = require('./Utils');
 
 var Exceptions = require('./Exceptions');
 
 var URI = require('./URI');
 
 var Parser = require('./Parser');
 
 var SIPMessage = require('./SIPMessage');
 
 var sanityCheck = require('./sanityCheck');
 
 var config = require('./Config');
 
 var debug = require('debug')('JsSIP:UA');
 
 var debugerror = require('debug')('JsSIP:ERROR:UA');
 
 debugerror.log = console.warn.bind(console);
 var C = {
   // UA status codes.
   STATUS_INIT: 0,
   STATUS_READY: 1,
   STATUS_USER_CLOSED: 2,
   STATUS_NOT_READY: 3,
   // UA error codes.
   CONFIGURATION_ERROR: 1,
   NETWORK_ERROR: 2
 };
 /**
  * The User-Agent class.
  * @class JsSIP.UA
  * @param {Object} configuration Configuration parameters.
  * @throws {JsSIP.Exceptions.ConfigurationError} If a configuration parameter is invalid.
  * @throws {TypeError} If no configuration is given.
  */
 
 module.exports = /*#__PURE__*/function (_EventEmitter) {
   _inherits(UA, _EventEmitter);
 
   var _super = _createSuper(UA);
 
   _createClass(UA, null, [{
     key: "C",
     // Expose C object.
     get: function get() {
       return C;
     }
   }]);
 
   function UA(configuration) {
     var _this;
 
     _classCallCheck(this, UA);
 
     debug('new() [configuration:%o]', configuration);
     _this = _super.call(this);
     _this._cache = {
       credentials: {}
     };
     _this._configuration = Object.assign({}, config.settings);
     _this._dynConfiguration = {};
     _this._dialogs = {}; // User actions outside any session/dialog (MESSAGE).
 
     _this._applicants = {};
     _this._sessions = {};
     _this._transport = null;
     _this._contact = null;
     _this._status = C.STATUS_INIT;
     _this._error = null;
     _this._transactions = {
       nist: {},
       nict: {},
       ist: {},
       ict: {}
     }; // Custom UA empty object for high level use.
 
     _this._data = {};
     _this._closeTimer = null; // Check configuration argument.
 
     if (configuration === undefined) {
       throw new TypeError('Not enough arguments');
     } // Load configuration.
 
 
     try {
       _this._loadConfig(configuration);
     } catch (e) {
       _this._status = C.STATUS_NOT_READY;
       _this._error = C.CONFIGURATION_ERROR;
       throw e;
     } // Initialize registrator.
 
 
     _this._registrator = new Registrator(_assertThisInitialized(_this));
     return _this;
   }
 
   _createClass(UA, [{
     key: "start",
     // =================
     //  High Level API
     // =================
 
     /**
      * Connect to the server if status = STATUS_INIT.
      * Resume UA after being closed.
      */
     value: function start() {
       debug('start()');
 
       if (this._status === C.STATUS_INIT) {
         this._transport.connect();
       } else if (this._status === C.STATUS_USER_CLOSED) {
         debug('restarting UA'); // Disconnect.
 
         if (this._closeTimer !== null) {
           clearTimeout(this._closeTimer);
           this._closeTimer = null;
 
           this._transport.disconnect();
         } // Reconnect.
 
 
         this._status = C.STATUS_INIT;
 
         this._transport.connect();
       } else if (this._status === C.STATUS_READY) {
         debug('UA is in READY status, not restarted');
       } else {
         debug('ERROR: connection is down, Auto-Recovery system is trying to reconnect');
       } // Set dynamic configuration.
 
 
       this._dynConfiguration.register = this._configuration.register;
     }
     /**
      * Register.
      */
 
   }, {
     key: "register",
     value: function register() {
       debug('register()');
       this._dynConfiguration.register = true;
 
       this._registrator.register();
     }
     /**
      * Unregister.
      */
 
   }, {
     key: "unregister",
     value: function unregister(options) {
       debug('unregister()');
       this._dynConfiguration.register = false;
 
       this._registrator.unregister(options);
     }
     /**
      * Get the Registrator instance.
      */
 
   }, {
     key: "registrator",
     value: function registrator() {
       return this._registrator;
     }
     /**
      * Registration state.
      */
 
   }, {
     key: "isRegistered",
     value: function isRegistered() {
       return this._registrator.registered;
     }
     /**
      * Connection state.
      */
 
   }, {
     key: "isConnected",
     value: function isConnected() {
       return this._transport.isConnected();
     }
     /**
      * Make an outgoing call.
      *
      * -param {String} target
      * -param {Object} [options]
      *
      * -throws {TypeError}
      *
      */
 
   }, {
     key: "call",
     value: function call(target, options) {
       debug('call()');
       var session = new RTCSession(this);
       session.connect(target, options);
       return session;
     }
     /**
      * Send a message.
      *
      * -param {String} target
      * -param {String} body
      * -param {Object} [options]
      *
      * -throws {TypeError}
      *
      */
 
   }, {
     key: "sendMessage",
     value: function sendMessage(target, body, options) {
       debug('sendMessage()');
       var message = new Message(this);
       message.send(target, body, options);
       return message;
     }
     /**
      * Terminate ongoing sessions.
      */
 
   }, {
     key: "terminateSessions",
     value: function terminateSessions(options) {
       debug('terminateSessions()');
 
       for (var idx in this._sessions) {
         if (!this._sessions[idx].isEnded()) {
           this._sessions[idx].terminate(options);
         }
       }
     }
     /**
      * Gracefully close.
      *
      */
 
   }, {
     key: "stop",
     value: function stop() {
       var _this2 = this;
 
       debug('stop()'); // Remove dynamic settings.
 
       this._dynConfiguration = {};
 
       if (this._status === C.STATUS_USER_CLOSED) {
         debug('UA already closed');
         return;
       } // Close registrator.
 
 
       this._registrator.close(); // If there are session wait a bit so CANCEL/BYE can be sent and their responses received.
 
 
       var num_sessions = Object.keys(this._sessions).length; // Run  _terminate_ on every Session.
 
       for (var session in this._sessions) {
         if (Object.prototype.hasOwnProperty.call(this._sessions, session)) {
           debug("closing session ".concat(session));
 
           try {
             this._sessions[session].terminate();
           } catch (error) {}
         }
       } // Run  _close_ on every applicant.
 
 
       for (var applicant in this._applicants) {
         if (Object.prototype.hasOwnProperty.call(this._applicants, applicant)) try {
           this._applicants[applicant].close();
         } catch (error) {}
       }
 
       this._status = C.STATUS_USER_CLOSED;
       var num_transactions = Object.keys(this._transactions.nict).length + Object.keys(this._transactions.nist).length + Object.keys(this._transactions.ict).length + Object.keys(this._transactions.ist).length;
 
       if (num_transactions === 0 && num_sessions === 0) {
         this._transport.disconnect();
       } else {
         this._closeTimer = setTimeout(function () {
           _this2._closeTimer = null;
 
           _this2._transport.disconnect();
         }, 2000);
       }
     }
     /**
      * Normalice a string into a valid SIP request URI
      * -param {String} target
      * -returns {JsSIP.URI|undefined}
      */
 
   }, {
     key: "normalizeTarget",
     value: function normalizeTarget(target) {
       return Utils.normalizeTarget(target, this._configuration.hostport_params);
     }
     /**
      * Allow retrieving configuration and autogenerated fields in runtime.
      */
 
   }, {
     key: "get",
     value: function get(parameter) {
       switch (parameter) {
         case 'authorization_user':
           return this._configuration.authorization_user;
 
         case 'realm':
           return this._configuration.realm;
 
         case 'ha1':
           return this._configuration.ha1;
 
         case 'authorization_jwt':
           return this._configuration.authorization_jwt;
 
         default:
           debugerror('get() | cannot get "%s" parameter in runtime', parameter);
           return undefined;
       }
     }
     /**
      * Allow configuration changes in runtime.
      * Returns true if the parameter could be set.
      */
 
   }, {
     key: "set",
     value: function set(parameter, value) {
       switch (parameter) {
         case 'authorization_user':
           {
             this._configuration.authorization_user = String(value);
             break;
           }
 
         case 'password':
           {
             this._configuration.password = String(value);
             break;
           }
 
         case 'realm':
           {
             this._configuration.realm = String(value);
             break;
           }
 
         case 'ha1':
           {
             this._configuration.ha1 = String(value); // Delete the plain SIP password.
 
             this._configuration.password = null;
             break;
           }
 
         case 'authorization_jwt':
           {
             this._configuration.authorization_jwt = String(value);
             break;
           }
 
         case 'display_name':
           {
             this._configuration.display_name = value;
             break;
           }
 
         default:
           debugerror('set() | cannot set "%s" parameter in runtime', parameter);
           return false;
       }
 
       return true;
     } // ==========================
     // Event Handlers.
     // ==========================
 
     /**
      * new Transaction
      */
 
   }, {
     key: "newTransaction",
     value: function newTransaction(transaction) {
       this._transactions[transaction.type][transaction.id] = transaction;
       this.emit('newTransaction', {
         transaction: transaction
       });
     }
     /**
      * Transaction destroyed.
      */
 
   }, {
     key: "destroyTransaction",
     value: function destroyTransaction(transaction) {
       delete this._transactions[transaction.type][transaction.id];
       this.emit('transactionDestroyed', {
         transaction: transaction
       });
     }
     /**
      * new Dialog
      */
 
   }, {
     key: "newDialog",
     value: function newDialog(dialog) {
       this._dialogs[dialog.id] = dialog;
     }
     /**
      * Dialog destroyed.
      */
 
   }, {
     key: "destroyDialog",
     value: function destroyDialog(dialog) {
       delete this._dialogs[dialog.id];
     }
     /**
      *  new Message
      */
 
   }, {
     key: "newMessage",
     value: function newMessage(message, data) {
       this._applicants[message] = message;
       this.emit('newMessage', data);
     }
     /**
      *  Message destroyed.
      */
 
   }, {
     key: "destroyMessage",
     value: function destroyMessage(message) {
       delete this._applicants[message];
     }
     /**
      * new RTCSession
      */
 
   }, {
     key: "newRTCSession",
     value: function newRTCSession(session, data) {
       this._sessions[session.id] = session;
       this.emit('newRTCSession', data);
     }
     /**
      * RTCSession destroyed.
      */
 
   }, {
     key: "destroyRTCSession",
     value: function destroyRTCSession(session) {
       delete this._sessions[session.id];
     }
     /**
      * Registered
      */
 
   }, {
     key: "registered",
     value: function registered(data) {
       this.emit('registered', data);
     }
     /**
      * Unregistered
      */
 
   }, {
     key: "unregistered",
     value: function unregistered(data) {
       this.emit('unregistered', data);
     }
     /**
      * Registration Failed
      */
 
   }, {
     key: "registrationFailed",
     value: function registrationFailed(data) {
       this.emit('registrationFailed', data);
     } // =========================
     // ReceiveRequest.
     // =========================
 
     /**
      * Request reception
      */
 
   }, {
     key: "receiveRequest",
     value: function receiveRequest(request) {
       var method = request.method; // Check that request URI points to us.
 
       if (request.ruri.user !== this._configuration.uri.user && request.ruri.user !== this._contact.uri.user) {
         debug('Request-URI does not point to us');
 
         if (request.method !== JsSIP_C.ACK) {
           request.reply_sl(404);
         }
 
         return;
       } // Check request URI scheme.
 
 
       if (request.ruri.scheme === JsSIP_C.SIPS) {
         request.reply_sl(416);
         return;
       } // Check transaction.
 
 
       if (Transactions.checkTransaction(this, request)) {
         return;
       } // Create the server transaction.
 
 
       if (method === JsSIP_C.INVITE) {
         /* eslint-disable no-new */
         new Transactions.InviteServerTransaction(this, this._transport, request);
         /* eslint-enable no-new */
       } else if (method !== JsSIP_C.ACK && method !== JsSIP_C.CANCEL) {
         /* eslint-disable no-new */
         new Transactions.NonInviteServerTransaction(this, this._transport, request);
         /* eslint-enable no-new */
       }
       /* RFC3261 12.2.2
        * Requests that do not change in any way the state of a dialog may be
        * received within a dialog (for example, an OPTIONS request).
        * They are processed as if they had been received outside the dialog.
        */
 
 
       if (method === JsSIP_C.OPTIONS) {
         request.reply(200);
       } else if (method === JsSIP_C.MESSAGE) {
         if (this.listeners('newMessage').length === 0) {
           request.reply(405);
           return;
         }
 
         var message = new Message(this);
         message.init_incoming(request);
       } else if (method === JsSIP_C.INVITE) {
         // Initial INVITE.
         if (!request.to_tag && this.listeners('newRTCSession').length === 0) {
           request.reply(405);
           return;
         }
       }
 
       var dialog;
       var session; // Initial Request.
 
       if (!request.to_tag) {
         switch (method) {
           case JsSIP_C.INVITE:
             if (window.RTCPeerConnection) {
               // TODO
               if (request.hasHeader('replaces')) {
                 var replaces = request.replaces;
                 dialog = this._findDialog(replaces.call_id, replaces.from_tag, replaces.to_tag);
 
                 if (dialog) {
                   session = dialog.owner;
 
                   if (!session.isEnded()) {
                     session.receiveRequest(request);
                   } else {
                     request.reply(603);
                   }
                 } else {
                   request.reply(481);
                 }
               } else {
                 session = new RTCSession(this);
                 session.init_incoming(request);
               }
             } else {
               debugerror('INVITE received but WebRTC is not supported');
               request.reply(488);
             }
 
             break;
 
           case JsSIP_C.BYE:
             // Out of dialog BYE received.
             request.reply(481);
             break;
 
           case JsSIP_C.CANCEL:
             session = this._findSession(request);
 
             if (session) {
               session.receiveRequest(request);
             } else {
               debug('received CANCEL request for a non existent session');
             }
 
             break;
 
           case JsSIP_C.ACK:
             /* Absorb it.
              * ACK request without a corresponding Invite Transaction
              * and without To tag.
              */
             break;
 
           case JsSIP_C.NOTIFY:
             // Receive new sip event.
             this.emit('sipEvent', {
               event: request.event,
               request: request
             });
             request.reply(200);
             break;
 
           default:
             request.reply(405);
             break;
         }
       } // In-dialog request.
       else {
           dialog = this._findDialog(request.call_id, request.from_tag, request.to_tag);
 
           if (dialog) {
             dialog.receiveRequest(request);
           } else if (method === JsSIP_C.NOTIFY) {
             session = this._findSession(request);
 
             if (session) {
               session.receiveRequest(request);
             } else {
               debug('received NOTIFY request for a non existent subscription');
               request.reply(481, 'Subscription does not exist');
             }
           }
           /* RFC3261 12.2.2
            * Request with to tag, but no matching dialog found.
            * Exception: ACK for an Invite request for which a dialog has not
            * been created.
            */
           else if (method !== JsSIP_C.ACK) {
               request.reply(481);
             }
         }
     } // =================
     // Utils.
     // =================
 
     /**
      * Get the session to which the request belongs to, if any.
      */
 
   }, {
     key: "_findSession",
     value: function _findSession(_ref) {
       var call_id = _ref.call_id,
           from_tag = _ref.from_tag,
           to_tag = _ref.to_tag;
       var sessionIDa = call_id + from_tag;
       var sessionA = this._sessions[sessionIDa];
       var sessionIDb = call_id + to_tag;
       var sessionB = this._sessions[sessionIDb];
 
       if (sessionA) {
         return sessionA;
       } else if (sessionB) {
         return sessionB;
       } else {
         return null;
       }
     }
     /**
      * Get the dialog to which the request belongs to, if any.
      */
 
   }, {
     key: "_findDialog",
     value: function _findDialog(call_id, from_tag, to_tag) {
       var id = call_id + from_tag + to_tag;
       var dialog = this._dialogs[id];
 
       if (dialog) {
         return dialog;
       } else {
         id = call_id + to_tag + from_tag;
         dialog = this._dialogs[id];
 
         if (dialog) {
           return dialog;
         } else {
           return null;
         }
       }
     }
   }, {
     key: "_loadConfig",
     value: function _loadConfig(configuration) {
       // Check and load the given configuration.
       try {
         config.load(this._configuration, configuration);
       } catch (e) {
         throw e;
       } // Post Configuration Process.
       // Allow passing 0 number as display_name.
 
 
       if (this._configuration.display_name === 0) {
         this._configuration.display_name = '0';
       } // Instance-id for GRUU.
 
 
       if (!this._configuration.instance_id) {
         this._configuration.instance_id = Utils.newUUID();
       } // Jssip_id instance parameter. Static random tag of length 5.
 
 
       this._configuration.jssip_id = Utils.createRandomToken(5); // String containing this._configuration.uri without scheme and user.
 
       var hostport_params = this._configuration.uri.clone();
 
       hostport_params.user = null;
       this._configuration.hostport_params = hostport_params.toString().replace(/^sip:/i, ''); // Transport.
 
       try {
         this._transport = new Transport(this._configuration.sockets, {
           // Recovery options.
           max_interval: this._configuration.connection_recovery_max_interval,
           min_interval: this._configuration.connection_recovery_min_interval
         }); // Transport event callbacks.
 
         this._transport.onconnecting = onTransportConnecting.bind(this);
         this._transport.onconnect = onTransportConnect.bind(this);
         this._transport.ondisconnect = onTransportDisconnect.bind(this);
         this._transport.ondata = onTransportData.bind(this);
       } catch (e) {
         debugerror(e);
         throw new Exceptions.ConfigurationError('sockets', this._configuration.sockets);
       } // Remove sockets instance from configuration object.
 
 
       delete this._configuration.sockets; // Check whether authorization_user is explicitly defined.
       // Take 'this._configuration.uri.user' value if not.
 
       if (!this._configuration.authorization_user) {
         this._configuration.authorization_user = this._configuration.uri.user;
       } // If no 'registrar_server' is set use the 'uri' value without user portion and
       // without URI params/headers.
 
 
       if (!this._configuration.registrar_server) {
         var registrar_server = this._configuration.uri.clone();
 
         registrar_server.user = null;
         registrar_server.clearParams();
         registrar_server.clearHeaders();
         this._configuration.registrar_server = registrar_server;
       } // User no_answer_timeout.
 
 
       this._configuration.no_answer_timeout *= 1000; // Via Host.
 
       if (this._configuration.contact_uri) {
         this._configuration.via_host = this._configuration.contact_uri.host;
       } // Contact URI.
       else {
           this._configuration.contact_uri = new URI('sip', Utils.createRandomToken(8), this._configuration.via_host, null, {
             transport: 'ws'
           });
         }
 
       this._contact = {
         pub_gruu: null,
         temp_gruu: null,
         uri: this._configuration.contact_uri,
         toString: function toString() {
           var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
           var anonymous = options.anonymous || null;
           var outbound = options.outbound || null;
           var contact = '<';
 
           if (anonymous) {
             contact += this.temp_gruu || 'sip:anonymous@anonymous.invalid;transport=ws';
           } else {
             contact += this.pub_gruu || this.uri.toString();
           }
 
           if (outbound && (anonymous ? !this.temp_gruu : !this.pub_gruu)) {
             contact += ';ob';
           }
 
           contact += '>';
           return contact;
         }
       }; // Seal the configuration.
 
       var writable_parameters = ['authorization_user', 'password', 'realm', 'ha1', 'authorization_jwt', 'display_name', 'register'];
 
       for (var parameter in this._configuration) {
         if (Object.prototype.hasOwnProperty.call(this._configuration, parameter)) {
           if (writable_parameters.indexOf(parameter) !== -1) {
             Object.defineProperty(this._configuration, parameter, {
               writable: true,
               configurable: false
             });
           } else {
             Object.defineProperty(this._configuration, parameter, {
               writable: false,
               configurable: false
             });
           }
         }
       }
 
       debug('configuration parameters after validation:');
 
       for (var _parameter in this._configuration) {
         // Only show the user user configurable parameters.
         if (Object.prototype.hasOwnProperty.call(config.settings, _parameter)) {
           switch (_parameter) {
             case 'uri':
             case 'registrar_server':
               debug("- ".concat(_parameter, ": ").concat(this._configuration[_parameter]));
               break;
 
             case 'password':
             case 'ha1':
             case 'authorization_jwt':
               debug("- ".concat(_parameter, ": NOT SHOWN"));
               break;
 
             default:
               debug("- ".concat(_parameter, ": ").concat(JSON.stringify(this._configuration[_parameter])));
           }
         }
       }
 
       return;
     }
   }, {
     key: "C",
     get: function get() {
       return C;
     }
   }, {
     key: "status",
     get: function get() {
       return this._status;
     }
   }, {
     key: "contact",
     get: function get() {
       return this._contact;
     }
   }, {
     key: "configuration",
     get: function get() {
       return this._configuration;
     }
   }, {
     key: "transport",
     get: function get() {
       return this._transport;
     }
   }]);
 
   return UA;
 }(EventEmitter);
 /**
  * Transport event handlers
  */
 // Transport connecting event.
 
 
 function onTransportConnecting(data) {
   this.emit('connecting', data);
 } // Transport connected event.
 
 
 function onTransportConnect(data) {
   if (this._status === C.STATUS_USER_CLOSED) {
     return;
   }
 
   this._status = C.STATUS_READY;
   this._error = null;
   this.emit('connected', data);
 
   if (this._dynConfiguration.register) {
     this._registrator.register();
   }
 } // Transport disconnected event.
 
 
 function onTransportDisconnect(data) {
   // Run _onTransportError_ callback on every client transaction using _transport_.
   var client_transactions = ['nict', 'ict', 'nist', 'ist'];
 
   for (var _i = 0, _client_transactions = client_transactions; _i < _client_transactions.length; _i++) {
     var type = _client_transactions[_i];
 
     for (var id in this._transactions[type]) {
       if (Object.prototype.hasOwnProperty.call(this._transactions[type], id)) {
         this._transactions[type][id].onTransportError();
       }
     }
   }
 
   this.emit('disconnected', data); // Call registrator _onTransportClosed_.
 
   this._registrator.onTransportClosed();
 
   if (this._status !== C.STATUS_USER_CLOSED) {
     this._status = C.STATUS_NOT_READY;
     this._error = C.NETWORK_ERROR;
   }
 } // Transport data event.
 
 
 function onTransportData(data) {
   var transport = data.transport;
   var message = data.message;
   message = Parser.parseMessage(message, this);
 
   if (!message) {
     return;
   }
 
   if (this._status === C.STATUS_USER_CLOSED && message instanceof SIPMessage.IncomingRequest) {
     return;
   } // Do some sanity check.
 
 
   if (!sanityCheck(message, this, transport)) {
     return;
   }
 
   if (message instanceof SIPMessage.IncomingRequest) {
     message.transport = transport;
     this.receiveRequest(message);
   } else if (message instanceof SIPMessage.IncomingResponse) {
     /* Unike stated in 18.1.2, if a response does not match
     * any transaction, it is discarded here and no passed to the core
     * in order to be discarded there.
     */
     var transaction;
 
     switch (message.method) {
       case JsSIP_C.INVITE:
         transaction = this._transactions.ict[message.via_branch];
 
         if (transaction) {
           transaction.receiveResponse(message);
         }
 
         break;
 
       case JsSIP_C.ACK:
         // Just in case ;-).
         break;
 
       default:
         transaction = this._transactions.nict[message.via_branch];
 
         if (transaction) {
           transaction.receiveResponse(message);
         }
 
         break;
     }
   }
 }
 },{"./Config":1,"./Constants":2,"./Exceptions":6,"./Message":9,"./Parser":11,"./RTCSession":12,"./Registrator":17,"./SIPMessage":19,"./Transactions":22,"./Transport":23,"./URI":25,"./Utils":26,"./sanityCheck":28,"debug":30,"events":29}],25:[function(require,module,exports){
 "use strict";
 
 function _createForOfIteratorHelper(o, allowArrayLike) { var it; if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
 
 function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
 
 function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
 
 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
 function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
 
 function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
 
 var JsSIP_C = require('./Constants');
 
 var Utils = require('./Utils');
 
 var Grammar = require('./Grammar');
 /**
  * -param {String} [scheme]
  * -param {String} [user]
  * -param {String} host
  * -param {String} [port]
  * -param {Object} [parameters]
  * -param {Object} [headers]
  *
  */
 
 
 module.exports = /*#__PURE__*/function () {
   _createClass(URI, null, [{
     key: "parse",
 
     /**
       * Parse the given string and returns a JsSIP.URI instance or undefined if
       * it is an invalid URI.
       */
     value: function parse(uri) {
       uri = Grammar.parse(uri, 'SIP_URI');
 
       if (uri !== -1) {
         return uri;
       } else {
         return undefined;
       }
     }
   }]);
 
   function URI(scheme, user, host, port) {
     var parameters = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {};
     var headers = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : {};
 
     _classCallCheck(this, URI);
 
     // Checks.
     if (!host) {
       throw new TypeError('missing or invalid "host" parameter');
     } // Initialize parameters.
 
 
     this._parameters = {};
     this._headers = {};
     this._scheme = scheme || JsSIP_C.SIP;
     this._user = user;
     this._host = host;
     this._port = port;
 
     for (var param in parameters) {
       if (Object.prototype.hasOwnProperty.call(parameters, param)) {
         this.setParam(param, parameters[param]);
       }
     }
 
     for (var header in headers) {
       if (Object.prototype.hasOwnProperty.call(headers, header)) {
         this.setHeader(header, headers[header]);
       }
     }
   }
 
   _createClass(URI, [{
     key: "setParam",
     value: function setParam(key, value) {
       if (key) {
         this._parameters[key.toLowerCase()] = typeof value === 'undefined' || value === null ? null : value.toString();
       }
     }
   }, {
     key: "getParam",
     value: function getParam(key) {
       if (key) {
         return this._parameters[key.toLowerCase()];
       }
     }
   }, {
     key: "hasParam",
     value: function hasParam(key) {
       if (key) {
         return this._parameters.hasOwnProperty(key.toLowerCase()) && true || false;
       }
     }
   }, {
     key: "deleteParam",
     value: function deleteParam(parameter) {
       parameter = parameter.toLowerCase();
 
       if (this._parameters.hasOwnProperty(parameter)) {
         var value = this._parameters[parameter];
         delete this._parameters[parameter];
         return value;
       }
     }
   }, {
     key: "clearParams",
     value: function clearParams() {
       this._parameters = {};
     }
   }, {
     key: "setHeader",
     value: function setHeader(name, value) {
       this._headers[Utils.headerize(name)] = Array.isArray(value) ? value : [value];
     }
   }, {
     key: "getHeader",
     value: function getHeader(name) {
       if (name) {
         return this._headers[Utils.headerize(name)];
       }
     }
   }, {
     key: "hasHeader",
     value: function hasHeader(name) {
       if (name) {
         return this._headers.hasOwnProperty(Utils.headerize(name)) && true || false;
       }
     }
   }, {
     key: "deleteHeader",
     value: function deleteHeader(header) {
       header = Utils.headerize(header);
 
       if (this._headers.hasOwnProperty(header)) {
         var value = this._headers[header];
         delete this._headers[header];
         return value;
       }
     }
   }, {
     key: "clearHeaders",
     value: function clearHeaders() {
       this._headers = {};
     }
   }, {
     key: "clone",
     value: function clone() {
       return new URI(this._scheme, this._user, this._host, this._port, JSON.parse(JSON.stringify(this._parameters)), JSON.parse(JSON.stringify(this._headers)));
     }
   }, {
     key: "toString",
     value: function toString() {
       var headers = [];
       var uri = "".concat(this._scheme, ":");
 
       if (this._user) {
         uri += "".concat(Utils.escapeUser(this._user), "@");
       }
 
       uri += this._host;
 
       if (this._port || this._port === 0) {
         uri += ":".concat(this._port);
       }
 
       for (var parameter in this._parameters) {
         if (Object.prototype.hasOwnProperty.call(this._parameters, parameter)) {
           uri += ";".concat(parameter);
 
           if (this._parameters[parameter] !== null) {
             uri += "=".concat(this._parameters[parameter]);
           }
         }
       }
 
       for (var header in this._headers) {
         if (Object.prototype.hasOwnProperty.call(this._headers, header)) {
           var _iterator = _createForOfIteratorHelper(this._headers[header]),
               _step;
 
           try {
             for (_iterator.s(); !(_step = _iterator.n()).done;) {
               var item = _step.value;
               headers.push("".concat(header, "=").concat(item));
             }
           } catch (err) {
             _iterator.e(err);
           } finally {
             _iterator.f();
           }
         }
       }
 
       if (headers.length > 0) {
         uri += "?".concat(headers.join('&'));
       }
 
       return uri;
     }
   }, {
     key: "toAor",
     value: function toAor(show_port) {
       var aor = "".concat(this._scheme, ":");
 
       if (this._user) {
         aor += "".concat(Utils.escapeUser(this._user), "@");
       }
 
       aor += this._host;
 
       if (show_port && (this._port || this._port === 0)) {
         aor += ":".concat(this._port);
       }
 
       return aor;
     }
   }, {
     key: "scheme",
     get: function get() {
       return this._scheme;
     },
     set: function set(value) {
       this._scheme = value.toLowerCase();
     }
   }, {
     key: "user",
     get: function get() {
       return this._user;
     },
     set: function set(value) {
       this._user = value;
     }
   }, {
     key: "host",
     get: function get() {
       return this._host;
     },
     set: function set(value) {
       this._host = value.toLowerCase();
     }
   }, {
     key: "port",
     get: function get() {
       return this._port;
     },
     set: function set(value) {
       this._port = value === 0 ? value : parseInt(value, 10) || null;
     }
   }]);
 
   return URI;
 }();
 },{"./Constants":2,"./Grammar":7,"./Utils":26}],26:[function(require,module,exports){
 "use strict";
 
 function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
 
 function _createForOfIteratorHelper(o, allowArrayLike) { var it; if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
 
 function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
 
 function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
 
 var JsSIP_C = require('./Constants');
 
 var URI = require('./URI');
 
 var Grammar = require('./Grammar');
 
 exports.str_utf8_length = function (string) {
   return unescape(encodeURIComponent(string)).length;
 }; // Used by 'hasMethods'.
 
 
 var isFunction = exports.isFunction = function (fn) {
   if (fn !== undefined) {
     return Object.prototype.toString.call(fn) === '[object Function]' ? true : false;
   } else {
     return false;
   }
 };
 
 exports.isString = function (str) {
   if (str !== undefined) {
     return Object.prototype.toString.call(str) === '[object String]' ? true : false;
   } else {
     return false;
   }
 };
 
 exports.isDecimal = function (num) {
   return !isNaN(num) && parseFloat(num) === parseInt(num, 10);
 };
 
 exports.isEmpty = function (value) {
   return value === null || value === '' || value === undefined || Array.isArray(value) && value.length === 0 || typeof value === 'number' && isNaN(value);
 };
 
 exports.hasMethods = function (obj) {
   for (var _len = arguments.length, methodNames = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
     methodNames[_key - 1] = arguments[_key];
   }
 
   for (var _i = 0, _methodNames = methodNames; _i < _methodNames.length; _i++) {
     var methodName = _methodNames[_i];
 
     if (isFunction(obj[methodName])) {
       return false;
     }
   }
 
   return true;
 }; // Used by 'newTag'.
 
 
 var createRandomToken = exports.createRandomToken = function (size) {
   var base = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 32;
   var i,
       r,
       token = '';
 
   for (i = 0; i < size; i++) {
     r = Math.random() * base | 0;
     token += r.toString(base);
   }
 
   return token;
 };
 
 exports.newTag = function () {
   return createRandomToken(10);
 }; // https://stackoverflow.com/users/109538/broofa.
 
 
 exports.newUUID = function () {
   var UUID = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
     var r = Math.random() * 16 | 0,
         v = c === 'x' ? r : r & 0x3 | 0x8;
     return v.toString(16);
   });
   return UUID;
 };
 
 exports.hostType = function (host) {
   if (!host) {
     return;
   } else {
     host = Grammar.parse(host, 'host');
 
     if (host !== -1) {
       return host.host_type;
     }
   }
 };
 /**
 * Hex-escape a SIP URI user.
 * Don't hex-escape ':' (%3A), '+' (%2B), '?' (%3F"), '/' (%2F).
 *
 * Used by 'normalizeTarget'.
 */
 
 
 var escapeUser = exports.escapeUser = function (user) {
   return encodeURIComponent(decodeURIComponent(user)).replace(/%3A/ig, ':').replace(/%2B/ig, '+').replace(/%3F/ig, '?').replace(/%2F/ig, '/');
 };
 /**
 * Normalize SIP URI.
 * NOTE: It does not allow a SIP URI without username.
 * Accepts 'sip', 'sips' and 'tel' URIs and convert them into 'sip'.
 * Detects the domain part (if given) and properly hex-escapes the user portion.
 * If the user portion has only 'tel' number symbols the user portion is clean of 'tel' visual separators.
 */
 
 
 exports.normalizeTarget = function (target, domain) {
   // If no target is given then raise an error.
   if (!target) {
     return; // If a URI instance is given then return it.
   } else if (target instanceof URI) {
     return target; // If a string is given split it by '@':
     // - Last fragment is the desired domain.
     // - Otherwise append the given domain argument.
   } else if (typeof target === 'string') {
     var target_array = target.split('@');
     var target_user;
     var target_domain;
 
     switch (target_array.length) {
       case 1:
         if (!domain) {
           return;
         }
 
         target_user = target;
         target_domain = domain;
         break;
 
       case 2:
         target_user = target_array[0];
         target_domain = target_array[1];
         break;
 
       default:
         target_user = target_array.slice(0, target_array.length - 1).join('@');
         target_domain = target_array[target_array.length - 1];
     } // Remove the URI scheme (if present).
 
 
     target_user = target_user.replace(/^(sips?|tel):/i, ''); // Remove 'tel' visual separators if the user portion just contains 'tel' number symbols.
 
     if (/^[-.()]*\+?[0-9\-.()]+$/.test(target_user)) {
       target_user = target_user.replace(/[-.()]/g, '');
     } // Build the complete SIP URI.
 
 
     target = "".concat(JsSIP_C.SIP, ":").concat(escapeUser(target_user), "@").concat(target_domain); // Finally parse the resulting URI.
 
     var uri;
 
     if (uri = URI.parse(target)) {
       return uri;
     } else {
       return;
     }
   } else {
     return;
   }
 };
 
 exports.headerize = function (string) {
   var exceptions = {
     'Call-Id': 'Call-ID',
     'Cseq': 'CSeq',
     'Www-Authenticate': 'WWW-Authenticate'
   };
   var name = string.toLowerCase().replace(/_/g, '-').split('-');
   var hname = '';
   var parts = name.length;
   var part;
 
   for (part = 0; part < parts; part++) {
     if (part !== 0) {
       hname += '-';
     }
 
     hname += name[part].charAt(0).toUpperCase() + name[part].substring(1);
   }
 
   if (exceptions[hname]) {
     hname = exceptions[hname];
   }
 
   return hname;
 };
 
 exports.sipErrorCause = function (status_code) {
   for (var cause in JsSIP_C.SIP_ERROR_CAUSES) {
     if (JsSIP_C.SIP_ERROR_CAUSES[cause].indexOf(status_code) !== -1) {
       return JsSIP_C.causes[cause];
     }
   }
 
   return JsSIP_C.causes.SIP_FAILURE_CODE;
 };
 /**
 * Generate a random Test-Net IP (https://tools.ietf.org/html/rfc5735)
 */
 
 
 exports.getRandomTestNetIP = function () {
   function getOctet(from, to) {
     return Math.floor(Math.random() * (to - from + 1) + from);
   }
 
   return "192.0.2.".concat(getOctet(1, 254));
 }; // MD5 (Message-Digest Algorithm) https://www.webtoolkit.info.
 
 
 exports.calculateMD5 = function (string) {
   function rotateLeft(lValue, iShiftBits) {
     return lValue << iShiftBits | lValue >>> 32 - iShiftBits;
   }
 
   function addUnsigned(lX, lY) {
     var lX8 = lX & 0x80000000;
     var lY8 = lY & 0x80000000;
     var lX4 = lX & 0x40000000;
     var lY4 = lY & 0x40000000;
     var lResult = (lX & 0x3FFFFFFF) + (lY & 0x3FFFFFFF);
 
     if (lX4 & lY4) {
       return lResult ^ 0x80000000 ^ lX8 ^ lY8;
     }
 
     if (lX4 | lY4) {
       if (lResult & 0x40000000) {
         return lResult ^ 0xC0000000 ^ lX8 ^ lY8;
       } else {
         return lResult ^ 0x40000000 ^ lX8 ^ lY8;
       }
     } else {
       return lResult ^ lX8 ^ lY8;
     }
   }
 
   function doF(x, y, z) {
     return x & y | ~x & z;
   }
 
   function doG(x, y, z) {
     return x & z | y & ~z;
   }
 
   function doH(x, y, z) {
     return x ^ y ^ z;
   }
 
   function doI(x, y, z) {
     return y ^ (x | ~z);
   }
 
   function doFF(a, b, c, d, x, s, ac) {
     a = addUnsigned(a, addUnsigned(addUnsigned(doF(b, c, d), x), ac));
     return addUnsigned(rotateLeft(a, s), b);
   }
 
   function doGG(a, b, c, d, x, s, ac) {
     a = addUnsigned(a, addUnsigned(addUnsigned(doG(b, c, d), x), ac));
     return addUnsigned(rotateLeft(a, s), b);
   }
 
   function doHH(a, b, c, d, x, s, ac) {
     a = addUnsigned(a, addUnsigned(addUnsigned(doH(b, c, d), x), ac));
     return addUnsigned(rotateLeft(a, s), b);
   }
 
   function doII(a, b, c, d, x, s, ac) {
     a = addUnsigned(a, addUnsigned(addUnsigned(doI(b, c, d), x), ac));
     return addUnsigned(rotateLeft(a, s), b);
   }
 
   function convertToWordArray(str) {
     var lWordCount;
     var lMessageLength = str.length;
     var lNumberOfWords_temp1 = lMessageLength + 8;
     var lNumberOfWords_temp2 = (lNumberOfWords_temp1 - lNumberOfWords_temp1 % 64) / 64;
     var lNumberOfWords = (lNumberOfWords_temp2 + 1) * 16;
     var lWordArray = new Array(lNumberOfWords - 1);
     var lBytePosition = 0;
     var lByteCount = 0;
 
     while (lByteCount < lMessageLength) {
       lWordCount = (lByteCount - lByteCount % 4) / 4;
       lBytePosition = lByteCount % 4 * 8;
       lWordArray[lWordCount] = lWordArray[lWordCount] | str.charCodeAt(lByteCount) << lBytePosition;
       lByteCount++;
     }
 
     lWordCount = (lByteCount - lByteCount % 4) / 4;
     lBytePosition = lByteCount % 4 * 8;
     lWordArray[lWordCount] = lWordArray[lWordCount] | 0x80 << lBytePosition;
     lWordArray[lNumberOfWords - 2] = lMessageLength << 3;
     lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29;
     return lWordArray;
   }
 
   function wordToHex(lValue) {
     var wordToHexValue = '',
         wordToHexValue_temp = '',
         lByte,
         lCount;
 
     for (lCount = 0; lCount <= 3; lCount++) {
       lByte = lValue >>> lCount * 8 & 255;
       wordToHexValue_temp = "0".concat(lByte.toString(16));
       wordToHexValue = wordToHexValue + wordToHexValue_temp.substr(wordToHexValue_temp.length - 2, 2);
     }
 
     return wordToHexValue;
   }
 
   function utf8Encode(str) {
     str = str.replace(/\r\n/g, '\n');
     var utftext = '';
 
     for (var n = 0; n < str.length; n++) {
       var _c = str.charCodeAt(n);
 
       if (_c < 128) {
         utftext += String.fromCharCode(_c);
       } else if (_c > 127 && _c < 2048) {
         utftext += String.fromCharCode(_c >> 6 | 192);
         utftext += String.fromCharCode(_c & 63 | 128);
       } else {
         utftext += String.fromCharCode(_c >> 12 | 224);
         utftext += String.fromCharCode(_c >> 6 & 63 | 128);
         utftext += String.fromCharCode(_c & 63 | 128);
       }
     }
 
     return utftext;
   }
 
   var x = [];
   var k, AA, BB, CC, DD, a, b, c, d;
   var S11 = 7,
       S12 = 12,
       S13 = 17,
       S14 = 22;
   var S21 = 5,
       S22 = 9,
       S23 = 14,
       S24 = 20;
   var S31 = 4,
       S32 = 11,
       S33 = 16,
       S34 = 23;
   var S41 = 6,
       S42 = 10,
       S43 = 15,
       S44 = 21;
   string = utf8Encode(string);
   x = convertToWordArray(string);
   a = 0x67452301;
   b = 0xEFCDAB89;
   c = 0x98BADCFE;
   d = 0x10325476;
 
   for (k = 0; k < x.length; k += 16) {
     AA = a;
     BB = b;
     CC = c;
     DD = d;
     a = doFF(a, b, c, d, x[k + 0], S11, 0xD76AA478);
     d = doFF(d, a, b, c, x[k + 1], S12, 0xE8C7B756);
     c = doFF(c, d, a, b, x[k + 2], S13, 0x242070DB);
     b = doFF(b, c, d, a, x[k + 3], S14, 0xC1BDCEEE);
     a = doFF(a, b, c, d, x[k + 4], S11, 0xF57C0FAF);
     d = doFF(d, a, b, c, x[k + 5], S12, 0x4787C62A);
     c = doFF(c, d, a, b, x[k + 6], S13, 0xA8304613);
     b = doFF(b, c, d, a, x[k + 7], S14, 0xFD469501);
     a = doFF(a, b, c, d, x[k + 8], S11, 0x698098D8);
     d = doFF(d, a, b, c, x[k + 9], S12, 0x8B44F7AF);
     c = doFF(c, d, a, b, x[k + 10], S13, 0xFFFF5BB1);
     b = doFF(b, c, d, a, x[k + 11], S14, 0x895CD7BE);
     a = doFF(a, b, c, d, x[k + 12], S11, 0x6B901122);
     d = doFF(d, a, b, c, x[k + 13], S12, 0xFD987193);
     c = doFF(c, d, a, b, x[k + 14], S13, 0xA679438E);
     b = doFF(b, c, d, a, x[k + 15], S14, 0x49B40821);
     a = doGG(a, b, c, d, x[k + 1], S21, 0xF61E2562);
     d = doGG(d, a, b, c, x[k + 6], S22, 0xC040B340);
     c = doGG(c, d, a, b, x[k + 11], S23, 0x265E5A51);
     b = doGG(b, c, d, a, x[k + 0], S24, 0xE9B6C7AA);
     a = doGG(a, b, c, d, x[k + 5], S21, 0xD62F105D);
     d = doGG(d, a, b, c, x[k + 10], S22, 0x2441453);
     c = doGG(c, d, a, b, x[k + 15], S23, 0xD8A1E681);
     b = doGG(b, c, d, a, x[k + 4], S24, 0xE7D3FBC8);
     a = doGG(a, b, c, d, x[k + 9], S21, 0x21E1CDE6);
     d = doGG(d, a, b, c, x[k + 14], S22, 0xC33707D6);
     c = doGG(c, d, a, b, x[k + 3], S23, 0xF4D50D87);
     b = doGG(b, c, d, a, x[k + 8], S24, 0x455A14ED);
     a = doGG(a, b, c, d, x[k + 13], S21, 0xA9E3E905);
     d = doGG(d, a, b, c, x[k + 2], S22, 0xFCEFA3F8);
     c = doGG(c, d, a, b, x[k + 7], S23, 0x676F02D9);
     b = doGG(b, c, d, a, x[k + 12], S24, 0x8D2A4C8A);
     a = doHH(a, b, c, d, x[k + 5], S31, 0xFFFA3942);
     d = doHH(d, a, b, c, x[k + 8], S32, 0x8771F681);
     c = doHH(c, d, a, b, x[k + 11], S33, 0x6D9D6122);
     b = doHH(b, c, d, a, x[k + 14], S34, 0xFDE5380C);
     a = doHH(a, b, c, d, x[k + 1], S31, 0xA4BEEA44);
     d = doHH(d, a, b, c, x[k + 4], S32, 0x4BDECFA9);
     c = doHH(c, d, a, b, x[k + 7], S33, 0xF6BB4B60);
     b = doHH(b, c, d, a, x[k + 10], S34, 0xBEBFBC70);
     a = doHH(a, b, c, d, x[k + 13], S31, 0x289B7EC6);
     d = doHH(d, a, b, c, x[k + 0], S32, 0xEAA127FA);
     c = doHH(c, d, a, b, x[k + 3], S33, 0xD4EF3085);
     b = doHH(b, c, d, a, x[k + 6], S34, 0x4881D05);
     a = doHH(a, b, c, d, x[k + 9], S31, 0xD9D4D039);
     d = doHH(d, a, b, c, x[k + 12], S32, 0xE6DB99E5);
     c = doHH(c, d, a, b, x[k + 15], S33, 0x1FA27CF8);
     b = doHH(b, c, d, a, x[k + 2], S34, 0xC4AC5665);
     a = doII(a, b, c, d, x[k + 0], S41, 0xF4292244);
     d = doII(d, a, b, c, x[k + 7], S42, 0x432AFF97);
     c = doII(c, d, a, b, x[k + 14], S43, 0xAB9423A7);
     b = doII(b, c, d, a, x[k + 5], S44, 0xFC93A039);
     a = doII(a, b, c, d, x[k + 12], S41, 0x655B59C3);
     d = doII(d, a, b, c, x[k + 3], S42, 0x8F0CCC92);
     c = doII(c, d, a, b, x[k + 10], S43, 0xFFEFF47D);
     b = doII(b, c, d, a, x[k + 1], S44, 0x85845DD1);
     a = doII(a, b, c, d, x[k + 8], S41, 0x6FA87E4F);
     d = doII(d, a, b, c, x[k + 15], S42, 0xFE2CE6E0);
     c = doII(c, d, a, b, x[k + 6], S43, 0xA3014314);
     b = doII(b, c, d, a, x[k + 13], S44, 0x4E0811A1);
     a = doII(a, b, c, d, x[k + 4], S41, 0xF7537E82);
     d = doII(d, a, b, c, x[k + 11], S42, 0xBD3AF235);
     c = doII(c, d, a, b, x[k + 2], S43, 0x2AD7D2BB);
     b = doII(b, c, d, a, x[k + 9], S44, 0xEB86D391);
     a = addUnsigned(a, AA);
     b = addUnsigned(b, BB);
     c = addUnsigned(c, CC);
     d = addUnsigned(d, DD);
   }
 
   var temp = wordToHex(a) + wordToHex(b) + wordToHex(c) + wordToHex(d);
   return temp.toLowerCase();
 };
 
 exports.closeMediaStream = function (stream) {
   if (!stream) {
     return;
   } // Latest spec states that MediaStream has no stop() method and instead must
   // call stop() on every MediaStreamTrack.
 
 
   try {
     var tracks;
 
     if (stream.getTracks) {
       tracks = stream.getTracks();
 
       var _iterator = _createForOfIteratorHelper(tracks),
           _step;
 
       try {
         for (_iterator.s(); !(_step = _iterator.n()).done;) {
           var track = _step.value;
           track.stop();
         }
       } catch (err) {
         _iterator.e(err);
       } finally {
         _iterator.f();
       }
     } else {
       tracks = stream.getAudioTracks();
 
       var _iterator2 = _createForOfIteratorHelper(tracks),
           _step2;
 
       try {
         for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
           var _track = _step2.value;
 
           _track.stop();
         }
       } catch (err) {
         _iterator2.e(err);
       } finally {
         _iterator2.f();
       }
 
       tracks = stream.getVideoTracks();
 
       var _iterator3 = _createForOfIteratorHelper(tracks),
           _step3;
 
       try {
         for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
           var _track2 = _step3.value;
 
           _track2.stop();
         }
       } catch (err) {
         _iterator3.e(err);
       } finally {
         _iterator3.f();
       }
     }
   } catch (error) {
     // Deprecated by the spec, but still in use.
     // NOTE: In Temasys IE plugin stream.stop is a callable 'object'.
     if (typeof stream.stop === 'function' || _typeof(stream.stop) === 'object') {
       stream.stop();
     }
   }
 };
 
 exports.cloneArray = function (array) {
   return array && array.slice() || [];
 };
 
 exports.cloneObject = function (obj) {
   var fallback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
   return obj && Object.assign({}, obj) || fallback;
 };
 },{"./Constants":2,"./Grammar":7,"./URI":25}],27:[function(require,module,exports){
 "use strict";
 
 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
 function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
 
 function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
 
 var Grammar = require('./Grammar');
 
 var debug = require('debug')('JsSIP:WebSocketInterface');
 
 var debugerror = require('debug')('JsSIP:ERROR:WebSocketInterface');
 
 debugerror.log = console.warn.bind(console);
 
 module.exports = /*#__PURE__*/function () {
   function WebSocketInterface(url) {
     _classCallCheck(this, WebSocketInterface);
 
     debug('new() [url:"%s"]', url);
     this._url = url;
     this._sip_uri = null;
     this._via_transport = null;
     this._ws = null;
     var parsed_url = Grammar.parse(url, 'absoluteURI');
 
     if (parsed_url === -1) {
       debugerror("invalid WebSocket URI: ".concat(url));
       throw new TypeError("Invalid argument: ".concat(url));
     } else if (parsed_url.scheme !== 'wss' && parsed_url.scheme !== 'ws') {
       debugerror("invalid WebSocket URI scheme: ".concat(parsed_url.scheme));
       throw new TypeError("Invalid argument: ".concat(url));
     } else {
       this._sip_uri = "sip:".concat(parsed_url.host).concat(parsed_url.port ? ":".concat(parsed_url.port) : '', ";transport=ws");
       this._via_transport = parsed_url.scheme.toUpperCase();
     }
   }
 
   _createClass(WebSocketInterface, [{
     key: "connect",
     value: function connect() {
       debug('connect()');
 
       if (this.isConnected()) {
         debug("WebSocket ".concat(this._url, " is already connected"));
         return;
       } else if (this.isConnecting()) {
         debug("WebSocket ".concat(this._url, " is connecting"));
         return;
       }
 
       if (this._ws) {
         this.disconnect();
       }
 
       debug("connecting to WebSocket ".concat(this._url));
 
       try {
         this._ws = new WebSocket(this._url, 'sip');
         this._ws.binaryType = 'arraybuffer';
         this._ws.onopen = this._onOpen.bind(this);
         this._ws.onclose = this._onClose.bind(this);
         this._ws.onmessage = this._onMessage.bind(this);
         this._ws.onerror = this._onError.bind(this);
       } catch (e) {
         this._onError(e);
       }
     }
   }, {
     key: "disconnect",
     value: function disconnect() {
       debug('disconnect()');
 
       if (this._ws) {
         // Unbind websocket event callbacks.
         this._ws.onopen = function () {};
 
         this._ws.onclose = function () {};
 
         this._ws.onmessage = function () {};
 
         this._ws.onerror = function () {};
 
         this._ws.close();
 
         this._ws = null;
       }
     }
   }, {
     key: "send",
     value: function send(message) {
       debug('send()');
 
       if (this.isConnected()) {
         this._ws.send(message);
 
         return true;
       } else {
         debugerror('unable to send message, WebSocket is not open');
         return false;
       }
     }
   }, {
     key: "isConnected",
     value: function isConnected() {
       return this._ws && this._ws.readyState === this._ws.OPEN;
     }
   }, {
     key: "isConnecting",
     value: function isConnecting() {
       return this._ws && this._ws.readyState === this._ws.CONNECTING;
     }
     /**
      * WebSocket Event Handlers
      */
 
   }, {
     key: "_onOpen",
     value: function _onOpen() {
       debug("WebSocket ".concat(this._url, " connected"));
       this.onconnect();
     }
   }, {
     key: "_onClose",
     value: function _onClose(_ref) {
       var wasClean = _ref.wasClean,
           code = _ref.code,
           reason = _ref.reason;
       debug("WebSocket ".concat(this._url, " closed"));
 
       if (wasClean === false) {
         debug('WebSocket abrupt disconnection');
       }
 
       var data = {
         socket: this,
         error: !wasClean,
         code: code,
         reason: reason
       };
       this.ondisconnect(data);
     }
   }, {
     key: "_onMessage",
     value: function _onMessage(_ref2) {
       var data = _ref2.data;
       debug('received WebSocket message');
       this.ondata(data);
     }
   }, {
     key: "_onError",
     value: function _onError(e) {
       debugerror("WebSocket ".concat(this._url, " error: ").concat(e));
     }
   }, {
     key: "via_transport",
     get: function get() {
       return this._via_transport;
     },
     set: function set(value) {
       this._via_transport = value.toUpperCase();
     }
   }, {
     key: "sip_uri",
     get: function get() {
       return this._sip_uri;
     }
   }, {
     key: "url",
     get: function get() {
       return this._url;
     }
   }]);
 
   return WebSocketInterface;
 }();
 },{"./Grammar":7,"debug":30}],28:[function(require,module,exports){
 "use strict";
 
 function _createForOfIteratorHelper(o, allowArrayLike) { var it; if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
 
 function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
 
 function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
 
 var JsSIP_C = require('./Constants');
 
 var SIPMessage = require('./SIPMessage');
 
 var Utils = require('./Utils');
 
 var debug = require('debug')('JsSIP:sanityCheck'); // Checks for requests and responses.
 
 
 var all = [minimumHeaders]; // Checks for requests.
 
 var requests = [rfc3261_8_2_2_1, rfc3261_16_3_4, rfc3261_18_3_request, rfc3261_8_2_2_2]; // Checks for responses.
 
 var responses = [rfc3261_8_1_3_3, rfc3261_18_3_response]; // local variables.
 
 var message;
 var ua;
 var transport;
 
 module.exports = function (m, u, t) {
   message = m;
   ua = u;
   transport = t;
 
   var _iterator = _createForOfIteratorHelper(all),
       _step;
 
   try {
     for (_iterator.s(); !(_step = _iterator.n()).done;) {
       var _check2 = _step.value;
 
       if (_check2() === false) {
         return false;
       }
     }
   } catch (err) {
     _iterator.e(err);
   } finally {
     _iterator.f();
   }
 
   if (message instanceof SIPMessage.IncomingRequest) {
     var _iterator2 = _createForOfIteratorHelper(requests),
         _step2;
 
     try {
       for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
         var check = _step2.value;
 
         if (check() === false) {
           return false;
         }
       }
     } catch (err) {
       _iterator2.e(err);
     } finally {
       _iterator2.f();
     }
   } else if (message instanceof SIPMessage.IncomingResponse) {
     var _iterator3 = _createForOfIteratorHelper(responses),
         _step3;
 
     try {
       for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
         var _check = _step3.value;
 
         if (_check() === false) {
           return false;
         }
       }
     } catch (err) {
       _iterator3.e(err);
     } finally {
       _iterator3.f();
     }
   } // Everything is OK.
 
 
   return true;
 };
 /*
  * Sanity Check for incoming Messages
  *
  * Requests:
  *  - _rfc3261_8_2_2_1_ Receive a Request with a non supported URI scheme
  *  - _rfc3261_16_3_4_ Receive a Request already sent by us
  *   Does not look at via sent-by but at jssip_id, which is inserted as
  *   a prefix in all initial requests generated by the ua
  *  - _rfc3261_18_3_request_ Body Content-Length
  *  - _rfc3261_8_2_2_2_ Merged Requests
  *
  * Responses:
  *  - _rfc3261_8_1_3_3_ Multiple Via headers
  *  - _rfc3261_18_3_response_ Body Content-Length
  *
  * All:
  *  - Minimum headers in a SIP message
  */
 // Sanity Check functions for requests.
 
 
 function rfc3261_8_2_2_1() {
   if (message.s('to').uri.scheme !== 'sip') {
     reply(416);
     return false;
   }
 }
 
 function rfc3261_16_3_4() {
   if (!message.to_tag) {
     if (message.call_id.substr(0, 5) === ua.configuration.jssip_id) {
       reply(482);
       return false;
     }
   }
 }
 
 function rfc3261_18_3_request() {
   var len = Utils.str_utf8_length(message.body);
   var contentLength = message.getHeader('content-length');
 
   if (len < contentLength) {
     reply(400);
     return false;
   }
 }
 
 function rfc3261_8_2_2_2() {
   var fromTag = message.from_tag;
   var call_id = message.call_id;
   var cseq = message.cseq;
   var tr; // Accept any in-dialog request.
 
   if (message.to_tag) {
     return;
   } // INVITE request.
 
 
   if (message.method === JsSIP_C.INVITE) {
     // If the branch matches the key of any IST then assume it is a retransmission
     // and ignore the INVITE.
     // TODO: we should reply the last response.
     if (ua._transactions.ist[message.via_branch]) {
       return false;
     } // Otherwise check whether it is a merged request.
     else {
         for (var transaction in ua._transactions.ist) {
           if (Object.prototype.hasOwnProperty.call(ua._transactions.ist, transaction)) {
             tr = ua._transactions.ist[transaction];
 
             if (tr.request.from_tag === fromTag && tr.request.call_id === call_id && tr.request.cseq === cseq) {
               reply(482);
               return false;
             }
           }
         }
       }
   } // Non INVITE request.
   // If the branch matches the key of any NIST then assume it is a retransmission
   // and ignore the request.
   // TODO: we should reply the last response.
   else if (ua._transactions.nist[message.via_branch]) {
       return false;
     } // Otherwise check whether it is a merged request.
     else {
         for (var _transaction in ua._transactions.nist) {
           if (Object.prototype.hasOwnProperty.call(ua._transactions.nist, _transaction)) {
             tr = ua._transactions.nist[_transaction];
 
             if (tr.request.from_tag === fromTag && tr.request.call_id === call_id && tr.request.cseq === cseq) {
               reply(482);
               return false;
             }
           }
         }
       }
 } // Sanity Check functions for responses.
 
 
 function rfc3261_8_1_3_3() {
   if (message.getHeaders('via').length > 1) {
     debug('more than one Via header field present in the response, dropping the response');
     return false;
   }
 }
 
 function rfc3261_18_3_response() {
   var len = Utils.str_utf8_length(message.body),
       contentLength = message.getHeader('content-length');
 
   if (len < contentLength) {
     debug('message body length is lower than the value in Content-Length header field, dropping the response');
     return false;
   }
 } // Sanity Check functions for requests and responses.
 
 
 function minimumHeaders() {
   var mandatoryHeaders = ['from', 'to', 'call_id', 'cseq', 'via'];
 
   for (var _i = 0, _mandatoryHeaders = mandatoryHeaders; _i < _mandatoryHeaders.length; _i++) {
     var header = _mandatoryHeaders[_i];
 
     if (!message.hasHeader(header)) {
       debug("missing mandatory header field : ".concat(header, ", dropping the response"));
       return false;
     }
   }
 } // Reply.
 
 
 function reply(status_code) {
   var vias = message.getHeaders('via');
   var to;
   var response = "SIP/2.0 ".concat(status_code, " ").concat(JsSIP_C.REASON_PHRASE[status_code], "\r\n");
 
   var _iterator4 = _createForOfIteratorHelper(vias),
       _step4;
 
   try {
     for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
       var via = _step4.value;
       response += "Via: ".concat(via, "\r\n");
     }
   } catch (err) {
     _iterator4.e(err);
   } finally {
     _iterator4.f();
   }
 
   to = message.getHeader('To');
 
   if (!message.to_tag) {
     to += ";tag=".concat(Utils.newTag());
   }
 
   response += "To: ".concat(to, "\r\n");
   response += "From: ".concat(message.getHeader('From'), "\r\n");
   response += "Call-ID: ".concat(message.call_id, "\r\n");
   response += "CSeq: ".concat(message.cseq, " ").concat(message.method, "\r\n");
   response += '\r\n';
   transport.send(response);
 }
 },{"./Constants":2,"./SIPMessage":19,"./Utils":26,"debug":30}],29:[function(require,module,exports){
 // Copyright Joyent, Inc. and other Node contributors.
 //
 // Permission is hereby granted, free of charge, to any person obtaining a
 // copy of this software and associated documentation files (the
 // "Software"), to deal in the Software without restriction, including
 // without limitation the rights to use, copy, modify, merge, publish,
 // distribute, sublicense, and/or sell copies of the Software, and to permit
 // persons to whom the Software is furnished to do so, subject to the
 // following conditions:
 //
 // The above copyright notice and this permission notice shall be included
 // in all copies or substantial portions of the Software.
 //
 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
 // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
 // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
 // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
 // USE OR OTHER DEALINGS IN THE SOFTWARE.
 
 var objectCreate = Object.create || objectCreatePolyfill
 var objectKeys = Object.keys || objectKeysPolyfill
 var bind = Function.prototype.bind || functionBindPolyfill
 
 function EventEmitter() {
   if (!this._events || !Object.prototype.hasOwnProperty.call(this, '_events')) {
     this._events = objectCreate(null);
     this._eventsCount = 0;
   }
 
   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.
 var defaultMaxListeners = 10;
 
 var hasDefineProperty;
 try {
   var o = {};
   if (Object.defineProperty) Object.defineProperty(o, 'x', { value: 0 });
   hasDefineProperty = o.x === 0;
 } catch (err) { hasDefineProperty = false }
 if (hasDefineProperty) {
   Object.defineProperty(EventEmitter, 'defaultMaxListeners', {
     enumerable: true,
     get: function() {
       return defaultMaxListeners;
     },
     set: function(arg) {
       // check whether the input is a positive number (whose value is zero or
       // greater and not a NaN).
       if (typeof arg !== 'number' || arg < 0 || arg !== arg)
         throw new TypeError('"defaultMaxListeners" must be a positive number');
       defaultMaxListeners = arg;
     }
   });
 } else {
   EventEmitter.defaultMaxListeners = defaultMaxListeners;
 }
 
 // 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 setMaxListeners(n) {
   if (typeof n !== 'number' || n < 0 || isNaN(n))
     throw new TypeError('"n" argument must be a positive number');
   this._maxListeners = n;
   return this;
 };
 
 function $getMaxListeners(that) {
   if (that._maxListeners === undefined)
     return EventEmitter.defaultMaxListeners;
   return that._maxListeners;
 }
 
 EventEmitter.prototype.getMaxListeners = function getMaxListeners() {
   return $getMaxListeners(this);
 };
 
 // These standalone emit* functions are used to optimize calling of event
 // handlers for fast cases because emit() itself often has a variable number of
 // arguments and can be deoptimized because of that. These functions always have
 // the same number of arguments and thus do not get deoptimized, so the code
 // inside them can execute faster.
 function emitNone(handler, isFn, self) {
   if (isFn)
     handler.call(self);
   else {
     var len = handler.length;
     var listeners = arrayClone(handler, len);
     for (var i = 0; i < len; ++i)
       listeners[i].call(self);
   }
 }
 function emitOne(handler, isFn, self, arg1) {
   if (isFn)
     handler.call(self, arg1);
   else {
     var len = handler.length;
     var listeners = arrayClone(handler, len);
     for (var i = 0; i < len; ++i)
       listeners[i].call(self, arg1);
   }
 }
 function emitTwo(handler, isFn, self, arg1, arg2) {
   if (isFn)
     handler.call(self, arg1, arg2);
   else {
     var len = handler.length;
     var listeners = arrayClone(handler, len);
     for (var i = 0; i < len; ++i)
       listeners[i].call(self, arg1, arg2);
   }
 }
 function emitThree(handler, isFn, self, arg1, arg2, arg3) {
   if (isFn)
     handler.call(self, arg1, arg2, arg3);
   else {
     var len = handler.length;
     var listeners = arrayClone(handler, len);
     for (var i = 0; i < len; ++i)
       listeners[i].call(self, arg1, arg2, arg3);
   }
 }
 
 function emitMany(handler, isFn, self, args) {
   if (isFn)
     handler.apply(self, args);
   else {
     var len = handler.length;
     var listeners = arrayClone(handler, len);
     for (var i = 0; i < len; ++i)
       listeners[i].apply(self, args);
   }
 }
 
 EventEmitter.prototype.emit = function emit(type) {
   var er, handler, len, args, i, events;
   var doError = (type === 'error');
 
   events = this._events;
   if (events)
     doError = (doError && events.error == null);
   else if (!doError)
     return false;
 
   // If there is no 'error' event listener then throw.
   if (doError) {
     if (arguments.length > 1)
       er = arguments[1];
     if (er instanceof Error) {
       throw er; // Unhandled 'error' event
     } else {
       // At least give some kind of context to the user
       var err = new Error('Unhandled "error" event. (' + er + ')');
       err.context = er;
       throw err;
     }
     return false;
   }
 
   handler = events[type];
 
   if (!handler)
     return false;
 
   var isFn = typeof handler === 'function';
   len = arguments.length;
   switch (len) {
       // fast cases
     case 1:
       emitNone(handler, isFn, this);
       break;
     case 2:
       emitOne(handler, isFn, this, arguments[1]);
       break;
     case 3:
       emitTwo(handler, isFn, this, arguments[1], arguments[2]);
       break;
     case 4:
       emitThree(handler, isFn, this, arguments[1], arguments[2], arguments[3]);
       break;
       // slower
     default:
       args = new Array(len - 1);
       for (i = 1; i < len; i++)
         args[i - 1] = arguments[i];
       emitMany(handler, isFn, this, args);
   }
 
   return true;
 };
 
 function _addListener(target, type, listener, prepend) {
   var m;
   var events;
   var existing;
 
   if (typeof listener !== 'function')
     throw new TypeError('"listener" argument must be a function');
 
   events = target._events;
   if (!events) {
     events = target._events = objectCreate(null);
     target._eventsCount = 0;
   } else {
     // To avoid recursion in the case that type === "newListener"! Before
     // adding it to the listeners, first emit "newListener".
     if (events.newListener) {
       target.emit('newListener', type,
           listener.listener ? listener.listener : listener);
 
       // Re-assign `events` because a newListener handler could have caused the
       // this._events to be assigned to a new object
       events = target._events;
     }
     existing = events[type];
   }
 
   if (!existing) {
     // Optimize the case of one listener. Don't need the extra array object.
     existing = events[type] = listener;
     ++target._eventsCount;
   } else {
     if (typeof existing === 'function') {
       // Adding the second element, need to change to array.
       existing = events[type] =
           prepend ? [listener, existing] : [existing, listener];
     } else {
       // If we've already got an array, just append.
       if (prepend) {
         existing.unshift(listener);
       } else {
         existing.push(listener);
       }
     }
 
     // Check for listener leak
     if (!existing.warned) {
       m = $getMaxListeners(target);
       if (m && m > 0 && existing.length > m) {
         existing.warned = true;
         var w = new Error('Possible EventEmitter memory leak detected. ' +
             existing.length + ' "' + String(type) + '" listeners ' +
             'added. Use emitter.setMaxListeners() to ' +
             'increase limit.');
         w.name = 'MaxListenersExceededWarning';
         w.emitter = target;
         w.type = type;
         w.count = existing.length;
         if (typeof console === 'object' && console.warn) {
           console.warn('%s: %s', w.name, w.message);
         }
       }
     }
   }
 
   return target;
 }
 
 EventEmitter.prototype.addListener = function addListener(type, listener) {
   return _addListener(this, type, listener, false);
 };
 
 EventEmitter.prototype.on = EventEmitter.prototype.addListener;
 
 EventEmitter.prototype.prependListener =
     function prependListener(type, listener) {
       return _addListener(this, type, listener, true);
     };
 
 function onceWrapper() {
   if (!this.fired) {
     this.target.removeListener(this.type, this.wrapFn);
     this.fired = true;
     switch (arguments.length) {
       case 0:
         return this.listener.call(this.target);
       case 1:
         return this.listener.call(this.target, arguments[0]);
       case 2:
         return this.listener.call(this.target, arguments[0], arguments[1]);
       case 3:
         return this.listener.call(this.target, arguments[0], arguments[1],
             arguments[2]);
       default:
         var args = new Array(arguments.length);
         for (var i = 0; i < args.length; ++i)
           args[i] = arguments[i];
         this.listener.apply(this.target, args);
     }
   }
 }
 
 function _onceWrap(target, type, listener) {
   var state = { fired: false, wrapFn: undefined, target: target, type: type, listener: listener };
   var wrapped = bind.call(onceWrapper, state);
   wrapped.listener = listener;
   state.wrapFn = wrapped;
   return wrapped;
 }
 
 EventEmitter.prototype.once = function once(type, listener) {
   if (typeof listener !== 'function')
     throw new TypeError('"listener" argument must be a function');
   this.on(type, _onceWrap(this, type, listener));
   return this;
 };
 
 EventEmitter.prototype.prependOnceListener =
     function prependOnceListener(type, listener) {
       if (typeof listener !== 'function')
         throw new TypeError('"listener" argument must be a function');
       this.prependListener(type, _onceWrap(this, type, listener));
       return this;
     };
 
 // Emits a 'removeListener' event if and only if the listener was removed.
 EventEmitter.prototype.removeListener =
     function removeListener(type, listener) {
       var list, events, position, i, originalListener;
 
       if (typeof listener !== 'function')
         throw new TypeError('"listener" argument must be a function');
 
       events = this._events;
       if (!events)
         return this;
 
       list = events[type];
       if (!list)
         return this;
 
       if (list === listener || list.listener === listener) {
         if (--this._eventsCount === 0)
           this._events = objectCreate(null);
         else {
           delete events[type];
           if (events.removeListener)
             this.emit('removeListener', type, list.listener || listener);
         }
       } else if (typeof list !== 'function') {
         position = -1;
 
         for (i = list.length - 1; i >= 0; i--) {
           if (list[i] === listener || list[i].listener === listener) {
             originalListener = list[i].listener;
             position = i;
             break;
           }
         }
 
         if (position < 0)
           return this;
 
         if (position === 0)
           list.shift();
         else
           spliceOne(list, position);
 
         if (list.length === 1)
           events[type] = list[0];
 
         if (events.removeListener)
           this.emit('removeListener', type, originalListener || listener);
       }
 
       return this;
     };
 
 EventEmitter.prototype.removeAllListeners =
     function removeAllListeners(type) {
       var listeners, events, i;
 
       events = this._events;
       if (!events)
         return this;
 
       // not listening for removeListener, no need to emit
       if (!events.removeListener) {
         if (arguments.length === 0) {
           this._events = objectCreate(null);
           this._eventsCount = 0;
         } else if (events[type]) {
           if (--this._eventsCount === 0)
             this._events = objectCreate(null);
           else
             delete events[type];
         }
         return this;
       }
 
       // emit removeListener for all listeners on all events
       if (arguments.length === 0) {
         var keys = objectKeys(events);
         var key;
         for (i = 0; i < keys.length; ++i) {
           key = keys[i];
           if (key === 'removeListener') continue;
           this.removeAllListeners(key);
         }
         this.removeAllListeners('removeListener');
         this._events = objectCreate(null);
         this._eventsCount = 0;
         return this;
       }
 
       listeners = events[type];
 
       if (typeof listeners === 'function') {
         this.removeListener(type, listeners);
       } else if (listeners) {
         // LIFO order
         for (i = listeners.length - 1; i >= 0; i--) {
           this.removeListener(type, listeners[i]);
         }
       }
 
       return this;
     };
 
 function _listeners(target, type, unwrap) {
   var events = target._events;
 
   if (!events)
     return [];
 
   var evlistener = events[type];
   if (!evlistener)
     return [];
 
   if (typeof evlistener === 'function')
     return unwrap ? [evlistener.listener || evlistener] : [evlistener];
 
   return unwrap ? unwrapListeners(evlistener) : arrayClone(evlistener, evlistener.length);
 }
 
 EventEmitter.prototype.listeners = function listeners(type) {
   return _listeners(this, type, true);
 };
 
 EventEmitter.prototype.rawListeners = function rawListeners(type) {
   return _listeners(this, type, false);
 };
 
 EventEmitter.listenerCount = function(emitter, type) {
   if (typeof emitter.listenerCount === 'function') {
     return emitter.listenerCount(type);
   } else {
     return listenerCount.call(emitter, type);
   }
 };
 
 EventEmitter.prototype.listenerCount = listenerCount;
 function listenerCount(type) {
   var events = this._events;
 
   if (events) {
     var evlistener = events[type];
 
     if (typeof evlistener === 'function') {
       return 1;
     } else if (evlistener) {
       return evlistener.length;
     }
   }
 
   return 0;
 }
 
 EventEmitter.prototype.eventNames = function eventNames() {
   return this._eventsCount > 0 ? Reflect.ownKeys(this._events) : [];
 };
 
 // About 1.5x faster than the two-arg version of Array#splice().
 function spliceOne(list, index) {
   for (var i = index, k = i + 1, n = list.length; k < n; i += 1, k += 1)
     list[i] = list[k];
   list.pop();
 }
 
 function arrayClone(arr, n) {
   var copy = new Array(n);
   for (var i = 0; i < n; ++i)
     copy[i] = arr[i];
   return copy;
 }
 
 function unwrapListeners(arr) {
   var ret = new Array(arr.length);
   for (var i = 0; i < ret.length; ++i) {
     ret[i] = arr[i].listener || arr[i];
   }
   return ret;
 }
 
 function objectCreatePolyfill(proto) {
   var F = function() {};
   F.prototype = proto;
   return new F;
 }
 function objectKeysPolyfill(obj) {
   var keys = [];
   for (var k in obj) if (Object.prototype.hasOwnProperty.call(obj, k)) {
     keys.push(k);
   }
   return k;
 }
 function functionBindPolyfill(context) {
   var fn = this;
   return function () {
     return fn.apply(context, arguments);
   };
 }
 
 },{}],30:[function(require,module,exports){
 (function (process){
 /* eslint-env browser */
 
 /**
  * This is the web browser implementation of `debug()`.
  */
 
 exports.log = log;
 exports.formatArgs = formatArgs;
 exports.save = save;
 exports.load = load;
 exports.useColors = useColors;
 exports.storage = localstorage();
 
 /**
  * Colors.
  */
 
 exports.colors = [
 	'#0000CC',
 	'#0000FF',
 	'#0033CC',
 	'#0033FF',
 	'#0066CC',
 	'#0066FF',
 	'#0099CC',
 	'#0099FF',
 	'#00CC00',
 	'#00CC33',
 	'#00CC66',
 	'#00CC99',
 	'#00CCCC',
 	'#00CCFF',
 	'#3300CC',
 	'#3300FF',
 	'#3333CC',
 	'#3333FF',
 	'#3366CC',
 	'#3366FF',
 	'#3399CC',
 	'#3399FF',
 	'#33CC00',
 	'#33CC33',
 	'#33CC66',
 	'#33CC99',
 	'#33CCCC',
 	'#33CCFF',
 	'#6600CC',
 	'#6600FF',
 	'#6633CC',
 	'#6633FF',
 	'#66CC00',
 	'#66CC33',
 	'#9900CC',
 	'#9900FF',
 	'#9933CC',
 	'#9933FF',
 	'#99CC00',
 	'#99CC33',
 	'#CC0000',
 	'#CC0033',
 	'#CC0066',
 	'#CC0099',
 	'#CC00CC',
 	'#CC00FF',
 	'#CC3300',
 	'#CC3333',
 	'#CC3366',
 	'#CC3399',
 	'#CC33CC',
 	'#CC33FF',
 	'#CC6600',
 	'#CC6633',
 	'#CC9900',
 	'#CC9933',
 	'#CCCC00',
 	'#CCCC33',
 	'#FF0000',
 	'#FF0033',
 	'#FF0066',
 	'#FF0099',
 	'#FF00CC',
 	'#FF00FF',
 	'#FF3300',
 	'#FF3333',
 	'#FF3366',
 	'#FF3399',
 	'#FF33CC',
 	'#FF33FF',
 	'#FF6600',
 	'#FF6633',
 	'#FF9900',
 	'#FF9933',
 	'#FFCC00',
 	'#FFCC33'
 ];
 
 /**
  * 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
  */
 
 // eslint-disable-next-line complexity
 function useColors() {
 	// NB: In an Electron preload script, document will be defined but not fully
 	// initialized. Since we know we're in Chrome, we'll just detect this case
 	// explicitly
 	if (typeof window !== 'undefined' && window.process && (window.process.type === 'renderer' || window.process.__nwjs)) {
 		return true;
 	}
 
 	// Internet Explorer and Edge do not support colors.
 	if (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/)) {
 		return false;
 	}
 
 	// Is webkit? http://stackoverflow.com/a/16459606/376773
 	// document is undefined in react-native: https://github.com/facebook/react-native/pull/1632
 	return (typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance) ||
 		// Is firebug? http://stackoverflow.com/a/398120/376773
 		(typeof window !== 'undefined' && window.console && (window.console.firebug || (window.console.exception && window.console.table))) ||
 		// Is firefox >= v31?
 		// https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages
 		(typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31) ||
 		// Double check webkit in userAgent just in case we are in a worker
 		(typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/));
 }
 
 /**
  * Colorize log arguments if enabled.
  *
  * @api public
  */
 
 function formatArgs(args) {
 	args[0] = (this.useColors ? '%c' : '') +
 		this.namespace +
 		(this.useColors ? ' %c' : ' ') +
 		args[0] +
 		(this.useColors ? '%c ' : ' ') +
 		'+' + module.exports.humanize(this.diff);
 
 	if (!this.useColors) {
 		return;
 	}
 
 	const c = 'color: ' + this.color;
 	args.splice(1, 0, c, 'color: inherit');
 
 	// 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
 	let index = 0;
 	let lastC = 0;
 	args[0].replace(/%[a-zA-Z%]/g, match => {
 		if (match === '%%') {
 			return;
 		}
 		index++;
 		if (match === '%c') {
 			// We only are interested in the *last* %c
 			// (the user may have provided their own)
 			lastC = index;
 		}
 	});
 
 	args.splice(lastC, 0, c);
 }
 
 /**
  * Invokes `console.log()` when available.
  * No-op when `console.log` is not a "function".
  *
  * @api public
  */
 function log(...args) {
 	// This hackery is required for IE8/9, where
 	// the `console.log` function doesn't have 'apply'
 	return typeof console === 'object' &&
 		console.log &&
 		console.log(...args);
 }
 
 /**
  * Save `namespaces`.
  *
  * @param {String} namespaces
  * @api private
  */
 function save(namespaces) {
 	try {
 		if (namespaces) {
 			exports.storage.setItem('debug', namespaces);
 		} else {
 			exports.storage.removeItem('debug');
 		}
 	} catch (error) {
 		// Swallow
 		// XXX (@Qix-) should we be logging these?
 	}
 }
 
 /**
  * Load `namespaces`.
  *
  * @return {String} returns the previously persisted debug modes
  * @api private
  */
 function load() {
 	let r;
 	try {
 		r = exports.storage.getItem('debug');
 	} catch (error) {
 		// Swallow
 		// XXX (@Qix-) should we be logging these?
 	}
 
 	// If debug isn't set in LS, and we're in Electron, try to load $DEBUG
 	if (!r && typeof process !== 'undefined' && 'env' in process) {
 		r = process.env.DEBUG;
 	}
 
 	return r;
 }
 
 /**
  * Localstorage attempts to return the localstorage.
  *
  * This is necessary because safari throws
  * when a user disables cookies/localstorage
  * and you attempt to access it.
  *
  * @return {LocalStorage}
  * @api private
  */
 
 function localstorage() {
 	try {
 		// TVMLKit (Apple TV JS Runtime) does not have a window object, just localStorage in the global context
 		// The Browser also has localStorage in the global context.
 		return localStorage;
 	} catch (error) {
 		// Swallow
 		// XXX (@Qix-) should we be logging these?
 	}
 }
 
 module.exports = require('./common')(exports);
 
 const {formatters} = module.exports;
 
 /**
  * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default.
  */
 
 formatters.j = function (v) {
 	try {
 		return JSON.stringify(v);
 	} catch (error) {
 		return '[UnexpectedJSONParseError]: ' + error.message;
 	}
 };
 
 }).call(this,require('_process'))
 },{"./common":31,"_process":33}],31:[function(require,module,exports){
 
 /**
  * This is the common logic for both the Node.js and web browser
  * implementations of `debug()`.
  */
 
 function setup(env) {
 	createDebug.debug = createDebug;
 	createDebug.default = createDebug;
 	createDebug.coerce = coerce;
 	createDebug.disable = disable;
 	createDebug.enable = enable;
 	createDebug.enabled = enabled;
 	createDebug.humanize = require('ms');
 
 	Object.keys(env).forEach(key => {
 		createDebug[key] = env[key];
 	});
 
 	/**
 	* Active `debug` instances.
 	*/
 	createDebug.instances = [];
 
 	/**
 	* The currently active debug mode names, and names to skip.
 	*/
 
 	createDebug.names = [];
 	createDebug.skips = [];
 
 	/**
 	* Map of special "%n" handling functions, for the debug "format" argument.
 	*
 	* Valid key names are a single, lower or upper-case letter, i.e. "n" and "N".
 	*/
 	createDebug.formatters = {};
 
 	/**
 	* Selects a color for a debug namespace
 	* @param {String} namespace The namespace string for the for the debug instance to be colored
 	* @return {Number|String} An ANSI color code for the given namespace
 	* @api private
 	*/
 	function selectColor(namespace) {
 		let hash = 0;
 
 		for (let i = 0; i < namespace.length; i++) {
 			hash = ((hash << 5) - hash) + namespace.charCodeAt(i);
 			hash |= 0; // Convert to 32bit integer
 		}
 
 		return createDebug.colors[Math.abs(hash) % createDebug.colors.length];
 	}
 	createDebug.selectColor = selectColor;
 
 	/**
 	* Create a debugger with the given `namespace`.
 	*
 	* @param {String} namespace
 	* @return {Function}
 	* @api public
 	*/
 	function createDebug(namespace) {
 		let prevTime;
 
 		function debug(...args) {
 			// Disabled?
 			if (!debug.enabled) {
 				return;
 			}
 
 			const self = debug;
 
 			// Set `diff` timestamp
 			const curr = Number(new Date());
 			const ms = curr - (prevTime || curr);
 			self.diff = ms;
 			self.prev = prevTime;
 			self.curr = curr;
 			prevTime = curr;
 
 			args[0] = createDebug.coerce(args[0]);
 
 			if (typeof args[0] !== 'string') {
 				// Anything else let's inspect with %O
 				args.unshift('%O');
 			}
 
 			// Apply any `formatters` transformations
 			let index = 0;
 			args[0] = args[0].replace(/%([a-zA-Z%])/g, (match, format) => {
 				// If we encounter an escaped % then don't increase the array index
 				if (match === '%%') {
 					return match;
 				}
 				index++;
 				const formatter = createDebug.formatters[format];
 				if (typeof formatter === 'function') {
 					const 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;
 			});
 
 			// Apply env-specific formatting (colors, etc.)
 			createDebug.formatArgs.call(self, args);
 
 			const logFn = self.log || createDebug.log;
 			logFn.apply(self, args);
 		}
 
 		debug.namespace = namespace;
 		debug.enabled = createDebug.enabled(namespace);
 		debug.useColors = createDebug.useColors();
 		debug.color = selectColor(namespace);
 		debug.destroy = destroy;
 		debug.extend = extend;
 		// Debug.formatArgs = formatArgs;
 		// debug.rawLog = rawLog;
 
 		// env-specific initialization logic for debug instances
 		if (typeof createDebug.init === 'function') {
 			createDebug.init(debug);
 		}
 
 		createDebug.instances.push(debug);
 
 		return debug;
 	}
 
 	function destroy() {
 		const index = createDebug.instances.indexOf(this);
 		if (index !== -1) {
 			createDebug.instances.splice(index, 1);
 			return true;
 		}
 		return false;
 	}
 
 	function extend(namespace, delimiter) {
 		const newDebug = createDebug(this.namespace + (typeof delimiter === 'undefined' ? ':' : delimiter) + namespace);
 		newDebug.log = this.log;
 		return newDebug;
 	}
 
 	/**
 	* Enables a debug mode by namespaces. This can include modes
 	* separated by a colon and wildcards.
 	*
 	* @param {String} namespaces
 	* @api public
 	*/
 	function enable(namespaces) {
 		createDebug.save(namespaces);
 
 		createDebug.names = [];
 		createDebug.skips = [];
 
 		let i;
 		const split = (typeof namespaces === 'string' ? namespaces : '').split(/[\s,]+/);
 		const len = split.length;
 
 		for (i = 0; i < len; i++) {
 			if (!split[i]) {
 				// ignore empty strings
 				continue;
 			}
 
 			namespaces = split[i].replace(/\*/g, '.*?');
 
 			if (namespaces[0] === '-') {
 				createDebug.skips.push(new RegExp('^' + namespaces.substr(1) + '$'));
 			} else {
 				createDebug.names.push(new RegExp('^' + namespaces + '$'));
 			}
 		}
 
 		for (i = 0; i < createDebug.instances.length; i++) {
 			const instance = createDebug.instances[i];
 			instance.enabled = createDebug.enabled(instance.namespace);
 		}
 	}
 
 	/**
 	* Disable debug output.
 	*
 	* @return {String} namespaces
 	* @api public
 	*/
 	function disable() {
 		const namespaces = [
 			...createDebug.names.map(toNamespace),
 			...createDebug.skips.map(toNamespace).map(namespace => '-' + namespace)
 		].join(',');
 		createDebug.enable('');
 		return namespaces;
 	}
 
 	/**
 	* Returns true if the given mode name is enabled, false otherwise.
 	*
 	* @param {String} name
 	* @return {Boolean}
 	* @api public
 	*/
 	function enabled(name) {
 		if (name[name.length - 1] === '*') {
 			return true;
 		}
 
 		let i;
 		let len;
 
 		for (i = 0, len = createDebug.skips.length; i < len; i++) {
 			if (createDebug.skips[i].test(name)) {
 				return false;
 			}
 		}
 
 		for (i = 0, len = createDebug.names.length; i < len; i++) {
 			if (createDebug.names[i].test(name)) {
 				return true;
 			}
 		}
 
 		return false;
 	}
 
 	/**
 	* Convert regexp to namespace
 	*
 	* @param {RegExp} regxep
 	* @return {String} namespace
 	* @api private
 	*/
 	function toNamespace(regexp) {
 		return regexp.toString()
 			.substring(2, regexp.toString().length - 2)
 			.replace(/\.\*\?$/, '*');
 	}
 
 	/**
 	* Coerce `val`.
 	*
 	* @param {Mixed} val
 	* @return {Mixed}
 	* @api private
 	*/
 	function coerce(val) {
 		if (val instanceof Error) {
 			return val.stack || val.message;
 		}
 		return val;
 	}
 
 	createDebug.enable(createDebug.load());
 
 	return createDebug;
 }
 
 module.exports = setup;
 
 },{"ms":32}],32:[function(require,module,exports){
 /**
  * Helpers.
  */
 
 var s = 1000;
 var m = s * 60;
 var h = m * 60;
 var d = h * 24;
 var w = d * 7;
 var y = d * 365.25;
 
 /**
  * Parse or format the given `val`.
  *
  * Options:
  *
  *  - `long` verbose formatting [false]
  *
  * @param {String|Number} val
  * @param {Object} [options]
  * @throws {Error} throw an error if val is not a non-empty string or a number
  * @return {String|Number}
  * @api public
  */
 
 module.exports = function(val, options) {
   options = options || {};
   var type = typeof val;
   if (type === 'string' && val.length > 0) {
     return parse(val);
   } else if (type === 'number' && isFinite(val)) {
     return options.long ? fmtLong(val) : fmtShort(val);
   }
   throw new Error(
     'val is not a non-empty string or a valid number. val=' +
       JSON.stringify(val)
   );
 };
 
 /**
  * Parse the given `str` and return milliseconds.
  *
  * @param {String} str
  * @return {Number}
  * @api private
  */
 
 function parse(str) {
   str = String(str);
   if (str.length > 100) {
     return;
   }
   var match = /^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|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 'yrs':
     case 'yr':
     case 'y':
       return n * y;
     case 'weeks':
     case 'week':
     case 'w':
       return n * w;
     case 'days':
     case 'day':
     case 'd':
       return n * d;
     case 'hours':
     case 'hour':
     case 'hrs':
     case 'hr':
     case 'h':
       return n * h;
     case 'minutes':
     case 'minute':
     case 'mins':
     case 'min':
     case 'm':
       return n * m;
     case 'seconds':
     case 'second':
     case 'secs':
     case 'sec':
     case 's':
       return n * s;
     case 'milliseconds':
     case 'millisecond':
     case 'msecs':
     case 'msec':
     case 'ms':
       return n;
     default:
       return undefined;
   }
 }
 
 /**
  * Short format for `ms`.
  *
  * @param {Number} ms
  * @return {String}
  * @api private
  */
 
 function fmtShort(ms) {
   var msAbs = Math.abs(ms);
   if (msAbs >= d) {
     return Math.round(ms / d) + 'd';
   }
   if (msAbs >= h) {
     return Math.round(ms / h) + 'h';
   }
   if (msAbs >= m) {
     return Math.round(ms / m) + 'm';
   }
   if (msAbs >= s) {
     return Math.round(ms / s) + 's';
   }
   return ms + 'ms';
 }
 
 /**
  * Long format for `ms`.
  *
  * @param {Number} ms
  * @return {String}
  * @api private
  */
 
 function fmtLong(ms) {
   var msAbs = Math.abs(ms);
   if (msAbs >= d) {
     return plural(ms, msAbs, d, 'day');
   }
   if (msAbs >= h) {
     return plural(ms, msAbs, h, 'hour');
   }
   if (msAbs >= m) {
     return plural(ms, msAbs, m, 'minute');
   }
   if (msAbs >= s) {
     return plural(ms, msAbs, s, 'second');
   }
   return ms + ' ms';
 }
 
 /**
  * Pluralization helper.
  */
 
 function plural(ms, msAbs, n, name) {
   var isPlural = msAbs >= n * 1.5;
   return Math.round(ms / n) + ' ' + name + (isPlural ? 's' : '');
 }
 
 },{}],33:[function(require,module,exports){
 // shim for using process in browser
 var process = module.exports = {};
 
 // cached from whatever global is present so that test runners that stub it
 // don't break things.  But we need to wrap it in a try catch in case it is
 // wrapped in strict mode code which doesn't define any globals.  It's inside a
 // function because try/catches deoptimize in certain engines.
 
 var cachedSetTimeout;
 var cachedClearTimeout;
 
 function defaultSetTimout() {
     throw new Error('setTimeout has not been defined');
 }
 function defaultClearTimeout () {
     throw new Error('clearTimeout has not been defined');
 }
 (function () {
     try {
         if (typeof setTimeout === 'function') {
             cachedSetTimeout = setTimeout;
         } else {
             cachedSetTimeout = defaultSetTimout;
         }
     } catch (e) {
         cachedSetTimeout = defaultSetTimout;
     }
     try {
         if (typeof clearTimeout === 'function') {
             cachedClearTimeout = clearTimeout;
         } else {
             cachedClearTimeout = defaultClearTimeout;
         }
     } catch (e) {
         cachedClearTimeout = defaultClearTimeout;
     }
 } ())
 function runTimeout(fun) {
     if (cachedSetTimeout === setTimeout) {
         //normal enviroments in sane situations
         return setTimeout(fun, 0);
     }
     // if setTimeout wasn't available but was latter defined
     if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {
         cachedSetTimeout = setTimeout;
         return setTimeout(fun, 0);
     }
     try {
         // when when somebody has screwed with setTimeout but no I.E. maddness
         return cachedSetTimeout(fun, 0);
     } catch(e){
         try {
             // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
             return cachedSetTimeout.call(null, fun, 0);
         } catch(e){
             // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error
             return cachedSetTimeout.call(this, fun, 0);
         }
     }
 
 
 }
 function runClearTimeout(marker) {
     if (cachedClearTimeout === clearTimeout) {
         //normal enviroments in sane situations
         return clearTimeout(marker);
     }
     // if clearTimeout wasn't available but was latter defined
     if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {
         cachedClearTimeout = clearTimeout;
         return clearTimeout(marker);
     }
     try {
         // when when somebody has screwed with setTimeout but no I.E. maddness
         return cachedClearTimeout(marker);
     } catch (e){
         try {
             // When we are in I.E. but the script has been evaled so I.E. doesn't  trust the global object when called normally
             return cachedClearTimeout.call(null, marker);
         } catch (e){
             // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.
             // Some versions of I.E. have different rules for clearTimeout vs setTimeout
             return cachedClearTimeout.call(this, marker);
         }
     }
 
 
 
 }
 var queue = [];
 var draining = false;
 var currentQueue;
 var queueIndex = -1;
 
 function cleanUpNextTick() {
     if (!draining || !currentQueue) {
         return;
     }
     draining = false;
     if (currentQueue.length) {
         queue = currentQueue.concat(queue);
     } else {
         queueIndex = -1;
     }
     if (queue.length) {
         drainQueue();
     }
 }
 
 function drainQueue() {
     if (draining) {
         return;
     }
     var timeout = runTimeout(cleanUpNextTick);
     draining = true;
 
     var len = queue.length;
     while(len) {
         currentQueue = queue;
         queue = [];
         while (++queueIndex < len) {
             if (currentQueue) {
                 currentQueue[queueIndex].run();
             }
         }
         queueIndex = -1;
         len = queue.length;
     }
     currentQueue = null;
     draining = false;
     runClearTimeout(timeout);
 }
 
 process.nextTick = function (fun) {
     var args = new Array(arguments.length - 1);
     if (arguments.length > 1) {
         for (var i = 1; i < arguments.length; i++) {
             args[i - 1] = arguments[i];
         }
     }
     queue.push(new Item(fun, args));
     if (queue.length === 1 && !draining) {
         runTimeout(drainQueue);
     }
 };
 
 // v8 likes predictible objects
 function Item(fun, array) {
     this.fun = fun;
     this.array = array;
 }
 Item.prototype.run = function () {
     this.fun.apply(null, this.array);
 };
 process.title = 'browser';
 process.browser = true;
 process.env = {};
 process.argv = [];
 process.version = ''; // empty string to avoid regexp issues
 process.versions = {};
 
 function noop() {}
 
 process.on = noop;
 process.addListener = noop;
 process.once = noop;
 process.off = noop;
 process.removeListener = noop;
 process.removeAllListeners = noop;
 process.emit = noop;
 process.prependListener = noop;
 process.prependOnceListener = noop;
 
 process.listeners = function (name) { return [] }
 
 process.binding = function (name) {
     throw new Error('process.binding is not supported');
 };
 
 process.cwd = function () { return '/' };
 process.chdir = function (dir) {
     throw new Error('process.chdir is not supported');
 };
 process.umask = function() { return 0; };
 
 },{}],34:[function(require,module,exports){
 var grammar = module.exports = {
   v: [{
     name: 'version',
     reg: /^(\d*)$/
   }],
   o: [{
     // o=- 20518 0 IN IP4 203.0.113.1
     // NB: sessionId will be a String in most cases because it is huge
     name: 'origin',
     reg: /^(\S*) (\d*) (\d*) (\S*) IP(\d) (\S*)/,
     names: ['username', 'sessionId', 'sessionVersion', 'netType', 'ipVer', 'address'],
     format: '%s %s %d %s IP%d %s'
   }],
   // default parsing of these only (though some of these feel outdated)
   s: [{ name: 'name' }],
   i: [{ name: 'description' }],
   u: [{ name: 'uri' }],
   e: [{ name: 'email' }],
   p: [{ name: 'phone' }],
   z: [{ name: 'timezones' }], // TODO: this one can actually be parsed properly...
   r: [{ name: 'repeats' }],   // TODO: this one can also be parsed properly
   // k: [{}], // outdated thing ignored
   t: [{
     // t=0 0
     name: 'timing',
     reg: /^(\d*) (\d*)/,
     names: ['start', 'stop'],
     format: '%d %d'
   }],
   c: [{
     // c=IN IP4 10.47.197.26
     name: 'connection',
     reg: /^IN IP(\d) (\S*)/,
     names: ['version', 'ip'],
     format: 'IN IP%d %s'
   }],
   b: [{
     // b=AS:4000
     push: 'bandwidth',
     reg: /^(TIAS|AS|CT|RR|RS):(\d*)/,
     names: ['type', 'limit'],
     format: '%s:%s'
   }],
   m: [{
     // m=video 51744 RTP/AVP 126 97 98 34 31
     // NB: special - pushes to session
     // TODO: rtp/fmtp should be filtered by the payloads found here?
     reg: /^(\w*) (\d*) ([\w/]*)(?: (.*))?/,
     names: ['type', 'port', 'protocol', 'payloads'],
     format: '%s %d %s %s'
   }],
   a: [
     {
       // a=rtpmap:110 opus/48000/2
       push: 'rtp',
       reg: /^rtpmap:(\d*) ([\w\-.]*)(?:\s*\/(\d*)(?:\s*\/(\S*))?)?/,
       names: ['payload', 'codec', 'rate', 'encoding'],
       format: function (o) {
         return (o.encoding)
           ? 'rtpmap:%d %s/%s/%s'
           : o.rate
             ? 'rtpmap:%d %s/%s'
             : 'rtpmap:%d %s';
       }
     },
     {
       // a=fmtp:108 profile-level-id=24;object=23;bitrate=64000
       // a=fmtp:111 minptime=10; useinbandfec=1
       push: 'fmtp',
       reg: /^fmtp:(\d*) ([\S| ]*)/,
       names: ['payload', 'config'],
       format: 'fmtp:%d %s'
     },
     {
       // a=control:streamid=0
       name: 'control',
       reg: /^control:(.*)/,
       format: 'control:%s'
     },
     {
       // a=rtcp:65179 IN IP4 193.84.77.194
       name: 'rtcp',
       reg: /^rtcp:(\d*)(?: (\S*) IP(\d) (\S*))?/,
       names: ['port', 'netType', 'ipVer', 'address'],
       format: function (o) {
         return (o.address != null)
           ? 'rtcp:%d %s IP%d %s'
           : 'rtcp:%d';
       }
     },
     {
       // a=rtcp-fb:98 trr-int 100
       push: 'rtcpFbTrrInt',
       reg: /^rtcp-fb:(\*|\d*) trr-int (\d*)/,
       names: ['payload', 'value'],
       format: 'rtcp-fb:%d trr-int %d'
     },
     {
       // a=rtcp-fb:98 nack rpsi
       push: 'rtcpFb',
       reg: /^rtcp-fb:(\*|\d*) ([\w-_]*)(?: ([\w-_]*))?/,
       names: ['payload', 'type', 'subtype'],
       format: function (o) {
         return (o.subtype != null)
           ? 'rtcp-fb:%s %s %s'
           : 'rtcp-fb:%s %s';
       }
     },
     {
       // a=extmap:2 urn:ietf:params:rtp-hdrext:toffset
       // a=extmap:1/recvonly URI-gps-string
       // a=extmap:3 urn:ietf:params:rtp-hdrext:encrypt urn:ietf:params:rtp-hdrext:smpte-tc 25@600/24
       push: 'ext',
       reg: /^extmap:(\d+)(?:\/(\w+))?(?: (urn:ietf:params:rtp-hdrext:encrypt))? (\S*)(?: (\S*))?/,
       names: ['value', 'direction', 'encrypt-uri', 'uri', 'config'],
       format: function (o) {
         return (
           'extmap:%d' +
           (o.direction ? '/%s' : '%v') +
           (o['encrypt-uri'] ? ' %s' : '%v') +
           ' %s' +
           (o.config ? ' %s' : '')
         );
       }
     },
     {
       // a=extmap-allow-mixed
       name: 'extmapAllowMixed',
       reg: /^(extmap-allow-mixed)/
     },
     {
       // a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:PS1uQCVeeCFCanVmcjkpPywjNWhcYD0mXXtxaVBR|2^20|1:32
       push: 'crypto',
       reg: /^crypto:(\d*) ([\w_]*) (\S*)(?: (\S*))?/,
       names: ['id', 'suite', 'config', 'sessionConfig'],
       format: function (o) {
         return (o.sessionConfig != null)
           ? 'crypto:%d %s %s %s'
           : 'crypto:%d %s %s';
       }
     },
     {
       // a=setup:actpass
       name: 'setup',
       reg: /^setup:(\w*)/,
       format: 'setup:%s'
     },
     {
       // a=connection:new
       name: 'connectionType',
       reg: /^connection:(new|existing)/,
       format: 'connection:%s'
     },
     {
       // a=mid:1
       name: 'mid',
       reg: /^mid:([^\s]*)/,
       format: 'mid:%s'
     },
     {
       // a=msid:0c8b064d-d807-43b4-b434-f92a889d8587 98178685-d409-46e0-8e16-7ef0db0db64a
       name: 'msid',
       reg: /^msid:(.*)/,
       format: 'msid:%s'
     },
     {
       // a=ptime:20
       name: 'ptime',
       reg: /^ptime:(\d*(?:\.\d*)*)/,
       format: 'ptime:%d'
     },
     {
       // a=maxptime:60
       name: 'maxptime',
       reg: /^maxptime:(\d*(?:\.\d*)*)/,
       format: 'maxptime:%d'
     },
     {
       // a=sendrecv
       name: 'direction',
       reg: /^(sendrecv|recvonly|sendonly|inactive)/
     },
     {
       // a=ice-lite
       name: 'icelite',
       reg: /^(ice-lite)/
     },
     {
       // a=ice-ufrag:F7gI
       name: 'iceUfrag',
       reg: /^ice-ufrag:(\S*)/,
       format: 'ice-ufrag:%s'
     },
     {
       // a=ice-pwd:x9cml/YzichV2+XlhiMu8g
       name: 'icePwd',
       reg: /^ice-pwd:(\S*)/,
       format: 'ice-pwd:%s'
     },
     {
       // a=fingerprint:SHA-1 00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF:00:11:22:33
       name: 'fingerprint',
       reg: /^fingerprint:(\S*) (\S*)/,
       names: ['type', 'hash'],
       format: 'fingerprint:%s %s'
     },
     {
       // a=candidate:0 1 UDP 2113667327 203.0.113.1 54400 typ host
       // a=candidate:1162875081 1 udp 2113937151 192.168.34.75 60017 typ host generation 0 network-id 3 network-cost 10
       // a=candidate:3289912957 2 udp 1845501695 193.84.77.194 60017 typ srflx raddr 192.168.34.75 rport 60017 generation 0 network-id 3 network-cost 10
       // a=candidate:229815620 1 tcp 1518280447 192.168.150.19 60017 typ host tcptype active generation 0 network-id 3 network-cost 10
       // a=candidate:3289912957 2 tcp 1845501695 193.84.77.194 60017 typ srflx raddr 192.168.34.75 rport 60017 tcptype passive generation 0 network-id 3 network-cost 10
       push:'candidates',
       reg: /^candidate:(\S*) (\d*) (\S*) (\d*) (\S*) (\d*) typ (\S*)(?: raddr (\S*) rport (\d*))?(?: tcptype (\S*))?(?: generation (\d*))?(?: network-id (\d*))?(?: network-cost (\d*))?/,
       names: ['foundation', 'component', 'transport', 'priority', 'ip', 'port', 'type', 'raddr', 'rport', 'tcptype', 'generation', 'network-id', 'network-cost'],
       format: function (o) {
         var str = 'candidate:%s %d %s %d %s %d typ %s';
 
         str += (o.raddr != null) ? ' raddr %s rport %d' : '%v%v';
 
         // NB: candidate has three optional chunks, so %void middles one if it's missing
         str += (o.tcptype != null) ? ' tcptype %s' : '%v';
 
         if (o.generation != null) {
           str += ' generation %d';
         }
 
         str += (o['network-id'] != null) ? ' network-id %d' : '%v';
         str += (o['network-cost'] != null) ? ' network-cost %d' : '%v';
         return str;
       }
     },
     {
       // a=end-of-candidates (keep after the candidates line for readability)
       name: 'endOfCandidates',
       reg: /^(end-of-candidates)/
     },
     {
       // a=remote-candidates:1 203.0.113.1 54400 2 203.0.113.1 54401 ...
       name: 'remoteCandidates',
       reg: /^remote-candidates:(.*)/,
       format: 'remote-candidates:%s'
     },
     {
       // a=ice-options:google-ice
       name: 'iceOptions',
       reg: /^ice-options:(\S*)/,
       format: 'ice-options:%s'
     },
     {
       // a=ssrc:2566107569 cname:t9YU8M1UxTF8Y1A1
       push: 'ssrcs',
       reg: /^ssrc:(\d*) ([\w_-]*)(?::(.*))?/,
       names: ['id', 'attribute', 'value'],
       format: function (o) {
         var str = 'ssrc:%d';
         if (o.attribute != null) {
           str += ' %s';
           if (o.value != null) {
             str += ':%s';
           }
         }
         return str;
       }
     },
     {
       // a=ssrc-group:FEC 1 2
       // a=ssrc-group:FEC-FR 3004364195 1080772241
       push: 'ssrcGroups',
       // token-char = %x21 / %x23-27 / %x2A-2B / %x2D-2E / %x30-39 / %x41-5A / %x5E-7E
       reg: /^ssrc-group:([\x21\x23\x24\x25\x26\x27\x2A\x2B\x2D\x2E\w]*) (.*)/,
       names: ['semantics', 'ssrcs'],
       format: 'ssrc-group:%s %s'
     },
     {
       // a=msid-semantic: WMS Jvlam5X3SX1OP6pn20zWogvaKJz5Hjf9OnlV
       name: 'msidSemantic',
       reg: /^msid-semantic:\s?(\w*) (\S*)/,
       names: ['semantic', 'token'],
       format: 'msid-semantic: %s %s' // space after ':' is not accidental
     },
     {
       // a=group:BUNDLE audio video
       push: 'groups',
       reg: /^group:(\w*) (.*)/,
       names: ['type', 'mids'],
       format: 'group:%s %s'
     },
     {
       // a=rtcp-mux
       name: 'rtcpMux',
       reg: /^(rtcp-mux)/
     },
     {
       // a=rtcp-rsize
       name: 'rtcpRsize',
       reg: /^(rtcp-rsize)/
     },
     {
       // a=sctpmap:5000 webrtc-datachannel 1024
       name: 'sctpmap',
       reg: /^sctpmap:([\w_/]*) (\S*)(?: (\S*))?/,
       names: ['sctpmapNumber', 'app', 'maxMessageSize'],
       format: function (o) {
         return (o.maxMessageSize != null)
           ? 'sctpmap:%s %s %s'
           : 'sctpmap:%s %s';
       }
     },
     {
       // a=x-google-flag:conference
       name: 'xGoogleFlag',
       reg: /^x-google-flag:([^\s]*)/,
       format: 'x-google-flag:%s'
     },
     {
       // a=rid:1 send max-width=1280;max-height=720;max-fps=30;depend=0
       push: 'rids',
       reg: /^rid:([\d\w]+) (\w+)(?: ([\S| ]*))?/,
       names: ['id', 'direction', 'params'],
       format: function (o) {
         return (o.params) ? 'rid:%s %s %s' : 'rid:%s %s';
       }
     },
     {
       // a=imageattr:97 send [x=800,y=640,sar=1.1,q=0.6] [x=480,y=320] recv [x=330,y=250]
       // a=imageattr:* send [x=800,y=640] recv *
       // a=imageattr:100 recv [x=320,y=240]
       push: 'imageattrs',
       reg: new RegExp(
         // a=imageattr:97
         '^imageattr:(\\d+|\\*)' +
         // send [x=800,y=640,sar=1.1,q=0.6] [x=480,y=320]
         '[\\s\\t]+(send|recv)[\\s\\t]+(\\*|\\[\\S+\\](?:[\\s\\t]+\\[\\S+\\])*)' +
         // recv [x=330,y=250]
         '(?:[\\s\\t]+(recv|send)[\\s\\t]+(\\*|\\[\\S+\\](?:[\\s\\t]+\\[\\S+\\])*))?'
       ),
       names: ['pt', 'dir1', 'attrs1', 'dir2', 'attrs2'],
       format: function (o) {
         return 'imageattr:%s %s %s' + (o.dir2 ? ' %s %s' : '');
       }
     },
     {
       // a=simulcast:send 1,2,3;~4,~5 recv 6;~7,~8
       // a=simulcast:recv 1;4,5 send 6;7
       name: 'simulcast',
       reg: new RegExp(
         // a=simulcast:
         '^simulcast:' +
         // send 1,2,3;~4,~5
         '(send|recv) ([a-zA-Z0-9\\-_~;,]+)' +
         // space + recv 6;~7,~8
         '(?:\\s?(send|recv) ([a-zA-Z0-9\\-_~;,]+))?' +
         // end
         '$'
       ),
       names: ['dir1', 'list1', 'dir2', 'list2'],
       format: function (o) {
         return 'simulcast:%s %s' + (o.dir2 ? ' %s %s' : '');
       }
     },
     {
       // old simulcast draft 03 (implemented by Firefox)
       //   https://tools.ietf.org/html/draft-ietf-mmusic-sdp-simulcast-03
       // a=simulcast: recv pt=97;98 send pt=97
       // a=simulcast: send rid=5;6;7 paused=6,7
       name: 'simulcast_03',
       reg: /^simulcast:[\s\t]+([\S+\s\t]+)$/,
       names: ['value'],
       format: 'simulcast: %s'
     },
     {
       // a=framerate:25
       // a=framerate:29.97
       name: 'framerate',
       reg: /^framerate:(\d+(?:$|\.\d+))/,
       format: 'framerate:%s'
     },
     {
       // RFC4570
       // a=source-filter: incl IN IP4 239.5.2.31 10.1.15.5
       name: 'sourceFilter',
       reg: /^source-filter: *(excl|incl) (\S*) (IP4|IP6|\*) (\S*) (.*)/,
       names: ['filterMode', 'netType', 'addressTypes', 'destAddress', 'srcList'],
       format: 'source-filter: %s %s %s %s %s'
     },
     {
       // a=bundle-only
       name: 'bundleOnly',
       reg: /^(bundle-only)/
     },
     {
       // a=label:1
       name: 'label',
       reg: /^label:(.+)/,
       format: 'label:%s'
     },
     {
       // RFC version 26 for SCTP over DTLS
       // https://tools.ietf.org/html/draft-ietf-mmusic-sctp-sdp-26#section-5
       name: 'sctpPort',
       reg: /^sctp-port:(\d+)$/,
       format: 'sctp-port:%s'
     },
     {
       // RFC version 26 for SCTP over DTLS
       // https://tools.ietf.org/html/draft-ietf-mmusic-sctp-sdp-26#section-6
       name: 'maxMessageSize',
       reg: /^max-message-size:(\d+)$/,
       format: 'max-message-size:%s'
     },
     {
       // RFC7273
       // a=ts-refclk:ptp=IEEE1588-2008:39-A7-94-FF-FE-07-CB-D0:37
       push:'tsRefClocks',
       reg: /^ts-refclk:([^\s=]*)(?:=(\S*))?/,
       names: ['clksrc', 'clksrcExt'],
       format: function (o) {
         return 'ts-refclk:%s' + (o.clksrcExt != null ? '=%s' : '');
       }
     },
     {
       // RFC7273
       // a=mediaclk:direct=963214424
       name:'mediaClk',
       reg: /^mediaclk:(?:id=(\S*))? *([^\s=]*)(?:=(\S*))?(?: *rate=(\d+)\/(\d+))?/,
       names: ['id', 'mediaClockName', 'mediaClockValue', 'rateNumerator', 'rateDenominator'],
       format: function (o) {
         var str = 'mediaclk:';
         str += (o.id != null ? 'id=%s %s' : '%v%s');
         str += (o.mediaClockValue != null ? '=%s' : '');
         str += (o.rateNumerator != null ? ' rate=%s' : '');
         str += (o.rateDenominator != null ? '/%s' : '');
         return str;
       }
     },
     {
       // a=keywds:keywords
       name: 'keywords',
       reg: /^keywds:(.+)$/,
       format: 'keywds:%s'
     },
     {
       // a=content:main
       name: 'content',
       reg: /^content:(.+)/,
       format: 'content:%s'
     },
     // BFCP https://tools.ietf.org/html/rfc4583
     {
       // a=floorctrl:c-s
       name: 'bfcpFloorCtrl',
       reg: /^floorctrl:(c-only|s-only|c-s)/,
       format: 'floorctrl:%s'
     },
     {
       // a=confid:1
       name: 'bfcpConfId',
       reg: /^confid:(\d+)/,
       format: 'confid:%s'
     },
     {
       // a=userid:1
       name: 'bfcpUserId',
       reg: /^userid:(\d+)/,
       format: 'userid:%s'
     },
     {
       // a=floorid:1
       name: 'bfcpFloorId',
       reg: /^floorid:(.+) (?:m-stream|mstrm):(.+)/,
       names: ['id', 'mStream'],
       format: 'floorid:%s mstrm:%s'
     },
     {
       // any a= that we don't understand is kept verbatim on media.invalid
       push: 'invalid',
       names: ['value']
     }
   ]
 };
 
 // set sensible defaults to avoid polluting the grammar with boring details
 Object.keys(grammar).forEach(function (key) {
   var objs = grammar[key];
   objs.forEach(function (obj) {
     if (!obj.reg) {
       obj.reg = /(.*)/;
     }
     if (!obj.format) {
       obj.format = '%s';
     }
   });
 });
 
 },{}],35:[function(require,module,exports){
 var parser = require('./parser');
 var writer = require('./writer');
 
 exports.write = writer;
 exports.parse = parser.parse;
 exports.parseParams = parser.parseParams;
 exports.parseFmtpConfig = parser.parseFmtpConfig; // Alias of parseParams().
 exports.parsePayloads = parser.parsePayloads;
 exports.parseRemoteCandidates = parser.parseRemoteCandidates;
 exports.parseImageAttributes = parser.parseImageAttributes;
 exports.parseSimulcastStreamList = parser.parseSimulcastStreamList;
 
 },{"./parser":36,"./writer":37}],36:[function(require,module,exports){
 var toIntIfInt = function (v) {
   return String(Number(v)) === v ? Number(v) : v;
 };
 
 var attachProperties = function (match, location, names, rawName) {
   if (rawName && !names) {
     location[rawName] = toIntIfInt(match[1]);
   }
   else {
     for (var i = 0; i < names.length; i += 1) {
       if (match[i+1] != null) {
         location[names[i]] = toIntIfInt(match[i+1]);
       }
     }
   }
 };
 
 var parseReg = function (obj, location, content) {
   var needsBlank = obj.name && obj.names;
   if (obj.push && !location[obj.push]) {
     location[obj.push] = [];
   }
   else if (needsBlank && !location[obj.name]) {
     location[obj.name] = {};
   }
   var keyLocation = obj.push ?
     {} :  // blank object that will be pushed
     needsBlank ? location[obj.name] : location; // otherwise, named location or root
 
   attachProperties(content.match(obj.reg), keyLocation, obj.names, obj.name);
 
   if (obj.push) {
     location[obj.push].push(keyLocation);
   }
 };
 
 var grammar = require('./grammar');
 var validLine = RegExp.prototype.test.bind(/^([a-z])=(.*)/);
 
 exports.parse = function (sdp) {
   var session = {}
     , media = []
     , location = session; // points at where properties go under (one of the above)
 
   // parse lines we understand
   sdp.split(/(\r\n|\r|\n)/).filter(validLine).forEach(function (l) {
     var type = l[0];
     var content = l.slice(2);
     if (type === 'm') {
       media.push({rtp: [], fmtp: []});
       location = media[media.length-1]; // point at latest media line
     }
 
     for (var j = 0; j < (grammar[type] || []).length; j += 1) {
       var obj = grammar[type][j];
       if (obj.reg.test(content)) {
         return parseReg(obj, location, content);
       }
     }
   });
 
   session.media = media; // link it up
   return session;
 };
 
 var paramReducer = function (acc, expr) {
   var s = expr.split(/=(.+)/, 2);
   if (s.length === 2) {
     acc[s[0]] = toIntIfInt(s[1]);
   } else if (s.length === 1 && expr.length > 1) {
     acc[s[0]] = undefined;
   }
   return acc;
 };
 
 exports.parseParams = function (str) {
   return str.split(/;\s?/).reduce(paramReducer, {});
 };
 
 // For backward compatibility - alias will be removed in 3.0.0
 exports.parseFmtpConfig = exports.parseParams;
 
 exports.parsePayloads = function (str) {
   return str.toString().split(' ').map(Number);
 };
 
 exports.parseRemoteCandidates = function (str) {
   var candidates = [];
   var parts = str.split(' ').map(toIntIfInt);
   for (var i = 0; i < parts.length; i += 3) {
     candidates.push({
       component: parts[i],
       ip: parts[i + 1],
       port: parts[i + 2]
     });
   }
   return candidates;
 };
 
 exports.parseImageAttributes = function (str) {
   return str.split(' ').map(function (item) {
     return item.substring(1, item.length-1).split(',').reduce(paramReducer, {});
   });
 };
 
 exports.parseSimulcastStreamList = function (str) {
   return str.split(';').map(function (stream) {
     return stream.split(',').map(function (format) {
       var scid, paused = false;
 
       if (format[0] !== '~') {
         scid = toIntIfInt(format);
       } else {
         scid = toIntIfInt(format.substring(1, format.length));
         paused = true;
       }
 
       return {
         scid: scid,
         paused: paused
       };
     });
   });
 };
 
 },{"./grammar":34}],37:[function(require,module,exports){
 var grammar = require('./grammar');
 
 // customized util.format - discards excess arguments and can void middle ones
 var formatRegExp = /%[sdv%]/g;
 var format = function (formatStr) {
   var i = 1;
   var args = arguments;
   var len = args.length;
   return formatStr.replace(formatRegExp, function (x) {
     if (i >= len) {
       return x; // missing argument
     }
     var arg = args[i];
     i += 1;
     switch (x) {
     case '%%':
       return '%';
     case '%s':
       return String(arg);
     case '%d':
       return Number(arg);
     case '%v':
       return '';
     }
   });
   // NB: we discard excess arguments - they are typically undefined from makeLine
 };
 
 var makeLine = function (type, obj, location) {
   var str = obj.format instanceof Function ?
     (obj.format(obj.push ? location : location[obj.name])) :
     obj.format;
 
   var args = [type + '=' + str];
   if (obj.names) {
     for (var i = 0; i < obj.names.length; i += 1) {
       var n = obj.names[i];
       if (obj.name) {
         args.push(location[obj.name][n]);
       }
       else { // for mLine and push attributes
         args.push(location[obj.names[i]]);
       }
     }
   }
   else {
     args.push(location[obj.name]);
   }
   return format.apply(null, args);
 };
 
 // RFC specified order
 // TODO: extend this with all the rest
 var defaultOuterOrder = [
   'v', 'o', 's', 'i',
   'u', 'e', 'p', 'c',
   'b', 't', 'r', 'z', 'a'
 ];
 var defaultInnerOrder = ['i', 'c', 'b', 'a'];
 
 
 module.exports = function (session, opts) {
   opts = opts || {};
   // ensure certain properties exist
   if (session.version == null) {
     session.version = 0; // 'v=0' must be there (only defined version atm)
   }
   if (session.name == null) {
     session.name = ' '; // 's= ' must be there if no meaningful name set
   }
   session.media.forEach(function (mLine) {
     if (mLine.payloads == null) {
       mLine.payloads = '';
     }
   });
 
   var outerOrder = opts.outerOrder || defaultOuterOrder;
   var innerOrder = opts.innerOrder || defaultInnerOrder;
   var sdp = [];
 
   // loop through outerOrder for matching properties on session
   outerOrder.forEach(function (type) {
     grammar[type].forEach(function (obj) {
       if (obj.name in session && session[obj.name] != null) {
         sdp.push(makeLine(type, obj, session));
       }
       else if (obj.push in session && session[obj.push] != null) {
         session[obj.push].forEach(function (el) {
           sdp.push(makeLine(type, obj, el));
         });
       }
     });
   });
 
   // then for each media line, follow the innerOrder
   session.media.forEach(function (mLine) {
     sdp.push(makeLine('m', grammar.m[0], mLine));
 
     innerOrder.forEach(function (type) {
       grammar[type].forEach(function (obj) {
         if (obj.name in mLine && mLine[obj.name] != null) {
           sdp.push(makeLine(type, obj, mLine));
         }
         else if (obj.push in mLine && mLine[obj.push] != null) {
           mLine[obj.push].forEach(function (el) {
             sdp.push(makeLine(type, obj, el));
           });
         }
       });
     });
   });
 
   return sdp.join('\r\n') + '\r\n';
 };
 
 },{"./grammar":34}],38:[function(require,module,exports){
 module.exports={
   "name": "jssip",
   "title": "JsSIP",
   "description": "the Javascript SIP library",
   "version": "3.7.0",
   "homepage": "https://jssip.net",
   "author": "José Luis Millán <jmillan@aliax.net> (https://github.com/jmillan)",
   "contributors": [
     "Iñaki Baz Castillo <ibc@aliax.net> (https://github.com/ibc)"
   ],
   "types": "lib/JsSIP.d.ts",
   "main": "lib-es5/JsSIP.js",
   "keywords": [
     "sip",
     "websocket",
     "webrtc",
     "node",
     "browser",
     "library"
   ],
   "license": "MIT",
   "repository": {
     "type": "git",
     "url": "https://github.com/versatica/JsSIP.git"
   },
   "bugs": {
     "url": "https://github.com/versatica/JsSIP/issues"
   },
   "dependencies": {
     "@types/debug": "^4.1.5",
     "@types/node": "^14.14.13",
     "debug": "^4.3.1",
     "events": "^3.2.0",
     "sdp-transform": "^2.14.1"
   },
   "devDependencies": {
     "@babel/core": "^7.12.10",
     "@babel/preset-env": "^7.12.10",
     "ansi-colors": "^3.2.4",
     "browserify": "^16.5.1",
     "eslint": "^5.16.0",
     "fancy-log": "^1.3.3",
     "gulp": "^4.0.2",
     "gulp-babel": "^8.0.0",
     "gulp-eslint": "^5.0.0",
     "gulp-expect-file": "^1.0.2",
     "gulp-header": "^2.0.9",
     "gulp-nodeunit-runner": "^0.2.2",
     "gulp-plumber": "^1.2.1",
     "gulp-rename": "^1.4.0",
     "gulp-uglify-es": "^1.0.4",
     "pegjs": "^0.7.0",
     "vinyl-buffer": "^1.0.1",
     "vinyl-source-stream": "^2.0.0"
   },
   "scripts": {
     "lint": "gulp lint",
     "test": "gulp test",
     "prepublishOnly": "gulp babel"
   }
 }
 
 },{}]},{},[8])(8)
 });
 /*
  * JsSIP v3.7.0
  * the Javascript SIP library
  * Copyright: 2012-2020 José Luis Millán <jmillan@aliax.net> (https://github.com/jmillan)
  * Homepage: https://jssip.net
  * License: MIT
  */
 
 (function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.JsSIP = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
 "use strict";
 
 function _createForOfIteratorHelper(o, allowArrayLike) { var it; if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
 
 function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
 
 function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
 
 var Utils = require('./Utils');
 
 var JsSIP_C = require('./Constants');
 
 var Grammar = require('./Grammar');
 
 var URI = require('./URI');
 
 var Socket = require('./Socket');
 
 var Exceptions = require('./Exceptions'); // Default settings.
 
 
 exports.settings = {
   // SIP authentication.
   authorization_user: null,
   password: null,
   realm: null,
   ha1: null,
   authorization_jwt: null,
   // SIP account.
   display_name: null,
   uri: null,
   contact_uri: null,
   // SIP instance id (GRUU).
   instance_id: null,
   // Preloaded SIP Route header field.
   use_preloaded_route: false,
   // Session parameters.
   session_timers: true,
   session_timers_refresh_method: JsSIP_C.UPDATE,
   session_timers_force_refresher: false,
   no_answer_timeout: 60,
   // Registration parameters.
   register: true,
   register_expires: 600,
   registrar_server: null,
   // Connection options.
   sockets: null,
   connection_recovery_max_interval: JsSIP_C.CONNECTION_RECOVERY_MAX_INTERVAL,
   connection_recovery_min_interval: JsSIP_C.CONNECTION_RECOVERY_MIN_INTERVAL,
 
   /*
    * Host address.
    * Value to be set in Via sent_by and host part of Contact FQDN.
   */
   via_host: "".concat(Utils.createRandomToken(12), ".invalid")
 }; // Configuration checks.
 
 var checks = {
   mandatory: {
     sockets: function sockets(_sockets2) {
       /* Allow defining sockets parameter as:
        *  Socket: socket
        *  Array of Socket: [socket1, socket2]
        *  Array of Objects: [{socket: socket1, weight:1}, {socket: Socket2, weight:0}]
        *  Array of Objects and Socket: [{socket: socket1}, socket2]
        */
       var _sockets = [];
 
       if (Socket.isSocket(_sockets2)) {
         _sockets.push({
           socket: _sockets2
         });
       } else if (Array.isArray(_sockets2) && _sockets2.length) {
         var _iterator = _createForOfIteratorHelper(_sockets2),
             _step;
 
         try {
           for (_iterator.s(); !(_step = _iterator.n()).done;) {
             var socket = _step.value;
 
             if (Object.prototype.hasOwnProperty.call(socket, 'socket') && Socket.isSocket(socket.socket)) {
               _sockets.push(socket);
             } else if (Socket.isSocket(socket)) {
               _sockets.push({
                 socket: socket
               });
             }
           }
         } catch (err) {
           _iterator.e(err);
         } finally {
           _iterator.f();
         }
       } else {
         return;
       }
 
       return _sockets;
     },
     uri: function uri(_uri) {
       if (!/^sip:/i.test(_uri)) {
         _uri = "".concat(JsSIP_C.SIP, ":").concat(_uri);
       }
 
       var parsed = URI.parse(_uri);
 
       if (!parsed) {
         return;
       } else if (!parsed.user) {
         return;
       } else {
         return parsed;
       }
     }
   },
   optional: {
     authorization_user: function authorization_user(_authorization_user) {
       if (Grammar.parse("\"".concat(_authorization_user, "\""), 'quoted_string') === -1) {
         return;
       } else {
         return _authorization_user;
       }
     },
     authorization_jwt: function authorization_jwt(_authorization_jwt) {
       if (typeof _authorization_jwt === 'string') {
         return _authorization_jwt;
       }
     },
     user_agent: function user_agent(_user_agent) {
       if (typeof _user_agent === 'string') {
         return _user_agent;
       }
     },
     connection_recovery_max_interval: function connection_recovery_max_interval(_connection_recovery_max_interval) {
       if (Utils.isDecimal(_connection_recovery_max_interval)) {
         var value = Number(_connection_recovery_max_interval);
 
         if (value > 0) {
           return value;
         }
       }
     },
     connection_recovery_min_interval: function connection_recovery_min_interval(_connection_recovery_min_interval) {
       if (Utils.isDecimal(_connection_recovery_min_interval)) {
         var value = Number(_connection_recovery_min_interval);
 
         if (value > 0) {
           return value;
         }
       }
     },
     contact_uri: function contact_uri(_contact_uri) {
       if (typeof _contact_uri === 'string') {
         var uri = Grammar.parse(_contact_uri, 'SIP_URI');
 
         if (uri !== -1) {
           return uri;
         }
       }
     },
     display_name: function display_name(_display_name) {
       return _display_name;
     },
     instance_id: function instance_id(_instance_id) {
       if (/^uuid:/i.test(_instance_id)) {
         _instance_id = _instance_id.substr(5);
       }
 
       if (Grammar.parse(_instance_id, 'uuid') === -1) {
         return;
       } else {
         return _instance_id;
       }
     },
     no_answer_timeout: function no_answer_timeout(_no_answer_timeout) {
       if (Utils.isDecimal(_no_answer_timeout)) {
         var value = Number(_no_answer_timeout);
 
         if (value > 0) {
           return value;
         }
       }
     },
     session_timers: function session_timers(_session_timers) {
       if (typeof _session_timers === 'boolean') {
         return _session_timers;
       }
     },
     session_timers_refresh_method: function session_timers_refresh_method(method) {
       if (typeof method === 'string') {
         method = method.toUpperCase();
 
         if (method === JsSIP_C.INVITE || method === JsSIP_C.UPDATE) {
           return method;
         }
       }
     },
     session_timers_force_refresher: function session_timers_force_refresher(_session_timers_force_refresher) {
       if (typeof _session_timers_force_refresher === 'boolean') {
         return _session_timers_force_refresher;
       }
     },
     password: function password(_password) {
       return String(_password);
     },
     realm: function realm(_realm) {
       return String(_realm);
     },
     ha1: function ha1(_ha) {
       return String(_ha);
     },
     register: function register(_register) {
       if (typeof _register === 'boolean') {
         return _register;
       }
     },
     register_expires: function register_expires(_register_expires) {
       if (Utils.isDecimal(_register_expires)) {
         var value = Number(_register_expires);
 
         if (value > 0) {
           return value;
         }
       }
     },
     registrar_server: function registrar_server(_registrar_server) {
       if (!/^sip:/i.test(_registrar_server)) {
         _registrar_server = "".concat(JsSIP_C.SIP, ":").concat(_registrar_server);
       }
 
       var parsed = URI.parse(_registrar_server);
 
       if (!parsed) {
         return;
       } else if (parsed.user) {
         return;
       } else {
         return parsed;
       }
     },
     use_preloaded_route: function use_preloaded_route(_use_preloaded_route) {
       if (typeof _use_preloaded_route === 'boolean') {
         return _use_preloaded_route;
       }
     }
   }
 };
 
 exports.load = function (dst, src) {
   // Check Mandatory parameters.
   for (var parameter in checks.mandatory) {
     if (!src.hasOwnProperty(parameter)) {
       throw new Exceptions.ConfigurationError(parameter);
     } else {
       var value = src[parameter];
       var checked_value = checks.mandatory[parameter](value);
 
       if (checked_value !== undefined) {
         dst[parameter] = checked_value;
       } else {
         throw new Exceptions.ConfigurationError(parameter, value);
       }
     }
   } // Check Optional parameters.
 
 
   for (var _parameter in checks.optional) {
     if (src.hasOwnProperty(_parameter)) {
       var _value = src[_parameter];
       /* If the parameter value is null, empty string, undefined, empty array
        * or it's a number with NaN value, then apply its default value.
        */
 
       if (Utils.isEmpty(_value)) {
         continue;
       }
 
       var _checked_value = checks.optional[_parameter](_value);
 
       if (_checked_value !== undefined) {
         dst[_parameter] = _checked_value;
       } else {
         throw new Exceptions.ConfigurationError(_parameter, _value);
       }
     }
   }
 };
 },{"./Constants":2,"./Exceptions":6,"./Grammar":7,"./Socket":20,"./URI":25,"./Utils":26}],2:[function(require,module,exports){
 "use strict";
 
 var pkg = require('../package.json');
 
 module.exports = {
   USER_AGENT: "".concat(pkg.title, " ").concat(pkg.version),
   // SIP scheme.
   SIP: 'sip',
   SIPS: 'sips',
   // End and Failure causes.
   causes: {
     // Generic error causes.
     CONNECTION_ERROR: 'Connection Error',
     REQUEST_TIMEOUT: 'Request Timeout',
     SIP_FAILURE_CODE: 'SIP Failure Code',
     INTERNAL_ERROR: 'Internal Error',
     // SIP error causes.
     BUSY: 'Busy',
     REJECTED: 'Rejected',
     REDIRECTED: 'Redirected',
     UNAVAILABLE: 'Unavailable',
     NOT_FOUND: 'Not Found',
     ADDRESS_INCOMPLETE: 'Address Incomplete',
     INCOMPATIBLE_SDP: 'Incompatible SDP',
     MISSING_SDP: 'Missing SDP',
     AUTHENTICATION_ERROR: 'Authentication Error',
     // Session error causes.
     BYE: 'Terminated',
     WEBRTC_ERROR: 'WebRTC Error',
     CANCELED: 'Canceled',
     NO_ANSWER: 'No Answer',
     EXPIRES: 'Expires',
     NO_ACK: 'No ACK',
     DIALOG_ERROR: 'Dialog Error',
     USER_DENIED_MEDIA_ACCESS: 'User Denied Media Access',
     BAD_MEDIA_DESCRIPTION: 'Bad Media Description',
     RTP_TIMEOUT: 'RTP Timeout'
   },
   SIP_ERROR_CAUSES: {
     REDIRECTED: [300, 301, 302, 305, 380],
     BUSY: [486, 600],
     REJECTED: [403, 603],
     NOT_FOUND: [404, 604],
     UNAVAILABLE: [480, 410, 408, 430],
     ADDRESS_INCOMPLETE: [484, 424],
     INCOMPATIBLE_SDP: [488, 606],
     AUTHENTICATION_ERROR: [401, 407]
   },
   // SIP Methods.
   ACK: 'ACK',
   BYE: 'BYE',
   CANCEL: 'CANCEL',
   INFO: 'INFO',
   INVITE: 'INVITE',
   MESSAGE: 'MESSAGE',
   NOTIFY: 'NOTIFY',
   OPTIONS: 'OPTIONS',
   REGISTER: 'REGISTER',
   REFER: 'REFER',
   UPDATE: 'UPDATE',
   SUBSCRIBE: 'SUBSCRIBE',
   // DTMF transport methods.
   DTMF_TRANSPORT: {
     INFO: 'INFO',
     RFC2833: 'RFC2833'
   },
 
   /* SIP Response Reasons
    * DOC: https://www.iana.org/assignments/sip-parameters
    * Copied from https://github.com/versatica/OverSIP/blob/master/lib/oversip/sip/constants.rb#L7
    */
   REASON_PHRASE: {
     100: 'Trying',
     180: 'Ringing',
     181: 'Call Is Being Forwarded',
     182: 'Queued',
     183: 'Session Progress',
     199: 'Early Dialog Terminated',
     // draft-ietf-sipcore-199
     200: 'OK',
     202: 'Accepted',
     // RFC 3265
     204: 'No Notification',
     // RFC 5839
     300: 'Multiple Choices',
     301: 'Moved Permanently',
     302: 'Moved Temporarily',
     305: 'Use Proxy',
     380: 'Alternative Service',
     400: 'Bad Request',
     401: 'Unauthorized',
     402: 'Payment Required',
     403: 'Forbidden',
     404: 'Not Found',
     405: 'Method Not Allowed',
     406: 'Not Acceptable',
     407: 'Proxy Authentication Required',
     408: 'Request Timeout',
     410: 'Gone',
     412: 'Conditional Request Failed',
     // RFC 3903
     413: 'Request Entity Too Large',
     414: 'Request-URI Too Long',
     415: 'Unsupported Media Type',
     416: 'Unsupported URI Scheme',
     417: 'Unknown Resource-Priority',
     // RFC 4412
     420: 'Bad Extension',
     421: 'Extension Required',
     422: 'Session Interval Too Small',
     // RFC 4028
     423: 'Interval Too Brief',
     424: 'Bad Location Information',
     // RFC 6442
     428: 'Use Identity Header',
     // RFC 4474
     429: 'Provide Referrer Identity',
     // RFC 3892
     430: 'Flow Failed',
     // RFC 5626
     433: 'Anonymity Disallowed',
     // RFC 5079
     436: 'Bad Identity-Info',
     // RFC 4474
     437: 'Unsupported Certificate',
     // RFC 4744
     438: 'Invalid Identity Header',
     // RFC 4744
     439: 'First Hop Lacks Outbound Support',
     // RFC 5626
     440: 'Max-Breadth Exceeded',
     // RFC 5393
     469: 'Bad Info Package',
     // draft-ietf-sipcore-info-events
     470: 'Consent Needed',
     // RFC 5360
     478: 'Unresolvable Destination',
     // Custom code copied from Kamailio.
     480: 'Temporarily Unavailable',
     481: 'Call/Transaction Does Not Exist',
     482: 'Loop Detected',
     483: 'Too Many Hops',
     484: 'Address Incomplete',
     485: 'Ambiguous',
     486: 'Busy Here',
     487: 'Request Terminated',
     488: 'Not Acceptable Here',
     489: 'Bad Event',
     // RFC 3265
     491: 'Request Pending',
     493: 'Undecipherable',
     494: 'Security Agreement Required',
     // RFC 3329
     500: 'JsSIP Internal Error',
     501: 'Not Implemented',
     502: 'Bad Gateway',
     503: 'Service Unavailable',
     504: 'Server Time-out',
     505: 'Version Not Supported',
     513: 'Message Too Large',
     580: 'Precondition Failure',
     // RFC 3312
     600: 'Busy Everywhere',
     603: 'Decline',
     604: 'Does Not Exist Anywhere',
     606: 'Not Acceptable'
   },
   ALLOWED_METHODS: 'INVITE,ACK,CANCEL,BYE,UPDATE,MESSAGE,OPTIONS,REFER,INFO,NOTIFY',
   ACCEPTED_BODY_TYPES: 'application/sdp, application/dtmf-relay',
   MAX_FORWARDS: 69,
   SESSION_EXPIRES: 90,
   MIN_SESSION_EXPIRES: 60,
   CONNECTION_RECOVERY_MAX_INTERVAL: 30,
   CONNECTION_RECOVERY_MIN_INTERVAL: 2
 };
 },{"../package.json":38}],3:[function(require,module,exports){
 "use strict";
 
 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
 function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
 
 function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
 
 var SIPMessage = require('./SIPMessage');
 
 var JsSIP_C = require('./Constants');
 
 var Transactions = require('./Transactions');
 
 var Dialog_RequestSender = require('./Dialog/RequestSender');
 
 var Utils = require('./Utils');
 
 var debug = require('debug')('JsSIP:Dialog');
 
 var C = {
   // Dialog states.
   STATUS_EARLY: 1,
   STATUS_CONFIRMED: 2
 }; // RFC 3261 12.1.
 
 module.exports = /*#__PURE__*/function () {
   _createClass(Dialog, null, [{
     key: "C",
     // Expose C object.
     get: function get() {
       return C;
     }
   }]);
 
   function Dialog(owner, message, type) {
     var state = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : C.STATUS_CONFIRMED;
 
     _classCallCheck(this, Dialog);
 
     this._owner = owner;
     this._ua = owner._ua;
     this._uac_pending_reply = false;
     this._uas_pending_reply = false;
 
     if (!message.hasHeader('contact')) {
       return {
         error: 'unable to create a Dialog without Contact header field'
       };
     }
 
     if (message instanceof SIPMessage.IncomingResponse) {
       state = message.status_code < 200 ? C.STATUS_EARLY : C.STATUS_CONFIRMED;
     }
 
     var contact = message.parseHeader('contact'); // RFC 3261 12.1.1.
 
     if (type === 'UAS') {
       this._id = {
         call_id: message.call_id,
         local_tag: message.to_tag,
         remote_tag: message.from_tag,
         toString: function toString() {
           return this.call_id + this.local_tag + this.remote_tag;
         }
       };
       this._state = state;
       this._remote_seqnum = message.cseq;
       this._local_uri = message.parseHeader('to').uri;
       this._remote_uri = message.parseHeader('from').uri;
       this._remote_target = contact.uri;
       this._route_set = message.getHeaders('record-route');
       this._ack_seqnum = this._remote_seqnum;
     } // RFC 3261 12.1.2.
     else if (type === 'UAC') {
         this._id = {
           call_id: message.call_id,
           local_tag: message.from_tag,
           remote_tag: message.to_tag,
           toString: function toString() {
             return this.call_id + this.local_tag + this.remote_tag;
           }
         };
         this._state = state;
         this._local_seqnum = message.cseq;
         this._local_uri = message.parseHeader('from').uri;
         this._remote_uri = message.parseHeader('to').uri;
         this._remote_target = contact.uri;
         this._route_set = message.getHeaders('record-route').reverse();
         this._ack_seqnum = null;
       }
 
     this._ua.newDialog(this);
 
     debug("new ".concat(type, " dialog created with status ").concat(this._state === C.STATUS_EARLY ? 'EARLY' : 'CONFIRMED'));
   }
 
   _createClass(Dialog, [{
     key: "update",
     value: function update(message, type) {
       this._state = C.STATUS_CONFIRMED;
       debug("dialog ".concat(this._id.toString(), "  changed to CONFIRMED state"));
 
       if (type === 'UAC') {
         // RFC 3261 13.2.2.4.
         this._route_set = message.getHeaders('record-route').reverse();
       }
     }
   }, {
     key: "terminate",
     value: function terminate() {
       debug("dialog ".concat(this._id.toString(), " deleted"));
 
       this._ua.destroyDialog(this);
     }
   }, {
     key: "sendRequest",
     value: function sendRequest(method) {
       var _this = this;
 
       var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
       var extraHeaders = Utils.cloneArray(options.extraHeaders);
       var eventHandlers = Utils.cloneObject(options.eventHandlers);
       var body = options.body || null;
 
       var request = this._createRequest(method, extraHeaders, body); // Increase the local CSeq on authentication.
 
 
       eventHandlers.onAuthenticated = function () {
         _this._local_seqnum += 1;
       };
 
       var request_sender = new Dialog_RequestSender(this, request, eventHandlers);
       request_sender.send(); // Return the instance of OutgoingRequest.
 
       return request;
     }
   }, {
     key: "receiveRequest",
     value: function receiveRequest(request) {
       // Check in-dialog request.
       if (!this._checkInDialogRequest(request)) {
         return;
       } // ACK received. Cleanup this._ack_seqnum.
 
 
       if (request.method === JsSIP_C.ACK && this._ack_seqnum !== null) {
         this._ack_seqnum = null;
       } // INVITE received. Set this._ack_seqnum.
       else if (request.method === JsSIP_C.INVITE) {
           this._ack_seqnum = request.cseq;
         }
 
       this._owner.receiveRequest(request);
     } // RFC 3261 12.2.1.1.
 
   }, {
     key: "_createRequest",
     value: function _createRequest(method, extraHeaders, body) {
       extraHeaders = Utils.cloneArray(extraHeaders);
 
       if (!this._local_seqnum) {
         this._local_seqnum = Math.floor(Math.random() * 10000);
       }
 
       var cseq = method === JsSIP_C.CANCEL || method === JsSIP_C.ACK ? this._local_seqnum : this._local_seqnum += 1;
       var request = new SIPMessage.OutgoingRequest(method, this._remote_target, this._ua, {
         'cseq': cseq,
         'call_id': this._id.call_id,
         'from_uri': this._local_uri,
         'from_tag': this._id.local_tag,
         'to_uri': this._remote_uri,
         'to_tag': this._id.remote_tag,
         'route_set': this._route_set
       }, extraHeaders, body);
       return request;
     } // RFC 3261 12.2.2.
 
   }, {
     key: "_checkInDialogRequest",
     value: function _checkInDialogRequest(request) {
       var _this2 = this;
 
       if (!this._remote_seqnum) {
         this._remote_seqnum = request.cseq;
       } else if (request.cseq < this._remote_seqnum) {
         if (request.method === JsSIP_C.ACK) {
           // We are not expecting any ACK with lower seqnum than the current one.
           // Or this is not the ACK we are waiting for.
           if (this._ack_seqnum === null || request.cseq !== this._ack_seqnum) {
             return false;
           }
         } else {
           request.reply(500);
           return false;
         }
       } else if (request.cseq > this._remote_seqnum) {
         this._remote_seqnum = request.cseq;
       } // RFC3261 14.2 Modifying an Existing Session -UAS BEHAVIOR-.
 
 
       if (request.method === JsSIP_C.INVITE || request.method === JsSIP_C.UPDATE && request.body) {
         if (this._uac_pending_reply === true) {
           request.reply(491);
         } else if (this._uas_pending_reply === true) {
           var retryAfter = (Math.random() * 10 | 0) + 1;
           request.reply(500, null, ["Retry-After:".concat(retryAfter)]);
           return false;
         } else {
           this._uas_pending_reply = true;
 
           var stateChanged = function stateChanged() {
             if (request.server_transaction.state === Transactions.C.STATUS_ACCEPTED || request.server_transaction.state === Transactions.C.STATUS_COMPLETED || request.server_transaction.state === Transactions.C.STATUS_TERMINATED) {
               request.server_transaction.removeListener('stateChanged', stateChanged);
               _this2._uas_pending_reply = false;
             }
           };
 
           request.server_transaction.on('stateChanged', stateChanged);
         } // RFC3261 12.2.2 Replace the dialog`s remote target URI if the request is accepted.
 
 
         if (request.hasHeader('contact')) {
           request.server_transaction.on('stateChanged', function () {
             if (request.server_transaction.state === Transactions.C.STATUS_ACCEPTED) {
               _this2._remote_target = request.parseHeader('contact').uri;
             }
           });
         }
       } else if (request.method === JsSIP_C.NOTIFY) {
         // RFC6665 3.2 Replace the dialog`s remote target URI if the request is accepted.
         if (request.hasHeader('contact')) {
           request.server_transaction.on('stateChanged', function () {
             if (request.server_transaction.state === Transactions.C.STATUS_COMPLETED) {
               _this2._remote_target = request.parseHeader('contact').uri;
             }
           });
         }
       }
 
       return true;
     }
   }, {
     key: "id",
     get: function get() {
       return this._id;
     }
   }, {
     key: "local_seqnum",
     get: function get() {
       return this._local_seqnum;
     },
     set: function set(num) {
       this._local_seqnum = num;
     }
   }, {
     key: "owner",
     get: function get() {
       return this._owner;
     }
   }, {
     key: "uac_pending_reply",
     get: function get() {
       return this._uac_pending_reply;
     },
     set: function set(pending) {
       this._uac_pending_reply = pending;
     }
   }, {
     key: "uas_pending_reply",
     get: function get() {
       return this._uas_pending_reply;
     }
   }]);
 
   return Dialog;
 }();
 },{"./Constants":2,"./Dialog/RequestSender":4,"./SIPMessage":19,"./Transactions":22,"./Utils":26,"debug":30}],4:[function(require,module,exports){
 "use strict";
 
 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
 function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
 
 function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
 
 var JsSIP_C = require('../Constants');
 
 var Transactions = require('../Transactions');
 
 var RTCSession = require('../RTCSession');
 
 var RequestSender = require('../RequestSender'); // Default event handlers.
 
 
 var EventHandlers = {
   onRequestTimeout: function onRequestTimeout() {},
   onTransportError: function onTransportError() {},
   onSuccessResponse: function onSuccessResponse() {},
   onErrorResponse: function onErrorResponse() {},
   onAuthenticated: function onAuthenticated() {},
   onDialogError: function onDialogError() {}
 };
 
 module.exports = /*#__PURE__*/function () {
   function DialogRequestSender(dialog, request, eventHandlers) {
     _classCallCheck(this, DialogRequestSender);
 
     this._dialog = dialog;
     this._ua = dialog._ua;
     this._request = request;
     this._eventHandlers = eventHandlers; // RFC3261 14.1 Modifying an Existing Session. UAC Behavior.
 
     this._reattempt = false;
     this._reattemptTimer = null; // Define the undefined handlers.
 
     for (var handler in EventHandlers) {
       if (Object.prototype.hasOwnProperty.call(EventHandlers, handler)) {
         if (!this._eventHandlers[handler]) {
           this._eventHandlers[handler] = EventHandlers[handler];
         }
       }
     }
   }
 
   _createClass(DialogRequestSender, [{
     key: "send",
     value: function send() {
       var _this = this;
 
       var request_sender = new RequestSender(this._ua, this._request, {
         onRequestTimeout: function onRequestTimeout() {
           _this._eventHandlers.onRequestTimeout();
         },
         onTransportError: function onTransportError() {
           _this._eventHandlers.onTransportError();
         },
         onAuthenticated: function onAuthenticated(request) {
           _this._eventHandlers.onAuthenticated(request);
         },
         onReceiveResponse: function onReceiveResponse(response) {
           _this._receiveResponse(response);
         }
       });
       request_sender.send(); // RFC3261 14.2 Modifying an Existing Session -UAC BEHAVIOR-.
 
       if ((this._request.method === JsSIP_C.INVITE || this._request.method === JsSIP_C.UPDATE && this._request.body) && request_sender.clientTransaction.state !== Transactions.C.STATUS_TERMINATED) {
         this._dialog.uac_pending_reply = true;
 
         var stateChanged = function stateChanged() {
           if (request_sender.clientTransaction.state === Transactions.C.STATUS_ACCEPTED || request_sender.clientTransaction.state === Transactions.C.STATUS_COMPLETED || request_sender.clientTransaction.state === Transactions.C.STATUS_TERMINATED) {
             request_sender.clientTransaction.removeListener('stateChanged', stateChanged);
             _this._dialog.uac_pending_reply = false;
           }
         };
 
         request_sender.clientTransaction.on('stateChanged', stateChanged);
       }
     }
   }, {
     key: "_receiveResponse",
     value: function _receiveResponse(response) {
       var _this2 = this;
 
       // RFC3261 12.2.1.2 408 or 481 is received for a request within a dialog.
       if (response.status_code === 408 || response.status_code === 481) {
         this._eventHandlers.onDialogError(response);
       } else if (response.method === JsSIP_C.INVITE && response.status_code === 491) {
         if (this._reattempt) {
           if (response.status_code >= 200 && response.status_code < 300) {
             this._eventHandlers.onSuccessResponse(response);
           } else if (response.status_code >= 300) {
             this._eventHandlers.onErrorResponse(response);
           }
         } else {
           this._request.cseq = this._dialog.local_seqnum += 1;
           this._reattemptTimer = setTimeout(function () {
             // TODO: look at dialog state instead.
             if (_this2._dialog.owner.status !== RTCSession.C.STATUS_TERMINATED) {
               _this2._reattempt = true;
 
               _this2._request_sender.send();
             }
           }, 1000);
         }
       } else if (response.status_code >= 200 && response.status_code < 300) {
         this._eventHandlers.onSuccessResponse(response);
       } else if (response.status_code >= 300) {
         this._eventHandlers.onErrorResponse(response);
       }
     }
   }, {
     key: "request",
     get: function get() {
       return this._request;
     }
   }]);
 
   return DialogRequestSender;
 }();
 },{"../Constants":2,"../RTCSession":12,"../RequestSender":18,"../Transactions":22}],5:[function(require,module,exports){
 "use strict";
 
 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
 function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
 
 function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
 
 var Utils = require('./Utils');
 
 var debug = require('debug')('JsSIP:DigestAuthentication');
 
 var debugerror = require('debug')('JsSIP:ERROR:DigestAuthentication');
 
 debugerror.log = console.warn.bind(console);
 
 module.exports = /*#__PURE__*/function () {
   function DigestAuthentication(credentials) {
     _classCallCheck(this, DigestAuthentication);
 
     this._credentials = credentials;
     this._cnonce = null;
     this._nc = 0;
     this._ncHex = '00000000';
     this._algorithm = null;
     this._realm = null;
     this._nonce = null;
     this._opaque = null;
     this._stale = null;
     this._qop = null;
     this._method = null;
     this._uri = null;
     this._ha1 = null;
     this._response = null;
   }
 
   _createClass(DigestAuthentication, [{
     key: "get",
     value: function get(parameter) {
       switch (parameter) {
         case 'realm':
           return this._realm;
 
         case 'ha1':
           return this._ha1;
 
         default:
           debugerror('get() | cannot get "%s" parameter', parameter);
           return undefined;
       }
     }
     /**
     * Performs Digest authentication given a SIP request and the challenge
     * received in a response to that request.
     * Returns true if auth was successfully generated, false otherwise.
     */
 
   }, {
     key: "authenticate",
     value: function authenticate(_ref, challenge)
     /* test interface */
     {
       var method = _ref.method,
           ruri = _ref.ruri,
           body = _ref.body;
       var cnonce = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : null;
       this._algorithm = challenge.algorithm;
       this._realm = challenge.realm;
       this._nonce = challenge.nonce;
       this._opaque = challenge.opaque;
       this._stale = challenge.stale;
 
       if (this._algorithm) {
         if (this._algorithm !== 'MD5') {
           debugerror('authenticate() | challenge with Digest algorithm different than "MD5", authentication aborted');
           return false;
         }
       } else {
         this._algorithm = 'MD5';
       }
 
       if (!this._nonce) {
         debugerror('authenticate() | challenge without Digest nonce, authentication aborted');
         return false;
       }
 
       if (!this._realm) {
         debugerror('authenticate() | challenge without Digest realm, authentication aborted');
         return false;
       } // If no plain SIP password is provided.
 
 
       if (!this._credentials.password) {
         // If ha1 is not provided we cannot authenticate.
         if (!this._credentials.ha1) {
           debugerror('authenticate() | no plain SIP password nor ha1 provided, authentication aborted');
           return false;
         } // If the realm does not match the stored realm we cannot authenticate.
 
 
         if (this._credentials.realm !== this._realm) {
           debugerror('authenticate() | no plain SIP password, and stored `realm` does not match the given `realm`, cannot authenticate [stored:"%s", given:"%s"]', this._credentials.realm, this._realm);
           return false;
         }
       } // 'qop' can contain a list of values (Array). Let's choose just one.
 
 
       if (challenge.qop) {
         if (challenge.qop.indexOf('auth-int') > -1) {
           this._qop = 'auth-int';
         } else if (challenge.qop.indexOf('auth') > -1) {
           this._qop = 'auth';
         } else {
           // Otherwise 'qop' is present but does not contain 'auth' or 'auth-int', so abort here.
           debugerror('authenticate() | challenge without Digest qop different than "auth" or "auth-int", authentication aborted');
           return false;
         }
       } else {
         this._qop = null;
       } // Fill other attributes.
 
 
       this._method = method;
       this._uri = ruri;
       this._cnonce = cnonce || Utils.createRandomToken(12);
       this._nc += 1;
       var hex = Number(this._nc).toString(16);
       this._ncHex = '00000000'.substr(0, 8 - hex.length) + hex; // Nc-value = 8LHEX. Max value = 'FFFFFFFF'.
 
       if (this._nc === 4294967296) {
         this._nc = 1;
         this._ncHex = '00000001';
       } // Calculate the Digest "response" value.
       // If we have plain SIP password then regenerate ha1.
 
 
       if (this._credentials.password) {
         // HA1 = MD5(A1) = MD5(username:realm:password).
         this._ha1 = Utils.calculateMD5("".concat(this._credentials.username, ":").concat(this._realm, ":").concat(this._credentials.password));
       } // Otherwise reuse the stored ha1.
       else {
           this._ha1 = this._credentials.ha1;
         }
 
       var a2;
       var ha2;
 
       if (this._qop === 'auth') {
         // HA2 = MD5(A2) = MD5(method:digestURI).
         a2 = "".concat(this._method, ":").concat(this._uri);
         ha2 = Utils.calculateMD5(a2);
         debug('authenticate() | using qop=auth [a2:"%s"]', a2); // Response = MD5(HA1:nonce:nonceCount:credentialsNonce:qop:HA2).
 
         this._response = Utils.calculateMD5("".concat(this._ha1, ":").concat(this._nonce, ":").concat(this._ncHex, ":").concat(this._cnonce, ":auth:").concat(ha2));
       } else if (this._qop === 'auth-int') {
         // HA2 = MD5(A2) = MD5(method:digestURI:MD5(entityBody)).
         a2 = "".concat(this._method, ":").concat(this._uri, ":").concat(Utils.calculateMD5(body ? body : ''));
         ha2 = Utils.calculateMD5(a2);
         debug('authenticate() | using qop=auth-int [a2:"%s"]', a2); // Response = MD5(HA1:nonce:nonceCount:credentialsNonce:qop:HA2).
 
         this._response = Utils.calculateMD5("".concat(this._ha1, ":").concat(this._nonce, ":").concat(this._ncHex, ":").concat(this._cnonce, ":auth-int:").concat(ha2));
       } else if (this._qop === null) {
         // HA2 = MD5(A2) = MD5(method:digestURI).
         a2 = "".concat(this._method, ":").concat(this._uri);
         ha2 = Utils.calculateMD5(a2);
         debug('authenticate() | using qop=null [a2:"%s"]', a2); // Response = MD5(HA1:nonce:HA2).
 
         this._response = Utils.calculateMD5("".concat(this._ha1, ":").concat(this._nonce, ":").concat(ha2));
       }
 
       debug('authenticate() | response generated');
       return true;
     }
     /**
     * Return the Proxy-Authorization or WWW-Authorization header value.
     */
 
   }, {
     key: "toString",
     value: function toString() {
       var auth_params = [];
 
       if (!this._response) {
         throw new Error('response field does not exist, cannot generate Authorization header');
       }
 
       auth_params.push("algorithm=".concat(this._algorithm));
       auth_params.push("username=\"".concat(this._credentials.username, "\""));
       auth_params.push("realm=\"".concat(this._realm, "\""));
       auth_params.push("nonce=\"".concat(this._nonce, "\""));
       auth_params.push("uri=\"".concat(this._uri, "\""));
       auth_params.push("response=\"".concat(this._response, "\""));
 
       if (this._opaque) {
         auth_params.push("opaque=\"".concat(this._opaque, "\""));
       }
 
       if (this._qop) {
         auth_params.push("qop=".concat(this._qop));
         auth_params.push("cnonce=\"".concat(this._cnonce, "\""));
         auth_params.push("nc=".concat(this._ncHex));
       }
 
       return "Digest ".concat(auth_params.join(', '));
     }
   }]);
 
   return DigestAuthentication;
 }();
 },{"./Utils":26,"debug":30}],6:[function(require,module,exports){
 "use strict";
 
 function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
 
 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
 function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
 
 function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
 
 function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
 
 function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
 
 function _wrapNativeSuper(Class) { var _cache = typeof Map === "function" ? new Map() : undefined; _wrapNativeSuper = function _wrapNativeSuper(Class) { if (Class === null || !_isNativeFunction(Class)) return Class; if (typeof Class !== "function") { throw new TypeError("Super expression must either be null or a function"); } if (typeof _cache !== "undefined") { if (_cache.has(Class)) return _cache.get(Class); _cache.set(Class, Wrapper); } function Wrapper() { return _construct(Class, arguments, _getPrototypeOf(this).constructor); } Wrapper.prototype = Object.create(Class.prototype, { constructor: { value: Wrapper, enumerable: false, writable: true, configurable: true } }); return _setPrototypeOf(Wrapper, Class); }; return _wrapNativeSuper(Class); }
 
 function _construct(Parent, args, Class) { if (_isNativeReflectConstruct()) { _construct = Reflect.construct; } else { _construct = function _construct(Parent, args, Class) { var a = [null]; a.push.apply(a, args); var Constructor = Function.bind.apply(Parent, a); var instance = new Constructor(); if (Class) _setPrototypeOf(instance, Class.prototype); return instance; }; } return _construct.apply(null, arguments); }
 
 function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }
 
 function _isNativeFunction(fn) { return Function.toString.call(fn).indexOf("[native code]") !== -1; }
 
 function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
 
 function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
 
 var ConfigurationError = /*#__PURE__*/function (_Error) {
   _inherits(ConfigurationError, _Error);
 
   var _super = _createSuper(ConfigurationError);
 
   function ConfigurationError(parameter, value) {
     var _this;
 
     _classCallCheck(this, ConfigurationError);
 
     _this = _super.call(this);
     _this.code = 1;
     _this.name = 'CONFIGURATION_ERROR';
     _this.parameter = parameter;
     _this.value = value;
     _this.message = !_this.value ? "Missing parameter: ".concat(_this.parameter) : "Invalid value ".concat(JSON.stringify(_this.value), " for parameter \"").concat(_this.parameter, "\"");
     return _this;
   }
 
   return ConfigurationError;
 }( /*#__PURE__*/_wrapNativeSuper(Error));
 
 var InvalidStateError = /*#__PURE__*/function (_Error2) {
   _inherits(InvalidStateError, _Error2);
 
   var _super2 = _createSuper(InvalidStateError);
 
   function InvalidStateError(status) {
     var _this2;
 
     _classCallCheck(this, InvalidStateError);
 
     _this2 = _super2.call(this);
     _this2.code = 2;
     _this2.name = 'INVALID_STATE_ERROR';
     _this2.status = status;
     _this2.message = "Invalid status: ".concat(status);
     return _this2;
   }
 
   return InvalidStateError;
 }( /*#__PURE__*/_wrapNativeSuper(Error));
 
 var NotSupportedError = /*#__PURE__*/function (_Error3) {
   _inherits(NotSupportedError, _Error3);
 
   var _super3 = _createSuper(NotSupportedError);
 
   function NotSupportedError(message) {
     var _this3;
 
     _classCallCheck(this, NotSupportedError);
 
     _this3 = _super3.call(this);
     _this3.code = 3;
     _this3.name = 'NOT_SUPPORTED_ERROR';
     _this3.message = message;
     return _this3;
   }
 
   return NotSupportedError;
 }( /*#__PURE__*/_wrapNativeSuper(Error));
 
 var NotReadyError = /*#__PURE__*/function (_Error4) {
   _inherits(NotReadyError, _Error4);
 
   var _super4 = _createSuper(NotReadyError);
 
   function NotReadyError(message) {
     var _this4;
 
     _classCallCheck(this, NotReadyError);
 
     _this4 = _super4.call(this);
     _this4.code = 4;
     _this4.name = 'NOT_READY_ERROR';
     _this4.message = message;
     return _this4;
   }
 
   return NotReadyError;
 }( /*#__PURE__*/_wrapNativeSuper(Error));
 
 module.exports = {
   ConfigurationError: ConfigurationError,
   InvalidStateError: InvalidStateError,
   NotSupportedError: NotSupportedError,
   NotReadyError: NotReadyError
 };
 },{}],7:[function(require,module,exports){
 "use strict";
 
 module.exports = function () {
   /*
    * Generated by PEG.js 0.7.0.
    *
    * http://pegjs.majda.cz/
    */
   function quote(s) {
     /*
      * ECMA-262, 5th ed., 7.8.4: All characters may appear literally in a
      * string literal except for the closing quote character, backslash,
      * carriage return, line separator, paragraph separator, and line feed.
      * Any character may appear in the form of an escape sequence.
      *
      * For portability, we also escape escape all control and non-ASCII
      * characters. Note that "\0" and "\v" escape sequences are not used
      * because JSHint does not like the first and IE the second.
      */
     return '"' + s.replace(/\\/g, '\\\\') // backslash
     .replace(/"/g, '\\"') // closing quote character
     .replace(/\x08/g, '\\b') // backspace
     .replace(/\t/g, '\\t') // horizontal tab
     .replace(/\n/g, '\\n') // line feed
     .replace(/\f/g, '\\f') // form feed
     .replace(/\r/g, '\\r') // carriage return
     .replace(/[\x00-\x07\x0B\x0E-\x1F\x80-\uFFFF]/g, escape) + '"';
   }
 
   var result = {
     /*
      * Parses the input with a generated parser. If the parsing is successfull,
      * returns a value explicitly or implicitly specified by the grammar from
      * which the parser was generated (see |PEG.buildParser|). If the parsing is
      * unsuccessful, throws |PEG.parser.SyntaxError| describing the error.
      */
     parse: function parse(input, startRule) {
       var parseFunctions = {
         "CRLF": parse_CRLF,
         "DIGIT": parse_DIGIT,
         "ALPHA": parse_ALPHA,
         "HEXDIG": parse_HEXDIG,
         "WSP": parse_WSP,
         "OCTET": parse_OCTET,
         "DQUOTE": parse_DQUOTE,
         "SP": parse_SP,
         "HTAB": parse_HTAB,
         "alphanum": parse_alphanum,
         "reserved": parse_reserved,
         "unreserved": parse_unreserved,
         "mark": parse_mark,
         "escaped": parse_escaped,
         "LWS": parse_LWS,
         "SWS": parse_SWS,
         "HCOLON": parse_HCOLON,
         "TEXT_UTF8_TRIM": parse_TEXT_UTF8_TRIM,
         "TEXT_UTF8char": parse_TEXT_UTF8char,
         "UTF8_NONASCII": parse_UTF8_NONASCII,
         "UTF8_CONT": parse_UTF8_CONT,
         "LHEX": parse_LHEX,
         "token": parse_token,
         "token_nodot": parse_token_nodot,
         "separators": parse_separators,
         "word": parse_word,
         "STAR": parse_STAR,
         "SLASH": parse_SLASH,
         "EQUAL": parse_EQUAL,
         "LPAREN": parse_LPAREN,
         "RPAREN": parse_RPAREN,
         "RAQUOT": parse_RAQUOT,
         "LAQUOT": parse_LAQUOT,
         "COMMA": parse_COMMA,
         "SEMI": parse_SEMI,
         "COLON": parse_COLON,
         "LDQUOT": parse_LDQUOT,
         "RDQUOT": parse_RDQUOT,
         "comment": parse_comment,
         "ctext": parse_ctext,
         "quoted_string": parse_quoted_string,
         "quoted_string_clean": parse_quoted_string_clean,
         "qdtext": parse_qdtext,
         "quoted_pair": parse_quoted_pair,
         "SIP_URI_noparams": parse_SIP_URI_noparams,
         "SIP_URI": parse_SIP_URI,
         "uri_scheme": parse_uri_scheme,
         "uri_scheme_sips": parse_uri_scheme_sips,
         "uri_scheme_sip": parse_uri_scheme_sip,
         "userinfo": parse_userinfo,
         "user": parse_user,
         "user_unreserved": parse_user_unreserved,
         "password": parse_password,
         "hostport": parse_hostport,
         "host": parse_host,
         "hostname": parse_hostname,
         "domainlabel": parse_domainlabel,
         "toplabel": parse_toplabel,
         "IPv6reference": parse_IPv6reference,
         "IPv6address": parse_IPv6address,
         "h16": parse_h16,
         "ls32": parse_ls32,
         "IPv4address": parse_IPv4address,
         "dec_octet": parse_dec_octet,
         "port": parse_port,
         "uri_parameters": parse_uri_parameters,
         "uri_parameter": parse_uri_parameter,
         "transport_param": parse_transport_param,
         "user_param": parse_user_param,
         "method_param": parse_method_param,
         "ttl_param": parse_ttl_param,
         "maddr_param": parse_maddr_param,
         "lr_param": parse_lr_param,
         "other_param": parse_other_param,
         "pname": parse_pname,
         "pvalue": parse_pvalue,
         "paramchar": parse_paramchar,
         "param_unreserved": parse_param_unreserved,
         "headers": parse_headers,
         "header": parse_header,
         "hname": parse_hname,
         "hvalue": parse_hvalue,
         "hnv_unreserved": parse_hnv_unreserved,
         "Request_Response": parse_Request_Response,
         "Request_Line": parse_Request_Line,
         "Request_URI": parse_Request_URI,
         "absoluteURI": parse_absoluteURI,
         "hier_part": parse_hier_part,
         "net_path": parse_net_path,
         "abs_path": parse_abs_path,
         "opaque_part": parse_opaque_part,
         "uric": parse_uric,
         "uric_no_slash": parse_uric_no_slash,
         "path_segments": parse_path_segments,
         "segment": parse_segment,
         "param": parse_param,
         "pchar": parse_pchar,
         "scheme": parse_scheme,
         "authority": parse_authority,
         "srvr": parse_srvr,
         "reg_name": parse_reg_name,
         "query": parse_query,
         "SIP_Version": parse_SIP_Version,
         "INVITEm": parse_INVITEm,
         "ACKm": parse_ACKm,
         "OPTIONSm": parse_OPTIONSm,
         "BYEm": parse_BYEm,
         "CANCELm": parse_CANCELm,
         "REGISTERm": parse_REGISTERm,
         "SUBSCRIBEm": parse_SUBSCRIBEm,
         "NOTIFYm": parse_NOTIFYm,
         "REFERm": parse_REFERm,
         "Method": parse_Method,
         "Status_Line": parse_Status_Line,
         "Status_Code": parse_Status_Code,
         "extension_code": parse_extension_code,
         "Reason_Phrase": parse_Reason_Phrase,
         "Allow_Events": parse_Allow_Events,
         "Call_ID": parse_Call_ID,
         "Contact": parse_Contact,
         "contact_param": parse_contact_param,
         "name_addr": parse_name_addr,
         "display_name": parse_display_name,
         "contact_params": parse_contact_params,
         "c_p_q": parse_c_p_q,
         "c_p_expires": parse_c_p_expires,
         "delta_seconds": parse_delta_seconds,
         "qvalue": parse_qvalue,
         "generic_param": parse_generic_param,
         "gen_value": parse_gen_value,
         "Content_Disposition": parse_Content_Disposition,
         "disp_type": parse_disp_type,
         "disp_param": parse_disp_param,
         "handling_param": parse_handling_param,
         "Content_Encoding": parse_Content_Encoding,
         "Content_Length": parse_Content_Length,
         "Content_Type": parse_Content_Type,
         "media_type": parse_media_type,
         "m_type": parse_m_type,
         "discrete_type": parse_discrete_type,
         "composite_type": parse_composite_type,
         "extension_token": parse_extension_token,
         "x_token": parse_x_token,
         "m_subtype": parse_m_subtype,
         "m_parameter": parse_m_parameter,
         "m_value": parse_m_value,
         "CSeq": parse_CSeq,
         "CSeq_value": parse_CSeq_value,
         "Expires": parse_Expires,
         "Event": parse_Event,
         "event_type": parse_event_type,
         "From": parse_From,
         "from_param": parse_from_param,
         "tag_param": parse_tag_param,
         "Max_Forwards": parse_Max_Forwards,
         "Min_Expires": parse_Min_Expires,
         "Name_Addr_Header": parse_Name_Addr_Header,
         "Proxy_Authenticate": parse_Proxy_Authenticate,
         "challenge": parse_challenge,
         "other_challenge": parse_other_challenge,
         "auth_param": parse_auth_param,
         "digest_cln": parse_digest_cln,
         "realm": parse_realm,
         "realm_value": parse_realm_value,
         "domain": parse_domain,
         "URI": parse_URI,
         "nonce": parse_nonce,
         "nonce_value": parse_nonce_value,
         "opaque": parse_opaque,
         "stale": parse_stale,
         "algorithm": parse_algorithm,
         "qop_options": parse_qop_options,
         "qop_value": parse_qop_value,
         "Proxy_Require": parse_Proxy_Require,
         "Record_Route": parse_Record_Route,
         "rec_route": parse_rec_route,
         "Reason": parse_Reason,
         "reason_param": parse_reason_param,
         "reason_cause": parse_reason_cause,
         "Require": parse_Require,
         "Route": parse_Route,
         "route_param": parse_route_param,
         "Subscription_State": parse_Subscription_State,
         "substate_value": parse_substate_value,
         "subexp_params": parse_subexp_params,
         "event_reason_value": parse_event_reason_value,
         "Subject": parse_Subject,
         "Supported": parse_Supported,
         "To": parse_To,
         "to_param": parse_to_param,
         "Via": parse_Via,
         "via_param": parse_via_param,
         "via_params": parse_via_params,
         "via_ttl": parse_via_ttl,
         "via_maddr": parse_via_maddr,
         "via_received": parse_via_received,
         "via_branch": parse_via_branch,
         "response_port": parse_response_port,
         "rport": parse_rport,
         "sent_protocol": parse_sent_protocol,
         "protocol_name": parse_protocol_name,
         "transport": parse_transport,
         "sent_by": parse_sent_by,
         "via_host": parse_via_host,
         "via_port": parse_via_port,
         "ttl": parse_ttl,
         "WWW_Authenticate": parse_WWW_Authenticate,
         "Session_Expires": parse_Session_Expires,
         "s_e_expires": parse_s_e_expires,
         "s_e_params": parse_s_e_params,
         "s_e_refresher": parse_s_e_refresher,
         "extension_header": parse_extension_header,
         "header_value": parse_header_value,
         "message_body": parse_message_body,
         "uuid_URI": parse_uuid_URI,
         "uuid": parse_uuid,
         "hex4": parse_hex4,
         "hex8": parse_hex8,
         "hex12": parse_hex12,
         "Refer_To": parse_Refer_To,
         "Replaces": parse_Replaces,
         "call_id": parse_call_id,
         "replaces_param": parse_replaces_param,
         "to_tag": parse_to_tag,
         "from_tag": parse_from_tag,
         "early_flag": parse_early_flag
       };
 
       if (startRule !== undefined) {
         if (parseFunctions[startRule] === undefined) {
           throw new Error("Invalid rule name: " + quote(startRule) + ".");
         }
       } else {
         startRule = "CRLF";
       }
 
       var pos = 0;
       var reportFailures = 0;
       var rightmostFailuresPos = 0;
       var rightmostFailuresExpected = [];
 
       function padLeft(input, padding, length) {
         var result = input;
         var padLength = length - input.length;
 
         for (var i = 0; i < padLength; i++) {
           result = padding + result;
         }
 
         return result;
       }
 
       function escape(ch) {
         var charCode = ch.charCodeAt(0);
         var escapeChar;
         var length;
 
         if (charCode <= 0xFF) {
           escapeChar = 'x';
           length = 2;
         } else {
           escapeChar = 'u';
           length = 4;
         }
 
         return '\\' + escapeChar + padLeft(charCode.toString(16).toUpperCase(), '0', length);
       }
 
       function matchFailed(failure) {
         if (pos < rightmostFailuresPos) {
           return;
         }
 
         if (pos > rightmostFailuresPos) {
           rightmostFailuresPos = pos;
           rightmostFailuresExpected = [];
         }
 
         rightmostFailuresExpected.push(failure);
       }
 
       function parse_CRLF() {
         var result0;
 
         if (input.substr(pos, 2) === "\r\n") {
           result0 = "\r\n";
           pos += 2;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"\\r\\n\"");
           }
         }
 
         return result0;
       }
 
       function parse_DIGIT() {
         var result0;
 
         if (/^[0-9]/.test(input.charAt(pos))) {
           result0 = input.charAt(pos);
           pos++;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("[0-9]");
           }
         }
 
         return result0;
       }
 
       function parse_ALPHA() {
         var result0;
 
         if (/^[a-zA-Z]/.test(input.charAt(pos))) {
           result0 = input.charAt(pos);
           pos++;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("[a-zA-Z]");
           }
         }
 
         return result0;
       }
 
       function parse_HEXDIG() {
         var result0;
 
         if (/^[0-9a-fA-F]/.test(input.charAt(pos))) {
           result0 = input.charAt(pos);
           pos++;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("[0-9a-fA-F]");
           }
         }
 
         return result0;
       }
 
       function parse_WSP() {
         var result0;
         result0 = parse_SP();
 
         if (result0 === null) {
           result0 = parse_HTAB();
         }
 
         return result0;
       }
 
       function parse_OCTET() {
         var result0;
 
         if (/^[\0-\xFF]/.test(input.charAt(pos))) {
           result0 = input.charAt(pos);
           pos++;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("[\\0-\\xFF]");
           }
         }
 
         return result0;
       }
 
       function parse_DQUOTE() {
         var result0;
 
         if (/^["]/.test(input.charAt(pos))) {
           result0 = input.charAt(pos);
           pos++;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("[\"]");
           }
         }
 
         return result0;
       }
 
       function parse_SP() {
         var result0;
 
         if (input.charCodeAt(pos) === 32) {
           result0 = " ";
           pos++;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\" \"");
           }
         }
 
         return result0;
       }
 
       function parse_HTAB() {
         var result0;
 
         if (input.charCodeAt(pos) === 9) {
           result0 = "\t";
           pos++;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"\\t\"");
           }
         }
 
         return result0;
       }
 
       function parse_alphanum() {
         var result0;
 
         if (/^[a-zA-Z0-9]/.test(input.charAt(pos))) {
           result0 = input.charAt(pos);
           pos++;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("[a-zA-Z0-9]");
           }
         }
 
         return result0;
       }
 
       function parse_reserved() {
         var result0;
 
         if (input.charCodeAt(pos) === 59) {
           result0 = ";";
           pos++;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\";\"");
           }
         }
 
         if (result0 === null) {
           if (input.charCodeAt(pos) === 47) {
             result0 = "/";
             pos++;
           } else {
             result0 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"/\"");
             }
           }
 
           if (result0 === null) {
             if (input.charCodeAt(pos) === 63) {
               result0 = "?";
               pos++;
             } else {
               result0 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\"?\"");
               }
             }
 
             if (result0 === null) {
               if (input.charCodeAt(pos) === 58) {
                 result0 = ":";
                 pos++;
               } else {
                 result0 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\":\"");
                 }
               }
 
               if (result0 === null) {
                 if (input.charCodeAt(pos) === 64) {
                   result0 = "@";
                   pos++;
                 } else {
                   result0 = null;
 
                   if (reportFailures === 0) {
                     matchFailed("\"@\"");
                   }
                 }
 
                 if (result0 === null) {
                   if (input.charCodeAt(pos) === 38) {
                     result0 = "&";
                     pos++;
                   } else {
                     result0 = null;
 
                     if (reportFailures === 0) {
                       matchFailed("\"&\"");
                     }
                   }
 
                   if (result0 === null) {
                     if (input.charCodeAt(pos) === 61) {
                       result0 = "=";
                       pos++;
                     } else {
                       result0 = null;
 
                       if (reportFailures === 0) {
                         matchFailed("\"=\"");
                       }
                     }
 
                     if (result0 === null) {
                       if (input.charCodeAt(pos) === 43) {
                         result0 = "+";
                         pos++;
                       } else {
                         result0 = null;
 
                         if (reportFailures === 0) {
                           matchFailed("\"+\"");
                         }
                       }
 
                       if (result0 === null) {
                         if (input.charCodeAt(pos) === 36) {
                           result0 = "$";
                           pos++;
                         } else {
                           result0 = null;
 
                           if (reportFailures === 0) {
                             matchFailed("\"$\"");
                           }
                         }
 
                         if (result0 === null) {
                           if (input.charCodeAt(pos) === 44) {
                             result0 = ",";
                             pos++;
                           } else {
                             result0 = null;
 
                             if (reportFailures === 0) {
                               matchFailed("\",\"");
                             }
                           }
                         }
                       }
                     }
                   }
                 }
               }
             }
           }
         }
 
         return result0;
       }
 
       function parse_unreserved() {
         var result0;
         result0 = parse_alphanum();
 
         if (result0 === null) {
           result0 = parse_mark();
         }
 
         return result0;
       }
 
       function parse_mark() {
         var result0;
 
         if (input.charCodeAt(pos) === 45) {
           result0 = "-";
           pos++;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"-\"");
           }
         }
 
         if (result0 === null) {
           if (input.charCodeAt(pos) === 95) {
             result0 = "_";
             pos++;
           } else {
             result0 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"_\"");
             }
           }
 
           if (result0 === null) {
             if (input.charCodeAt(pos) === 46) {
               result0 = ".";
               pos++;
             } else {
               result0 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\".\"");
               }
             }
 
             if (result0 === null) {
               if (input.charCodeAt(pos) === 33) {
                 result0 = "!";
                 pos++;
               } else {
                 result0 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\"!\"");
                 }
               }
 
               if (result0 === null) {
                 if (input.charCodeAt(pos) === 126) {
                   result0 = "~";
                   pos++;
                 } else {
                   result0 = null;
 
                   if (reportFailures === 0) {
                     matchFailed("\"~\"");
                   }
                 }
 
                 if (result0 === null) {
                   if (input.charCodeAt(pos) === 42) {
                     result0 = "*";
                     pos++;
                   } else {
                     result0 = null;
 
                     if (reportFailures === 0) {
                       matchFailed("\"*\"");
                     }
                   }
 
                   if (result0 === null) {
                     if (input.charCodeAt(pos) === 39) {
                       result0 = "'";
                       pos++;
                     } else {
                       result0 = null;
 
                       if (reportFailures === 0) {
                         matchFailed("\"'\"");
                       }
                     }
 
                     if (result0 === null) {
                       if (input.charCodeAt(pos) === 40) {
                         result0 = "(";
                         pos++;
                       } else {
                         result0 = null;
 
                         if (reportFailures === 0) {
                           matchFailed("\"(\"");
                         }
                       }
 
                       if (result0 === null) {
                         if (input.charCodeAt(pos) === 41) {
                           result0 = ")";
                           pos++;
                         } else {
                           result0 = null;
 
                           if (reportFailures === 0) {
                             matchFailed("\")\"");
                           }
                         }
                       }
                     }
                   }
                 }
               }
             }
           }
         }
 
         return result0;
       }
 
       function parse_escaped() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
 
         if (input.charCodeAt(pos) === 37) {
           result0 = "%";
           pos++;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"%\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_HEXDIG();
 
           if (result1 !== null) {
             result2 = parse_HEXDIG();
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset, escaped) {
             return escaped.join('');
           }(pos0, result0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_LWS() {
         var result0, result1, result2;
         var pos0, pos1, pos2;
         pos0 = pos;
         pos1 = pos;
         pos2 = pos;
         result0 = [];
         result1 = parse_WSP();
 
         while (result1 !== null) {
           result0.push(result1);
           result1 = parse_WSP();
         }
 
         if (result0 !== null) {
           result1 = parse_CRLF();
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos2;
           }
         } else {
           result0 = null;
           pos = pos2;
         }
 
         result0 = result0 !== null ? result0 : "";
 
         if (result0 !== null) {
           result2 = parse_WSP();
 
           if (result2 !== null) {
             result1 = [];
 
             while (result2 !== null) {
               result1.push(result2);
               result2 = parse_WSP();
             }
           } else {
             result1 = null;
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             return " ";
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_SWS() {
         var result0;
         result0 = parse_LWS();
         result0 = result0 !== null ? result0 : "";
         return result0;
       }
 
       function parse_HCOLON() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
         result0 = [];
         result1 = parse_SP();
 
         if (result1 === null) {
           result1 = parse_HTAB();
         }
 
         while (result1 !== null) {
           result0.push(result1);
           result1 = parse_SP();
 
           if (result1 === null) {
             result1 = parse_HTAB();
           }
         }
 
         if (result0 !== null) {
           if (input.charCodeAt(pos) === 58) {
             result1 = ":";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\":\"");
             }
           }
 
           if (result1 !== null) {
             result2 = parse_SWS();
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             return ':';
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_TEXT_UTF8_TRIM() {
         var result0, result1, result2, result3;
         var pos0, pos1, pos2;
         pos0 = pos;
         pos1 = pos;
         result1 = parse_TEXT_UTF8char();
 
         if (result1 !== null) {
           result0 = [];
 
           while (result1 !== null) {
             result0.push(result1);
             result1 = parse_TEXT_UTF8char();
           }
         } else {
           result0 = null;
         }
 
         if (result0 !== null) {
           result1 = [];
           pos2 = pos;
           result2 = [];
           result3 = parse_LWS();
 
           while (result3 !== null) {
             result2.push(result3);
             result3 = parse_LWS();
           }
 
           if (result2 !== null) {
             result3 = parse_TEXT_UTF8char();
 
             if (result3 !== null) {
               result2 = [result2, result3];
             } else {
               result2 = null;
               pos = pos2;
             }
           } else {
             result2 = null;
             pos = pos2;
           }
 
           while (result2 !== null) {
             result1.push(result2);
             pos2 = pos;
             result2 = [];
             result3 = parse_LWS();
 
             while (result3 !== null) {
               result2.push(result3);
               result3 = parse_LWS();
             }
 
             if (result2 !== null) {
               result3 = parse_TEXT_UTF8char();
 
               if (result3 !== null) {
                 result2 = [result2, result3];
               } else {
                 result2 = null;
                 pos = pos2;
               }
             } else {
               result2 = null;
               pos = pos2;
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             return input.substring(pos, offset);
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_TEXT_UTF8char() {
         var result0;
 
         if (/^[!-~]/.test(input.charAt(pos))) {
           result0 = input.charAt(pos);
           pos++;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("[!-~]");
           }
         }
 
         if (result0 === null) {
           result0 = parse_UTF8_NONASCII();
         }
 
         return result0;
       }
 
       function parse_UTF8_NONASCII() {
         var result0;
 
         if (/^[\x80-\uFFFF]/.test(input.charAt(pos))) {
           result0 = input.charAt(pos);
           pos++;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("[\\x80-\\uFFFF]");
           }
         }
 
         return result0;
       }
 
       function parse_UTF8_CONT() {
         var result0;
 
         if (/^[\x80-\xBF]/.test(input.charAt(pos))) {
           result0 = input.charAt(pos);
           pos++;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("[\\x80-\\xBF]");
           }
         }
 
         return result0;
       }
 
       function parse_LHEX() {
         var result0;
         result0 = parse_DIGIT();
 
         if (result0 === null) {
           if (/^[a-f]/.test(input.charAt(pos))) {
             result0 = input.charAt(pos);
             pos++;
           } else {
             result0 = null;
 
             if (reportFailures === 0) {
               matchFailed("[a-f]");
             }
           }
         }
 
         return result0;
       }
 
       function parse_token() {
         var result0, result1;
         var pos0;
         pos0 = pos;
         result1 = parse_alphanum();
 
         if (result1 === null) {
           if (input.charCodeAt(pos) === 45) {
             result1 = "-";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"-\"");
             }
           }
 
           if (result1 === null) {
             if (input.charCodeAt(pos) === 46) {
               result1 = ".";
               pos++;
             } else {
               result1 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\".\"");
               }
             }
 
             if (result1 === null) {
               if (input.charCodeAt(pos) === 33) {
                 result1 = "!";
                 pos++;
               } else {
                 result1 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\"!\"");
                 }
               }
 
               if (result1 === null) {
                 if (input.charCodeAt(pos) === 37) {
                   result1 = "%";
                   pos++;
                 } else {
                   result1 = null;
 
                   if (reportFailures === 0) {
                     matchFailed("\"%\"");
                   }
                 }
 
                 if (result1 === null) {
                   if (input.charCodeAt(pos) === 42) {
                     result1 = "*";
                     pos++;
                   } else {
                     result1 = null;
 
                     if (reportFailures === 0) {
                       matchFailed("\"*\"");
                     }
                   }
 
                   if (result1 === null) {
                     if (input.charCodeAt(pos) === 95) {
                       result1 = "_";
                       pos++;
                     } else {
                       result1 = null;
 
                       if (reportFailures === 0) {
                         matchFailed("\"_\"");
                       }
                     }
 
                     if (result1 === null) {
                       if (input.charCodeAt(pos) === 43) {
                         result1 = "+";
                         pos++;
                       } else {
                         result1 = null;
 
                         if (reportFailures === 0) {
                           matchFailed("\"+\"");
                         }
                       }
 
                       if (result1 === null) {
                         if (input.charCodeAt(pos) === 96) {
                           result1 = "`";
                           pos++;
                         } else {
                           result1 = null;
 
                           if (reportFailures === 0) {
                             matchFailed("\"`\"");
                           }
                         }
 
                         if (result1 === null) {
                           if (input.charCodeAt(pos) === 39) {
                             result1 = "'";
                             pos++;
                           } else {
                             result1 = null;
 
                             if (reportFailures === 0) {
                               matchFailed("\"'\"");
                             }
                           }
 
                           if (result1 === null) {
                             if (input.charCodeAt(pos) === 126) {
                               result1 = "~";
                               pos++;
                             } else {
                               result1 = null;
 
                               if (reportFailures === 0) {
                                 matchFailed("\"~\"");
                               }
                             }
                           }
                         }
                       }
                     }
                   }
                 }
               }
             }
           }
         }
 
         if (result1 !== null) {
           result0 = [];
 
           while (result1 !== null) {
             result0.push(result1);
             result1 = parse_alphanum();
 
             if (result1 === null) {
               if (input.charCodeAt(pos) === 45) {
                 result1 = "-";
                 pos++;
               } else {
                 result1 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\"-\"");
                 }
               }
 
               if (result1 === null) {
                 if (input.charCodeAt(pos) === 46) {
                   result1 = ".";
                   pos++;
                 } else {
                   result1 = null;
 
                   if (reportFailures === 0) {
                     matchFailed("\".\"");
                   }
                 }
 
                 if (result1 === null) {
                   if (input.charCodeAt(pos) === 33) {
                     result1 = "!";
                     pos++;
                   } else {
                     result1 = null;
 
                     if (reportFailures === 0) {
                       matchFailed("\"!\"");
                     }
                   }
 
                   if (result1 === null) {
                     if (input.charCodeAt(pos) === 37) {
                       result1 = "%";
                       pos++;
                     } else {
                       result1 = null;
 
                       if (reportFailures === 0) {
                         matchFailed("\"%\"");
                       }
                     }
 
                     if (result1 === null) {
                       if (input.charCodeAt(pos) === 42) {
                         result1 = "*";
                         pos++;
                       } else {
                         result1 = null;
 
                         if (reportFailures === 0) {
                           matchFailed("\"*\"");
                         }
                       }
 
                       if (result1 === null) {
                         if (input.charCodeAt(pos) === 95) {
                           result1 = "_";
                           pos++;
                         } else {
                           result1 = null;
 
                           if (reportFailures === 0) {
                             matchFailed("\"_\"");
                           }
                         }
 
                         if (result1 === null) {
                           if (input.charCodeAt(pos) === 43) {
                             result1 = "+";
                             pos++;
                           } else {
                             result1 = null;
 
                             if (reportFailures === 0) {
                               matchFailed("\"+\"");
                             }
                           }
 
                           if (result1 === null) {
                             if (input.charCodeAt(pos) === 96) {
                               result1 = "`";
                               pos++;
                             } else {
                               result1 = null;
 
                               if (reportFailures === 0) {
                                 matchFailed("\"`\"");
                               }
                             }
 
                             if (result1 === null) {
                               if (input.charCodeAt(pos) === 39) {
                                 result1 = "'";
                                 pos++;
                               } else {
                                 result1 = null;
 
                                 if (reportFailures === 0) {
                                   matchFailed("\"'\"");
                                 }
                               }
 
                               if (result1 === null) {
                                 if (input.charCodeAt(pos) === 126) {
                                   result1 = "~";
                                   pos++;
                                 } else {
                                   result1 = null;
 
                                   if (reportFailures === 0) {
                                     matchFailed("\"~\"");
                                   }
                                 }
                               }
                             }
                           }
                         }
                       }
                     }
                   }
                 }
               }
             }
           }
         } else {
           result0 = null;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             return input.substring(pos, offset);
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_token_nodot() {
         var result0, result1;
         var pos0;
         pos0 = pos;
         result1 = parse_alphanum();
 
         if (result1 === null) {
           if (input.charCodeAt(pos) === 45) {
             result1 = "-";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"-\"");
             }
           }
 
           if (result1 === null) {
             if (input.charCodeAt(pos) === 33) {
               result1 = "!";
               pos++;
             } else {
               result1 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\"!\"");
               }
             }
 
             if (result1 === null) {
               if (input.charCodeAt(pos) === 37) {
                 result1 = "%";
                 pos++;
               } else {
                 result1 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\"%\"");
                 }
               }
 
               if (result1 === null) {
                 if (input.charCodeAt(pos) === 42) {
                   result1 = "*";
                   pos++;
                 } else {
                   result1 = null;
 
                   if (reportFailures === 0) {
                     matchFailed("\"*\"");
                   }
                 }
 
                 if (result1 === null) {
                   if (input.charCodeAt(pos) === 95) {
                     result1 = "_";
                     pos++;
                   } else {
                     result1 = null;
 
                     if (reportFailures === 0) {
                       matchFailed("\"_\"");
                     }
                   }
 
                   if (result1 === null) {
                     if (input.charCodeAt(pos) === 43) {
                       result1 = "+";
                       pos++;
                     } else {
                       result1 = null;
 
                       if (reportFailures === 0) {
                         matchFailed("\"+\"");
                       }
                     }
 
                     if (result1 === null) {
                       if (input.charCodeAt(pos) === 96) {
                         result1 = "`";
                         pos++;
                       } else {
                         result1 = null;
 
                         if (reportFailures === 0) {
                           matchFailed("\"`\"");
                         }
                       }
 
                       if (result1 === null) {
                         if (input.charCodeAt(pos) === 39) {
                           result1 = "'";
                           pos++;
                         } else {
                           result1 = null;
 
                           if (reportFailures === 0) {
                             matchFailed("\"'\"");
                           }
                         }
 
                         if (result1 === null) {
                           if (input.charCodeAt(pos) === 126) {
                             result1 = "~";
                             pos++;
                           } else {
                             result1 = null;
 
                             if (reportFailures === 0) {
                               matchFailed("\"~\"");
                             }
                           }
                         }
                       }
                     }
                   }
                 }
               }
             }
           }
         }
 
         if (result1 !== null) {
           result0 = [];
 
           while (result1 !== null) {
             result0.push(result1);
             result1 = parse_alphanum();
 
             if (result1 === null) {
               if (input.charCodeAt(pos) === 45) {
                 result1 = "-";
                 pos++;
               } else {
                 result1 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\"-\"");
                 }
               }
 
               if (result1 === null) {
                 if (input.charCodeAt(pos) === 33) {
                   result1 = "!";
                   pos++;
                 } else {
                   result1 = null;
 
                   if (reportFailures === 0) {
                     matchFailed("\"!\"");
                   }
                 }
 
                 if (result1 === null) {
                   if (input.charCodeAt(pos) === 37) {
                     result1 = "%";
                     pos++;
                   } else {
                     result1 = null;
 
                     if (reportFailures === 0) {
                       matchFailed("\"%\"");
                     }
                   }
 
                   if (result1 === null) {
                     if (input.charCodeAt(pos) === 42) {
                       result1 = "*";
                       pos++;
                     } else {
                       result1 = null;
 
                       if (reportFailures === 0) {
                         matchFailed("\"*\"");
                       }
                     }
 
                     if (result1 === null) {
                       if (input.charCodeAt(pos) === 95) {
                         result1 = "_";
                         pos++;
                       } else {
                         result1 = null;
 
                         if (reportFailures === 0) {
                           matchFailed("\"_\"");
                         }
                       }
 
                       if (result1 === null) {
                         if (input.charCodeAt(pos) === 43) {
                           result1 = "+";
                           pos++;
                         } else {
                           result1 = null;
 
                           if (reportFailures === 0) {
                             matchFailed("\"+\"");
                           }
                         }
 
                         if (result1 === null) {
                           if (input.charCodeAt(pos) === 96) {
                             result1 = "`";
                             pos++;
                           } else {
                             result1 = null;
 
                             if (reportFailures === 0) {
                               matchFailed("\"`\"");
                             }
                           }
 
                           if (result1 === null) {
                             if (input.charCodeAt(pos) === 39) {
                               result1 = "'";
                               pos++;
                             } else {
                               result1 = null;
 
                               if (reportFailures === 0) {
                                 matchFailed("\"'\"");
                               }
                             }
 
                             if (result1 === null) {
                               if (input.charCodeAt(pos) === 126) {
                                 result1 = "~";
                                 pos++;
                               } else {
                                 result1 = null;
 
                                 if (reportFailures === 0) {
                                   matchFailed("\"~\"");
                                 }
                               }
                             }
                           }
                         }
                       }
                     }
                   }
                 }
               }
             }
           }
         } else {
           result0 = null;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             return input.substring(pos, offset);
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_separators() {
         var result0;
 
         if (input.charCodeAt(pos) === 40) {
           result0 = "(";
           pos++;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"(\"");
           }
         }
 
         if (result0 === null) {
           if (input.charCodeAt(pos) === 41) {
             result0 = ")";
             pos++;
           } else {
             result0 = null;
 
             if (reportFailures === 0) {
               matchFailed("\")\"");
             }
           }
 
           if (result0 === null) {
             if (input.charCodeAt(pos) === 60) {
               result0 = "<";
               pos++;
             } else {
               result0 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\"<\"");
               }
             }
 
             if (result0 === null) {
               if (input.charCodeAt(pos) === 62) {
                 result0 = ">";
                 pos++;
               } else {
                 result0 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\">\"");
                 }
               }
 
               if (result0 === null) {
                 if (input.charCodeAt(pos) === 64) {
                   result0 = "@";
                   pos++;
                 } else {
                   result0 = null;
 
                   if (reportFailures === 0) {
                     matchFailed("\"@\"");
                   }
                 }
 
                 if (result0 === null) {
                   if (input.charCodeAt(pos) === 44) {
                     result0 = ",";
                     pos++;
                   } else {
                     result0 = null;
 
                     if (reportFailures === 0) {
                       matchFailed("\",\"");
                     }
                   }
 
                   if (result0 === null) {
                     if (input.charCodeAt(pos) === 59) {
                       result0 = ";";
                       pos++;
                     } else {
                       result0 = null;
 
                       if (reportFailures === 0) {
                         matchFailed("\";\"");
                       }
                     }
 
                     if (result0 === null) {
                       if (input.charCodeAt(pos) === 58) {
                         result0 = ":";
                         pos++;
                       } else {
                         result0 = null;
 
                         if (reportFailures === 0) {
                           matchFailed("\":\"");
                         }
                       }
 
                       if (result0 === null) {
                         if (input.charCodeAt(pos) === 92) {
                           result0 = "\\";
                           pos++;
                         } else {
                           result0 = null;
 
                           if (reportFailures === 0) {
                             matchFailed("\"\\\\\"");
                           }
                         }
 
                         if (result0 === null) {
                           result0 = parse_DQUOTE();
 
                           if (result0 === null) {
                             if (input.charCodeAt(pos) === 47) {
                               result0 = "/";
                               pos++;
                             } else {
                               result0 = null;
 
                               if (reportFailures === 0) {
                                 matchFailed("\"/\"");
                               }
                             }
 
                             if (result0 === null) {
                               if (input.charCodeAt(pos) === 91) {
                                 result0 = "[";
                                 pos++;
                               } else {
                                 result0 = null;
 
                                 if (reportFailures === 0) {
                                   matchFailed("\"[\"");
                                 }
                               }
 
                               if (result0 === null) {
                                 if (input.charCodeAt(pos) === 93) {
                                   result0 = "]";
                                   pos++;
                                 } else {
                                   result0 = null;
 
                                   if (reportFailures === 0) {
                                     matchFailed("\"]\"");
                                   }
                                 }
 
                                 if (result0 === null) {
                                   if (input.charCodeAt(pos) === 63) {
                                     result0 = "?";
                                     pos++;
                                   } else {
                                     result0 = null;
 
                                     if (reportFailures === 0) {
                                       matchFailed("\"?\"");
                                     }
                                   }
 
                                   if (result0 === null) {
                                     if (input.charCodeAt(pos) === 61) {
                                       result0 = "=";
                                       pos++;
                                     } else {
                                       result0 = null;
 
                                       if (reportFailures === 0) {
                                         matchFailed("\"=\"");
                                       }
                                     }
 
                                     if (result0 === null) {
                                       if (input.charCodeAt(pos) === 123) {
                                         result0 = "{";
                                         pos++;
                                       } else {
                                         result0 = null;
 
                                         if (reportFailures === 0) {
                                           matchFailed("\"{\"");
                                         }
                                       }
 
                                       if (result0 === null) {
                                         if (input.charCodeAt(pos) === 125) {
                                           result0 = "}";
                                           pos++;
                                         } else {
                                           result0 = null;
 
                                           if (reportFailures === 0) {
                                             matchFailed("\"}\"");
                                           }
                                         }
 
                                         if (result0 === null) {
                                           result0 = parse_SP();
 
                                           if (result0 === null) {
                                             result0 = parse_HTAB();
                                           }
                                         }
                                       }
                                     }
                                   }
                                 }
                               }
                             }
                           }
                         }
                       }
                     }
                   }
                 }
               }
             }
           }
         }
 
         return result0;
       }
 
       function parse_word() {
         var result0, result1;
         var pos0;
         pos0 = pos;
         result1 = parse_alphanum();
 
         if (result1 === null) {
           if (input.charCodeAt(pos) === 45) {
             result1 = "-";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"-\"");
             }
           }
 
           if (result1 === null) {
             if (input.charCodeAt(pos) === 46) {
               result1 = ".";
               pos++;
             } else {
               result1 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\".\"");
               }
             }
 
             if (result1 === null) {
               if (input.charCodeAt(pos) === 33) {
                 result1 = "!";
                 pos++;
               } else {
                 result1 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\"!\"");
                 }
               }
 
               if (result1 === null) {
                 if (input.charCodeAt(pos) === 37) {
                   result1 = "%";
                   pos++;
                 } else {
                   result1 = null;
 
                   if (reportFailures === 0) {
                     matchFailed("\"%\"");
                   }
                 }
 
                 if (result1 === null) {
                   if (input.charCodeAt(pos) === 42) {
                     result1 = "*";
                     pos++;
                   } else {
                     result1 = null;
 
                     if (reportFailures === 0) {
                       matchFailed("\"*\"");
                     }
                   }
 
                   if (result1 === null) {
                     if (input.charCodeAt(pos) === 95) {
                       result1 = "_";
                       pos++;
                     } else {
                       result1 = null;
 
                       if (reportFailures === 0) {
                         matchFailed("\"_\"");
                       }
                     }
 
                     if (result1 === null) {
                       if (input.charCodeAt(pos) === 43) {
                         result1 = "+";
                         pos++;
                       } else {
                         result1 = null;
 
                         if (reportFailures === 0) {
                           matchFailed("\"+\"");
                         }
                       }
 
                       if (result1 === null) {
                         if (input.charCodeAt(pos) === 96) {
                           result1 = "`";
                           pos++;
                         } else {
                           result1 = null;
 
                           if (reportFailures === 0) {
                             matchFailed("\"`\"");
                           }
                         }
 
                         if (result1 === null) {
                           if (input.charCodeAt(pos) === 39) {
                             result1 = "'";
                             pos++;
                           } else {
                             result1 = null;
 
                             if (reportFailures === 0) {
                               matchFailed("\"'\"");
                             }
                           }
 
                           if (result1 === null) {
                             if (input.charCodeAt(pos) === 126) {
                               result1 = "~";
                               pos++;
                             } else {
                               result1 = null;
 
                               if (reportFailures === 0) {
                                 matchFailed("\"~\"");
                               }
                             }
 
                             if (result1 === null) {
                               if (input.charCodeAt(pos) === 40) {
                                 result1 = "(";
                                 pos++;
                               } else {
                                 result1 = null;
 
                                 if (reportFailures === 0) {
                                   matchFailed("\"(\"");
                                 }
                               }
 
                               if (result1 === null) {
                                 if (input.charCodeAt(pos) === 41) {
                                   result1 = ")";
                                   pos++;
                                 } else {
                                   result1 = null;
 
                                   if (reportFailures === 0) {
                                     matchFailed("\")\"");
                                   }
                                 }
 
                                 if (result1 === null) {
                                   if (input.charCodeAt(pos) === 60) {
                                     result1 = "<";
                                     pos++;
                                   } else {
                                     result1 = null;
 
                                     if (reportFailures === 0) {
                                       matchFailed("\"<\"");
                                     }
                                   }
 
                                   if (result1 === null) {
                                     if (input.charCodeAt(pos) === 62) {
                                       result1 = ">";
                                       pos++;
                                     } else {
                                       result1 = null;
 
                                       if (reportFailures === 0) {
                                         matchFailed("\">\"");
                                       }
                                     }
 
                                     if (result1 === null) {
                                       if (input.charCodeAt(pos) === 58) {
                                         result1 = ":";
                                         pos++;
                                       } else {
                                         result1 = null;
 
                                         if (reportFailures === 0) {
                                           matchFailed("\":\"");
                                         }
                                       }
 
                                       if (result1 === null) {
                                         if (input.charCodeAt(pos) === 92) {
                                           result1 = "\\";
                                           pos++;
                                         } else {
                                           result1 = null;
 
                                           if (reportFailures === 0) {
                                             matchFailed("\"\\\\\"");
                                           }
                                         }
 
                                         if (result1 === null) {
                                           result1 = parse_DQUOTE();
 
                                           if (result1 === null) {
                                             if (input.charCodeAt(pos) === 47) {
                                               result1 = "/";
                                               pos++;
                                             } else {
                                               result1 = null;
 
                                               if (reportFailures === 0) {
                                                 matchFailed("\"/\"");
                                               }
                                             }
 
                                             if (result1 === null) {
                                               if (input.charCodeAt(pos) === 91) {
                                                 result1 = "[";
                                                 pos++;
                                               } else {
                                                 result1 = null;
 
                                                 if (reportFailures === 0) {
                                                   matchFailed("\"[\"");
                                                 }
                                               }
 
                                               if (result1 === null) {
                                                 if (input.charCodeAt(pos) === 93) {
                                                   result1 = "]";
                                                   pos++;
                                                 } else {
                                                   result1 = null;
 
                                                   if (reportFailures === 0) {
                                                     matchFailed("\"]\"");
                                                   }
                                                 }
 
                                                 if (result1 === null) {
                                                   if (input.charCodeAt(pos) === 63) {
                                                     result1 = "?";
                                                     pos++;
                                                   } else {
                                                     result1 = null;
 
                                                     if (reportFailures === 0) {
                                                       matchFailed("\"?\"");
                                                     }
                                                   }
 
                                                   if (result1 === null) {
                                                     if (input.charCodeAt(pos) === 123) {
                                                       result1 = "{";
                                                       pos++;
                                                     } else {
                                                       result1 = null;
 
                                                       if (reportFailures === 0) {
                                                         matchFailed("\"{\"");
                                                       }
                                                     }
 
                                                     if (result1 === null) {
                                                       if (input.charCodeAt(pos) === 125) {
                                                         result1 = "}";
                                                         pos++;
                                                       } else {
                                                         result1 = null;
 
                                                         if (reportFailures === 0) {
                                                           matchFailed("\"}\"");
                                                         }
                                                       }
                                                     }
                                                   }
                                                 }
                                               }
                                             }
                                           }
                                         }
                                       }
                                     }
                                   }
                                 }
                               }
                             }
                           }
                         }
                       }
                     }
                   }
                 }
               }
             }
           }
         }
 
         if (result1 !== null) {
           result0 = [];
 
           while (result1 !== null) {
             result0.push(result1);
             result1 = parse_alphanum();
 
             if (result1 === null) {
               if (input.charCodeAt(pos) === 45) {
                 result1 = "-";
                 pos++;
               } else {
                 result1 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\"-\"");
                 }
               }
 
               if (result1 === null) {
                 if (input.charCodeAt(pos) === 46) {
                   result1 = ".";
                   pos++;
                 } else {
                   result1 = null;
 
                   if (reportFailures === 0) {
                     matchFailed("\".\"");
                   }
                 }
 
                 if (result1 === null) {
                   if (input.charCodeAt(pos) === 33) {
                     result1 = "!";
                     pos++;
                   } else {
                     result1 = null;
 
                     if (reportFailures === 0) {
                       matchFailed("\"!\"");
                     }
                   }
 
                   if (result1 === null) {
                     if (input.charCodeAt(pos) === 37) {
                       result1 = "%";
                       pos++;
                     } else {
                       result1 = null;
 
                       if (reportFailures === 0) {
                         matchFailed("\"%\"");
                       }
                     }
 
                     if (result1 === null) {
                       if (input.charCodeAt(pos) === 42) {
                         result1 = "*";
                         pos++;
                       } else {
                         result1 = null;
 
                         if (reportFailures === 0) {
                           matchFailed("\"*\"");
                         }
                       }
 
                       if (result1 === null) {
                         if (input.charCodeAt(pos) === 95) {
                           result1 = "_";
                           pos++;
                         } else {
                           result1 = null;
 
                           if (reportFailures === 0) {
                             matchFailed("\"_\"");
                           }
                         }
 
                         if (result1 === null) {
                           if (input.charCodeAt(pos) === 43) {
                             result1 = "+";
                             pos++;
                           } else {
                             result1 = null;
 
                             if (reportFailures === 0) {
                               matchFailed("\"+\"");
                             }
                           }
 
                           if (result1 === null) {
                             if (input.charCodeAt(pos) === 96) {
                               result1 = "`";
                               pos++;
                             } else {
                               result1 = null;
 
                               if (reportFailures === 0) {
                                 matchFailed("\"`\"");
                               }
                             }
 
                             if (result1 === null) {
                               if (input.charCodeAt(pos) === 39) {
                                 result1 = "'";
                                 pos++;
                               } else {
                                 result1 = null;
 
                                 if (reportFailures === 0) {
                                   matchFailed("\"'\"");
                                 }
                               }
 
                               if (result1 === null) {
                                 if (input.charCodeAt(pos) === 126) {
                                   result1 = "~";
                                   pos++;
                                 } else {
                                   result1 = null;
 
                                   if (reportFailures === 0) {
                                     matchFailed("\"~\"");
                                   }
                                 }
 
                                 if (result1 === null) {
                                   if (input.charCodeAt(pos) === 40) {
                                     result1 = "(";
                                     pos++;
                                   } else {
                                     result1 = null;
 
                                     if (reportFailures === 0) {
                                       matchFailed("\"(\"");
                                     }
                                   }
 
                                   if (result1 === null) {
                                     if (input.charCodeAt(pos) === 41) {
                                       result1 = ")";
                                       pos++;
                                     } else {
                                       result1 = null;
 
                                       if (reportFailures === 0) {
                                         matchFailed("\")\"");
                                       }
                                     }
 
                                     if (result1 === null) {
                                       if (input.charCodeAt(pos) === 60) {
                                         result1 = "<";
                                         pos++;
                                       } else {
                                         result1 = null;
 
                                         if (reportFailures === 0) {
                                           matchFailed("\"<\"");
                                         }
                                       }
 
                                       if (result1 === null) {
                                         if (input.charCodeAt(pos) === 62) {
                                           result1 = ">";
                                           pos++;
                                         } else {
                                           result1 = null;
 
                                           if (reportFailures === 0) {
                                             matchFailed("\">\"");
                                           }
                                         }
 
                                         if (result1 === null) {
                                           if (input.charCodeAt(pos) === 58) {
                                             result1 = ":";
                                             pos++;
                                           } else {
                                             result1 = null;
 
                                             if (reportFailures === 0) {
                                               matchFailed("\":\"");
                                             }
                                           }
 
                                           if (result1 === null) {
                                             if (input.charCodeAt(pos) === 92) {
                                               result1 = "\\";
                                               pos++;
                                             } else {
                                               result1 = null;
 
                                               if (reportFailures === 0) {
                                                 matchFailed("\"\\\\\"");
                                               }
                                             }
 
                                             if (result1 === null) {
                                               result1 = parse_DQUOTE();
 
                                               if (result1 === null) {
                                                 if (input.charCodeAt(pos) === 47) {
                                                   result1 = "/";
                                                   pos++;
                                                 } else {
                                                   result1 = null;
 
                                                   if (reportFailures === 0) {
                                                     matchFailed("\"/\"");
                                                   }
                                                 }
 
                                                 if (result1 === null) {
                                                   if (input.charCodeAt(pos) === 91) {
                                                     result1 = "[";
                                                     pos++;
                                                   } else {
                                                     result1 = null;
 
                                                     if (reportFailures === 0) {
                                                       matchFailed("\"[\"");
                                                     }
                                                   }
 
                                                   if (result1 === null) {
                                                     if (input.charCodeAt(pos) === 93) {
                                                       result1 = "]";
                                                       pos++;
                                                     } else {
                                                       result1 = null;
 
                                                       if (reportFailures === 0) {
                                                         matchFailed("\"]\"");
                                                       }
                                                     }
 
                                                     if (result1 === null) {
                                                       if (input.charCodeAt(pos) === 63) {
                                                         result1 = "?";
                                                         pos++;
                                                       } else {
                                                         result1 = null;
 
                                                         if (reportFailures === 0) {
                                                           matchFailed("\"?\"");
                                                         }
                                                       }
 
                                                       if (result1 === null) {
                                                         if (input.charCodeAt(pos) === 123) {
                                                           result1 = "{";
                                                           pos++;
                                                         } else {
                                                           result1 = null;
 
                                                           if (reportFailures === 0) {
                                                             matchFailed("\"{\"");
                                                           }
                                                         }
 
                                                         if (result1 === null) {
                                                           if (input.charCodeAt(pos) === 125) {
                                                             result1 = "}";
                                                             pos++;
                                                           } else {
                                                             result1 = null;
 
                                                             if (reportFailures === 0) {
                                                               matchFailed("\"}\"");
                                                             }
                                                           }
                                                         }
                                                       }
                                                     }
                                                   }
                                                 }
                                               }
                                             }
                                           }
                                         }
                                       }
                                     }
                                   }
                                 }
                               }
                             }
                           }
                         }
                       }
                     }
                   }
                 }
               }
             }
           }
         } else {
           result0 = null;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             return input.substring(pos, offset);
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_STAR() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_SWS();
 
         if (result0 !== null) {
           if (input.charCodeAt(pos) === 42) {
             result1 = "*";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"*\"");
             }
           }
 
           if (result1 !== null) {
             result2 = parse_SWS();
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             return "*";
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_SLASH() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_SWS();
 
         if (result0 !== null) {
           if (input.charCodeAt(pos) === 47) {
             result1 = "/";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"/\"");
             }
           }
 
           if (result1 !== null) {
             result2 = parse_SWS();
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             return "/";
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_EQUAL() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_SWS();
 
         if (result0 !== null) {
           if (input.charCodeAt(pos) === 61) {
             result1 = "=";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"=\"");
             }
           }
 
           if (result1 !== null) {
             result2 = parse_SWS();
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             return "=";
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_LPAREN() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_SWS();
 
         if (result0 !== null) {
           if (input.charCodeAt(pos) === 40) {
             result1 = "(";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"(\"");
             }
           }
 
           if (result1 !== null) {
             result2 = parse_SWS();
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             return "(";
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_RPAREN() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_SWS();
 
         if (result0 !== null) {
           if (input.charCodeAt(pos) === 41) {
             result1 = ")";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\")\"");
             }
           }
 
           if (result1 !== null) {
             result2 = parse_SWS();
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             return ")";
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_RAQUOT() {
         var result0, result1;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
 
         if (input.charCodeAt(pos) === 62) {
           result0 = ">";
           pos++;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\">\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_SWS();
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             return ">";
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_LAQUOT() {
         var result0, result1;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_SWS();
 
         if (result0 !== null) {
           if (input.charCodeAt(pos) === 60) {
             result1 = "<";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"<\"");
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             return "<";
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_COMMA() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_SWS();
 
         if (result0 !== null) {
           if (input.charCodeAt(pos) === 44) {
             result1 = ",";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\",\"");
             }
           }
 
           if (result1 !== null) {
             result2 = parse_SWS();
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             return ",";
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_SEMI() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_SWS();
 
         if (result0 !== null) {
           if (input.charCodeAt(pos) === 59) {
             result1 = ";";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\";\"");
             }
           }
 
           if (result1 !== null) {
             result2 = parse_SWS();
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             return ";";
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_COLON() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_SWS();
 
         if (result0 !== null) {
           if (input.charCodeAt(pos) === 58) {
             result1 = ":";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\":\"");
             }
           }
 
           if (result1 !== null) {
             result2 = parse_SWS();
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             return ":";
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_LDQUOT() {
         var result0, result1;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_SWS();
 
         if (result0 !== null) {
           result1 = parse_DQUOTE();
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             return "\"";
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_RDQUOT() {
         var result0, result1;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_DQUOTE();
 
         if (result0 !== null) {
           result1 = parse_SWS();
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             return "\"";
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_comment() {
         var result0, result1, result2;
         var pos0;
         pos0 = pos;
         result0 = parse_LPAREN();
 
         if (result0 !== null) {
           result1 = [];
           result2 = parse_ctext();
 
           if (result2 === null) {
             result2 = parse_quoted_pair();
 
             if (result2 === null) {
               result2 = parse_comment();
             }
           }
 
           while (result2 !== null) {
             result1.push(result2);
             result2 = parse_ctext();
 
             if (result2 === null) {
               result2 = parse_quoted_pair();
 
               if (result2 === null) {
                 result2 = parse_comment();
               }
             }
           }
 
           if (result1 !== null) {
             result2 = parse_RPAREN();
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos0;
             }
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_ctext() {
         var result0;
 
         if (/^[!-']/.test(input.charAt(pos))) {
           result0 = input.charAt(pos);
           pos++;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("[!-']");
           }
         }
 
         if (result0 === null) {
           if (/^[*-[]/.test(input.charAt(pos))) {
             result0 = input.charAt(pos);
             pos++;
           } else {
             result0 = null;
 
             if (reportFailures === 0) {
               matchFailed("[*-[]");
             }
           }
 
           if (result0 === null) {
             if (/^[\]-~]/.test(input.charAt(pos))) {
               result0 = input.charAt(pos);
               pos++;
             } else {
               result0 = null;
 
               if (reportFailures === 0) {
                 matchFailed("[\\]-~]");
               }
             }
 
             if (result0 === null) {
               result0 = parse_UTF8_NONASCII();
 
               if (result0 === null) {
                 result0 = parse_LWS();
               }
             }
           }
         }
 
         return result0;
       }
 
       function parse_quoted_string() {
         var result0, result1, result2, result3;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_SWS();
 
         if (result0 !== null) {
           result1 = parse_DQUOTE();
 
           if (result1 !== null) {
             result2 = [];
             result3 = parse_qdtext();
 
             if (result3 === null) {
               result3 = parse_quoted_pair();
             }
 
             while (result3 !== null) {
               result2.push(result3);
               result3 = parse_qdtext();
 
               if (result3 === null) {
                 result3 = parse_quoted_pair();
               }
             }
 
             if (result2 !== null) {
               result3 = parse_DQUOTE();
 
               if (result3 !== null) {
                 result0 = [result0, result1, result2, result3];
               } else {
                 result0 = null;
                 pos = pos1;
               }
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             return input.substring(pos, offset);
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_quoted_string_clean() {
         var result0, result1, result2, result3;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_SWS();
 
         if (result0 !== null) {
           result1 = parse_DQUOTE();
 
           if (result1 !== null) {
             result2 = [];
             result3 = parse_qdtext();
 
             if (result3 === null) {
               result3 = parse_quoted_pair();
             }
 
             while (result3 !== null) {
               result2.push(result3);
               result3 = parse_qdtext();
 
               if (result3 === null) {
                 result3 = parse_quoted_pair();
               }
             }
 
             if (result2 !== null) {
               result3 = parse_DQUOTE();
 
               if (result3 !== null) {
                 result0 = [result0, result1, result2, result3];
               } else {
                 result0 = null;
                 pos = pos1;
               }
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             var trimmed = input.substring(pos, offset).trim();
             return trimmed.substring(1, trimmed.length - 1) // remove outer quotes
             .replace(/\\([\x00-\x09\x0b-\x0c\x0e-\x7f])/g, '$1');
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_qdtext() {
         var result0;
         result0 = parse_LWS();
 
         if (result0 === null) {
           if (input.charCodeAt(pos) === 33) {
             result0 = "!";
             pos++;
           } else {
             result0 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"!\"");
             }
           }
 
           if (result0 === null) {
             if (/^[#-[]/.test(input.charAt(pos))) {
               result0 = input.charAt(pos);
               pos++;
             } else {
               result0 = null;
 
               if (reportFailures === 0) {
                 matchFailed("[#-[]");
               }
             }
 
             if (result0 === null) {
               if (/^[\]-~]/.test(input.charAt(pos))) {
                 result0 = input.charAt(pos);
                 pos++;
               } else {
                 result0 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("[\\]-~]");
                 }
               }
 
               if (result0 === null) {
                 result0 = parse_UTF8_NONASCII();
               }
             }
           }
         }
 
         return result0;
       }
 
       function parse_quoted_pair() {
         var result0, result1;
         var pos0;
         pos0 = pos;
 
         if (input.charCodeAt(pos) === 92) {
           result0 = "\\";
           pos++;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"\\\\\"");
           }
         }
 
         if (result0 !== null) {
           if (/^[\0-\t]/.test(input.charAt(pos))) {
             result1 = input.charAt(pos);
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("[\\0-\\t]");
             }
           }
 
           if (result1 === null) {
             if (/^[\x0B-\f]/.test(input.charAt(pos))) {
               result1 = input.charAt(pos);
               pos++;
             } else {
               result1 = null;
 
               if (reportFailures === 0) {
                 matchFailed("[\\x0B-\\f]");
               }
             }
 
             if (result1 === null) {
               if (/^[\x0E-]/.test(input.charAt(pos))) {
                 result1 = input.charAt(pos);
                 pos++;
               } else {
                 result1 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("[\\x0E-]");
                 }
               }
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_SIP_URI_noparams() {
         var result0, result1, result2, result3;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_uri_scheme();
 
         if (result0 !== null) {
           if (input.charCodeAt(pos) === 58) {
             result1 = ":";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\":\"");
             }
           }
 
           if (result1 !== null) {
             result2 = parse_userinfo();
             result2 = result2 !== null ? result2 : "";
 
             if (result2 !== null) {
               result3 = parse_hostport();
 
               if (result3 !== null) {
                 result0 = [result0, result1, result2, result3];
               } else {
                 result0 = null;
                 pos = pos1;
               }
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             try {
               data.uri = new URI(data.scheme, data.user, data.host, data.port);
               delete data.scheme;
               delete data.user;
               delete data.host;
               delete data.host_type;
               delete data.port;
             } catch (e) {
               data = -1;
             }
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_SIP_URI() {
         var result0, result1, result2, result3, result4, result5;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_uri_scheme();
 
         if (result0 !== null) {
           if (input.charCodeAt(pos) === 58) {
             result1 = ":";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\":\"");
             }
           }
 
           if (result1 !== null) {
             result2 = parse_userinfo();
             result2 = result2 !== null ? result2 : "";
 
             if (result2 !== null) {
               result3 = parse_hostport();
 
               if (result3 !== null) {
                 result4 = parse_uri_parameters();
 
                 if (result4 !== null) {
                   result5 = parse_headers();
                   result5 = result5 !== null ? result5 : "";
 
                   if (result5 !== null) {
                     result0 = [result0, result1, result2, result3, result4, result5];
                   } else {
                     result0 = null;
                     pos = pos1;
                   }
                 } else {
                   result0 = null;
                   pos = pos1;
                 }
               } else {
                 result0 = null;
                 pos = pos1;
               }
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             var header;
 
             try {
               data.uri = new URI(data.scheme, data.user, data.host, data.port, data.uri_params, data.uri_headers);
               delete data.scheme;
               delete data.user;
               delete data.host;
               delete data.host_type;
               delete data.port;
               delete data.uri_params;
 
               if (startRule === 'SIP_URI') {
                 data = data.uri;
               }
             } catch (e) {
               data = -1;
             }
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_uri_scheme() {
         var result0;
         result0 = parse_uri_scheme_sips();
 
         if (result0 === null) {
           result0 = parse_uri_scheme_sip();
         }
 
         return result0;
       }
 
       function parse_uri_scheme_sips() {
         var result0;
         var pos0;
         pos0 = pos;
 
         if (input.substr(pos, 4).toLowerCase() === "sips") {
           result0 = input.substr(pos, 4);
           pos += 4;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"sips\"");
           }
         }
 
         if (result0 !== null) {
           result0 = function (offset, scheme) {
             data.scheme = scheme.toLowerCase();
           }(pos0, result0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_uri_scheme_sip() {
         var result0;
         var pos0;
         pos0 = pos;
 
         if (input.substr(pos, 3).toLowerCase() === "sip") {
           result0 = input.substr(pos, 3);
           pos += 3;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"sip\"");
           }
         }
 
         if (result0 !== null) {
           result0 = function (offset, scheme) {
             data.scheme = scheme.toLowerCase();
           }(pos0, result0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_userinfo() {
         var result0, result1, result2;
         var pos0, pos1, pos2;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_user();
 
         if (result0 !== null) {
           pos2 = pos;
 
           if (input.charCodeAt(pos) === 58) {
             result1 = ":";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\":\"");
             }
           }
 
           if (result1 !== null) {
             result2 = parse_password();
 
             if (result2 !== null) {
               result1 = [result1, result2];
             } else {
               result1 = null;
               pos = pos2;
             }
           } else {
             result1 = null;
             pos = pos2;
           }
 
           result1 = result1 !== null ? result1 : "";
 
           if (result1 !== null) {
             if (input.charCodeAt(pos) === 64) {
               result2 = "@";
               pos++;
             } else {
               result2 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\"@\"");
               }
             }
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             data.user = decodeURIComponent(input.substring(pos - 1, offset));
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_user() {
         var result0, result1;
         result1 = parse_unreserved();
 
         if (result1 === null) {
           result1 = parse_escaped();
 
           if (result1 === null) {
             result1 = parse_user_unreserved();
           }
         }
 
         if (result1 !== null) {
           result0 = [];
 
           while (result1 !== null) {
             result0.push(result1);
             result1 = parse_unreserved();
 
             if (result1 === null) {
               result1 = parse_escaped();
 
               if (result1 === null) {
                 result1 = parse_user_unreserved();
               }
             }
           }
         } else {
           result0 = null;
         }
 
         return result0;
       }
 
       function parse_user_unreserved() {
         var result0;
 
         if (input.charCodeAt(pos) === 38) {
           result0 = "&";
           pos++;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"&\"");
           }
         }
 
         if (result0 === null) {
           if (input.charCodeAt(pos) === 61) {
             result0 = "=";
             pos++;
           } else {
             result0 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"=\"");
             }
           }
 
           if (result0 === null) {
             if (input.charCodeAt(pos) === 43) {
               result0 = "+";
               pos++;
             } else {
               result0 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\"+\"");
               }
             }
 
             if (result0 === null) {
               if (input.charCodeAt(pos) === 36) {
                 result0 = "$";
                 pos++;
               } else {
                 result0 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\"$\"");
                 }
               }
 
               if (result0 === null) {
                 if (input.charCodeAt(pos) === 44) {
                   result0 = ",";
                   pos++;
                 } else {
                   result0 = null;
 
                   if (reportFailures === 0) {
                     matchFailed("\",\"");
                   }
                 }
 
                 if (result0 === null) {
                   if (input.charCodeAt(pos) === 59) {
                     result0 = ";";
                     pos++;
                   } else {
                     result0 = null;
 
                     if (reportFailures === 0) {
                       matchFailed("\";\"");
                     }
                   }
 
                   if (result0 === null) {
                     if (input.charCodeAt(pos) === 63) {
                       result0 = "?";
                       pos++;
                     } else {
                       result0 = null;
 
                       if (reportFailures === 0) {
                         matchFailed("\"?\"");
                       }
                     }
 
                     if (result0 === null) {
                       if (input.charCodeAt(pos) === 47) {
                         result0 = "/";
                         pos++;
                       } else {
                         result0 = null;
 
                         if (reportFailures === 0) {
                           matchFailed("\"/\"");
                         }
                       }
                     }
                   }
                 }
               }
             }
           }
         }
 
         return result0;
       }
 
       function parse_password() {
         var result0, result1;
         var pos0;
         pos0 = pos;
         result0 = [];
         result1 = parse_unreserved();
 
         if (result1 === null) {
           result1 = parse_escaped();
 
           if (result1 === null) {
             if (input.charCodeAt(pos) === 38) {
               result1 = "&";
               pos++;
             } else {
               result1 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\"&\"");
               }
             }
 
             if (result1 === null) {
               if (input.charCodeAt(pos) === 61) {
                 result1 = "=";
                 pos++;
               } else {
                 result1 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\"=\"");
                 }
               }
 
               if (result1 === null) {
                 if (input.charCodeAt(pos) === 43) {
                   result1 = "+";
                   pos++;
                 } else {
                   result1 = null;
 
                   if (reportFailures === 0) {
                     matchFailed("\"+\"");
                   }
                 }
 
                 if (result1 === null) {
                   if (input.charCodeAt(pos) === 36) {
                     result1 = "$";
                     pos++;
                   } else {
                     result1 = null;
 
                     if (reportFailures === 0) {
                       matchFailed("\"$\"");
                     }
                   }
 
                   if (result1 === null) {
                     if (input.charCodeAt(pos) === 44) {
                       result1 = ",";
                       pos++;
                     } else {
                       result1 = null;
 
                       if (reportFailures === 0) {
                         matchFailed("\",\"");
                       }
                     }
                   }
                 }
               }
             }
           }
         }
 
         while (result1 !== null) {
           result0.push(result1);
           result1 = parse_unreserved();
 
           if (result1 === null) {
             result1 = parse_escaped();
 
             if (result1 === null) {
               if (input.charCodeAt(pos) === 38) {
                 result1 = "&";
                 pos++;
               } else {
                 result1 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\"&\"");
                 }
               }
 
               if (result1 === null) {
                 if (input.charCodeAt(pos) === 61) {
                   result1 = "=";
                   pos++;
                 } else {
                   result1 = null;
 
                   if (reportFailures === 0) {
                     matchFailed("\"=\"");
                   }
                 }
 
                 if (result1 === null) {
                   if (input.charCodeAt(pos) === 43) {
                     result1 = "+";
                     pos++;
                   } else {
                     result1 = null;
 
                     if (reportFailures === 0) {
                       matchFailed("\"+\"");
                     }
                   }
 
                   if (result1 === null) {
                     if (input.charCodeAt(pos) === 36) {
                       result1 = "$";
                       pos++;
                     } else {
                       result1 = null;
 
                       if (reportFailures === 0) {
                         matchFailed("\"$\"");
                       }
                     }
 
                     if (result1 === null) {
                       if (input.charCodeAt(pos) === 44) {
                         result1 = ",";
                         pos++;
                       } else {
                         result1 = null;
 
                         if (reportFailures === 0) {
                           matchFailed("\",\"");
                         }
                       }
                     }
                   }
                 }
               }
             }
           }
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             data.password = input.substring(pos, offset);
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_hostport() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
         result0 = parse_host();
 
         if (result0 !== null) {
           pos1 = pos;
 
           if (input.charCodeAt(pos) === 58) {
             result1 = ":";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\":\"");
             }
           }
 
           if (result1 !== null) {
             result2 = parse_port();
 
             if (result2 !== null) {
               result1 = [result1, result2];
             } else {
               result1 = null;
               pos = pos1;
             }
           } else {
             result1 = null;
             pos = pos1;
           }
 
           result1 = result1 !== null ? result1 : "";
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_host() {
         var result0;
         var pos0;
         pos0 = pos;
         result0 = parse_hostname();
 
         if (result0 === null) {
           result0 = parse_IPv4address();
 
           if (result0 === null) {
             result0 = parse_IPv6reference();
           }
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             data.host = input.substring(pos, offset).toLowerCase();
             return data.host;
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_hostname() {
         var result0, result1, result2;
         var pos0, pos1, pos2;
         pos0 = pos;
         pos1 = pos;
         result0 = [];
         pos2 = pos;
         result1 = parse_domainlabel();
 
         if (result1 !== null) {
           if (input.charCodeAt(pos) === 46) {
             result2 = ".";
             pos++;
           } else {
             result2 = null;
 
             if (reportFailures === 0) {
               matchFailed("\".\"");
             }
           }
 
           if (result2 !== null) {
             result1 = [result1, result2];
           } else {
             result1 = null;
             pos = pos2;
           }
         } else {
           result1 = null;
           pos = pos2;
         }
 
         while (result1 !== null) {
           result0.push(result1);
           pos2 = pos;
           result1 = parse_domainlabel();
 
           if (result1 !== null) {
             if (input.charCodeAt(pos) === 46) {
               result2 = ".";
               pos++;
             } else {
               result2 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\".\"");
               }
             }
 
             if (result2 !== null) {
               result1 = [result1, result2];
             } else {
               result1 = null;
               pos = pos2;
             }
           } else {
             result1 = null;
             pos = pos2;
           }
         }
 
         if (result0 !== null) {
           result1 = parse_toplabel();
 
           if (result1 !== null) {
             if (input.charCodeAt(pos) === 46) {
               result2 = ".";
               pos++;
             } else {
               result2 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\".\"");
               }
             }
 
             result2 = result2 !== null ? result2 : "";
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             data.host_type = 'domain';
             return input.substring(pos, offset);
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_domainlabel() {
         var result0, result1, result2;
         var pos0;
         pos0 = pos;
         result0 = parse_alphanum();
 
         if (result0 !== null) {
           result1 = [];
           result2 = parse_alphanum();
 
           if (result2 === null) {
             if (input.charCodeAt(pos) === 45) {
               result2 = "-";
               pos++;
             } else {
               result2 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\"-\"");
               }
             }
 
             if (result2 === null) {
               if (input.charCodeAt(pos) === 95) {
                 result2 = "_";
                 pos++;
               } else {
                 result2 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\"_\"");
                 }
               }
             }
           }
 
           while (result2 !== null) {
             result1.push(result2);
             result2 = parse_alphanum();
 
             if (result2 === null) {
               if (input.charCodeAt(pos) === 45) {
                 result2 = "-";
                 pos++;
               } else {
                 result2 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\"-\"");
                 }
               }
 
               if (result2 === null) {
                 if (input.charCodeAt(pos) === 95) {
                   result2 = "_";
                   pos++;
                 } else {
                   result2 = null;
 
                   if (reportFailures === 0) {
                     matchFailed("\"_\"");
                   }
                 }
               }
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_toplabel() {
         var result0, result1, result2;
         var pos0;
         pos0 = pos;
         result0 = parse_ALPHA();
 
         if (result0 !== null) {
           result1 = [];
           result2 = parse_alphanum();
 
           if (result2 === null) {
             if (input.charCodeAt(pos) === 45) {
               result2 = "-";
               pos++;
             } else {
               result2 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\"-\"");
               }
             }
 
             if (result2 === null) {
               if (input.charCodeAt(pos) === 95) {
                 result2 = "_";
                 pos++;
               } else {
                 result2 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\"_\"");
                 }
               }
             }
           }
 
           while (result2 !== null) {
             result1.push(result2);
             result2 = parse_alphanum();
 
             if (result2 === null) {
               if (input.charCodeAt(pos) === 45) {
                 result2 = "-";
                 pos++;
               } else {
                 result2 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\"-\"");
                 }
               }
 
               if (result2 === null) {
                 if (input.charCodeAt(pos) === 95) {
                   result2 = "_";
                   pos++;
                 } else {
                   result2 = null;
 
                   if (reportFailures === 0) {
                     matchFailed("\"_\"");
                   }
                 }
               }
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_IPv6reference() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
 
         if (input.charCodeAt(pos) === 91) {
           result0 = "[";
           pos++;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"[\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_IPv6address();
 
           if (result1 !== null) {
             if (input.charCodeAt(pos) === 93) {
               result2 = "]";
               pos++;
             } else {
               result2 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\"]\"");
               }
             }
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             data.host_type = 'IPv6';
             return input.substring(pos, offset);
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_IPv6address() {
         var result0, result1, result2, result3, result4, result5, result6, result7, result8, result9, result10, result11, result12;
         var pos0, pos1, pos2;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_h16();
 
         if (result0 !== null) {
           if (input.charCodeAt(pos) === 58) {
             result1 = ":";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\":\"");
             }
           }
 
           if (result1 !== null) {
             result2 = parse_h16();
 
             if (result2 !== null) {
               if (input.charCodeAt(pos) === 58) {
                 result3 = ":";
                 pos++;
               } else {
                 result3 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\":\"");
                 }
               }
 
               if (result3 !== null) {
                 result4 = parse_h16();
 
                 if (result4 !== null) {
                   if (input.charCodeAt(pos) === 58) {
                     result5 = ":";
                     pos++;
                   } else {
                     result5 = null;
 
                     if (reportFailures === 0) {
                       matchFailed("\":\"");
                     }
                   }
 
                   if (result5 !== null) {
                     result6 = parse_h16();
 
                     if (result6 !== null) {
                       if (input.charCodeAt(pos) === 58) {
                         result7 = ":";
                         pos++;
                       } else {
                         result7 = null;
 
                         if (reportFailures === 0) {
                           matchFailed("\":\"");
                         }
                       }
 
                       if (result7 !== null) {
                         result8 = parse_h16();
 
                         if (result8 !== null) {
                           if (input.charCodeAt(pos) === 58) {
                             result9 = ":";
                             pos++;
                           } else {
                             result9 = null;
 
                             if (reportFailures === 0) {
                               matchFailed("\":\"");
                             }
                           }
 
                           if (result9 !== null) {
                             result10 = parse_h16();
 
                             if (result10 !== null) {
                               if (input.charCodeAt(pos) === 58) {
                                 result11 = ":";
                                 pos++;
                               } else {
                                 result11 = null;
 
                                 if (reportFailures === 0) {
                                   matchFailed("\":\"");
                                 }
                               }
 
                               if (result11 !== null) {
                                 result12 = parse_ls32();
 
                                 if (result12 !== null) {
                                   result0 = [result0, result1, result2, result3, result4, result5, result6, result7, result8, result9, result10, result11, result12];
                                 } else {
                                   result0 = null;
                                   pos = pos1;
                                 }
                               } else {
                                 result0 = null;
                                 pos = pos1;
                               }
                             } else {
                               result0 = null;
                               pos = pos1;
                             }
                           } else {
                             result0 = null;
                             pos = pos1;
                           }
                         } else {
                           result0 = null;
                           pos = pos1;
                         }
                       } else {
                         result0 = null;
                         pos = pos1;
                       }
                     } else {
                       result0 = null;
                       pos = pos1;
                     }
                   } else {
                     result0 = null;
                     pos = pos1;
                   }
                 } else {
                   result0 = null;
                   pos = pos1;
                 }
               } else {
                 result0 = null;
                 pos = pos1;
               }
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 === null) {
           pos1 = pos;
 
           if (input.substr(pos, 2) === "::") {
             result0 = "::";
             pos += 2;
           } else {
             result0 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"::\"");
             }
           }
 
           if (result0 !== null) {
             result1 = parse_h16();
 
             if (result1 !== null) {
               if (input.charCodeAt(pos) === 58) {
                 result2 = ":";
                 pos++;
               } else {
                 result2 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\":\"");
                 }
               }
 
               if (result2 !== null) {
                 result3 = parse_h16();
 
                 if (result3 !== null) {
                   if (input.charCodeAt(pos) === 58) {
                     result4 = ":";
                     pos++;
                   } else {
                     result4 = null;
 
                     if (reportFailures === 0) {
                       matchFailed("\":\"");
                     }
                   }
 
                   if (result4 !== null) {
                     result5 = parse_h16();
 
                     if (result5 !== null) {
                       if (input.charCodeAt(pos) === 58) {
                         result6 = ":";
                         pos++;
                       } else {
                         result6 = null;
 
                         if (reportFailures === 0) {
                           matchFailed("\":\"");
                         }
                       }
 
                       if (result6 !== null) {
                         result7 = parse_h16();
 
                         if (result7 !== null) {
                           if (input.charCodeAt(pos) === 58) {
                             result8 = ":";
                             pos++;
                           } else {
                             result8 = null;
 
                             if (reportFailures === 0) {
                               matchFailed("\":\"");
                             }
                           }
 
                           if (result8 !== null) {
                             result9 = parse_h16();
 
                             if (result9 !== null) {
                               if (input.charCodeAt(pos) === 58) {
                                 result10 = ":";
                                 pos++;
                               } else {
                                 result10 = null;
 
                                 if (reportFailures === 0) {
                                   matchFailed("\":\"");
                                 }
                               }
 
                               if (result10 !== null) {
                                 result11 = parse_ls32();
 
                                 if (result11 !== null) {
                                   result0 = [result0, result1, result2, result3, result4, result5, result6, result7, result8, result9, result10, result11];
                                 } else {
                                   result0 = null;
                                   pos = pos1;
                                 }
                               } else {
                                 result0 = null;
                                 pos = pos1;
                               }
                             } else {
                               result0 = null;
                               pos = pos1;
                             }
                           } else {
                             result0 = null;
                             pos = pos1;
                           }
                         } else {
                           result0 = null;
                           pos = pos1;
                         }
                       } else {
                         result0 = null;
                         pos = pos1;
                       }
                     } else {
                       result0 = null;
                       pos = pos1;
                     }
                   } else {
                     result0 = null;
                     pos = pos1;
                   }
                 } else {
                   result0 = null;
                   pos = pos1;
                 }
               } else {
                 result0 = null;
                 pos = pos1;
               }
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
 
           if (result0 === null) {
             pos1 = pos;
 
             if (input.substr(pos, 2) === "::") {
               result0 = "::";
               pos += 2;
             } else {
               result0 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\"::\"");
               }
             }
 
             if (result0 !== null) {
               result1 = parse_h16();
 
               if (result1 !== null) {
                 if (input.charCodeAt(pos) === 58) {
                   result2 = ":";
                   pos++;
                 } else {
                   result2 = null;
 
                   if (reportFailures === 0) {
                     matchFailed("\":\"");
                   }
                 }
 
                 if (result2 !== null) {
                   result3 = parse_h16();
 
                   if (result3 !== null) {
                     if (input.charCodeAt(pos) === 58) {
                       result4 = ":";
                       pos++;
                     } else {
                       result4 = null;
 
                       if (reportFailures === 0) {
                         matchFailed("\":\"");
                       }
                     }
 
                     if (result4 !== null) {
                       result5 = parse_h16();
 
                       if (result5 !== null) {
                         if (input.charCodeAt(pos) === 58) {
                           result6 = ":";
                           pos++;
                         } else {
                           result6 = null;
 
                           if (reportFailures === 0) {
                             matchFailed("\":\"");
                           }
                         }
 
                         if (result6 !== null) {
                           result7 = parse_h16();
 
                           if (result7 !== null) {
                             if (input.charCodeAt(pos) === 58) {
                               result8 = ":";
                               pos++;
                             } else {
                               result8 = null;
 
                               if (reportFailures === 0) {
                                 matchFailed("\":\"");
                               }
                             }
 
                             if (result8 !== null) {
                               result9 = parse_ls32();
 
                               if (result9 !== null) {
                                 result0 = [result0, result1, result2, result3, result4, result5, result6, result7, result8, result9];
                               } else {
                                 result0 = null;
                                 pos = pos1;
                               }
                             } else {
                               result0 = null;
                               pos = pos1;
                             }
                           } else {
                             result0 = null;
                             pos = pos1;
                           }
                         } else {
                           result0 = null;
                           pos = pos1;
                         }
                       } else {
                         result0 = null;
                         pos = pos1;
                       }
                     } else {
                       result0 = null;
                       pos = pos1;
                     }
                   } else {
                     result0 = null;
                     pos = pos1;
                   }
                 } else {
                   result0 = null;
                   pos = pos1;
                 }
               } else {
                 result0 = null;
                 pos = pos1;
               }
             } else {
               result0 = null;
               pos = pos1;
             }
 
             if (result0 === null) {
               pos1 = pos;
 
               if (input.substr(pos, 2) === "::") {
                 result0 = "::";
                 pos += 2;
               } else {
                 result0 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\"::\"");
                 }
               }
 
               if (result0 !== null) {
                 result1 = parse_h16();
 
                 if (result1 !== null) {
                   if (input.charCodeAt(pos) === 58) {
                     result2 = ":";
                     pos++;
                   } else {
                     result2 = null;
 
                     if (reportFailures === 0) {
                       matchFailed("\":\"");
                     }
                   }
 
                   if (result2 !== null) {
                     result3 = parse_h16();
 
                     if (result3 !== null) {
                       if (input.charCodeAt(pos) === 58) {
                         result4 = ":";
                         pos++;
                       } else {
                         result4 = null;
 
                         if (reportFailures === 0) {
                           matchFailed("\":\"");
                         }
                       }
 
                       if (result4 !== null) {
                         result5 = parse_h16();
 
                         if (result5 !== null) {
                           if (input.charCodeAt(pos) === 58) {
                             result6 = ":";
                             pos++;
                           } else {
                             result6 = null;
 
                             if (reportFailures === 0) {
                               matchFailed("\":\"");
                             }
                           }
 
                           if (result6 !== null) {
                             result7 = parse_ls32();
 
                             if (result7 !== null) {
                               result0 = [result0, result1, result2, result3, result4, result5, result6, result7];
                             } else {
                               result0 = null;
                               pos = pos1;
                             }
                           } else {
                             result0 = null;
                             pos = pos1;
                           }
                         } else {
                           result0 = null;
                           pos = pos1;
                         }
                       } else {
                         result0 = null;
                         pos = pos1;
                       }
                     } else {
                       result0 = null;
                       pos = pos1;
                     }
                   } else {
                     result0 = null;
                     pos = pos1;
                   }
                 } else {
                   result0 = null;
                   pos = pos1;
                 }
               } else {
                 result0 = null;
                 pos = pos1;
               }
 
               if (result0 === null) {
                 pos1 = pos;
 
                 if (input.substr(pos, 2) === "::") {
                   result0 = "::";
                   pos += 2;
                 } else {
                   result0 = null;
 
                   if (reportFailures === 0) {
                     matchFailed("\"::\"");
                   }
                 }
 
                 if (result0 !== null) {
                   result1 = parse_h16();
 
                   if (result1 !== null) {
                     if (input.charCodeAt(pos) === 58) {
                       result2 = ":";
                       pos++;
                     } else {
                       result2 = null;
 
                       if (reportFailures === 0) {
                         matchFailed("\":\"");
                       }
                     }
 
                     if (result2 !== null) {
                       result3 = parse_h16();
 
                       if (result3 !== null) {
                         if (input.charCodeAt(pos) === 58) {
                           result4 = ":";
                           pos++;
                         } else {
                           result4 = null;
 
                           if (reportFailures === 0) {
                             matchFailed("\":\"");
                           }
                         }
 
                         if (result4 !== null) {
                           result5 = parse_ls32();
 
                           if (result5 !== null) {
                             result0 = [result0, result1, result2, result3, result4, result5];
                           } else {
                             result0 = null;
                             pos = pos1;
                           }
                         } else {
                           result0 = null;
                           pos = pos1;
                         }
                       } else {
                         result0 = null;
                         pos = pos1;
                       }
                     } else {
                       result0 = null;
                       pos = pos1;
                     }
                   } else {
                     result0 = null;
                     pos = pos1;
                   }
                 } else {
                   result0 = null;
                   pos = pos1;
                 }
 
                 if (result0 === null) {
                   pos1 = pos;
 
                   if (input.substr(pos, 2) === "::") {
                     result0 = "::";
                     pos += 2;
                   } else {
                     result0 = null;
 
                     if (reportFailures === 0) {
                       matchFailed("\"::\"");
                     }
                   }
 
                   if (result0 !== null) {
                     result1 = parse_h16();
 
                     if (result1 !== null) {
                       if (input.charCodeAt(pos) === 58) {
                         result2 = ":";
                         pos++;
                       } else {
                         result2 = null;
 
                         if (reportFailures === 0) {
                           matchFailed("\":\"");
                         }
                       }
 
                       if (result2 !== null) {
                         result3 = parse_ls32();
 
                         if (result3 !== null) {
                           result0 = [result0, result1, result2, result3];
                         } else {
                           result0 = null;
                           pos = pos1;
                         }
                       } else {
                         result0 = null;
                         pos = pos1;
                       }
                     } else {
                       result0 = null;
                       pos = pos1;
                     }
                   } else {
                     result0 = null;
                     pos = pos1;
                   }
 
                   if (result0 === null) {
                     pos1 = pos;
 
                     if (input.substr(pos, 2) === "::") {
                       result0 = "::";
                       pos += 2;
                     } else {
                       result0 = null;
 
                       if (reportFailures === 0) {
                         matchFailed("\"::\"");
                       }
                     }
 
                     if (result0 !== null) {
                       result1 = parse_ls32();
 
                       if (result1 !== null) {
                         result0 = [result0, result1];
                       } else {
                         result0 = null;
                         pos = pos1;
                       }
                     } else {
                       result0 = null;
                       pos = pos1;
                     }
 
                     if (result0 === null) {
                       pos1 = pos;
 
                       if (input.substr(pos, 2) === "::") {
                         result0 = "::";
                         pos += 2;
                       } else {
                         result0 = null;
 
                         if (reportFailures === 0) {
                           matchFailed("\"::\"");
                         }
                       }
 
                       if (result0 !== null) {
                         result1 = parse_h16();
 
                         if (result1 !== null) {
                           result0 = [result0, result1];
                         } else {
                           result0 = null;
                           pos = pos1;
                         }
                       } else {
                         result0 = null;
                         pos = pos1;
                       }
 
                       if (result0 === null) {
                         pos1 = pos;
                         result0 = parse_h16();
 
                         if (result0 !== null) {
                           if (input.substr(pos, 2) === "::") {
                             result1 = "::";
                             pos += 2;
                           } else {
                             result1 = null;
 
                             if (reportFailures === 0) {
                               matchFailed("\"::\"");
                             }
                           }
 
                           if (result1 !== null) {
                             result2 = parse_h16();
 
                             if (result2 !== null) {
                               if (input.charCodeAt(pos) === 58) {
                                 result3 = ":";
                                 pos++;
                               } else {
                                 result3 = null;
 
                                 if (reportFailures === 0) {
                                   matchFailed("\":\"");
                                 }
                               }
 
                               if (result3 !== null) {
                                 result4 = parse_h16();
 
                                 if (result4 !== null) {
                                   if (input.charCodeAt(pos) === 58) {
                                     result5 = ":";
                                     pos++;
                                   } else {
                                     result5 = null;
 
                                     if (reportFailures === 0) {
                                       matchFailed("\":\"");
                                     }
                                   }
 
                                   if (result5 !== null) {
                                     result6 = parse_h16();
 
                                     if (result6 !== null) {
                                       if (input.charCodeAt(pos) === 58) {
                                         result7 = ":";
                                         pos++;
                                       } else {
                                         result7 = null;
 
                                         if (reportFailures === 0) {
                                           matchFailed("\":\"");
                                         }
                                       }
 
                                       if (result7 !== null) {
                                         result8 = parse_h16();
 
                                         if (result8 !== null) {
                                           if (input.charCodeAt(pos) === 58) {
                                             result9 = ":";
                                             pos++;
                                           } else {
                                             result9 = null;
 
                                             if (reportFailures === 0) {
                                               matchFailed("\":\"");
                                             }
                                           }
 
                                           if (result9 !== null) {
                                             result10 = parse_ls32();
 
                                             if (result10 !== null) {
                                               result0 = [result0, result1, result2, result3, result4, result5, result6, result7, result8, result9, result10];
                                             } else {
                                               result0 = null;
                                               pos = pos1;
                                             }
                                           } else {
                                             result0 = null;
                                             pos = pos1;
                                           }
                                         } else {
                                           result0 = null;
                                           pos = pos1;
                                         }
                                       } else {
                                         result0 = null;
                                         pos = pos1;
                                       }
                                     } else {
                                       result0 = null;
                                       pos = pos1;
                                     }
                                   } else {
                                     result0 = null;
                                     pos = pos1;
                                   }
                                 } else {
                                   result0 = null;
                                   pos = pos1;
                                 }
                               } else {
                                 result0 = null;
                                 pos = pos1;
                               }
                             } else {
                               result0 = null;
                               pos = pos1;
                             }
                           } else {
                             result0 = null;
                             pos = pos1;
                           }
                         } else {
                           result0 = null;
                           pos = pos1;
                         }
 
                         if (result0 === null) {
                           pos1 = pos;
                           result0 = parse_h16();
 
                           if (result0 !== null) {
                             pos2 = pos;
 
                             if (input.charCodeAt(pos) === 58) {
                               result1 = ":";
                               pos++;
                             } else {
                               result1 = null;
 
                               if (reportFailures === 0) {
                                 matchFailed("\":\"");
                               }
                             }
 
                             if (result1 !== null) {
                               result2 = parse_h16();
 
                               if (result2 !== null) {
                                 result1 = [result1, result2];
                               } else {
                                 result1 = null;
                                 pos = pos2;
                               }
                             } else {
                               result1 = null;
                               pos = pos2;
                             }
 
                             result1 = result1 !== null ? result1 : "";
 
                             if (result1 !== null) {
                               if (input.substr(pos, 2) === "::") {
                                 result2 = "::";
                                 pos += 2;
                               } else {
                                 result2 = null;
 
                                 if (reportFailures === 0) {
                                   matchFailed("\"::\"");
                                 }
                               }
 
                               if (result2 !== null) {
                                 result3 = parse_h16();
 
                                 if (result3 !== null) {
                                   if (input.charCodeAt(pos) === 58) {
                                     result4 = ":";
                                     pos++;
                                   } else {
                                     result4 = null;
 
                                     if (reportFailures === 0) {
                                       matchFailed("\":\"");
                                     }
                                   }
 
                                   if (result4 !== null) {
                                     result5 = parse_h16();
 
                                     if (result5 !== null) {
                                       if (input.charCodeAt(pos) === 58) {
                                         result6 = ":";
                                         pos++;
                                       } else {
                                         result6 = null;
 
                                         if (reportFailures === 0) {
                                           matchFailed("\":\"");
                                         }
                                       }
 
                                       if (result6 !== null) {
                                         result7 = parse_h16();
 
                                         if (result7 !== null) {
                                           if (input.charCodeAt(pos) === 58) {
                                             result8 = ":";
                                             pos++;
                                           } else {
                                             result8 = null;
 
                                             if (reportFailures === 0) {
                                               matchFailed("\":\"");
                                             }
                                           }
 
                                           if (result8 !== null) {
                                             result9 = parse_ls32();
 
                                             if (result9 !== null) {
                                               result0 = [result0, result1, result2, result3, result4, result5, result6, result7, result8, result9];
                                             } else {
                                               result0 = null;
                                               pos = pos1;
                                             }
                                           } else {
                                             result0 = null;
                                             pos = pos1;
                                           }
                                         } else {
                                           result0 = null;
                                           pos = pos1;
                                         }
                                       } else {
                                         result0 = null;
                                         pos = pos1;
                                       }
                                     } else {
                                       result0 = null;
                                       pos = pos1;
                                     }
                                   } else {
                                     result0 = null;
                                     pos = pos1;
                                   }
                                 } else {
                                   result0 = null;
                                   pos = pos1;
                                 }
                               } else {
                                 result0 = null;
                                 pos = pos1;
                               }
                             } else {
                               result0 = null;
                               pos = pos1;
                             }
                           } else {
                             result0 = null;
                             pos = pos1;
                           }
 
                           if (result0 === null) {
                             pos1 = pos;
                             result0 = parse_h16();
 
                             if (result0 !== null) {
                               pos2 = pos;
 
                               if (input.charCodeAt(pos) === 58) {
                                 result1 = ":";
                                 pos++;
                               } else {
                                 result1 = null;
 
                                 if (reportFailures === 0) {
                                   matchFailed("\":\"");
                                 }
                               }
 
                               if (result1 !== null) {
                                 result2 = parse_h16();
 
                                 if (result2 !== null) {
                                   result1 = [result1, result2];
                                 } else {
                                   result1 = null;
                                   pos = pos2;
                                 }
                               } else {
                                 result1 = null;
                                 pos = pos2;
                               }
 
                               result1 = result1 !== null ? result1 : "";
 
                               if (result1 !== null) {
                                 pos2 = pos;
 
                                 if (input.charCodeAt(pos) === 58) {
                                   result2 = ":";
                                   pos++;
                                 } else {
                                   result2 = null;
 
                                   if (reportFailures === 0) {
                                     matchFailed("\":\"");
                                   }
                                 }
 
                                 if (result2 !== null) {
                                   result3 = parse_h16();
 
                                   if (result3 !== null) {
                                     result2 = [result2, result3];
                                   } else {
                                     result2 = null;
                                     pos = pos2;
                                   }
                                 } else {
                                   result2 = null;
                                   pos = pos2;
                                 }
 
                                 result2 = result2 !== null ? result2 : "";
 
                                 if (result2 !== null) {
                                   if (input.substr(pos, 2) === "::") {
                                     result3 = "::";
                                     pos += 2;
                                   } else {
                                     result3 = null;
 
                                     if (reportFailures === 0) {
                                       matchFailed("\"::\"");
                                     }
                                   }
 
                                   if (result3 !== null) {
                                     result4 = parse_h16();
 
                                     if (result4 !== null) {
                                       if (input.charCodeAt(pos) === 58) {
                                         result5 = ":";
                                         pos++;
                                       } else {
                                         result5 = null;
 
                                         if (reportFailures === 0) {
                                           matchFailed("\":\"");
                                         }
                                       }
 
                                       if (result5 !== null) {
                                         result6 = parse_h16();
 
                                         if (result6 !== null) {
                                           if (input.charCodeAt(pos) === 58) {
                                             result7 = ":";
                                             pos++;
                                           } else {
                                             result7 = null;
 
                                             if (reportFailures === 0) {
                                               matchFailed("\":\"");
                                             }
                                           }
 
                                           if (result7 !== null) {
                                             result8 = parse_ls32();
 
                                             if (result8 !== null) {
                                               result0 = [result0, result1, result2, result3, result4, result5, result6, result7, result8];
                                             } else {
                                               result0 = null;
                                               pos = pos1;
                                             }
                                           } else {
                                             result0 = null;
                                             pos = pos1;
                                           }
                                         } else {
                                           result0 = null;
                                           pos = pos1;
                                         }
                                       } else {
                                         result0 = null;
                                         pos = pos1;
                                       }
                                     } else {
                                       result0 = null;
                                       pos = pos1;
                                     }
                                   } else {
                                     result0 = null;
                                     pos = pos1;
                                   }
                                 } else {
                                   result0 = null;
                                   pos = pos1;
                                 }
                               } else {
                                 result0 = null;
                                 pos = pos1;
                               }
                             } else {
                               result0 = null;
                               pos = pos1;
                             }
 
                             if (result0 === null) {
                               pos1 = pos;
                               result0 = parse_h16();
 
                               if (result0 !== null) {
                                 pos2 = pos;
 
                                 if (input.charCodeAt(pos) === 58) {
                                   result1 = ":";
                                   pos++;
                                 } else {
                                   result1 = null;
 
                                   if (reportFailures === 0) {
                                     matchFailed("\":\"");
                                   }
                                 }
 
                                 if (result1 !== null) {
                                   result2 = parse_h16();
 
                                   if (result2 !== null) {
                                     result1 = [result1, result2];
                                   } else {
                                     result1 = null;
                                     pos = pos2;
                                   }
                                 } else {
                                   result1 = null;
                                   pos = pos2;
                                 }
 
                                 result1 = result1 !== null ? result1 : "";
 
                                 if (result1 !== null) {
                                   pos2 = pos;
 
                                   if (input.charCodeAt(pos) === 58) {
                                     result2 = ":";
                                     pos++;
                                   } else {
                                     result2 = null;
 
                                     if (reportFailures === 0) {
                                       matchFailed("\":\"");
                                     }
                                   }
 
                                   if (result2 !== null) {
                                     result3 = parse_h16();
 
                                     if (result3 !== null) {
                                       result2 = [result2, result3];
                                     } else {
                                       result2 = null;
                                       pos = pos2;
                                     }
                                   } else {
                                     result2 = null;
                                     pos = pos2;
                                   }
 
                                   result2 = result2 !== null ? result2 : "";
 
                                   if (result2 !== null) {
                                     pos2 = pos;
 
                                     if (input.charCodeAt(pos) === 58) {
                                       result3 = ":";
                                       pos++;
                                     } else {
                                       result3 = null;
 
                                       if (reportFailures === 0) {
                                         matchFailed("\":\"");
                                       }
                                     }
 
                                     if (result3 !== null) {
                                       result4 = parse_h16();
 
                                       if (result4 !== null) {
                                         result3 = [result3, result4];
                                       } else {
                                         result3 = null;
                                         pos = pos2;
                                       }
                                     } else {
                                       result3 = null;
                                       pos = pos2;
                                     }
 
                                     result3 = result3 !== null ? result3 : "";
 
                                     if (result3 !== null) {
                                       if (input.substr(pos, 2) === "::") {
                                         result4 = "::";
                                         pos += 2;
                                       } else {
                                         result4 = null;
 
                                         if (reportFailures === 0) {
                                           matchFailed("\"::\"");
                                         }
                                       }
 
                                       if (result4 !== null) {
                                         result5 = parse_h16();
 
                                         if (result5 !== null) {
                                           if (input.charCodeAt(pos) === 58) {
                                             result6 = ":";
                                             pos++;
                                           } else {
                                             result6 = null;
 
                                             if (reportFailures === 0) {
                                               matchFailed("\":\"");
                                             }
                                           }
 
                                           if (result6 !== null) {
                                             result7 = parse_ls32();
 
                                             if (result7 !== null) {
                                               result0 = [result0, result1, result2, result3, result4, result5, result6, result7];
                                             } else {
                                               result0 = null;
                                               pos = pos1;
                                             }
                                           } else {
                                             result0 = null;
                                             pos = pos1;
                                           }
                                         } else {
                                           result0 = null;
                                           pos = pos1;
                                         }
                                       } else {
                                         result0 = null;
                                         pos = pos1;
                                       }
                                     } else {
                                       result0 = null;
                                       pos = pos1;
                                     }
                                   } else {
                                     result0 = null;
                                     pos = pos1;
                                   }
                                 } else {
                                   result0 = null;
                                   pos = pos1;
                                 }
                               } else {
                                 result0 = null;
                                 pos = pos1;
                               }
 
                               if (result0 === null) {
                                 pos1 = pos;
                                 result0 = parse_h16();
 
                                 if (result0 !== null) {
                                   pos2 = pos;
 
                                   if (input.charCodeAt(pos) === 58) {
                                     result1 = ":";
                                     pos++;
                                   } else {
                                     result1 = null;
 
                                     if (reportFailures === 0) {
                                       matchFailed("\":\"");
                                     }
                                   }
 
                                   if (result1 !== null) {
                                     result2 = parse_h16();
 
                                     if (result2 !== null) {
                                       result1 = [result1, result2];
                                     } else {
                                       result1 = null;
                                       pos = pos2;
                                     }
                                   } else {
                                     result1 = null;
                                     pos = pos2;
                                   }
 
                                   result1 = result1 !== null ? result1 : "";
 
                                   if (result1 !== null) {
                                     pos2 = pos;
 
                                     if (input.charCodeAt(pos) === 58) {
                                       result2 = ":";
                                       pos++;
                                     } else {
                                       result2 = null;
 
                                       if (reportFailures === 0) {
                                         matchFailed("\":\"");
                                       }
                                     }
 
                                     if (result2 !== null) {
                                       result3 = parse_h16();
 
                                       if (result3 !== null) {
                                         result2 = [result2, result3];
                                       } else {
                                         result2 = null;
                                         pos = pos2;
                                       }
                                     } else {
                                       result2 = null;
                                       pos = pos2;
                                     }
 
                                     result2 = result2 !== null ? result2 : "";
 
                                     if (result2 !== null) {
                                       pos2 = pos;
 
                                       if (input.charCodeAt(pos) === 58) {
                                         result3 = ":";
                                         pos++;
                                       } else {
                                         result3 = null;
 
                                         if (reportFailures === 0) {
                                           matchFailed("\":\"");
                                         }
                                       }
 
                                       if (result3 !== null) {
                                         result4 = parse_h16();
 
                                         if (result4 !== null) {
                                           result3 = [result3, result4];
                                         } else {
                                           result3 = null;
                                           pos = pos2;
                                         }
                                       } else {
                                         result3 = null;
                                         pos = pos2;
                                       }
 
                                       result3 = result3 !== null ? result3 : "";
 
                                       if (result3 !== null) {
                                         pos2 = pos;
 
                                         if (input.charCodeAt(pos) === 58) {
                                           result4 = ":";
                                           pos++;
                                         } else {
                                           result4 = null;
 
                                           if (reportFailures === 0) {
                                             matchFailed("\":\"");
                                           }
                                         }
 
                                         if (result4 !== null) {
                                           result5 = parse_h16();
 
                                           if (result5 !== null) {
                                             result4 = [result4, result5];
                                           } else {
                                             result4 = null;
                                             pos = pos2;
                                           }
                                         } else {
                                           result4 = null;
                                           pos = pos2;
                                         }
 
                                         result4 = result4 !== null ? result4 : "";
 
                                         if (result4 !== null) {
                                           if (input.substr(pos, 2) === "::") {
                                             result5 = "::";
                                             pos += 2;
                                           } else {
                                             result5 = null;
 
                                             if (reportFailures === 0) {
                                               matchFailed("\"::\"");
                                             }
                                           }
 
                                           if (result5 !== null) {
                                             result6 = parse_ls32();
 
                                             if (result6 !== null) {
                                               result0 = [result0, result1, result2, result3, result4, result5, result6];
                                             } else {
                                               result0 = null;
                                               pos = pos1;
                                             }
                                           } else {
                                             result0 = null;
                                             pos = pos1;
                                           }
                                         } else {
                                           result0 = null;
                                           pos = pos1;
                                         }
                                       } else {
                                         result0 = null;
                                         pos = pos1;
                                       }
                                     } else {
                                       result0 = null;
                                       pos = pos1;
                                     }
                                   } else {
                                     result0 = null;
                                     pos = pos1;
                                   }
                                 } else {
                                   result0 = null;
                                   pos = pos1;
                                 }
 
                                 if (result0 === null) {
                                   pos1 = pos;
                                   result0 = parse_h16();
 
                                   if (result0 !== null) {
                                     pos2 = pos;
 
                                     if (input.charCodeAt(pos) === 58) {
                                       result1 = ":";
                                       pos++;
                                     } else {
                                       result1 = null;
 
                                       if (reportFailures === 0) {
                                         matchFailed("\":\"");
                                       }
                                     }
 
                                     if (result1 !== null) {
                                       result2 = parse_h16();
 
                                       if (result2 !== null) {
                                         result1 = [result1, result2];
                                       } else {
                                         result1 = null;
                                         pos = pos2;
                                       }
                                     } else {
                                       result1 = null;
                                       pos = pos2;
                                     }
 
                                     result1 = result1 !== null ? result1 : "";
 
                                     if (result1 !== null) {
                                       pos2 = pos;
 
                                       if (input.charCodeAt(pos) === 58) {
                                         result2 = ":";
                                         pos++;
                                       } else {
                                         result2 = null;
 
                                         if (reportFailures === 0) {
                                           matchFailed("\":\"");
                                         }
                                       }
 
                                       if (result2 !== null) {
                                         result3 = parse_h16();
 
                                         if (result3 !== null) {
                                           result2 = [result2, result3];
                                         } else {
                                           result2 = null;
                                           pos = pos2;
                                         }
                                       } else {
                                         result2 = null;
                                         pos = pos2;
                                       }
 
                                       result2 = result2 !== null ? result2 : "";
 
                                       if (result2 !== null) {
                                         pos2 = pos;
 
                                         if (input.charCodeAt(pos) === 58) {
                                           result3 = ":";
                                           pos++;
                                         } else {
                                           result3 = null;
 
                                           if (reportFailures === 0) {
                                             matchFailed("\":\"");
                                           }
                                         }
 
                                         if (result3 !== null) {
                                           result4 = parse_h16();
 
                                           if (result4 !== null) {
                                             result3 = [result3, result4];
                                           } else {
                                             result3 = null;
                                             pos = pos2;
                                           }
                                         } else {
                                           result3 = null;
                                           pos = pos2;
                                         }
 
                                         result3 = result3 !== null ? result3 : "";
 
                                         if (result3 !== null) {
                                           pos2 = pos;
 
                                           if (input.charCodeAt(pos) === 58) {
                                             result4 = ":";
                                             pos++;
                                           } else {
                                             result4 = null;
 
                                             if (reportFailures === 0) {
                                               matchFailed("\":\"");
                                             }
                                           }
 
                                           if (result4 !== null) {
                                             result5 = parse_h16();
 
                                             if (result5 !== null) {
                                               result4 = [result4, result5];
                                             } else {
                                               result4 = null;
                                               pos = pos2;
                                             }
                                           } else {
                                             result4 = null;
                                             pos = pos2;
                                           }
 
                                           result4 = result4 !== null ? result4 : "";
 
                                           if (result4 !== null) {
                                             pos2 = pos;
 
                                             if (input.charCodeAt(pos) === 58) {
                                               result5 = ":";
                                               pos++;
                                             } else {
                                               result5 = null;
 
                                               if (reportFailures === 0) {
                                                 matchFailed("\":\"");
                                               }
                                             }
 
                                             if (result5 !== null) {
                                               result6 = parse_h16();
 
                                               if (result6 !== null) {
                                                 result5 = [result5, result6];
                                               } else {
                                                 result5 = null;
                                                 pos = pos2;
                                               }
                                             } else {
                                               result5 = null;
                                               pos = pos2;
                                             }
 
                                             result5 = result5 !== null ? result5 : "";
 
                                             if (result5 !== null) {
                                               if (input.substr(pos, 2) === "::") {
                                                 result6 = "::";
                                                 pos += 2;
                                               } else {
                                                 result6 = null;
 
                                                 if (reportFailures === 0) {
                                                   matchFailed("\"::\"");
                                                 }
                                               }
 
                                               if (result6 !== null) {
                                                 result7 = parse_h16();
 
                                                 if (result7 !== null) {
                                                   result0 = [result0, result1, result2, result3, result4, result5, result6, result7];
                                                 } else {
                                                   result0 = null;
                                                   pos = pos1;
                                                 }
                                               } else {
                                                 result0 = null;
                                                 pos = pos1;
                                               }
                                             } else {
                                               result0 = null;
                                               pos = pos1;
                                             }
                                           } else {
                                             result0 = null;
                                             pos = pos1;
                                           }
                                         } else {
                                           result0 = null;
                                           pos = pos1;
                                         }
                                       } else {
                                         result0 = null;
                                         pos = pos1;
                                       }
                                     } else {
                                       result0 = null;
                                       pos = pos1;
                                     }
                                   } else {
                                     result0 = null;
                                     pos = pos1;
                                   }
 
                                   if (result0 === null) {
                                     pos1 = pos;
                                     result0 = parse_h16();
 
                                     if (result0 !== null) {
                                       pos2 = pos;
 
                                       if (input.charCodeAt(pos) === 58) {
                                         result1 = ":";
                                         pos++;
                                       } else {
                                         result1 = null;
 
                                         if (reportFailures === 0) {
                                           matchFailed("\":\"");
                                         }
                                       }
 
                                       if (result1 !== null) {
                                         result2 = parse_h16();
 
                                         if (result2 !== null) {
                                           result1 = [result1, result2];
                                         } else {
                                           result1 = null;
                                           pos = pos2;
                                         }
                                       } else {
                                         result1 = null;
                                         pos = pos2;
                                       }
 
                                       result1 = result1 !== null ? result1 : "";
 
                                       if (result1 !== null) {
                                         pos2 = pos;
 
                                         if (input.charCodeAt(pos) === 58) {
                                           result2 = ":";
                                           pos++;
                                         } else {
                                           result2 = null;
 
                                           if (reportFailures === 0) {
                                             matchFailed("\":\"");
                                           }
                                         }
 
                                         if (result2 !== null) {
                                           result3 = parse_h16();
 
                                           if (result3 !== null) {
                                             result2 = [result2, result3];
                                           } else {
                                             result2 = null;
                                             pos = pos2;
                                           }
                                         } else {
                                           result2 = null;
                                           pos = pos2;
                                         }
 
                                         result2 = result2 !== null ? result2 : "";
 
                                         if (result2 !== null) {
                                           pos2 = pos;
 
                                           if (input.charCodeAt(pos) === 58) {
                                             result3 = ":";
                                             pos++;
                                           } else {
                                             result3 = null;
 
                                             if (reportFailures === 0) {
                                               matchFailed("\":\"");
                                             }
                                           }
 
                                           if (result3 !== null) {
                                             result4 = parse_h16();
 
                                             if (result4 !== null) {
                                               result3 = [result3, result4];
                                             } else {
                                               result3 = null;
                                               pos = pos2;
                                             }
                                           } else {
                                             result3 = null;
                                             pos = pos2;
                                           }
 
                                           result3 = result3 !== null ? result3 : "";
 
                                           if (result3 !== null) {
                                             pos2 = pos;
 
                                             if (input.charCodeAt(pos) === 58) {
                                               result4 = ":";
                                               pos++;
                                             } else {
                                               result4 = null;
 
                                               if (reportFailures === 0) {
                                                 matchFailed("\":\"");
                                               }
                                             }
 
                                             if (result4 !== null) {
                                               result5 = parse_h16();
 
                                               if (result5 !== null) {
                                                 result4 = [result4, result5];
                                               } else {
                                                 result4 = null;
                                                 pos = pos2;
                                               }
                                             } else {
                                               result4 = null;
                                               pos = pos2;
                                             }
 
                                             result4 = result4 !== null ? result4 : "";
 
                                             if (result4 !== null) {
                                               pos2 = pos;
 
                                               if (input.charCodeAt(pos) === 58) {
                                                 result5 = ":";
                                                 pos++;
                                               } else {
                                                 result5 = null;
 
                                                 if (reportFailures === 0) {
                                                   matchFailed("\":\"");
                                                 }
                                               }
 
                                               if (result5 !== null) {
                                                 result6 = parse_h16();
 
                                                 if (result6 !== null) {
                                                   result5 = [result5, result6];
                                                 } else {
                                                   result5 = null;
                                                   pos = pos2;
                                                 }
                                               } else {
                                                 result5 = null;
                                                 pos = pos2;
                                               }
 
                                               result5 = result5 !== null ? result5 : "";
 
                                               if (result5 !== null) {
                                                 pos2 = pos;
 
                                                 if (input.charCodeAt(pos) === 58) {
                                                   result6 = ":";
                                                   pos++;
                                                 } else {
                                                   result6 = null;
 
                                                   if (reportFailures === 0) {
                                                     matchFailed("\":\"");
                                                   }
                                                 }
 
                                                 if (result6 !== null) {
                                                   result7 = parse_h16();
 
                                                   if (result7 !== null) {
                                                     result6 = [result6, result7];
                                                   } else {
                                                     result6 = null;
                                                     pos = pos2;
                                                   }
                                                 } else {
                                                   result6 = null;
                                                   pos = pos2;
                                                 }
 
                                                 result6 = result6 !== null ? result6 : "";
 
                                                 if (result6 !== null) {
                                                   if (input.substr(pos, 2) === "::") {
                                                     result7 = "::";
                                                     pos += 2;
                                                   } else {
                                                     result7 = null;
 
                                                     if (reportFailures === 0) {
                                                       matchFailed("\"::\"");
                                                     }
                                                   }
 
                                                   if (result7 !== null) {
                                                     result0 = [result0, result1, result2, result3, result4, result5, result6, result7];
                                                   } else {
                                                     result0 = null;
                                                     pos = pos1;
                                                   }
                                                 } else {
                                                   result0 = null;
                                                   pos = pos1;
                                                 }
                                               } else {
                                                 result0 = null;
                                                 pos = pos1;
                                               }
                                             } else {
                                               result0 = null;
                                               pos = pos1;
                                             }
                                           } else {
                                             result0 = null;
                                             pos = pos1;
                                           }
                                         } else {
                                           result0 = null;
                                           pos = pos1;
                                         }
                                       } else {
                                         result0 = null;
                                         pos = pos1;
                                       }
                                     } else {
                                       result0 = null;
                                       pos = pos1;
                                     }
                                   }
                                 }
                               }
                             }
                           }
                         }
                       }
                     }
                   }
                 }
               }
             }
           }
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             data.host_type = 'IPv6';
             return input.substring(pos, offset);
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_h16() {
         var result0, result1, result2, result3;
         var pos0;
         pos0 = pos;
         result0 = parse_HEXDIG();
 
         if (result0 !== null) {
           result1 = parse_HEXDIG();
           result1 = result1 !== null ? result1 : "";
 
           if (result1 !== null) {
             result2 = parse_HEXDIG();
             result2 = result2 !== null ? result2 : "";
 
             if (result2 !== null) {
               result3 = parse_HEXDIG();
               result3 = result3 !== null ? result3 : "";
 
               if (result3 !== null) {
                 result0 = [result0, result1, result2, result3];
               } else {
                 result0 = null;
                 pos = pos0;
               }
             } else {
               result0 = null;
               pos = pos0;
             }
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_ls32() {
         var result0, result1, result2;
         var pos0;
         pos0 = pos;
         result0 = parse_h16();
 
         if (result0 !== null) {
           if (input.charCodeAt(pos) === 58) {
             result1 = ":";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\":\"");
             }
           }
 
           if (result1 !== null) {
             result2 = parse_h16();
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos0;
             }
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         if (result0 === null) {
           result0 = parse_IPv4address();
         }
 
         return result0;
       }
 
       function parse_IPv4address() {
         var result0, result1, result2, result3, result4, result5, result6;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_dec_octet();
 
         if (result0 !== null) {
           if (input.charCodeAt(pos) === 46) {
             result1 = ".";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\".\"");
             }
           }
 
           if (result1 !== null) {
             result2 = parse_dec_octet();
 
             if (result2 !== null) {
               if (input.charCodeAt(pos) === 46) {
                 result3 = ".";
                 pos++;
               } else {
                 result3 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\".\"");
                 }
               }
 
               if (result3 !== null) {
                 result4 = parse_dec_octet();
 
                 if (result4 !== null) {
                   if (input.charCodeAt(pos) === 46) {
                     result5 = ".";
                     pos++;
                   } else {
                     result5 = null;
 
                     if (reportFailures === 0) {
                       matchFailed("\".\"");
                     }
                   }
 
                   if (result5 !== null) {
                     result6 = parse_dec_octet();
 
                     if (result6 !== null) {
                       result0 = [result0, result1, result2, result3, result4, result5, result6];
                     } else {
                       result0 = null;
                       pos = pos1;
                     }
                   } else {
                     result0 = null;
                     pos = pos1;
                   }
                 } else {
                   result0 = null;
                   pos = pos1;
                 }
               } else {
                 result0 = null;
                 pos = pos1;
               }
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             data.host_type = 'IPv4';
             return input.substring(pos, offset);
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_dec_octet() {
         var result0, result1, result2;
         var pos0;
         pos0 = pos;
 
         if (input.substr(pos, 2) === "25") {
           result0 = "25";
           pos += 2;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"25\"");
           }
         }
 
         if (result0 !== null) {
           if (/^[0-5]/.test(input.charAt(pos))) {
             result1 = input.charAt(pos);
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("[0-5]");
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         if (result0 === null) {
           pos0 = pos;
 
           if (input.charCodeAt(pos) === 50) {
             result0 = "2";
             pos++;
           } else {
             result0 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"2\"");
             }
           }
 
           if (result0 !== null) {
             if (/^[0-4]/.test(input.charAt(pos))) {
               result1 = input.charAt(pos);
               pos++;
             } else {
               result1 = null;
 
               if (reportFailures === 0) {
                 matchFailed("[0-4]");
               }
             }
 
             if (result1 !== null) {
               result2 = parse_DIGIT();
 
               if (result2 !== null) {
                 result0 = [result0, result1, result2];
               } else {
                 result0 = null;
                 pos = pos0;
               }
             } else {
               result0 = null;
               pos = pos0;
             }
           } else {
             result0 = null;
             pos = pos0;
           }
 
           if (result0 === null) {
             pos0 = pos;
 
             if (input.charCodeAt(pos) === 49) {
               result0 = "1";
               pos++;
             } else {
               result0 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\"1\"");
               }
             }
 
             if (result0 !== null) {
               result1 = parse_DIGIT();
 
               if (result1 !== null) {
                 result2 = parse_DIGIT();
 
                 if (result2 !== null) {
                   result0 = [result0, result1, result2];
                 } else {
                   result0 = null;
                   pos = pos0;
                 }
               } else {
                 result0 = null;
                 pos = pos0;
               }
             } else {
               result0 = null;
               pos = pos0;
             }
 
             if (result0 === null) {
               pos0 = pos;
 
               if (/^[1-9]/.test(input.charAt(pos))) {
                 result0 = input.charAt(pos);
                 pos++;
               } else {
                 result0 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("[1-9]");
                 }
               }
 
               if (result0 !== null) {
                 result1 = parse_DIGIT();
 
                 if (result1 !== null) {
                   result0 = [result0, result1];
                 } else {
                   result0 = null;
                   pos = pos0;
                 }
               } else {
                 result0 = null;
                 pos = pos0;
               }
 
               if (result0 === null) {
                 result0 = parse_DIGIT();
               }
             }
           }
         }
 
         return result0;
       }
 
       function parse_port() {
         var result0, result1, result2, result3, result4;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_DIGIT();
         result0 = result0 !== null ? result0 : "";
 
         if (result0 !== null) {
           result1 = parse_DIGIT();
           result1 = result1 !== null ? result1 : "";
 
           if (result1 !== null) {
             result2 = parse_DIGIT();
             result2 = result2 !== null ? result2 : "";
 
             if (result2 !== null) {
               result3 = parse_DIGIT();
               result3 = result3 !== null ? result3 : "";
 
               if (result3 !== null) {
                 result4 = parse_DIGIT();
                 result4 = result4 !== null ? result4 : "";
 
                 if (result4 !== null) {
                   result0 = [result0, result1, result2, result3, result4];
                 } else {
                   result0 = null;
                   pos = pos1;
                 }
               } else {
                 result0 = null;
                 pos = pos1;
               }
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset, port) {
             port = parseInt(port.join(''));
             data.port = port;
             return port;
           }(pos0, result0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_uri_parameters() {
         var result0, result1, result2;
         var pos0;
         result0 = [];
         pos0 = pos;
 
         if (input.charCodeAt(pos) === 59) {
           result1 = ";";
           pos++;
         } else {
           result1 = null;
 
           if (reportFailures === 0) {
             matchFailed("\";\"");
           }
         }
 
         if (result1 !== null) {
           result2 = parse_uri_parameter();
 
           if (result2 !== null) {
             result1 = [result1, result2];
           } else {
             result1 = null;
             pos = pos0;
           }
         } else {
           result1 = null;
           pos = pos0;
         }
 
         while (result1 !== null) {
           result0.push(result1);
           pos0 = pos;
 
           if (input.charCodeAt(pos) === 59) {
             result1 = ";";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\";\"");
             }
           }
 
           if (result1 !== null) {
             result2 = parse_uri_parameter();
 
             if (result2 !== null) {
               result1 = [result1, result2];
             } else {
               result1 = null;
               pos = pos0;
             }
           } else {
             result1 = null;
             pos = pos0;
           }
         }
 
         return result0;
       }
 
       function parse_uri_parameter() {
         var result0;
         result0 = parse_transport_param();
 
         if (result0 === null) {
           result0 = parse_user_param();
 
           if (result0 === null) {
             result0 = parse_method_param();
 
             if (result0 === null) {
               result0 = parse_ttl_param();
 
               if (result0 === null) {
                 result0 = parse_maddr_param();
 
                 if (result0 === null) {
                   result0 = parse_lr_param();
 
                   if (result0 === null) {
                     result0 = parse_other_param();
                   }
                 }
               }
             }
           }
         }
 
         return result0;
       }
 
       function parse_transport_param() {
         var result0, result1;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
 
         if (input.substr(pos, 10).toLowerCase() === "transport=") {
           result0 = input.substr(pos, 10);
           pos += 10;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"transport=\"");
           }
         }
 
         if (result0 !== null) {
           if (input.substr(pos, 3).toLowerCase() === "udp") {
             result1 = input.substr(pos, 3);
             pos += 3;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"udp\"");
             }
           }
 
           if (result1 === null) {
             if (input.substr(pos, 3).toLowerCase() === "tcp") {
               result1 = input.substr(pos, 3);
               pos += 3;
             } else {
               result1 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\"tcp\"");
               }
             }
 
             if (result1 === null) {
               if (input.substr(pos, 4).toLowerCase() === "sctp") {
                 result1 = input.substr(pos, 4);
                 pos += 4;
               } else {
                 result1 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\"sctp\"");
                 }
               }
 
               if (result1 === null) {
                 if (input.substr(pos, 3).toLowerCase() === "tls") {
                   result1 = input.substr(pos, 3);
                   pos += 3;
                 } else {
                   result1 = null;
 
                   if (reportFailures === 0) {
                     matchFailed("\"tls\"");
                   }
                 }
 
                 if (result1 === null) {
                   result1 = parse_token();
                 }
               }
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset, transport) {
             if (!data.uri_params) data.uri_params = {};
             data.uri_params['transport'] = transport.toLowerCase();
           }(pos0, result0[1]);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_user_param() {
         var result0, result1;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
 
         if (input.substr(pos, 5).toLowerCase() === "user=") {
           result0 = input.substr(pos, 5);
           pos += 5;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"user=\"");
           }
         }
 
         if (result0 !== null) {
           if (input.substr(pos, 5).toLowerCase() === "phone") {
             result1 = input.substr(pos, 5);
             pos += 5;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"phone\"");
             }
           }
 
           if (result1 === null) {
             if (input.substr(pos, 2).toLowerCase() === "ip") {
               result1 = input.substr(pos, 2);
               pos += 2;
             } else {
               result1 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\"ip\"");
               }
             }
 
             if (result1 === null) {
               result1 = parse_token();
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset, user) {
             if (!data.uri_params) data.uri_params = {};
             data.uri_params['user'] = user.toLowerCase();
           }(pos0, result0[1]);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_method_param() {
         var result0, result1;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
 
         if (input.substr(pos, 7).toLowerCase() === "method=") {
           result0 = input.substr(pos, 7);
           pos += 7;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"method=\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_Method();
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset, method) {
             if (!data.uri_params) data.uri_params = {};
             data.uri_params['method'] = method;
           }(pos0, result0[1]);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_ttl_param() {
         var result0, result1;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
 
         if (input.substr(pos, 4).toLowerCase() === "ttl=") {
           result0 = input.substr(pos, 4);
           pos += 4;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"ttl=\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_ttl();
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset, ttl) {
             if (!data.params) data.params = {};
             data.params['ttl'] = ttl;
           }(pos0, result0[1]);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_maddr_param() {
         var result0, result1;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
 
         if (input.substr(pos, 6).toLowerCase() === "maddr=") {
           result0 = input.substr(pos, 6);
           pos += 6;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"maddr=\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_host();
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset, maddr) {
             if (!data.uri_params) data.uri_params = {};
             data.uri_params['maddr'] = maddr;
           }(pos0, result0[1]);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_lr_param() {
         var result0, result1, result2;
         var pos0, pos1, pos2;
         pos0 = pos;
         pos1 = pos;
 
         if (input.substr(pos, 2).toLowerCase() === "lr") {
           result0 = input.substr(pos, 2);
           pos += 2;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"lr\"");
           }
         }
 
         if (result0 !== null) {
           pos2 = pos;
 
           if (input.charCodeAt(pos) === 61) {
             result1 = "=";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"=\"");
             }
           }
 
           if (result1 !== null) {
             result2 = parse_token();
 
             if (result2 !== null) {
               result1 = [result1, result2];
             } else {
               result1 = null;
               pos = pos2;
             }
           } else {
             result1 = null;
             pos = pos2;
           }
 
           result1 = result1 !== null ? result1 : "";
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             if (!data.uri_params) data.uri_params = {};
             data.uri_params['lr'] = undefined;
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_other_param() {
         var result0, result1, result2;
         var pos0, pos1, pos2;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_pname();
 
         if (result0 !== null) {
           pos2 = pos;
 
           if (input.charCodeAt(pos) === 61) {
             result1 = "=";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"=\"");
             }
           }
 
           if (result1 !== null) {
             result2 = parse_pvalue();
 
             if (result2 !== null) {
               result1 = [result1, result2];
             } else {
               result1 = null;
               pos = pos2;
             }
           } else {
             result1 = null;
             pos = pos2;
           }
 
           result1 = result1 !== null ? result1 : "";
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset, param, value) {
             if (!data.uri_params) data.uri_params = {};
 
             if (typeof value === 'undefined') {
               value = undefined;
             } else {
               value = value[1];
             }
 
             data.uri_params[param.toLowerCase()] = value;
           }(pos0, result0[0], result0[1]);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_pname() {
         var result0, result1;
         var pos0;
         pos0 = pos;
         result1 = parse_paramchar();
 
         if (result1 !== null) {
           result0 = [];
 
           while (result1 !== null) {
             result0.push(result1);
             result1 = parse_paramchar();
           }
         } else {
           result0 = null;
         }
 
         if (result0 !== null) {
           result0 = function (offset, pname) {
             return pname.join('');
           }(pos0, result0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_pvalue() {
         var result0, result1;
         var pos0;
         pos0 = pos;
         result1 = parse_paramchar();
 
         if (result1 !== null) {
           result0 = [];
 
           while (result1 !== null) {
             result0.push(result1);
             result1 = parse_paramchar();
           }
         } else {
           result0 = null;
         }
 
         if (result0 !== null) {
           result0 = function (offset, pvalue) {
             return pvalue.join('');
           }(pos0, result0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_paramchar() {
         var result0;
         result0 = parse_param_unreserved();
 
         if (result0 === null) {
           result0 = parse_unreserved();
 
           if (result0 === null) {
             result0 = parse_escaped();
           }
         }
 
         return result0;
       }
 
       function parse_param_unreserved() {
         var result0;
 
         if (input.charCodeAt(pos) === 91) {
           result0 = "[";
           pos++;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"[\"");
           }
         }
 
         if (result0 === null) {
           if (input.charCodeAt(pos) === 93) {
             result0 = "]";
             pos++;
           } else {
             result0 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"]\"");
             }
           }
 
           if (result0 === null) {
             if (input.charCodeAt(pos) === 47) {
               result0 = "/";
               pos++;
             } else {
               result0 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\"/\"");
               }
             }
 
             if (result0 === null) {
               if (input.charCodeAt(pos) === 58) {
                 result0 = ":";
                 pos++;
               } else {
                 result0 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\":\"");
                 }
               }
 
               if (result0 === null) {
                 if (input.charCodeAt(pos) === 38) {
                   result0 = "&";
                   pos++;
                 } else {
                   result0 = null;
 
                   if (reportFailures === 0) {
                     matchFailed("\"&\"");
                   }
                 }
 
                 if (result0 === null) {
                   if (input.charCodeAt(pos) === 43) {
                     result0 = "+";
                     pos++;
                   } else {
                     result0 = null;
 
                     if (reportFailures === 0) {
                       matchFailed("\"+\"");
                     }
                   }
 
                   if (result0 === null) {
                     if (input.charCodeAt(pos) === 36) {
                       result0 = "$";
                       pos++;
                     } else {
                       result0 = null;
 
                       if (reportFailures === 0) {
                         matchFailed("\"$\"");
                       }
                     }
                   }
                 }
               }
             }
           }
         }
 
         return result0;
       }
 
       function parse_headers() {
         var result0, result1, result2, result3, result4;
         var pos0, pos1;
         pos0 = pos;
 
         if (input.charCodeAt(pos) === 63) {
           result0 = "?";
           pos++;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"?\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_header();
 
           if (result1 !== null) {
             result2 = [];
             pos1 = pos;
 
             if (input.charCodeAt(pos) === 38) {
               result3 = "&";
               pos++;
             } else {
               result3 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\"&\"");
               }
             }
 
             if (result3 !== null) {
               result4 = parse_header();
 
               if (result4 !== null) {
                 result3 = [result3, result4];
               } else {
                 result3 = null;
                 pos = pos1;
               }
             } else {
               result3 = null;
               pos = pos1;
             }
 
             while (result3 !== null) {
               result2.push(result3);
               pos1 = pos;
 
               if (input.charCodeAt(pos) === 38) {
                 result3 = "&";
                 pos++;
               } else {
                 result3 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\"&\"");
                 }
               }
 
               if (result3 !== null) {
                 result4 = parse_header();
 
                 if (result4 !== null) {
                   result3 = [result3, result4];
                 } else {
                   result3 = null;
                   pos = pos1;
                 }
               } else {
                 result3 = null;
                 pos = pos1;
               }
             }
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos0;
             }
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_header() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_hname();
 
         if (result0 !== null) {
           if (input.charCodeAt(pos) === 61) {
             result1 = "=";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"=\"");
             }
           }
 
           if (result1 !== null) {
             result2 = parse_hvalue();
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset, hname, hvalue) {
             hname = hname.join('').toLowerCase();
             hvalue = hvalue.join('');
             if (!data.uri_headers) data.uri_headers = {};
 
             if (!data.uri_headers[hname]) {
               data.uri_headers[hname] = [hvalue];
             } else {
               data.uri_headers[hname].push(hvalue);
             }
           }(pos0, result0[0], result0[2]);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_hname() {
         var result0, result1;
         result1 = parse_hnv_unreserved();
 
         if (result1 === null) {
           result1 = parse_unreserved();
 
           if (result1 === null) {
             result1 = parse_escaped();
           }
         }
 
         if (result1 !== null) {
           result0 = [];
 
           while (result1 !== null) {
             result0.push(result1);
             result1 = parse_hnv_unreserved();
 
             if (result1 === null) {
               result1 = parse_unreserved();
 
               if (result1 === null) {
                 result1 = parse_escaped();
               }
             }
           }
         } else {
           result0 = null;
         }
 
         return result0;
       }
 
       function parse_hvalue() {
         var result0, result1;
         result0 = [];
         result1 = parse_hnv_unreserved();
 
         if (result1 === null) {
           result1 = parse_unreserved();
 
           if (result1 === null) {
             result1 = parse_escaped();
           }
         }
 
         while (result1 !== null) {
           result0.push(result1);
           result1 = parse_hnv_unreserved();
 
           if (result1 === null) {
             result1 = parse_unreserved();
 
             if (result1 === null) {
               result1 = parse_escaped();
             }
           }
         }
 
         return result0;
       }
 
       function parse_hnv_unreserved() {
         var result0;
 
         if (input.charCodeAt(pos) === 91) {
           result0 = "[";
           pos++;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"[\"");
           }
         }
 
         if (result0 === null) {
           if (input.charCodeAt(pos) === 93) {
             result0 = "]";
             pos++;
           } else {
             result0 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"]\"");
             }
           }
 
           if (result0 === null) {
             if (input.charCodeAt(pos) === 47) {
               result0 = "/";
               pos++;
             } else {
               result0 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\"/\"");
               }
             }
 
             if (result0 === null) {
               if (input.charCodeAt(pos) === 63) {
                 result0 = "?";
                 pos++;
               } else {
                 result0 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\"?\"");
                 }
               }
 
               if (result0 === null) {
                 if (input.charCodeAt(pos) === 58) {
                   result0 = ":";
                   pos++;
                 } else {
                   result0 = null;
 
                   if (reportFailures === 0) {
                     matchFailed("\":\"");
                   }
                 }
 
                 if (result0 === null) {
                   if (input.charCodeAt(pos) === 43) {
                     result0 = "+";
                     pos++;
                   } else {
                     result0 = null;
 
                     if (reportFailures === 0) {
                       matchFailed("\"+\"");
                     }
                   }
 
                   if (result0 === null) {
                     if (input.charCodeAt(pos) === 36) {
                       result0 = "$";
                       pos++;
                     } else {
                       result0 = null;
 
                       if (reportFailures === 0) {
                         matchFailed("\"$\"");
                       }
                     }
                   }
                 }
               }
             }
           }
         }
 
         return result0;
       }
 
       function parse_Request_Response() {
         var result0;
         result0 = parse_Status_Line();
 
         if (result0 === null) {
           result0 = parse_Request_Line();
         }
 
         return result0;
       }
 
       function parse_Request_Line() {
         var result0, result1, result2, result3, result4;
         var pos0;
         pos0 = pos;
         result0 = parse_Method();
 
         if (result0 !== null) {
           result1 = parse_SP();
 
           if (result1 !== null) {
             result2 = parse_Request_URI();
 
             if (result2 !== null) {
               result3 = parse_SP();
 
               if (result3 !== null) {
                 result4 = parse_SIP_Version();
 
                 if (result4 !== null) {
                   result0 = [result0, result1, result2, result3, result4];
                 } else {
                   result0 = null;
                   pos = pos0;
                 }
               } else {
                 result0 = null;
                 pos = pos0;
               }
             } else {
               result0 = null;
               pos = pos0;
             }
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_Request_URI() {
         var result0;
         result0 = parse_SIP_URI();
 
         if (result0 === null) {
           result0 = parse_absoluteURI();
         }
 
         return result0;
       }
 
       function parse_absoluteURI() {
         var result0, result1, result2;
         var pos0;
         pos0 = pos;
         result0 = parse_scheme();
 
         if (result0 !== null) {
           if (input.charCodeAt(pos) === 58) {
             result1 = ":";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\":\"");
             }
           }
 
           if (result1 !== null) {
             result2 = parse_hier_part();
 
             if (result2 === null) {
               result2 = parse_opaque_part();
             }
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos0;
             }
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_hier_part() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
         result0 = parse_net_path();
 
         if (result0 === null) {
           result0 = parse_abs_path();
         }
 
         if (result0 !== null) {
           pos1 = pos;
 
           if (input.charCodeAt(pos) === 63) {
             result1 = "?";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"?\"");
             }
           }
 
           if (result1 !== null) {
             result2 = parse_query();
 
             if (result2 !== null) {
               result1 = [result1, result2];
             } else {
               result1 = null;
               pos = pos1;
             }
           } else {
             result1 = null;
             pos = pos1;
           }
 
           result1 = result1 !== null ? result1 : "";
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_net_path() {
         var result0, result1, result2;
         var pos0;
         pos0 = pos;
 
         if (input.substr(pos, 2) === "//") {
           result0 = "//";
           pos += 2;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"//\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_authority();
 
           if (result1 !== null) {
             result2 = parse_abs_path();
             result2 = result2 !== null ? result2 : "";
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos0;
             }
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_abs_path() {
         var result0, result1;
         var pos0;
         pos0 = pos;
 
         if (input.charCodeAt(pos) === 47) {
           result0 = "/";
           pos++;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"/\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_path_segments();
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_opaque_part() {
         var result0, result1, result2;
         var pos0;
         pos0 = pos;
         result0 = parse_uric_no_slash();
 
         if (result0 !== null) {
           result1 = [];
           result2 = parse_uric();
 
           while (result2 !== null) {
             result1.push(result2);
             result2 = parse_uric();
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_uric() {
         var result0;
         result0 = parse_reserved();
 
         if (result0 === null) {
           result0 = parse_unreserved();
 
           if (result0 === null) {
             result0 = parse_escaped();
           }
         }
 
         return result0;
       }
 
       function parse_uric_no_slash() {
         var result0;
         result0 = parse_unreserved();
 
         if (result0 === null) {
           result0 = parse_escaped();
 
           if (result0 === null) {
             if (input.charCodeAt(pos) === 59) {
               result0 = ";";
               pos++;
             } else {
               result0 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\";\"");
               }
             }
 
             if (result0 === null) {
               if (input.charCodeAt(pos) === 63) {
                 result0 = "?";
                 pos++;
               } else {
                 result0 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\"?\"");
                 }
               }
 
               if (result0 === null) {
                 if (input.charCodeAt(pos) === 58) {
                   result0 = ":";
                   pos++;
                 } else {
                   result0 = null;
 
                   if (reportFailures === 0) {
                     matchFailed("\":\"");
                   }
                 }
 
                 if (result0 === null) {
                   if (input.charCodeAt(pos) === 64) {
                     result0 = "@";
                     pos++;
                   } else {
                     result0 = null;
 
                     if (reportFailures === 0) {
                       matchFailed("\"@\"");
                     }
                   }
 
                   if (result0 === null) {
                     if (input.charCodeAt(pos) === 38) {
                       result0 = "&";
                       pos++;
                     } else {
                       result0 = null;
 
                       if (reportFailures === 0) {
                         matchFailed("\"&\"");
                       }
                     }
 
                     if (result0 === null) {
                       if (input.charCodeAt(pos) === 61) {
                         result0 = "=";
                         pos++;
                       } else {
                         result0 = null;
 
                         if (reportFailures === 0) {
                           matchFailed("\"=\"");
                         }
                       }
 
                       if (result0 === null) {
                         if (input.charCodeAt(pos) === 43) {
                           result0 = "+";
                           pos++;
                         } else {
                           result0 = null;
 
                           if (reportFailures === 0) {
                             matchFailed("\"+\"");
                           }
                         }
 
                         if (result0 === null) {
                           if (input.charCodeAt(pos) === 36) {
                             result0 = "$";
                             pos++;
                           } else {
                             result0 = null;
 
                             if (reportFailures === 0) {
                               matchFailed("\"$\"");
                             }
                           }
 
                           if (result0 === null) {
                             if (input.charCodeAt(pos) === 44) {
                               result0 = ",";
                               pos++;
                             } else {
                               result0 = null;
 
                               if (reportFailures === 0) {
                                 matchFailed("\",\"");
                               }
                             }
                           }
                         }
                       }
                     }
                   }
                 }
               }
             }
           }
         }
 
         return result0;
       }
 
       function parse_path_segments() {
         var result0, result1, result2, result3;
         var pos0, pos1;
         pos0 = pos;
         result0 = parse_segment();
 
         if (result0 !== null) {
           result1 = [];
           pos1 = pos;
 
           if (input.charCodeAt(pos) === 47) {
             result2 = "/";
             pos++;
           } else {
             result2 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"/\"");
             }
           }
 
           if (result2 !== null) {
             result3 = parse_segment();
 
             if (result3 !== null) {
               result2 = [result2, result3];
             } else {
               result2 = null;
               pos = pos1;
             }
           } else {
             result2 = null;
             pos = pos1;
           }
 
           while (result2 !== null) {
             result1.push(result2);
             pos1 = pos;
 
             if (input.charCodeAt(pos) === 47) {
               result2 = "/";
               pos++;
             } else {
               result2 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\"/\"");
               }
             }
 
             if (result2 !== null) {
               result3 = parse_segment();
 
               if (result3 !== null) {
                 result2 = [result2, result3];
               } else {
                 result2 = null;
                 pos = pos1;
               }
             } else {
               result2 = null;
               pos = pos1;
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_segment() {
         var result0, result1, result2, result3;
         var pos0, pos1;
         pos0 = pos;
         result0 = [];
         result1 = parse_pchar();
 
         while (result1 !== null) {
           result0.push(result1);
           result1 = parse_pchar();
         }
 
         if (result0 !== null) {
           result1 = [];
           pos1 = pos;
 
           if (input.charCodeAt(pos) === 59) {
             result2 = ";";
             pos++;
           } else {
             result2 = null;
 
             if (reportFailures === 0) {
               matchFailed("\";\"");
             }
           }
 
           if (result2 !== null) {
             result3 = parse_param();
 
             if (result3 !== null) {
               result2 = [result2, result3];
             } else {
               result2 = null;
               pos = pos1;
             }
           } else {
             result2 = null;
             pos = pos1;
           }
 
           while (result2 !== null) {
             result1.push(result2);
             pos1 = pos;
 
             if (input.charCodeAt(pos) === 59) {
               result2 = ";";
               pos++;
             } else {
               result2 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\";\"");
               }
             }
 
             if (result2 !== null) {
               result3 = parse_param();
 
               if (result3 !== null) {
                 result2 = [result2, result3];
               } else {
                 result2 = null;
                 pos = pos1;
               }
             } else {
               result2 = null;
               pos = pos1;
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_param() {
         var result0, result1;
         result0 = [];
         result1 = parse_pchar();
 
         while (result1 !== null) {
           result0.push(result1);
           result1 = parse_pchar();
         }
 
         return result0;
       }
 
       function parse_pchar() {
         var result0;
         result0 = parse_unreserved();
 
         if (result0 === null) {
           result0 = parse_escaped();
 
           if (result0 === null) {
             if (input.charCodeAt(pos) === 58) {
               result0 = ":";
               pos++;
             } else {
               result0 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\":\"");
               }
             }
 
             if (result0 === null) {
               if (input.charCodeAt(pos) === 64) {
                 result0 = "@";
                 pos++;
               } else {
                 result0 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\"@\"");
                 }
               }
 
               if (result0 === null) {
                 if (input.charCodeAt(pos) === 38) {
                   result0 = "&";
                   pos++;
                 } else {
                   result0 = null;
 
                   if (reportFailures === 0) {
                     matchFailed("\"&\"");
                   }
                 }
 
                 if (result0 === null) {
                   if (input.charCodeAt(pos) === 61) {
                     result0 = "=";
                     pos++;
                   } else {
                     result0 = null;
 
                     if (reportFailures === 0) {
                       matchFailed("\"=\"");
                     }
                   }
 
                   if (result0 === null) {
                     if (input.charCodeAt(pos) === 43) {
                       result0 = "+";
                       pos++;
                     } else {
                       result0 = null;
 
                       if (reportFailures === 0) {
                         matchFailed("\"+\"");
                       }
                     }
 
                     if (result0 === null) {
                       if (input.charCodeAt(pos) === 36) {
                         result0 = "$";
                         pos++;
                       } else {
                         result0 = null;
 
                         if (reportFailures === 0) {
                           matchFailed("\"$\"");
                         }
                       }
 
                       if (result0 === null) {
                         if (input.charCodeAt(pos) === 44) {
                           result0 = ",";
                           pos++;
                         } else {
                           result0 = null;
 
                           if (reportFailures === 0) {
                             matchFailed("\",\"");
                           }
                         }
                       }
                     }
                   }
                 }
               }
             }
           }
         }
 
         return result0;
       }
 
       function parse_scheme() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_ALPHA();
 
         if (result0 !== null) {
           result1 = [];
           result2 = parse_ALPHA();
 
           if (result2 === null) {
             result2 = parse_DIGIT();
 
             if (result2 === null) {
               if (input.charCodeAt(pos) === 43) {
                 result2 = "+";
                 pos++;
               } else {
                 result2 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\"+\"");
                 }
               }
 
               if (result2 === null) {
                 if (input.charCodeAt(pos) === 45) {
                   result2 = "-";
                   pos++;
                 } else {
                   result2 = null;
 
                   if (reportFailures === 0) {
                     matchFailed("\"-\"");
                   }
                 }
 
                 if (result2 === null) {
                   if (input.charCodeAt(pos) === 46) {
                     result2 = ".";
                     pos++;
                   } else {
                     result2 = null;
 
                     if (reportFailures === 0) {
                       matchFailed("\".\"");
                     }
                   }
                 }
               }
             }
           }
 
           while (result2 !== null) {
             result1.push(result2);
             result2 = parse_ALPHA();
 
             if (result2 === null) {
               result2 = parse_DIGIT();
 
               if (result2 === null) {
                 if (input.charCodeAt(pos) === 43) {
                   result2 = "+";
                   pos++;
                 } else {
                   result2 = null;
 
                   if (reportFailures === 0) {
                     matchFailed("\"+\"");
                   }
                 }
 
                 if (result2 === null) {
                   if (input.charCodeAt(pos) === 45) {
                     result2 = "-";
                     pos++;
                   } else {
                     result2 = null;
 
                     if (reportFailures === 0) {
                       matchFailed("\"-\"");
                     }
                   }
 
                   if (result2 === null) {
                     if (input.charCodeAt(pos) === 46) {
                       result2 = ".";
                       pos++;
                     } else {
                       result2 = null;
 
                       if (reportFailures === 0) {
                         matchFailed("\".\"");
                       }
                     }
                   }
                 }
               }
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             data.scheme = input.substring(pos, offset);
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_authority() {
         var result0;
         result0 = parse_srvr();
 
         if (result0 === null) {
           result0 = parse_reg_name();
         }
 
         return result0;
       }
 
       function parse_srvr() {
         var result0, result1;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_userinfo();
 
         if (result0 !== null) {
           if (input.charCodeAt(pos) === 64) {
             result1 = "@";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"@\"");
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         result0 = result0 !== null ? result0 : "";
 
         if (result0 !== null) {
           result1 = parse_hostport();
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         result0 = result0 !== null ? result0 : "";
         return result0;
       }
 
       function parse_reg_name() {
         var result0, result1;
         result1 = parse_unreserved();
 
         if (result1 === null) {
           result1 = parse_escaped();
 
           if (result1 === null) {
             if (input.charCodeAt(pos) === 36) {
               result1 = "$";
               pos++;
             } else {
               result1 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\"$\"");
               }
             }
 
             if (result1 === null) {
               if (input.charCodeAt(pos) === 44) {
                 result1 = ",";
                 pos++;
               } else {
                 result1 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\",\"");
                 }
               }
 
               if (result1 === null) {
                 if (input.charCodeAt(pos) === 59) {
                   result1 = ";";
                   pos++;
                 } else {
                   result1 = null;
 
                   if (reportFailures === 0) {
                     matchFailed("\";\"");
                   }
                 }
 
                 if (result1 === null) {
                   if (input.charCodeAt(pos) === 58) {
                     result1 = ":";
                     pos++;
                   } else {
                     result1 = null;
 
                     if (reportFailures === 0) {
                       matchFailed("\":\"");
                     }
                   }
 
                   if (result1 === null) {
                     if (input.charCodeAt(pos) === 64) {
                       result1 = "@";
                       pos++;
                     } else {
                       result1 = null;
 
                       if (reportFailures === 0) {
                         matchFailed("\"@\"");
                       }
                     }
 
                     if (result1 === null) {
                       if (input.charCodeAt(pos) === 38) {
                         result1 = "&";
                         pos++;
                       } else {
                         result1 = null;
 
                         if (reportFailures === 0) {
                           matchFailed("\"&\"");
                         }
                       }
 
                       if (result1 === null) {
                         if (input.charCodeAt(pos) === 61) {
                           result1 = "=";
                           pos++;
                         } else {
                           result1 = null;
 
                           if (reportFailures === 0) {
                             matchFailed("\"=\"");
                           }
                         }
 
                         if (result1 === null) {
                           if (input.charCodeAt(pos) === 43) {
                             result1 = "+";
                             pos++;
                           } else {
                             result1 = null;
 
                             if (reportFailures === 0) {
                               matchFailed("\"+\"");
                             }
                           }
                         }
                       }
                     }
                   }
                 }
               }
             }
           }
         }
 
         if (result1 !== null) {
           result0 = [];
 
           while (result1 !== null) {
             result0.push(result1);
             result1 = parse_unreserved();
 
             if (result1 === null) {
               result1 = parse_escaped();
 
               if (result1 === null) {
                 if (input.charCodeAt(pos) === 36) {
                   result1 = "$";
                   pos++;
                 } else {
                   result1 = null;
 
                   if (reportFailures === 0) {
                     matchFailed("\"$\"");
                   }
                 }
 
                 if (result1 === null) {
                   if (input.charCodeAt(pos) === 44) {
                     result1 = ",";
                     pos++;
                   } else {
                     result1 = null;
 
                     if (reportFailures === 0) {
                       matchFailed("\",\"");
                     }
                   }
 
                   if (result1 === null) {
                     if (input.charCodeAt(pos) === 59) {
                       result1 = ";";
                       pos++;
                     } else {
                       result1 = null;
 
                       if (reportFailures === 0) {
                         matchFailed("\";\"");
                       }
                     }
 
                     if (result1 === null) {
                       if (input.charCodeAt(pos) === 58) {
                         result1 = ":";
                         pos++;
                       } else {
                         result1 = null;
 
                         if (reportFailures === 0) {
                           matchFailed("\":\"");
                         }
                       }
 
                       if (result1 === null) {
                         if (input.charCodeAt(pos) === 64) {
                           result1 = "@";
                           pos++;
                         } else {
                           result1 = null;
 
                           if (reportFailures === 0) {
                             matchFailed("\"@\"");
                           }
                         }
 
                         if (result1 === null) {
                           if (input.charCodeAt(pos) === 38) {
                             result1 = "&";
                             pos++;
                           } else {
                             result1 = null;
 
                             if (reportFailures === 0) {
                               matchFailed("\"&\"");
                             }
                           }
 
                           if (result1 === null) {
                             if (input.charCodeAt(pos) === 61) {
                               result1 = "=";
                               pos++;
                             } else {
                               result1 = null;
 
                               if (reportFailures === 0) {
                                 matchFailed("\"=\"");
                               }
                             }
 
                             if (result1 === null) {
                               if (input.charCodeAt(pos) === 43) {
                                 result1 = "+";
                                 pos++;
                               } else {
                                 result1 = null;
 
                                 if (reportFailures === 0) {
                                   matchFailed("\"+\"");
                                 }
                               }
                             }
                           }
                         }
                       }
                     }
                   }
                 }
               }
             }
           }
         } else {
           result0 = null;
         }
 
         return result0;
       }
 
       function parse_query() {
         var result0, result1;
         result0 = [];
         result1 = parse_uric();
 
         while (result1 !== null) {
           result0.push(result1);
           result1 = parse_uric();
         }
 
         return result0;
       }
 
       function parse_SIP_Version() {
         var result0, result1, result2, result3, result4, result5;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
 
         if (input.substr(pos, 3).toLowerCase() === "sip") {
           result0 = input.substr(pos, 3);
           pos += 3;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"SIP\"");
           }
         }
 
         if (result0 !== null) {
           if (input.charCodeAt(pos) === 47) {
             result1 = "/";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"/\"");
             }
           }
 
           if (result1 !== null) {
             result3 = parse_DIGIT();
 
             if (result3 !== null) {
               result2 = [];
 
               while (result3 !== null) {
                 result2.push(result3);
                 result3 = parse_DIGIT();
               }
             } else {
               result2 = null;
             }
 
             if (result2 !== null) {
               if (input.charCodeAt(pos) === 46) {
                 result3 = ".";
                 pos++;
               } else {
                 result3 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\".\"");
                 }
               }
 
               if (result3 !== null) {
                 result5 = parse_DIGIT();
 
                 if (result5 !== null) {
                   result4 = [];
 
                   while (result5 !== null) {
                     result4.push(result5);
                     result5 = parse_DIGIT();
                   }
                 } else {
                   result4 = null;
                 }
 
                 if (result4 !== null) {
                   result0 = [result0, result1, result2, result3, result4];
                 } else {
                   result0 = null;
                   pos = pos1;
                 }
               } else {
                 result0 = null;
                 pos = pos1;
               }
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             data.sip_version = input.substring(pos, offset);
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_INVITEm() {
         var result0;
 
         if (input.substr(pos, 6) === "INVITE") {
           result0 = "INVITE";
           pos += 6;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"INVITE\"");
           }
         }
 
         return result0;
       }
 
       function parse_ACKm() {
         var result0;
 
         if (input.substr(pos, 3) === "ACK") {
           result0 = "ACK";
           pos += 3;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"ACK\"");
           }
         }
 
         return result0;
       }
 
       function parse_OPTIONSm() {
         var result0;
 
         if (input.substr(pos, 7) === "OPTIONS") {
           result0 = "OPTIONS";
           pos += 7;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"OPTIONS\"");
           }
         }
 
         return result0;
       }
 
       function parse_BYEm() {
         var result0;
 
         if (input.substr(pos, 3) === "BYE") {
           result0 = "BYE";
           pos += 3;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"BYE\"");
           }
         }
 
         return result0;
       }
 
       function parse_CANCELm() {
         var result0;
 
         if (input.substr(pos, 6) === "CANCEL") {
           result0 = "CANCEL";
           pos += 6;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"CANCEL\"");
           }
         }
 
         return result0;
       }
 
       function parse_REGISTERm() {
         var result0;
 
         if (input.substr(pos, 8) === "REGISTER") {
           result0 = "REGISTER";
           pos += 8;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"REGISTER\"");
           }
         }
 
         return result0;
       }
 
       function parse_SUBSCRIBEm() {
         var result0;
 
         if (input.substr(pos, 9) === "SUBSCRIBE") {
           result0 = "SUBSCRIBE";
           pos += 9;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"SUBSCRIBE\"");
           }
         }
 
         return result0;
       }
 
       function parse_NOTIFYm() {
         var result0;
 
         if (input.substr(pos, 6) === "NOTIFY") {
           result0 = "NOTIFY";
           pos += 6;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"NOTIFY\"");
           }
         }
 
         return result0;
       }
 
       function parse_REFERm() {
         var result0;
 
         if (input.substr(pos, 5) === "REFER") {
           result0 = "REFER";
           pos += 5;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"REFER\"");
           }
         }
 
         return result0;
       }
 
       function parse_Method() {
         var result0;
         var pos0;
         pos0 = pos;
         result0 = parse_INVITEm();
 
         if (result0 === null) {
           result0 = parse_ACKm();
 
           if (result0 === null) {
             result0 = parse_OPTIONSm();
 
             if (result0 === null) {
               result0 = parse_BYEm();
 
               if (result0 === null) {
                 result0 = parse_CANCELm();
 
                 if (result0 === null) {
                   result0 = parse_REGISTERm();
 
                   if (result0 === null) {
                     result0 = parse_SUBSCRIBEm();
 
                     if (result0 === null) {
                       result0 = parse_NOTIFYm();
 
                       if (result0 === null) {
                         result0 = parse_REFERm();
 
                         if (result0 === null) {
                           result0 = parse_token();
                         }
                       }
                     }
                   }
                 }
               }
             }
           }
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             data.method = input.substring(pos, offset);
             return data.method;
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_Status_Line() {
         var result0, result1, result2, result3, result4;
         var pos0;
         pos0 = pos;
         result0 = parse_SIP_Version();
 
         if (result0 !== null) {
           result1 = parse_SP();
 
           if (result1 !== null) {
             result2 = parse_Status_Code();
 
             if (result2 !== null) {
               result3 = parse_SP();
 
               if (result3 !== null) {
                 result4 = parse_Reason_Phrase();
 
                 if (result4 !== null) {
                   result0 = [result0, result1, result2, result3, result4];
                 } else {
                   result0 = null;
                   pos = pos0;
                 }
               } else {
                 result0 = null;
                 pos = pos0;
               }
             } else {
               result0 = null;
               pos = pos0;
             }
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_Status_Code() {
         var result0;
         var pos0;
         pos0 = pos;
         result0 = parse_extension_code();
 
         if (result0 !== null) {
           result0 = function (offset, status_code) {
             data.status_code = parseInt(status_code.join(''));
           }(pos0, result0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_extension_code() {
         var result0, result1, result2;
         var pos0;
         pos0 = pos;
         result0 = parse_DIGIT();
 
         if (result0 !== null) {
           result1 = parse_DIGIT();
 
           if (result1 !== null) {
             result2 = parse_DIGIT();
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos0;
             }
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_Reason_Phrase() {
         var result0, result1;
         var pos0;
         pos0 = pos;
         result0 = [];
         result1 = parse_reserved();
 
         if (result1 === null) {
           result1 = parse_unreserved();
 
           if (result1 === null) {
             result1 = parse_escaped();
 
             if (result1 === null) {
               result1 = parse_UTF8_NONASCII();
 
               if (result1 === null) {
                 result1 = parse_UTF8_CONT();
 
                 if (result1 === null) {
                   result1 = parse_SP();
 
                   if (result1 === null) {
                     result1 = parse_HTAB();
                   }
                 }
               }
             }
           }
         }
 
         while (result1 !== null) {
           result0.push(result1);
           result1 = parse_reserved();
 
           if (result1 === null) {
             result1 = parse_unreserved();
 
             if (result1 === null) {
               result1 = parse_escaped();
 
               if (result1 === null) {
                 result1 = parse_UTF8_NONASCII();
 
                 if (result1 === null) {
                   result1 = parse_UTF8_CONT();
 
                   if (result1 === null) {
                     result1 = parse_SP();
 
                     if (result1 === null) {
                       result1 = parse_HTAB();
                     }
                   }
                 }
               }
             }
           }
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             data.reason_phrase = input.substring(pos, offset);
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_Allow_Events() {
         var result0, result1, result2, result3;
         var pos0, pos1;
         pos0 = pos;
         result0 = parse_event_type();
 
         if (result0 !== null) {
           result1 = [];
           pos1 = pos;
           result2 = parse_COMMA();
 
           if (result2 !== null) {
             result3 = parse_event_type();
 
             if (result3 !== null) {
               result2 = [result2, result3];
             } else {
               result2 = null;
               pos = pos1;
             }
           } else {
             result2 = null;
             pos = pos1;
           }
 
           while (result2 !== null) {
             result1.push(result2);
             pos1 = pos;
             result2 = parse_COMMA();
 
             if (result2 !== null) {
               result3 = parse_event_type();
 
               if (result3 !== null) {
                 result2 = [result2, result3];
               } else {
                 result2 = null;
                 pos = pos1;
               }
             } else {
               result2 = null;
               pos = pos1;
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_Call_ID() {
         var result0, result1, result2;
         var pos0, pos1, pos2;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_word();
 
         if (result0 !== null) {
           pos2 = pos;
 
           if (input.charCodeAt(pos) === 64) {
             result1 = "@";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"@\"");
             }
           }
 
           if (result1 !== null) {
             result2 = parse_word();
 
             if (result2 !== null) {
               result1 = [result1, result2];
             } else {
               result1 = null;
               pos = pos2;
             }
           } else {
             result1 = null;
             pos = pos2;
           }
 
           result1 = result1 !== null ? result1 : "";
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             data = input.substring(pos, offset);
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_Contact() {
         var result0, result1, result2, result3;
         var pos0, pos1, pos2;
         pos0 = pos;
         result0 = parse_STAR();
 
         if (result0 === null) {
           pos1 = pos;
           result0 = parse_contact_param();
 
           if (result0 !== null) {
             result1 = [];
             pos2 = pos;
             result2 = parse_COMMA();
 
             if (result2 !== null) {
               result3 = parse_contact_param();
 
               if (result3 !== null) {
                 result2 = [result2, result3];
               } else {
                 result2 = null;
                 pos = pos2;
               }
             } else {
               result2 = null;
               pos = pos2;
             }
 
             while (result2 !== null) {
               result1.push(result2);
               pos2 = pos;
               result2 = parse_COMMA();
 
               if (result2 !== null) {
                 result3 = parse_contact_param();
 
                 if (result3 !== null) {
                   result2 = [result2, result3];
                 } else {
                   result2 = null;
                   pos = pos2;
                 }
               } else {
                 result2 = null;
                 pos = pos2;
               }
             }
 
             if (result1 !== null) {
               result0 = [result0, result1];
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             var idx, length;
             length = data.multi_header.length;
 
             for (idx = 0; idx < length; idx++) {
               if (data.multi_header[idx].parsed === null) {
                 data = null;
                 break;
               }
             }
 
             if (data !== null) {
               data = data.multi_header;
             } else {
               data = -1;
             }
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_contact_param() {
         var result0, result1, result2, result3;
         var pos0, pos1, pos2;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_SIP_URI_noparams();
 
         if (result0 === null) {
           result0 = parse_name_addr();
         }
 
         if (result0 !== null) {
           result1 = [];
           pos2 = pos;
           result2 = parse_SEMI();
 
           if (result2 !== null) {
             result3 = parse_contact_params();
 
             if (result3 !== null) {
               result2 = [result2, result3];
             } else {
               result2 = null;
               pos = pos2;
             }
           } else {
             result2 = null;
             pos = pos2;
           }
 
           while (result2 !== null) {
             result1.push(result2);
             pos2 = pos;
             result2 = parse_SEMI();
 
             if (result2 !== null) {
               result3 = parse_contact_params();
 
               if (result3 !== null) {
                 result2 = [result2, result3];
               } else {
                 result2 = null;
                 pos = pos2;
               }
             } else {
               result2 = null;
               pos = pos2;
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             var header;
             if (!data.multi_header) data.multi_header = [];
 
             try {
               header = new NameAddrHeader(data.uri, data.display_name, data.params);
               delete data.uri;
               delete data.display_name;
               delete data.params;
             } catch (e) {
               header = null;
             }
 
             data.multi_header.push({
               'possition': pos,
               'offset': offset,
               'parsed': header
             });
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_name_addr() {
         var result0, result1, result2, result3;
         var pos0;
         pos0 = pos;
         result0 = parse_display_name();
         result0 = result0 !== null ? result0 : "";
 
         if (result0 !== null) {
           result1 = parse_LAQUOT();
 
           if (result1 !== null) {
             result2 = parse_SIP_URI();
 
             if (result2 !== null) {
               result3 = parse_RAQUOT();
 
               if (result3 !== null) {
                 result0 = [result0, result1, result2, result3];
               } else {
                 result0 = null;
                 pos = pos0;
               }
             } else {
               result0 = null;
               pos = pos0;
             }
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_display_name() {
         var result0, result1, result2, result3;
         var pos0, pos1, pos2;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_token();
 
         if (result0 !== null) {
           result1 = [];
           pos2 = pos;
           result2 = parse_LWS();
 
           if (result2 !== null) {
             result3 = parse_token();
 
             if (result3 !== null) {
               result2 = [result2, result3];
             } else {
               result2 = null;
               pos = pos2;
             }
           } else {
             result2 = null;
             pos = pos2;
           }
 
           while (result2 !== null) {
             result1.push(result2);
             pos2 = pos;
             result2 = parse_LWS();
 
             if (result2 !== null) {
               result3 = parse_token();
 
               if (result3 !== null) {
                 result2 = [result2, result3];
               } else {
                 result2 = null;
                 pos = pos2;
               }
             } else {
               result2 = null;
               pos = pos2;
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 === null) {
           result0 = parse_quoted_string_clean();
         }
 
         if (result0 !== null) {
           result0 = function (offset, display_name) {
             if (typeof display_name === 'string') {
               // quoted_string_clean
               data.display_name = display_name;
             } else {
               // token ( LWS token )*
               data.display_name = display_name[1].reduce(function (acc, cur) {
                 return acc + cur[0] + cur[1];
               }, display_name[0]);
             }
           }(pos0, result0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_contact_params() {
         var result0;
         result0 = parse_c_p_q();
 
         if (result0 === null) {
           result0 = parse_c_p_expires();
 
           if (result0 === null) {
             result0 = parse_generic_param();
           }
         }
 
         return result0;
       }
 
       function parse_c_p_q() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
 
         if (input.substr(pos, 1).toLowerCase() === "q") {
           result0 = input.substr(pos, 1);
           pos++;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"q\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_EQUAL();
 
           if (result1 !== null) {
             result2 = parse_qvalue();
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset, q) {
             if (!data.params) data.params = {};
             data.params['q'] = q;
           }(pos0, result0[2]);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_c_p_expires() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
 
         if (input.substr(pos, 7).toLowerCase() === "expires") {
           result0 = input.substr(pos, 7);
           pos += 7;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"expires\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_EQUAL();
 
           if (result1 !== null) {
             result2 = parse_delta_seconds();
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset, expires) {
             if (!data.params) data.params = {};
             data.params['expires'] = expires;
           }(pos0, result0[2]);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_delta_seconds() {
         var result0, result1;
         var pos0;
         pos0 = pos;
         result1 = parse_DIGIT();
 
         if (result1 !== null) {
           result0 = [];
 
           while (result1 !== null) {
             result0.push(result1);
             result1 = parse_DIGIT();
           }
         } else {
           result0 = null;
         }
 
         if (result0 !== null) {
           result0 = function (offset, delta_seconds) {
             return parseInt(delta_seconds.join(''));
           }(pos0, result0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_qvalue() {
         var result0, result1, result2, result3, result4;
         var pos0, pos1, pos2;
         pos0 = pos;
         pos1 = pos;
 
         if (input.charCodeAt(pos) === 48) {
           result0 = "0";
           pos++;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"0\"");
           }
         }
 
         if (result0 !== null) {
           pos2 = pos;
 
           if (input.charCodeAt(pos) === 46) {
             result1 = ".";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\".\"");
             }
           }
 
           if (result1 !== null) {
             result2 = parse_DIGIT();
             result2 = result2 !== null ? result2 : "";
 
             if (result2 !== null) {
               result3 = parse_DIGIT();
               result3 = result3 !== null ? result3 : "";
 
               if (result3 !== null) {
                 result4 = parse_DIGIT();
                 result4 = result4 !== null ? result4 : "";
 
                 if (result4 !== null) {
                   result1 = [result1, result2, result3, result4];
                 } else {
                   result1 = null;
                   pos = pos2;
                 }
               } else {
                 result1 = null;
                 pos = pos2;
               }
             } else {
               result1 = null;
               pos = pos2;
             }
           } else {
             result1 = null;
             pos = pos2;
           }
 
           result1 = result1 !== null ? result1 : "";
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             return parseFloat(input.substring(pos, offset));
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_generic_param() {
         var result0, result1, result2;
         var pos0, pos1, pos2;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_token();
 
         if (result0 !== null) {
           pos2 = pos;
           result1 = parse_EQUAL();
 
           if (result1 !== null) {
             result2 = parse_gen_value();
 
             if (result2 !== null) {
               result1 = [result1, result2];
             } else {
               result1 = null;
               pos = pos2;
             }
           } else {
             result1 = null;
             pos = pos2;
           }
 
           result1 = result1 !== null ? result1 : "";
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset, param, value) {
             if (!data.params) data.params = {};
 
             if (typeof value === 'undefined') {
               value = undefined;
             } else {
               value = value[1];
             }
 
             data.params[param.toLowerCase()] = value;
           }(pos0, result0[0], result0[1]);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_gen_value() {
         var result0;
         result0 = parse_token();
 
         if (result0 === null) {
           result0 = parse_host();
 
           if (result0 === null) {
             result0 = parse_quoted_string();
           }
         }
 
         return result0;
       }
 
       function parse_Content_Disposition() {
         var result0, result1, result2, result3;
         var pos0, pos1;
         pos0 = pos;
         result0 = parse_disp_type();
 
         if (result0 !== null) {
           result1 = [];
           pos1 = pos;
           result2 = parse_SEMI();
 
           if (result2 !== null) {
             result3 = parse_disp_param();
 
             if (result3 !== null) {
               result2 = [result2, result3];
             } else {
               result2 = null;
               pos = pos1;
             }
           } else {
             result2 = null;
             pos = pos1;
           }
 
           while (result2 !== null) {
             result1.push(result2);
             pos1 = pos;
             result2 = parse_SEMI();
 
             if (result2 !== null) {
               result3 = parse_disp_param();
 
               if (result3 !== null) {
                 result2 = [result2, result3];
               } else {
                 result2 = null;
                 pos = pos1;
               }
             } else {
               result2 = null;
               pos = pos1;
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_disp_type() {
         var result0;
 
         if (input.substr(pos, 6).toLowerCase() === "render") {
           result0 = input.substr(pos, 6);
           pos += 6;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"render\"");
           }
         }
 
         if (result0 === null) {
           if (input.substr(pos, 7).toLowerCase() === "session") {
             result0 = input.substr(pos, 7);
             pos += 7;
           } else {
             result0 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"session\"");
             }
           }
 
           if (result0 === null) {
             if (input.substr(pos, 4).toLowerCase() === "icon") {
               result0 = input.substr(pos, 4);
               pos += 4;
             } else {
               result0 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\"icon\"");
               }
             }
 
             if (result0 === null) {
               if (input.substr(pos, 5).toLowerCase() === "alert") {
                 result0 = input.substr(pos, 5);
                 pos += 5;
               } else {
                 result0 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\"alert\"");
                 }
               }
 
               if (result0 === null) {
                 result0 = parse_token();
               }
             }
           }
         }
 
         return result0;
       }
 
       function parse_disp_param() {
         var result0;
         result0 = parse_handling_param();
 
         if (result0 === null) {
           result0 = parse_generic_param();
         }
 
         return result0;
       }
 
       function parse_handling_param() {
         var result0, result1, result2;
         var pos0;
         pos0 = pos;
 
         if (input.substr(pos, 8).toLowerCase() === "handling") {
           result0 = input.substr(pos, 8);
           pos += 8;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"handling\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_EQUAL();
 
           if (result1 !== null) {
             if (input.substr(pos, 8).toLowerCase() === "optional") {
               result2 = input.substr(pos, 8);
               pos += 8;
             } else {
               result2 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\"optional\"");
               }
             }
 
             if (result2 === null) {
               if (input.substr(pos, 8).toLowerCase() === "required") {
                 result2 = input.substr(pos, 8);
                 pos += 8;
               } else {
                 result2 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\"required\"");
                 }
               }
 
               if (result2 === null) {
                 result2 = parse_token();
               }
             }
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos0;
             }
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_Content_Encoding() {
         var result0, result1, result2, result3;
         var pos0, pos1;
         pos0 = pos;
         result0 = parse_token();
 
         if (result0 !== null) {
           result1 = [];
           pos1 = pos;
           result2 = parse_COMMA();
 
           if (result2 !== null) {
             result3 = parse_token();
 
             if (result3 !== null) {
               result2 = [result2, result3];
             } else {
               result2 = null;
               pos = pos1;
             }
           } else {
             result2 = null;
             pos = pos1;
           }
 
           while (result2 !== null) {
             result1.push(result2);
             pos1 = pos;
             result2 = parse_COMMA();
 
             if (result2 !== null) {
               result3 = parse_token();
 
               if (result3 !== null) {
                 result2 = [result2, result3];
               } else {
                 result2 = null;
                 pos = pos1;
               }
             } else {
               result2 = null;
               pos = pos1;
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_Content_Length() {
         var result0, result1;
         var pos0;
         pos0 = pos;
         result1 = parse_DIGIT();
 
         if (result1 !== null) {
           result0 = [];
 
           while (result1 !== null) {
             result0.push(result1);
             result1 = parse_DIGIT();
           }
         } else {
           result0 = null;
         }
 
         if (result0 !== null) {
           result0 = function (offset, length) {
             data = parseInt(length.join(''));
           }(pos0, result0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_Content_Type() {
         var result0;
         var pos0;
         pos0 = pos;
         result0 = parse_media_type();
 
         if (result0 !== null) {
           result0 = function (offset) {
             data = input.substring(pos, offset);
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_media_type() {
         var result0, result1, result2, result3, result4, result5;
         var pos0, pos1;
         pos0 = pos;
         result0 = parse_m_type();
 
         if (result0 !== null) {
           result1 = parse_SLASH();
 
           if (result1 !== null) {
             result2 = parse_m_subtype();
 
             if (result2 !== null) {
               result3 = [];
               pos1 = pos;
               result4 = parse_SEMI();
 
               if (result4 !== null) {
                 result5 = parse_m_parameter();
 
                 if (result5 !== null) {
                   result4 = [result4, result5];
                 } else {
                   result4 = null;
                   pos = pos1;
                 }
               } else {
                 result4 = null;
                 pos = pos1;
               }
 
               while (result4 !== null) {
                 result3.push(result4);
                 pos1 = pos;
                 result4 = parse_SEMI();
 
                 if (result4 !== null) {
                   result5 = parse_m_parameter();
 
                   if (result5 !== null) {
                     result4 = [result4, result5];
                   } else {
                     result4 = null;
                     pos = pos1;
                   }
                 } else {
                   result4 = null;
                   pos = pos1;
                 }
               }
 
               if (result3 !== null) {
                 result0 = [result0, result1, result2, result3];
               } else {
                 result0 = null;
                 pos = pos0;
               }
             } else {
               result0 = null;
               pos = pos0;
             }
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_m_type() {
         var result0;
         result0 = parse_discrete_type();
 
         if (result0 === null) {
           result0 = parse_composite_type();
         }
 
         return result0;
       }
 
       function parse_discrete_type() {
         var result0;
 
         if (input.substr(pos, 4).toLowerCase() === "text") {
           result0 = input.substr(pos, 4);
           pos += 4;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"text\"");
           }
         }
 
         if (result0 === null) {
           if (input.substr(pos, 5).toLowerCase() === "image") {
             result0 = input.substr(pos, 5);
             pos += 5;
           } else {
             result0 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"image\"");
             }
           }
 
           if (result0 === null) {
             if (input.substr(pos, 5).toLowerCase() === "audio") {
               result0 = input.substr(pos, 5);
               pos += 5;
             } else {
               result0 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\"audio\"");
               }
             }
 
             if (result0 === null) {
               if (input.substr(pos, 5).toLowerCase() === "video") {
                 result0 = input.substr(pos, 5);
                 pos += 5;
               } else {
                 result0 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\"video\"");
                 }
               }
 
               if (result0 === null) {
                 if (input.substr(pos, 11).toLowerCase() === "application") {
                   result0 = input.substr(pos, 11);
                   pos += 11;
                 } else {
                   result0 = null;
 
                   if (reportFailures === 0) {
                     matchFailed("\"application\"");
                   }
                 }
 
                 if (result0 === null) {
                   result0 = parse_extension_token();
                 }
               }
             }
           }
         }
 
         return result0;
       }
 
       function parse_composite_type() {
         var result0;
 
         if (input.substr(pos, 7).toLowerCase() === "message") {
           result0 = input.substr(pos, 7);
           pos += 7;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"message\"");
           }
         }
 
         if (result0 === null) {
           if (input.substr(pos, 9).toLowerCase() === "multipart") {
             result0 = input.substr(pos, 9);
             pos += 9;
           } else {
             result0 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"multipart\"");
             }
           }
 
           if (result0 === null) {
             result0 = parse_extension_token();
           }
         }
 
         return result0;
       }
 
       function parse_extension_token() {
         var result0;
         result0 = parse_token();
 
         if (result0 === null) {
           result0 = parse_x_token();
         }
 
         return result0;
       }
 
       function parse_x_token() {
         var result0, result1;
         var pos0;
         pos0 = pos;
 
         if (input.substr(pos, 2).toLowerCase() === "x-") {
           result0 = input.substr(pos, 2);
           pos += 2;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"x-\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_token();
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_m_subtype() {
         var result0;
         result0 = parse_extension_token();
 
         if (result0 === null) {
           result0 = parse_token();
         }
 
         return result0;
       }
 
       function parse_m_parameter() {
         var result0, result1, result2;
         var pos0;
         pos0 = pos;
         result0 = parse_token();
 
         if (result0 !== null) {
           result1 = parse_EQUAL();
 
           if (result1 !== null) {
             result2 = parse_m_value();
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos0;
             }
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_m_value() {
         var result0;
         result0 = parse_token();
 
         if (result0 === null) {
           result0 = parse_quoted_string();
         }
 
         return result0;
       }
 
       function parse_CSeq() {
         var result0, result1, result2;
         var pos0;
         pos0 = pos;
         result0 = parse_CSeq_value();
 
         if (result0 !== null) {
           result1 = parse_LWS();
 
           if (result1 !== null) {
             result2 = parse_Method();
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos0;
             }
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_CSeq_value() {
         var result0, result1;
         var pos0;
         pos0 = pos;
         result1 = parse_DIGIT();
 
         if (result1 !== null) {
           result0 = [];
 
           while (result1 !== null) {
             result0.push(result1);
             result1 = parse_DIGIT();
           }
         } else {
           result0 = null;
         }
 
         if (result0 !== null) {
           result0 = function (offset, cseq_value) {
             data.value = parseInt(cseq_value.join(''));
           }(pos0, result0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_Expires() {
         var result0;
         var pos0;
         pos0 = pos;
         result0 = parse_delta_seconds();
 
         if (result0 !== null) {
           result0 = function (offset, expires) {
             data = expires;
           }(pos0, result0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_Event() {
         var result0, result1, result2, result3;
         var pos0, pos1, pos2;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_event_type();
 
         if (result0 !== null) {
           result1 = [];
           pos2 = pos;
           result2 = parse_SEMI();
 
           if (result2 !== null) {
             result3 = parse_generic_param();
 
             if (result3 !== null) {
               result2 = [result2, result3];
             } else {
               result2 = null;
               pos = pos2;
             }
           } else {
             result2 = null;
             pos = pos2;
           }
 
           while (result2 !== null) {
             result1.push(result2);
             pos2 = pos;
             result2 = parse_SEMI();
 
             if (result2 !== null) {
               result3 = parse_generic_param();
 
               if (result3 !== null) {
                 result2 = [result2, result3];
               } else {
                 result2 = null;
                 pos = pos2;
               }
             } else {
               result2 = null;
               pos = pos2;
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset, event_type) {
             data.event = event_type.join('').toLowerCase();
           }(pos0, result0[0]);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_event_type() {
         var result0, result1, result2, result3;
         var pos0, pos1;
         pos0 = pos;
         result0 = parse_token_nodot();
 
         if (result0 !== null) {
           result1 = [];
           pos1 = pos;
 
           if (input.charCodeAt(pos) === 46) {
             result2 = ".";
             pos++;
           } else {
             result2 = null;
 
             if (reportFailures === 0) {
               matchFailed("\".\"");
             }
           }
 
           if (result2 !== null) {
             result3 = parse_token_nodot();
 
             if (result3 !== null) {
               result2 = [result2, result3];
             } else {
               result2 = null;
               pos = pos1;
             }
           } else {
             result2 = null;
             pos = pos1;
           }
 
           while (result2 !== null) {
             result1.push(result2);
             pos1 = pos;
 
             if (input.charCodeAt(pos) === 46) {
               result2 = ".";
               pos++;
             } else {
               result2 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\".\"");
               }
             }
 
             if (result2 !== null) {
               result3 = parse_token_nodot();
 
               if (result3 !== null) {
                 result2 = [result2, result3];
               } else {
                 result2 = null;
                 pos = pos1;
               }
             } else {
               result2 = null;
               pos = pos1;
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_From() {
         var result0, result1, result2, result3;
         var pos0, pos1, pos2;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_SIP_URI_noparams();
 
         if (result0 === null) {
           result0 = parse_name_addr();
         }
 
         if (result0 !== null) {
           result1 = [];
           pos2 = pos;
           result2 = parse_SEMI();
 
           if (result2 !== null) {
             result3 = parse_from_param();
 
             if (result3 !== null) {
               result2 = [result2, result3];
             } else {
               result2 = null;
               pos = pos2;
             }
           } else {
             result2 = null;
             pos = pos2;
           }
 
           while (result2 !== null) {
             result1.push(result2);
             pos2 = pos;
             result2 = parse_SEMI();
 
             if (result2 !== null) {
               result3 = parse_from_param();
 
               if (result3 !== null) {
                 result2 = [result2, result3];
               } else {
                 result2 = null;
                 pos = pos2;
               }
             } else {
               result2 = null;
               pos = pos2;
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             var tag = data.tag;
 
             try {
               data = new NameAddrHeader(data.uri, data.display_name, data.params);
 
               if (tag) {
                 data.setParam('tag', tag);
               }
             } catch (e) {
               data = -1;
             }
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_from_param() {
         var result0;
         result0 = parse_tag_param();
 
         if (result0 === null) {
           result0 = parse_generic_param();
         }
 
         return result0;
       }
 
       function parse_tag_param() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
 
         if (input.substr(pos, 3).toLowerCase() === "tag") {
           result0 = input.substr(pos, 3);
           pos += 3;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"tag\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_EQUAL();
 
           if (result1 !== null) {
             result2 = parse_token();
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset, tag) {
             data.tag = tag;
           }(pos0, result0[2]);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_Max_Forwards() {
         var result0, result1;
         var pos0;
         pos0 = pos;
         result1 = parse_DIGIT();
 
         if (result1 !== null) {
           result0 = [];
 
           while (result1 !== null) {
             result0.push(result1);
             result1 = parse_DIGIT();
           }
         } else {
           result0 = null;
         }
 
         if (result0 !== null) {
           result0 = function (offset, forwards) {
             data = parseInt(forwards.join(''));
           }(pos0, result0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_Min_Expires() {
         var result0;
         var pos0;
         pos0 = pos;
         result0 = parse_delta_seconds();
 
         if (result0 !== null) {
           result0 = function (offset, min_expires) {
             data = min_expires;
           }(pos0, result0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_Name_Addr_Header() {
         var result0, result1, result2, result3, result4, result5, result6;
         var pos0, pos1, pos2;
         pos0 = pos;
         pos1 = pos;
         result0 = [];
         result1 = parse_display_name();
 
         while (result1 !== null) {
           result0.push(result1);
           result1 = parse_display_name();
         }
 
         if (result0 !== null) {
           result1 = parse_LAQUOT();
 
           if (result1 !== null) {
             result2 = parse_SIP_URI();
 
             if (result2 !== null) {
               result3 = parse_RAQUOT();
 
               if (result3 !== null) {
                 result4 = [];
                 pos2 = pos;
                 result5 = parse_SEMI();
 
                 if (result5 !== null) {
                   result6 = parse_generic_param();
 
                   if (result6 !== null) {
                     result5 = [result5, result6];
                   } else {
                     result5 = null;
                     pos = pos2;
                   }
                 } else {
                   result5 = null;
                   pos = pos2;
                 }
 
                 while (result5 !== null) {
                   result4.push(result5);
                   pos2 = pos;
                   result5 = parse_SEMI();
 
                   if (result5 !== null) {
                     result6 = parse_generic_param();
 
                     if (result6 !== null) {
                       result5 = [result5, result6];
                     } else {
                       result5 = null;
                       pos = pos2;
                     }
                   } else {
                     result5 = null;
                     pos = pos2;
                   }
                 }
 
                 if (result4 !== null) {
                   result0 = [result0, result1, result2, result3, result4];
                 } else {
                   result0 = null;
                   pos = pos1;
                 }
               } else {
                 result0 = null;
                 pos = pos1;
               }
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             try {
               data = new NameAddrHeader(data.uri, data.display_name, data.params);
             } catch (e) {
               data = -1;
             }
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_Proxy_Authenticate() {
         var result0;
         result0 = parse_challenge();
         return result0;
       }
 
       function parse_challenge() {
         var result0, result1, result2, result3, result4, result5;
         var pos0, pos1;
         pos0 = pos;
 
         if (input.substr(pos, 6).toLowerCase() === "digest") {
           result0 = input.substr(pos, 6);
           pos += 6;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"Digest\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_LWS();
 
           if (result1 !== null) {
             result2 = parse_digest_cln();
 
             if (result2 !== null) {
               result3 = [];
               pos1 = pos;
               result4 = parse_COMMA();
 
               if (result4 !== null) {
                 result5 = parse_digest_cln();
 
                 if (result5 !== null) {
                   result4 = [result4, result5];
                 } else {
                   result4 = null;
                   pos = pos1;
                 }
               } else {
                 result4 = null;
                 pos = pos1;
               }
 
               while (result4 !== null) {
                 result3.push(result4);
                 pos1 = pos;
                 result4 = parse_COMMA();
 
                 if (result4 !== null) {
                   result5 = parse_digest_cln();
 
                   if (result5 !== null) {
                     result4 = [result4, result5];
                   } else {
                     result4 = null;
                     pos = pos1;
                   }
                 } else {
                   result4 = null;
                   pos = pos1;
                 }
               }
 
               if (result3 !== null) {
                 result0 = [result0, result1, result2, result3];
               } else {
                 result0 = null;
                 pos = pos0;
               }
             } else {
               result0 = null;
               pos = pos0;
             }
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         if (result0 === null) {
           result0 = parse_other_challenge();
         }
 
         return result0;
       }
 
       function parse_other_challenge() {
         var result0, result1, result2, result3, result4, result5;
         var pos0, pos1;
         pos0 = pos;
         result0 = parse_token();
 
         if (result0 !== null) {
           result1 = parse_LWS();
 
           if (result1 !== null) {
             result2 = parse_auth_param();
 
             if (result2 !== null) {
               result3 = [];
               pos1 = pos;
               result4 = parse_COMMA();
 
               if (result4 !== null) {
                 result5 = parse_auth_param();
 
                 if (result5 !== null) {
                   result4 = [result4, result5];
                 } else {
                   result4 = null;
                   pos = pos1;
                 }
               } else {
                 result4 = null;
                 pos = pos1;
               }
 
               while (result4 !== null) {
                 result3.push(result4);
                 pos1 = pos;
                 result4 = parse_COMMA();
 
                 if (result4 !== null) {
                   result5 = parse_auth_param();
 
                   if (result5 !== null) {
                     result4 = [result4, result5];
                   } else {
                     result4 = null;
                     pos = pos1;
                   }
                 } else {
                   result4 = null;
                   pos = pos1;
                 }
               }
 
               if (result3 !== null) {
                 result0 = [result0, result1, result2, result3];
               } else {
                 result0 = null;
                 pos = pos0;
               }
             } else {
               result0 = null;
               pos = pos0;
             }
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_auth_param() {
         var result0, result1, result2;
         var pos0;
         pos0 = pos;
         result0 = parse_token();
 
         if (result0 !== null) {
           result1 = parse_EQUAL();
 
           if (result1 !== null) {
             result2 = parse_token();
 
             if (result2 === null) {
               result2 = parse_quoted_string();
             }
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos0;
             }
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_digest_cln() {
         var result0;
         result0 = parse_realm();
 
         if (result0 === null) {
           result0 = parse_domain();
 
           if (result0 === null) {
             result0 = parse_nonce();
 
             if (result0 === null) {
               result0 = parse_opaque();
 
               if (result0 === null) {
                 result0 = parse_stale();
 
                 if (result0 === null) {
                   result0 = parse_algorithm();
 
                   if (result0 === null) {
                     result0 = parse_qop_options();
 
                     if (result0 === null) {
                       result0 = parse_auth_param();
                     }
                   }
                 }
               }
             }
           }
         }
 
         return result0;
       }
 
       function parse_realm() {
         var result0, result1, result2;
         var pos0;
         pos0 = pos;
 
         if (input.substr(pos, 5).toLowerCase() === "realm") {
           result0 = input.substr(pos, 5);
           pos += 5;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"realm\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_EQUAL();
 
           if (result1 !== null) {
             result2 = parse_realm_value();
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos0;
             }
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_realm_value() {
         var result0;
         var pos0;
         pos0 = pos;
         result0 = parse_quoted_string_clean();
 
         if (result0 !== null) {
           result0 = function (offset, realm) {
             data.realm = realm;
           }(pos0, result0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_domain() {
         var result0, result1, result2, result3, result4, result5, result6;
         var pos0, pos1;
         pos0 = pos;
 
         if (input.substr(pos, 6).toLowerCase() === "domain") {
           result0 = input.substr(pos, 6);
           pos += 6;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"domain\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_EQUAL();
 
           if (result1 !== null) {
             result2 = parse_LDQUOT();
 
             if (result2 !== null) {
               result3 = parse_URI();
 
               if (result3 !== null) {
                 result4 = [];
                 pos1 = pos;
                 result6 = parse_SP();
 
                 if (result6 !== null) {
                   result5 = [];
 
                   while (result6 !== null) {
                     result5.push(result6);
                     result6 = parse_SP();
                   }
                 } else {
                   result5 = null;
                 }
 
                 if (result5 !== null) {
                   result6 = parse_URI();
 
                   if (result6 !== null) {
                     result5 = [result5, result6];
                   } else {
                     result5 = null;
                     pos = pos1;
                   }
                 } else {
                   result5 = null;
                   pos = pos1;
                 }
 
                 while (result5 !== null) {
                   result4.push(result5);
                   pos1 = pos;
                   result6 = parse_SP();
 
                   if (result6 !== null) {
                     result5 = [];
 
                     while (result6 !== null) {
                       result5.push(result6);
                       result6 = parse_SP();
                     }
                   } else {
                     result5 = null;
                   }
 
                   if (result5 !== null) {
                     result6 = parse_URI();
 
                     if (result6 !== null) {
                       result5 = [result5, result6];
                     } else {
                       result5 = null;
                       pos = pos1;
                     }
                   } else {
                     result5 = null;
                     pos = pos1;
                   }
                 }
 
                 if (result4 !== null) {
                   result5 = parse_RDQUOT();
 
                   if (result5 !== null) {
                     result0 = [result0, result1, result2, result3, result4, result5];
                   } else {
                     result0 = null;
                     pos = pos0;
                   }
                 } else {
                   result0 = null;
                   pos = pos0;
                 }
               } else {
                 result0 = null;
                 pos = pos0;
               }
             } else {
               result0 = null;
               pos = pos0;
             }
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_URI() {
         var result0;
         result0 = parse_absoluteURI();
 
         if (result0 === null) {
           result0 = parse_abs_path();
         }
 
         return result0;
       }
 
       function parse_nonce() {
         var result0, result1, result2;
         var pos0;
         pos0 = pos;
 
         if (input.substr(pos, 5).toLowerCase() === "nonce") {
           result0 = input.substr(pos, 5);
           pos += 5;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"nonce\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_EQUAL();
 
           if (result1 !== null) {
             result2 = parse_nonce_value();
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos0;
             }
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_nonce_value() {
         var result0;
         var pos0;
         pos0 = pos;
         result0 = parse_quoted_string_clean();
 
         if (result0 !== null) {
           result0 = function (offset, nonce) {
             data.nonce = nonce;
           }(pos0, result0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_opaque() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
 
         if (input.substr(pos, 6).toLowerCase() === "opaque") {
           result0 = input.substr(pos, 6);
           pos += 6;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"opaque\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_EQUAL();
 
           if (result1 !== null) {
             result2 = parse_quoted_string_clean();
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset, opaque) {
             data.opaque = opaque;
           }(pos0, result0[2]);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_stale() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
 
         if (input.substr(pos, 5).toLowerCase() === "stale") {
           result0 = input.substr(pos, 5);
           pos += 5;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"stale\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_EQUAL();
 
           if (result1 !== null) {
             pos1 = pos;
 
             if (input.substr(pos, 4).toLowerCase() === "true") {
               result2 = input.substr(pos, 4);
               pos += 4;
             } else {
               result2 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\"true\"");
               }
             }
 
             if (result2 !== null) {
               result2 = function (offset) {
                 data.stale = true;
               }(pos1);
             }
 
             if (result2 === null) {
               pos = pos1;
             }
 
             if (result2 === null) {
               pos1 = pos;
 
               if (input.substr(pos, 5).toLowerCase() === "false") {
                 result2 = input.substr(pos, 5);
                 pos += 5;
               } else {
                 result2 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\"false\"");
                 }
               }
 
               if (result2 !== null) {
                 result2 = function (offset) {
                   data.stale = false;
                 }(pos1);
               }
 
               if (result2 === null) {
                 pos = pos1;
               }
             }
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos0;
             }
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_algorithm() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
 
         if (input.substr(pos, 9).toLowerCase() === "algorithm") {
           result0 = input.substr(pos, 9);
           pos += 9;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"algorithm\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_EQUAL();
 
           if (result1 !== null) {
             if (input.substr(pos, 3).toLowerCase() === "md5") {
               result2 = input.substr(pos, 3);
               pos += 3;
             } else {
               result2 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\"MD5\"");
               }
             }
 
             if (result2 === null) {
               if (input.substr(pos, 8).toLowerCase() === "md5-sess") {
                 result2 = input.substr(pos, 8);
                 pos += 8;
               } else {
                 result2 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\"MD5-sess\"");
                 }
               }
 
               if (result2 === null) {
                 result2 = parse_token();
               }
             }
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset, algorithm) {
             data.algorithm = algorithm.toUpperCase();
           }(pos0, result0[2]);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_qop_options() {
         var result0, result1, result2, result3, result4, result5, result6;
         var pos0, pos1, pos2;
         pos0 = pos;
 
         if (input.substr(pos, 3).toLowerCase() === "qop") {
           result0 = input.substr(pos, 3);
           pos += 3;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"qop\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_EQUAL();
 
           if (result1 !== null) {
             result2 = parse_LDQUOT();
 
             if (result2 !== null) {
               pos1 = pos;
               result3 = parse_qop_value();
 
               if (result3 !== null) {
                 result4 = [];
                 pos2 = pos;
 
                 if (input.charCodeAt(pos) === 44) {
                   result5 = ",";
                   pos++;
                 } else {
                   result5 = null;
 
                   if (reportFailures === 0) {
                     matchFailed("\",\"");
                   }
                 }
 
                 if (result5 !== null) {
                   result6 = parse_qop_value();
 
                   if (result6 !== null) {
                     result5 = [result5, result6];
                   } else {
                     result5 = null;
                     pos = pos2;
                   }
                 } else {
                   result5 = null;
                   pos = pos2;
                 }
 
                 while (result5 !== null) {
                   result4.push(result5);
                   pos2 = pos;
 
                   if (input.charCodeAt(pos) === 44) {
                     result5 = ",";
                     pos++;
                   } else {
                     result5 = null;
 
                     if (reportFailures === 0) {
                       matchFailed("\",\"");
                     }
                   }
 
                   if (result5 !== null) {
                     result6 = parse_qop_value();
 
                     if (result6 !== null) {
                       result5 = [result5, result6];
                     } else {
                       result5 = null;
                       pos = pos2;
                     }
                   } else {
                     result5 = null;
                     pos = pos2;
                   }
                 }
 
                 if (result4 !== null) {
                   result3 = [result3, result4];
                 } else {
                   result3 = null;
                   pos = pos1;
                 }
               } else {
                 result3 = null;
                 pos = pos1;
               }
 
               if (result3 !== null) {
                 result4 = parse_RDQUOT();
 
                 if (result4 !== null) {
                   result0 = [result0, result1, result2, result3, result4];
                 } else {
                   result0 = null;
                   pos = pos0;
                 }
               } else {
                 result0 = null;
                 pos = pos0;
               }
             } else {
               result0 = null;
               pos = pos0;
             }
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_qop_value() {
         var result0;
         var pos0;
         pos0 = pos;
 
         if (input.substr(pos, 8).toLowerCase() === "auth-int") {
           result0 = input.substr(pos, 8);
           pos += 8;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"auth-int\"");
           }
         }
 
         if (result0 === null) {
           if (input.substr(pos, 4).toLowerCase() === "auth") {
             result0 = input.substr(pos, 4);
             pos += 4;
           } else {
             result0 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"auth\"");
             }
           }
 
           if (result0 === null) {
             result0 = parse_token();
           }
         }
 
         if (result0 !== null) {
           result0 = function (offset, qop_value) {
             data.qop || (data.qop = []);
             data.qop.push(qop_value.toLowerCase());
           }(pos0, result0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_Proxy_Require() {
         var result0, result1, result2, result3;
         var pos0, pos1;
         pos0 = pos;
         result0 = parse_token();
 
         if (result0 !== null) {
           result1 = [];
           pos1 = pos;
           result2 = parse_COMMA();
 
           if (result2 !== null) {
             result3 = parse_token();
 
             if (result3 !== null) {
               result2 = [result2, result3];
             } else {
               result2 = null;
               pos = pos1;
             }
           } else {
             result2 = null;
             pos = pos1;
           }
 
           while (result2 !== null) {
             result1.push(result2);
             pos1 = pos;
             result2 = parse_COMMA();
 
             if (result2 !== null) {
               result3 = parse_token();
 
               if (result3 !== null) {
                 result2 = [result2, result3];
               } else {
                 result2 = null;
                 pos = pos1;
               }
             } else {
               result2 = null;
               pos = pos1;
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_Record_Route() {
         var result0, result1, result2, result3;
         var pos0, pos1, pos2;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_rec_route();
 
         if (result0 !== null) {
           result1 = [];
           pos2 = pos;
           result2 = parse_COMMA();
 
           if (result2 !== null) {
             result3 = parse_rec_route();
 
             if (result3 !== null) {
               result2 = [result2, result3];
             } else {
               result2 = null;
               pos = pos2;
             }
           } else {
             result2 = null;
             pos = pos2;
           }
 
           while (result2 !== null) {
             result1.push(result2);
             pos2 = pos;
             result2 = parse_COMMA();
 
             if (result2 !== null) {
               result3 = parse_rec_route();
 
               if (result3 !== null) {
                 result2 = [result2, result3];
               } else {
                 result2 = null;
                 pos = pos2;
               }
             } else {
               result2 = null;
               pos = pos2;
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             var idx, length;
             length = data.multi_header.length;
 
             for (idx = 0; idx < length; idx++) {
               if (data.multi_header[idx].parsed === null) {
                 data = null;
                 break;
               }
             }
 
             if (data !== null) {
               data = data.multi_header;
             } else {
               data = -1;
             }
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_rec_route() {
         var result0, result1, result2, result3;
         var pos0, pos1, pos2;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_name_addr();
 
         if (result0 !== null) {
           result1 = [];
           pos2 = pos;
           result2 = parse_SEMI();
 
           if (result2 !== null) {
             result3 = parse_generic_param();
 
             if (result3 !== null) {
               result2 = [result2, result3];
             } else {
               result2 = null;
               pos = pos2;
             }
           } else {
             result2 = null;
             pos = pos2;
           }
 
           while (result2 !== null) {
             result1.push(result2);
             pos2 = pos;
             result2 = parse_SEMI();
 
             if (result2 !== null) {
               result3 = parse_generic_param();
 
               if (result3 !== null) {
                 result2 = [result2, result3];
               } else {
                 result2 = null;
                 pos = pos2;
               }
             } else {
               result2 = null;
               pos = pos2;
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             var header;
             if (!data.multi_header) data.multi_header = [];
 
             try {
               header = new NameAddrHeader(data.uri, data.display_name, data.params);
               delete data.uri;
               delete data.display_name;
               delete data.params;
             } catch (e) {
               header = null;
             }
 
             data.multi_header.push({
               'possition': pos,
               'offset': offset,
               'parsed': header
             });
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_Reason() {
         var result0, result1, result2, result3;
         var pos0, pos1, pos2;
         pos0 = pos;
         pos1 = pos;
 
         if (input.substr(pos, 3).toLowerCase() === "sip") {
           result0 = input.substr(pos, 3);
           pos += 3;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"SIP\"");
           }
         }
 
         if (result0 === null) {
           result0 = parse_token();
         }
 
         if (result0 !== null) {
           result1 = [];
           pos2 = pos;
           result2 = parse_SEMI();
 
           if (result2 !== null) {
             result3 = parse_reason_param();
 
             if (result3 !== null) {
               result2 = [result2, result3];
             } else {
               result2 = null;
               pos = pos2;
             }
           } else {
             result2 = null;
             pos = pos2;
           }
 
           while (result2 !== null) {
             result1.push(result2);
             pos2 = pos;
             result2 = parse_SEMI();
 
             if (result2 !== null) {
               result3 = parse_reason_param();
 
               if (result3 !== null) {
                 result2 = [result2, result3];
               } else {
                 result2 = null;
                 pos = pos2;
               }
             } else {
               result2 = null;
               pos = pos2;
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset, protocol) {
             data.protocol = protocol.toLowerCase();
             if (!data.params) data.params = {};
 
             if (data.params.text && data.params.text[0] === '"') {
               var text = data.params.text;
               data.text = text.substring(1, text.length - 1);
               delete data.params.text;
             }
           }(pos0, result0[0]);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_reason_param() {
         var result0;
         result0 = parse_reason_cause();
 
         if (result0 === null) {
           result0 = parse_generic_param();
         }
 
         return result0;
       }
 
       function parse_reason_cause() {
         var result0, result1, result2, result3;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
 
         if (input.substr(pos, 5).toLowerCase() === "cause") {
           result0 = input.substr(pos, 5);
           pos += 5;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"cause\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_EQUAL();
 
           if (result1 !== null) {
             result3 = parse_DIGIT();
 
             if (result3 !== null) {
               result2 = [];
 
               while (result3 !== null) {
                 result2.push(result3);
                 result3 = parse_DIGIT();
               }
             } else {
               result2 = null;
             }
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset, cause) {
             data.cause = parseInt(cause.join(''));
           }(pos0, result0[2]);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_Require() {
         var result0, result1, result2, result3;
         var pos0, pos1;
         pos0 = pos;
         result0 = parse_token();
 
         if (result0 !== null) {
           result1 = [];
           pos1 = pos;
           result2 = parse_COMMA();
 
           if (result2 !== null) {
             result3 = parse_token();
 
             if (result3 !== null) {
               result2 = [result2, result3];
             } else {
               result2 = null;
               pos = pos1;
             }
           } else {
             result2 = null;
             pos = pos1;
           }
 
           while (result2 !== null) {
             result1.push(result2);
             pos1 = pos;
             result2 = parse_COMMA();
 
             if (result2 !== null) {
               result3 = parse_token();
 
               if (result3 !== null) {
                 result2 = [result2, result3];
               } else {
                 result2 = null;
                 pos = pos1;
               }
             } else {
               result2 = null;
               pos = pos1;
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_Route() {
         var result0, result1, result2, result3;
         var pos0, pos1;
         pos0 = pos;
         result0 = parse_route_param();
 
         if (result0 !== null) {
           result1 = [];
           pos1 = pos;
           result2 = parse_COMMA();
 
           if (result2 !== null) {
             result3 = parse_route_param();
 
             if (result3 !== null) {
               result2 = [result2, result3];
             } else {
               result2 = null;
               pos = pos1;
             }
           } else {
             result2 = null;
             pos = pos1;
           }
 
           while (result2 !== null) {
             result1.push(result2);
             pos1 = pos;
             result2 = parse_COMMA();
 
             if (result2 !== null) {
               result3 = parse_route_param();
 
               if (result3 !== null) {
                 result2 = [result2, result3];
               } else {
                 result2 = null;
                 pos = pos1;
               }
             } else {
               result2 = null;
               pos = pos1;
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_route_param() {
         var result0, result1, result2, result3;
         var pos0, pos1;
         pos0 = pos;
         result0 = parse_name_addr();
 
         if (result0 !== null) {
           result1 = [];
           pos1 = pos;
           result2 = parse_SEMI();
 
           if (result2 !== null) {
             result3 = parse_generic_param();
 
             if (result3 !== null) {
               result2 = [result2, result3];
             } else {
               result2 = null;
               pos = pos1;
             }
           } else {
             result2 = null;
             pos = pos1;
           }
 
           while (result2 !== null) {
             result1.push(result2);
             pos1 = pos;
             result2 = parse_SEMI();
 
             if (result2 !== null) {
               result3 = parse_generic_param();
 
               if (result3 !== null) {
                 result2 = [result2, result3];
               } else {
                 result2 = null;
                 pos = pos1;
               }
             } else {
               result2 = null;
               pos = pos1;
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_Subscription_State() {
         var result0, result1, result2, result3;
         var pos0, pos1;
         pos0 = pos;
         result0 = parse_substate_value();
 
         if (result0 !== null) {
           result1 = [];
           pos1 = pos;
           result2 = parse_SEMI();
 
           if (result2 !== null) {
             result3 = parse_subexp_params();
 
             if (result3 !== null) {
               result2 = [result2, result3];
             } else {
               result2 = null;
               pos = pos1;
             }
           } else {
             result2 = null;
             pos = pos1;
           }
 
           while (result2 !== null) {
             result1.push(result2);
             pos1 = pos;
             result2 = parse_SEMI();
 
             if (result2 !== null) {
               result3 = parse_subexp_params();
 
               if (result3 !== null) {
                 result2 = [result2, result3];
               } else {
                 result2 = null;
                 pos = pos1;
               }
             } else {
               result2 = null;
               pos = pos1;
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_substate_value() {
         var result0;
         var pos0;
         pos0 = pos;
 
         if (input.substr(pos, 6).toLowerCase() === "active") {
           result0 = input.substr(pos, 6);
           pos += 6;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"active\"");
           }
         }
 
         if (result0 === null) {
           if (input.substr(pos, 7).toLowerCase() === "pending") {
             result0 = input.substr(pos, 7);
             pos += 7;
           } else {
             result0 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"pending\"");
             }
           }
 
           if (result0 === null) {
             if (input.substr(pos, 10).toLowerCase() === "terminated") {
               result0 = input.substr(pos, 10);
               pos += 10;
             } else {
               result0 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\"terminated\"");
               }
             }
 
             if (result0 === null) {
               result0 = parse_token();
             }
           }
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             data.state = input.substring(pos, offset);
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_subexp_params() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
 
         if (input.substr(pos, 6).toLowerCase() === "reason") {
           result0 = input.substr(pos, 6);
           pos += 6;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"reason\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_EQUAL();
 
           if (result1 !== null) {
             result2 = parse_event_reason_value();
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset, reason) {
             if (typeof reason !== 'undefined') data.reason = reason;
           }(pos0, result0[2]);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         if (result0 === null) {
           pos0 = pos;
           pos1 = pos;
 
           if (input.substr(pos, 7).toLowerCase() === "expires") {
             result0 = input.substr(pos, 7);
             pos += 7;
           } else {
             result0 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"expires\"");
             }
           }
 
           if (result0 !== null) {
             result1 = parse_EQUAL();
 
             if (result1 !== null) {
               result2 = parse_delta_seconds();
 
               if (result2 !== null) {
                 result0 = [result0, result1, result2];
               } else {
                 result0 = null;
                 pos = pos1;
               }
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
 
           if (result0 !== null) {
             result0 = function (offset, expires) {
               if (typeof expires !== 'undefined') data.expires = expires;
             }(pos0, result0[2]);
           }
 
           if (result0 === null) {
             pos = pos0;
           }
 
           if (result0 === null) {
             pos0 = pos;
             pos1 = pos;
 
             if (input.substr(pos, 11).toLowerCase() === "retry_after") {
               result0 = input.substr(pos, 11);
               pos += 11;
             } else {
               result0 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\"retry_after\"");
               }
             }
 
             if (result0 !== null) {
               result1 = parse_EQUAL();
 
               if (result1 !== null) {
                 result2 = parse_delta_seconds();
 
                 if (result2 !== null) {
                   result0 = [result0, result1, result2];
                 } else {
                   result0 = null;
                   pos = pos1;
                 }
               } else {
                 result0 = null;
                 pos = pos1;
               }
             } else {
               result0 = null;
               pos = pos1;
             }
 
             if (result0 !== null) {
               result0 = function (offset, retry_after) {
                 if (typeof retry_after !== 'undefined') data.retry_after = retry_after;
               }(pos0, result0[2]);
             }
 
             if (result0 === null) {
               pos = pos0;
             }
 
             if (result0 === null) {
               result0 = parse_generic_param();
             }
           }
         }
 
         return result0;
       }
 
       function parse_event_reason_value() {
         var result0;
 
         if (input.substr(pos, 11).toLowerCase() === "deactivated") {
           result0 = input.substr(pos, 11);
           pos += 11;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"deactivated\"");
           }
         }
 
         if (result0 === null) {
           if (input.substr(pos, 9).toLowerCase() === "probation") {
             result0 = input.substr(pos, 9);
             pos += 9;
           } else {
             result0 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"probation\"");
             }
           }
 
           if (result0 === null) {
             if (input.substr(pos, 8).toLowerCase() === "rejected") {
               result0 = input.substr(pos, 8);
               pos += 8;
             } else {
               result0 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\"rejected\"");
               }
             }
 
             if (result0 === null) {
               if (input.substr(pos, 7).toLowerCase() === "timeout") {
                 result0 = input.substr(pos, 7);
                 pos += 7;
               } else {
                 result0 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\"timeout\"");
                 }
               }
 
               if (result0 === null) {
                 if (input.substr(pos, 6).toLowerCase() === "giveup") {
                   result0 = input.substr(pos, 6);
                   pos += 6;
                 } else {
                   result0 = null;
 
                   if (reportFailures === 0) {
                     matchFailed("\"giveup\"");
                   }
                 }
 
                 if (result0 === null) {
                   if (input.substr(pos, 10).toLowerCase() === "noresource") {
                     result0 = input.substr(pos, 10);
                     pos += 10;
                   } else {
                     result0 = null;
 
                     if (reportFailures === 0) {
                       matchFailed("\"noresource\"");
                     }
                   }
 
                   if (result0 === null) {
                     if (input.substr(pos, 9).toLowerCase() === "invariant") {
                       result0 = input.substr(pos, 9);
                       pos += 9;
                     } else {
                       result0 = null;
 
                       if (reportFailures === 0) {
                         matchFailed("\"invariant\"");
                       }
                     }
 
                     if (result0 === null) {
                       result0 = parse_token();
                     }
                   }
                 }
               }
             }
           }
         }
 
         return result0;
       }
 
       function parse_Subject() {
         var result0;
         result0 = parse_TEXT_UTF8_TRIM();
         result0 = result0 !== null ? result0 : "";
         return result0;
       }
 
       function parse_Supported() {
         var result0, result1, result2, result3;
         var pos0, pos1;
         pos0 = pos;
         result0 = parse_token();
 
         if (result0 !== null) {
           result1 = [];
           pos1 = pos;
           result2 = parse_COMMA();
 
           if (result2 !== null) {
             result3 = parse_token();
 
             if (result3 !== null) {
               result2 = [result2, result3];
             } else {
               result2 = null;
               pos = pos1;
             }
           } else {
             result2 = null;
             pos = pos1;
           }
 
           while (result2 !== null) {
             result1.push(result2);
             pos1 = pos;
             result2 = parse_COMMA();
 
             if (result2 !== null) {
               result3 = parse_token();
 
               if (result3 !== null) {
                 result2 = [result2, result3];
               } else {
                 result2 = null;
                 pos = pos1;
               }
             } else {
               result2 = null;
               pos = pos1;
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         result0 = result0 !== null ? result0 : "";
         return result0;
       }
 
       function parse_To() {
         var result0, result1, result2, result3;
         var pos0, pos1, pos2;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_SIP_URI_noparams();
 
         if (result0 === null) {
           result0 = parse_name_addr();
         }
 
         if (result0 !== null) {
           result1 = [];
           pos2 = pos;
           result2 = parse_SEMI();
 
           if (result2 !== null) {
             result3 = parse_to_param();
 
             if (result3 !== null) {
               result2 = [result2, result3];
             } else {
               result2 = null;
               pos = pos2;
             }
           } else {
             result2 = null;
             pos = pos2;
           }
 
           while (result2 !== null) {
             result1.push(result2);
             pos2 = pos;
             result2 = parse_SEMI();
 
             if (result2 !== null) {
               result3 = parse_to_param();
 
               if (result3 !== null) {
                 result2 = [result2, result3];
               } else {
                 result2 = null;
                 pos = pos2;
               }
             } else {
               result2 = null;
               pos = pos2;
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             var tag = data.tag;
 
             try {
               data = new NameAddrHeader(data.uri, data.display_name, data.params);
 
               if (tag) {
                 data.setParam('tag', tag);
               }
             } catch (e) {
               data = -1;
             }
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_to_param() {
         var result0;
         result0 = parse_tag_param();
 
         if (result0 === null) {
           result0 = parse_generic_param();
         }
 
         return result0;
       }
 
       function parse_Via() {
         var result0, result1, result2, result3;
         var pos0, pos1;
         pos0 = pos;
         result0 = parse_via_param();
 
         if (result0 !== null) {
           result1 = [];
           pos1 = pos;
           result2 = parse_COMMA();
 
           if (result2 !== null) {
             result3 = parse_via_param();
 
             if (result3 !== null) {
               result2 = [result2, result3];
             } else {
               result2 = null;
               pos = pos1;
             }
           } else {
             result2 = null;
             pos = pos1;
           }
 
           while (result2 !== null) {
             result1.push(result2);
             pos1 = pos;
             result2 = parse_COMMA();
 
             if (result2 !== null) {
               result3 = parse_via_param();
 
               if (result3 !== null) {
                 result2 = [result2, result3];
               } else {
                 result2 = null;
                 pos = pos1;
               }
             } else {
               result2 = null;
               pos = pos1;
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_via_param() {
         var result0, result1, result2, result3, result4, result5;
         var pos0, pos1;
         pos0 = pos;
         result0 = parse_sent_protocol();
 
         if (result0 !== null) {
           result1 = parse_LWS();
 
           if (result1 !== null) {
             result2 = parse_sent_by();
 
             if (result2 !== null) {
               result3 = [];
               pos1 = pos;
               result4 = parse_SEMI();
 
               if (result4 !== null) {
                 result5 = parse_via_params();
 
                 if (result5 !== null) {
                   result4 = [result4, result5];
                 } else {
                   result4 = null;
                   pos = pos1;
                 }
               } else {
                 result4 = null;
                 pos = pos1;
               }
 
               while (result4 !== null) {
                 result3.push(result4);
                 pos1 = pos;
                 result4 = parse_SEMI();
 
                 if (result4 !== null) {
                   result5 = parse_via_params();
 
                   if (result5 !== null) {
                     result4 = [result4, result5];
                   } else {
                     result4 = null;
                     pos = pos1;
                   }
                 } else {
                   result4 = null;
                   pos = pos1;
                 }
               }
 
               if (result3 !== null) {
                 result0 = [result0, result1, result2, result3];
               } else {
                 result0 = null;
                 pos = pos0;
               }
             } else {
               result0 = null;
               pos = pos0;
             }
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_via_params() {
         var result0;
         result0 = parse_via_ttl();
 
         if (result0 === null) {
           result0 = parse_via_maddr();
 
           if (result0 === null) {
             result0 = parse_via_received();
 
             if (result0 === null) {
               result0 = parse_via_branch();
 
               if (result0 === null) {
                 result0 = parse_response_port();
 
                 if (result0 === null) {
                   result0 = parse_generic_param();
                 }
               }
             }
           }
         }
 
         return result0;
       }
 
       function parse_via_ttl() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
 
         if (input.substr(pos, 3).toLowerCase() === "ttl") {
           result0 = input.substr(pos, 3);
           pos += 3;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"ttl\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_EQUAL();
 
           if (result1 !== null) {
             result2 = parse_ttl();
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset, via_ttl_value) {
             data.ttl = via_ttl_value;
           }(pos0, result0[2]);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_via_maddr() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
 
         if (input.substr(pos, 5).toLowerCase() === "maddr") {
           result0 = input.substr(pos, 5);
           pos += 5;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"maddr\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_EQUAL();
 
           if (result1 !== null) {
             result2 = parse_host();
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset, via_maddr) {
             data.maddr = via_maddr;
           }(pos0, result0[2]);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_via_received() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
 
         if (input.substr(pos, 8).toLowerCase() === "received") {
           result0 = input.substr(pos, 8);
           pos += 8;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"received\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_EQUAL();
 
           if (result1 !== null) {
             result2 = parse_IPv4address();
 
             if (result2 === null) {
               result2 = parse_IPv6address();
             }
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset, via_received) {
             data.received = via_received;
           }(pos0, result0[2]);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_via_branch() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
 
         if (input.substr(pos, 6).toLowerCase() === "branch") {
           result0 = input.substr(pos, 6);
           pos += 6;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"branch\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_EQUAL();
 
           if (result1 !== null) {
             result2 = parse_token();
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset, via_branch) {
             data.branch = via_branch;
           }(pos0, result0[2]);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_response_port() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
 
         if (input.substr(pos, 5).toLowerCase() === "rport") {
           result0 = input.substr(pos, 5);
           pos += 5;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"rport\"");
           }
         }
 
         if (result0 !== null) {
           pos1 = pos;
           result1 = parse_EQUAL();
 
           if (result1 !== null) {
             result2 = parse_rport();
 
             if (result2 !== null) {
               result1 = [result1, result2];
             } else {
               result1 = null;
               pos = pos1;
             }
           } else {
             result1 = null;
             pos = pos1;
           }
 
           result1 = result1 !== null ? result1 : "";
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_rport() {
         var result0, result1, result2, result3, result4;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_DIGIT();
         result0 = result0 !== null ? result0 : "";
 
         if (result0 !== null) {
           result1 = parse_DIGIT();
           result1 = result1 !== null ? result1 : "";
 
           if (result1 !== null) {
             result2 = parse_DIGIT();
             result2 = result2 !== null ? result2 : "";
 
             if (result2 !== null) {
               result3 = parse_DIGIT();
               result3 = result3 !== null ? result3 : "";
 
               if (result3 !== null) {
                 result4 = parse_DIGIT();
                 result4 = result4 !== null ? result4 : "";
 
                 if (result4 !== null) {
                   result0 = [result0, result1, result2, result3, result4];
                 } else {
                   result0 = null;
                   pos = pos1;
                 }
               } else {
                 result0 = null;
                 pos = pos1;
               }
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset, rport) {
             data.rport = parseInt(rport.join(''));
           }(pos0, result0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_sent_protocol() {
         var result0, result1, result2, result3, result4;
         var pos0;
         pos0 = pos;
         result0 = parse_protocol_name();
 
         if (result0 !== null) {
           result1 = parse_SLASH();
 
           if (result1 !== null) {
             result2 = parse_token();
 
             if (result2 !== null) {
               result3 = parse_SLASH();
 
               if (result3 !== null) {
                 result4 = parse_transport();
 
                 if (result4 !== null) {
                   result0 = [result0, result1, result2, result3, result4];
                 } else {
                   result0 = null;
                   pos = pos0;
                 }
               } else {
                 result0 = null;
                 pos = pos0;
               }
             } else {
               result0 = null;
               pos = pos0;
             }
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_protocol_name() {
         var result0;
         var pos0;
         pos0 = pos;
 
         if (input.substr(pos, 3).toLowerCase() === "sip") {
           result0 = input.substr(pos, 3);
           pos += 3;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"SIP\"");
           }
         }
 
         if (result0 === null) {
           result0 = parse_token();
         }
 
         if (result0 !== null) {
           result0 = function (offset, via_protocol) {
             data.protocol = via_protocol;
           }(pos0, result0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_transport() {
         var result0;
         var pos0;
         pos0 = pos;
 
         if (input.substr(pos, 3).toLowerCase() === "udp") {
           result0 = input.substr(pos, 3);
           pos += 3;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"UDP\"");
           }
         }
 
         if (result0 === null) {
           if (input.substr(pos, 3).toLowerCase() === "tcp") {
             result0 = input.substr(pos, 3);
             pos += 3;
           } else {
             result0 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"TCP\"");
             }
           }
 
           if (result0 === null) {
             if (input.substr(pos, 3).toLowerCase() === "tls") {
               result0 = input.substr(pos, 3);
               pos += 3;
             } else {
               result0 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\"TLS\"");
               }
             }
 
             if (result0 === null) {
               if (input.substr(pos, 4).toLowerCase() === "sctp") {
                 result0 = input.substr(pos, 4);
                 pos += 4;
               } else {
                 result0 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\"SCTP\"");
                 }
               }
 
               if (result0 === null) {
                 result0 = parse_token();
               }
             }
           }
         }
 
         if (result0 !== null) {
           result0 = function (offset, via_transport) {
             data.transport = via_transport;
           }(pos0, result0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_sent_by() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
         result0 = parse_via_host();
 
         if (result0 !== null) {
           pos1 = pos;
           result1 = parse_COLON();
 
           if (result1 !== null) {
             result2 = parse_via_port();
 
             if (result2 !== null) {
               result1 = [result1, result2];
             } else {
               result1 = null;
               pos = pos1;
             }
           } else {
             result1 = null;
             pos = pos1;
           }
 
           result1 = result1 !== null ? result1 : "";
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_via_host() {
         var result0;
         var pos0;
         pos0 = pos;
         result0 = parse_IPv4address();
 
         if (result0 === null) {
           result0 = parse_IPv6reference();
 
           if (result0 === null) {
             result0 = parse_hostname();
           }
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             data.host = input.substring(pos, offset);
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_via_port() {
         var result0, result1, result2, result3, result4;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_DIGIT();
         result0 = result0 !== null ? result0 : "";
 
         if (result0 !== null) {
           result1 = parse_DIGIT();
           result1 = result1 !== null ? result1 : "";
 
           if (result1 !== null) {
             result2 = parse_DIGIT();
             result2 = result2 !== null ? result2 : "";
 
             if (result2 !== null) {
               result3 = parse_DIGIT();
               result3 = result3 !== null ? result3 : "";
 
               if (result3 !== null) {
                 result4 = parse_DIGIT();
                 result4 = result4 !== null ? result4 : "";
 
                 if (result4 !== null) {
                   result0 = [result0, result1, result2, result3, result4];
                 } else {
                   result0 = null;
                   pos = pos1;
                 }
               } else {
                 result0 = null;
                 pos = pos1;
               }
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset, via_sent_by_port) {
             data.port = parseInt(via_sent_by_port.join(''));
           }(pos0, result0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_ttl() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_DIGIT();
 
         if (result0 !== null) {
           result1 = parse_DIGIT();
           result1 = result1 !== null ? result1 : "";
 
           if (result1 !== null) {
             result2 = parse_DIGIT();
             result2 = result2 !== null ? result2 : "";
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset, ttl) {
             return parseInt(ttl.join(''));
           }(pos0, result0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_WWW_Authenticate() {
         var result0;
         result0 = parse_challenge();
         return result0;
       }
 
       function parse_Session_Expires() {
         var result0, result1, result2, result3;
         var pos0, pos1;
         pos0 = pos;
         result0 = parse_s_e_expires();
 
         if (result0 !== null) {
           result1 = [];
           pos1 = pos;
           result2 = parse_SEMI();
 
           if (result2 !== null) {
             result3 = parse_s_e_params();
 
             if (result3 !== null) {
               result2 = [result2, result3];
             } else {
               result2 = null;
               pos = pos1;
             }
           } else {
             result2 = null;
             pos = pos1;
           }
 
           while (result2 !== null) {
             result1.push(result2);
             pos1 = pos;
             result2 = parse_SEMI();
 
             if (result2 !== null) {
               result3 = parse_s_e_params();
 
               if (result3 !== null) {
                 result2 = [result2, result3];
               } else {
                 result2 = null;
                 pos = pos1;
               }
             } else {
               result2 = null;
               pos = pos1;
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_s_e_expires() {
         var result0;
         var pos0;
         pos0 = pos;
         result0 = parse_delta_seconds();
 
         if (result0 !== null) {
           result0 = function (offset, expires) {
             data.expires = expires;
           }(pos0, result0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_s_e_params() {
         var result0;
         result0 = parse_s_e_refresher();
 
         if (result0 === null) {
           result0 = parse_generic_param();
         }
 
         return result0;
       }
 
       function parse_s_e_refresher() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
 
         if (input.substr(pos, 9).toLowerCase() === "refresher") {
           result0 = input.substr(pos, 9);
           pos += 9;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"refresher\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_EQUAL();
 
           if (result1 !== null) {
             if (input.substr(pos, 3).toLowerCase() === "uac") {
               result2 = input.substr(pos, 3);
               pos += 3;
             } else {
               result2 = null;
 
               if (reportFailures === 0) {
                 matchFailed("\"uac\"");
               }
             }
 
             if (result2 === null) {
               if (input.substr(pos, 3).toLowerCase() === "uas") {
                 result2 = input.substr(pos, 3);
                 pos += 3;
               } else {
                 result2 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\"uas\"");
                 }
               }
             }
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset, s_e_refresher_value) {
             data.refresher = s_e_refresher_value.toLowerCase();
           }(pos0, result0[2]);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_extension_header() {
         var result0, result1, result2;
         var pos0;
         pos0 = pos;
         result0 = parse_token();
 
         if (result0 !== null) {
           result1 = parse_HCOLON();
 
           if (result1 !== null) {
             result2 = parse_header_value();
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos0;
             }
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_header_value() {
         var result0, result1;
         result0 = [];
         result1 = parse_TEXT_UTF8char();
 
         if (result1 === null) {
           result1 = parse_UTF8_CONT();
 
           if (result1 === null) {
             result1 = parse_LWS();
           }
         }
 
         while (result1 !== null) {
           result0.push(result1);
           result1 = parse_TEXT_UTF8char();
 
           if (result1 === null) {
             result1 = parse_UTF8_CONT();
 
             if (result1 === null) {
               result1 = parse_LWS();
             }
           }
         }
 
         return result0;
       }
 
       function parse_message_body() {
         var result0, result1;
         result0 = [];
         result1 = parse_OCTET();
 
         while (result1 !== null) {
           result0.push(result1);
           result1 = parse_OCTET();
         }
 
         return result0;
       }
 
       function parse_uuid_URI() {
         var result0, result1;
         var pos0;
         pos0 = pos;
 
         if (input.substr(pos, 5) === "uuid:") {
           result0 = "uuid:";
           pos += 5;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"uuid:\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_uuid();
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_uuid() {
         var result0, result1, result2, result3, result4, result5, result6, result7, result8;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_hex8();
 
         if (result0 !== null) {
           if (input.charCodeAt(pos) === 45) {
             result1 = "-";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"-\"");
             }
           }
 
           if (result1 !== null) {
             result2 = parse_hex4();
 
             if (result2 !== null) {
               if (input.charCodeAt(pos) === 45) {
                 result3 = "-";
                 pos++;
               } else {
                 result3 = null;
 
                 if (reportFailures === 0) {
                   matchFailed("\"-\"");
                 }
               }
 
               if (result3 !== null) {
                 result4 = parse_hex4();
 
                 if (result4 !== null) {
                   if (input.charCodeAt(pos) === 45) {
                     result5 = "-";
                     pos++;
                   } else {
                     result5 = null;
 
                     if (reportFailures === 0) {
                       matchFailed("\"-\"");
                     }
                   }
 
                   if (result5 !== null) {
                     result6 = parse_hex4();
 
                     if (result6 !== null) {
                       if (input.charCodeAt(pos) === 45) {
                         result7 = "-";
                         pos++;
                       } else {
                         result7 = null;
 
                         if (reportFailures === 0) {
                           matchFailed("\"-\"");
                         }
                       }
 
                       if (result7 !== null) {
                         result8 = parse_hex12();
 
                         if (result8 !== null) {
                           result0 = [result0, result1, result2, result3, result4, result5, result6, result7, result8];
                         } else {
                           result0 = null;
                           pos = pos1;
                         }
                       } else {
                         result0 = null;
                         pos = pos1;
                       }
                     } else {
                       result0 = null;
                       pos = pos1;
                     }
                   } else {
                     result0 = null;
                     pos = pos1;
                   }
                 } else {
                   result0 = null;
                   pos = pos1;
                 }
               } else {
                 result0 = null;
                 pos = pos1;
               }
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset, uuid) {
             data = input.substring(pos + 5, offset);
           }(pos0, result0[0]);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_hex4() {
         var result0, result1, result2, result3;
         var pos0;
         pos0 = pos;
         result0 = parse_HEXDIG();
 
         if (result0 !== null) {
           result1 = parse_HEXDIG();
 
           if (result1 !== null) {
             result2 = parse_HEXDIG();
 
             if (result2 !== null) {
               result3 = parse_HEXDIG();
 
               if (result3 !== null) {
                 result0 = [result0, result1, result2, result3];
               } else {
                 result0 = null;
                 pos = pos0;
               }
             } else {
               result0 = null;
               pos = pos0;
             }
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_hex8() {
         var result0, result1;
         var pos0;
         pos0 = pos;
         result0 = parse_hex4();
 
         if (result0 !== null) {
           result1 = parse_hex4();
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_hex12() {
         var result0, result1, result2;
         var pos0;
         pos0 = pos;
         result0 = parse_hex4();
 
         if (result0 !== null) {
           result1 = parse_hex4();
 
           if (result1 !== null) {
             result2 = parse_hex4();
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos0;
             }
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_Refer_To() {
         var result0, result1, result2, result3;
         var pos0, pos1, pos2;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_SIP_URI_noparams();
 
         if (result0 === null) {
           result0 = parse_name_addr();
         }
 
         if (result0 !== null) {
           result1 = [];
           pos2 = pos;
           result2 = parse_SEMI();
 
           if (result2 !== null) {
             result3 = parse_generic_param();
 
             if (result3 !== null) {
               result2 = [result2, result3];
             } else {
               result2 = null;
               pos = pos2;
             }
           } else {
             result2 = null;
             pos = pos2;
           }
 
           while (result2 !== null) {
             result1.push(result2);
             pos2 = pos;
             result2 = parse_SEMI();
 
             if (result2 !== null) {
               result3 = parse_generic_param();
 
               if (result3 !== null) {
                 result2 = [result2, result3];
               } else {
                 result2 = null;
                 pos = pos2;
               }
             } else {
               result2 = null;
               pos = pos2;
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             try {
               data = new NameAddrHeader(data.uri, data.display_name, data.params);
             } catch (e) {
               data = -1;
             }
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_Replaces() {
         var result0, result1, result2, result3;
         var pos0, pos1;
         pos0 = pos;
         result0 = parse_call_id();
 
         if (result0 !== null) {
           result1 = [];
           pos1 = pos;
           result2 = parse_SEMI();
 
           if (result2 !== null) {
             result3 = parse_replaces_param();
 
             if (result3 !== null) {
               result2 = [result2, result3];
             } else {
               result2 = null;
               pos = pos1;
             }
           } else {
             result2 = null;
             pos = pos1;
           }
 
           while (result2 !== null) {
             result1.push(result2);
             pos1 = pos;
             result2 = parse_SEMI();
 
             if (result2 !== null) {
               result3 = parse_replaces_param();
 
               if (result3 !== null) {
                 result2 = [result2, result3];
               } else {
                 result2 = null;
                 pos = pos1;
               }
             } else {
               result2 = null;
               pos = pos1;
             }
           }
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos0;
           }
         } else {
           result0 = null;
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_call_id() {
         var result0, result1, result2;
         var pos0, pos1, pos2;
         pos0 = pos;
         pos1 = pos;
         result0 = parse_word();
 
         if (result0 !== null) {
           pos2 = pos;
 
           if (input.charCodeAt(pos) === 64) {
             result1 = "@";
             pos++;
           } else {
             result1 = null;
 
             if (reportFailures === 0) {
               matchFailed("\"@\"");
             }
           }
 
           if (result1 !== null) {
             result2 = parse_word();
 
             if (result2 !== null) {
               result1 = [result1, result2];
             } else {
               result1 = null;
               pos = pos2;
             }
           } else {
             result1 = null;
             pos = pos2;
           }
 
           result1 = result1 !== null ? result1 : "";
 
           if (result1 !== null) {
             result0 = [result0, result1];
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             data.call_id = input.substring(pos, offset);
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_replaces_param() {
         var result0;
         result0 = parse_to_tag();
 
         if (result0 === null) {
           result0 = parse_from_tag();
 
           if (result0 === null) {
             result0 = parse_early_flag();
 
             if (result0 === null) {
               result0 = parse_generic_param();
             }
           }
         }
 
         return result0;
       }
 
       function parse_to_tag() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
 
         if (input.substr(pos, 6) === "to-tag") {
           result0 = "to-tag";
           pos += 6;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"to-tag\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_EQUAL();
 
           if (result1 !== null) {
             result2 = parse_token();
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset, to_tag) {
             data.to_tag = to_tag;
           }(pos0, result0[2]);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_from_tag() {
         var result0, result1, result2;
         var pos0, pos1;
         pos0 = pos;
         pos1 = pos;
 
         if (input.substr(pos, 8) === "from-tag") {
           result0 = "from-tag";
           pos += 8;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"from-tag\"");
           }
         }
 
         if (result0 !== null) {
           result1 = parse_EQUAL();
 
           if (result1 !== null) {
             result2 = parse_token();
 
             if (result2 !== null) {
               result0 = [result0, result1, result2];
             } else {
               result0 = null;
               pos = pos1;
             }
           } else {
             result0 = null;
             pos = pos1;
           }
         } else {
           result0 = null;
           pos = pos1;
         }
 
         if (result0 !== null) {
           result0 = function (offset, from_tag) {
             data.from_tag = from_tag;
           }(pos0, result0[2]);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function parse_early_flag() {
         var result0;
         var pos0;
         pos0 = pos;
 
         if (input.substr(pos, 10) === "early-only") {
           result0 = "early-only";
           pos += 10;
         } else {
           result0 = null;
 
           if (reportFailures === 0) {
             matchFailed("\"early-only\"");
           }
         }
 
         if (result0 !== null) {
           result0 = function (offset) {
             data.early_only = true;
           }(pos0);
         }
 
         if (result0 === null) {
           pos = pos0;
         }
 
         return result0;
       }
 
       function cleanupExpected(expected) {
         expected.sort();
         var lastExpected = null;
         var cleanExpected = [];
 
         for (var i = 0; i < expected.length; i++) {
           if (expected[i] !== lastExpected) {
             cleanExpected.push(expected[i]);
             lastExpected = expected[i];
           }
         }
 
         return cleanExpected;
       }
 
       function computeErrorPosition() {
         /*
          * The first idea was to use |String.split| to break the input up to the
          * error position along newlines and derive the line and column from
          * there. However IE's |split| implementation is so broken that it was
          * enough to prevent it.
          */
         var line = 1;
         var column = 1;
         var seenCR = false;
 
         for (var i = 0; i < Math.max(pos, rightmostFailuresPos); i++) {
           var ch = input.charAt(i);
 
           if (ch === "\n") {
             if (!seenCR) {
               line++;
             }
 
             column = 1;
             seenCR = false;
           } else if (ch === "\r" || ch === "\u2028" || ch === "\u2029") {
             line++;
             column = 1;
             seenCR = true;
           } else {
             column++;
             seenCR = false;
           }
         }
 
         return {
           line: line,
           column: column
         };
       }
 
       var URI = require('./URI');
 
       var NameAddrHeader = require('./NameAddrHeader');
 
       var data = {};
       var result = parseFunctions[startRule]();
       /*
        * The parser is now in one of the following three states:
        *
        * 1. The parser successfully parsed the whole input.
        *
        *    - |result !== null|
        *    - |pos === input.length|
        *    - |rightmostFailuresExpected| may or may not contain something
        *
        * 2. The parser successfully parsed only a part of the input.
        *
        *    - |result !== null|
        *    - |pos < input.length|
        *    - |rightmostFailuresExpected| may or may not contain something
        *
        * 3. The parser did not successfully parse any part of the input.
        *
        *   - |result === null|
        *   - |pos === 0|
        *   - |rightmostFailuresExpected| contains at least one failure
        *
        * All code following this comment (including called functions) must
        * handle these states.
        */
 
       if (result === null || pos !== input.length) {
         var offset = Math.max(pos, rightmostFailuresPos);
         var found = offset < input.length ? input.charAt(offset) : null;
         var errorPosition = computeErrorPosition();
         new this.SyntaxError(cleanupExpected(rightmostFailuresExpected), found, offset, errorPosition.line, errorPosition.column);
         return -1;
       }
 
       return data;
     },
 
     /* Returns the parser source code. */
     toSource: function toSource() {
       return this._source;
     }
   };
   /* Thrown when a parser encounters a syntax error. */
 
   result.SyntaxError = function (expected, found, offset, line, column) {
     function buildMessage(expected, found) {
       var expectedHumanized, foundHumanized;
 
       switch (expected.length) {
         case 0:
           expectedHumanized = "end of input";
           break;
 
         case 1:
           expectedHumanized = expected[0];
           break;
 
         default:
           expectedHumanized = expected.slice(0, expected.length - 1).join(", ") + " or " + expected[expected.length - 1];
       }
 
       foundHumanized = found ? quote(found) : "end of input";
       return "Expected " + expectedHumanized + " but " + foundHumanized + " found.";
     }
 
     this.name = "SyntaxError";
     this.expected = expected;
     this.found = found;
     this.message = buildMessage(expected, found);
     this.offset = offset;
     this.line = line;
     this.column = column;
   };
 
   result.SyntaxError.prototype = Error.prototype;
   return result;
 }();
 },{"./NameAddrHeader":10,"./URI":25}],8:[function(require,module,exports){
 "use strict";
 
 var pkg = require('../package.json');
 
 var C = require('./Constants');
 
 var Exceptions = require('./Exceptions');
 
 var Utils = require('./Utils');
 
 var UA = require('./UA');
 
 var URI = require('./URI');
 
 var NameAddrHeader = require('./NameAddrHeader');
 
 var Grammar = require('./Grammar');
 
 var WebSocketInterface = require('./WebSocketInterface');
 
 var debug = require('debug')('JsSIP');
 
 debug('version %s', pkg.version);
 /**
  * Expose the JsSIP module.
  */
 
 module.exports = {
   C: C,
   Exceptions: Exceptions,
   Utils: Utils,
   UA: UA,
   URI: URI,
   NameAddrHeader: NameAddrHeader,
   WebSocketInterface: WebSocketInterface,
   Grammar: Grammar,
   // Expose the debug module.
   debug: require('debug'),
 
   get name() {
     return pkg.title;
   },
 
   get version() {
     return pkg.version;
   }
 
 };
 },{"../package.json":38,"./Constants":2,"./Exceptions":6,"./Grammar":7,"./NameAddrHeader":10,"./UA":24,"./URI":25,"./Utils":26,"./WebSocketInterface":27,"debug":30}],9:[function(require,module,exports){
 "use strict";
 
 function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
 
 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
 function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
 
 function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
 
 function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
 
 function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
 
 function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
 
 function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
 
 function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
 
 function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }
 
 function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
 
 var EventEmitter = require('events').EventEmitter;
 
 var JsSIP_C = require('./Constants');
 
 var SIPMessage = require('./SIPMessage');
 
 var Utils = require('./Utils');
 
 var RequestSender = require('./RequestSender');
 
 var Exceptions = require('./Exceptions');
 
 var debug = require('debug')('JsSIP:Message');
 
 module.exports = /*#__PURE__*/function (_EventEmitter) {
   _inherits(Message, _EventEmitter);
 
   var _super = _createSuper(Message);
 
   function Message(ua) {
     var _this;
 
     _classCallCheck(this, Message);
 
     _this = _super.call(this);
     _this._ua = ua;
     _this._request = null;
     _this._closed = false;
     _this._direction = null;
     _this._local_identity = null;
     _this._remote_identity = null; // Whether an incoming message has been replied.
 
     _this._is_replied = false; // Custom message empty object for high level use.
 
     _this._data = {};
     return _this;
   }
 
   _createClass(Message, [{
     key: "send",
     value: function send(target, body) {
       var _this2 = this;
 
       var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
       var originalTarget = target;
 
       if (target === undefined || body === undefined) {
         throw new TypeError('Not enough arguments');
       } // Check target validity.
 
 
       target = this._ua.normalizeTarget(target);
 
       if (!target) {
         throw new TypeError("Invalid target: ".concat(originalTarget));
       } // Get call options.
 
 
       var extraHeaders = Utils.cloneArray(options.extraHeaders);
       var eventHandlers = Utils.cloneObject(options.eventHandlers);
       var contentType = options.contentType || 'text/plain'; // Set event handlers.
 
       for (var event in eventHandlers) {
         if (Object.prototype.hasOwnProperty.call(eventHandlers, event)) {
           this.on(event, eventHandlers[event]);
         }
       }
 
       extraHeaders.push("Content-Type: ".concat(contentType));
       this._request = new SIPMessage.OutgoingRequest(JsSIP_C.MESSAGE, target, this._ua, null, extraHeaders);
 
       if (body) {
         this._request.body = body;
       }
 
       var request_sender = new RequestSender(this._ua, this._request, {
         onRequestTimeout: function onRequestTimeout() {
           _this2._onRequestTimeout();
         },
         onTransportError: function onTransportError() {
           _this2._onTransportError();
         },
         onReceiveResponse: function onReceiveResponse(response) {
           _this2._receiveResponse(response);
         }
       });
 
       this._newMessage('local', this._request);
 
       request_sender.send();
     }
   }, {
     key: "init_incoming",
     value: function init_incoming(request) {
       this._request = request;
 
       this._newMessage('remote', request); // Reply with a 200 OK if the user didn't reply.
 
 
       if (!this._is_replied) {
         this._is_replied = true;
         request.reply(200);
       }
 
       this._close();
     }
     /**
      * Accept the incoming Message
      * Only valid for incoming Messages
      */
 
   }, {
     key: "accept",
     value: function accept() {
       var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
       var extraHeaders = Utils.cloneArray(options.extraHeaders);
       var body = options.body;
 
       if (this._direction !== 'incoming') {
         throw new Exceptions.NotSupportedError('"accept" not supported for outgoing Message');
       }
 
       if (this._is_replied) {
         throw new Error('incoming Message already replied');
       }
 
       this._is_replied = true;
 
       this._request.reply(200, null, extraHeaders, body);
     }
     /**
      * Reject the incoming Message
      * Only valid for incoming Messages
      */
 
   }, {
     key: "reject",
     value: function reject() {
       var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
       var status_code = options.status_code || 480;
       var reason_phrase = options.reason_phrase;
       var extraHeaders = Utils.cloneArray(options.extraHeaders);
       var body = options.body;
 
       if (this._direction !== 'incoming') {
         throw new Exceptions.NotSupportedError('"reject" not supported for outgoing Message');
       }
 
       if (this._is_replied) {
         throw new Error('incoming Message already replied');
       }
 
       if (status_code < 300 || status_code >= 700) {
         throw new TypeError("Invalid status_code: ".concat(status_code));
       }
 
       this._is_replied = true;
 
       this._request.reply(status_code, reason_phrase, extraHeaders, body);
     }
   }, {
     key: "_receiveResponse",
     value: function _receiveResponse(response) {
       if (this._closed) {
         return;
       }
 
       switch (true) {
         case /^1[0-9]{2}$/.test(response.status_code):
           // Ignore provisional responses.
           break;
 
         case /^2[0-9]{2}$/.test(response.status_code):
           this._succeeded('remote', response);
 
           break;
 
         default:
           {
             var cause = Utils.sipErrorCause(response.status_code);
 
             this._failed('remote', response, cause);
 
             break;
           }
       }
     }
   }, {
     key: "_onRequestTimeout",
     value: function _onRequestTimeout() {
       if (this._closed) {
         return;
       }
 
       this._failed('system', null, JsSIP_C.causes.REQUEST_TIMEOUT);
     }
   }, {
     key: "_onTransportError",
     value: function _onTransportError() {
       if (this._closed) {
         return;
       }
 
       this._failed('system', null, JsSIP_C.causes.CONNECTION_ERROR);
     }
   }, {
     key: "_close",
     value: function _close() {
       this._closed = true;
 
       this._ua.destroyMessage(this);
     }
     /**
      * Internal Callbacks
      */
 
   }, {
     key: "_newMessage",
     value: function _newMessage(originator, request) {
       if (originator === 'remote') {
         this._direction = 'incoming';
         this._local_identity = request.to;
         this._remote_identity = request.from;
       } else if (originator === 'local') {
         this._direction = 'outgoing';
         this._local_identity = request.from;
         this._remote_identity = request.to;
       }
 
       this._ua.newMessage(this, {
         originator: originator,
         message: this,
         request: request
       });
     }
   }, {
     key: "_failed",
     value: function _failed(originator, response, cause) {
       debug('MESSAGE failed');
 
       this._close();
 
       debug('emit "failed"');
       this.emit('failed', {
         originator: originator,
         response: response || null,
         cause: cause
       });
     }
   }, {
     key: "_succeeded",
     value: function _succeeded(originator, response) {
       debug('MESSAGE succeeded');
 
       this._close();
 
       debug('emit "succeeded"');
       this.emit('succeeded', {
         originator: originator,
         response: response
       });
     }
   }, {
     key: "direction",
     get: function get() {
       return this._direction;
     }
   }, {
     key: "local_identity",
     get: function get() {
       return this._local_identity;
     }
   }, {
     key: "remote_identity",
     get: function get() {
       return this._remote_identity;
     }
   }]);
 
   return Message;
 }(EventEmitter);
 },{"./Constants":2,"./Exceptions":6,"./RequestSender":18,"./SIPMessage":19,"./Utils":26,"debug":30,"events":29}],10:[function(require,module,exports){
 "use strict";
 
 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
 function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
 
 function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
 
 var URI = require('./URI');
 
 var Grammar = require('./Grammar');
 
 module.exports = /*#__PURE__*/function () {
   _createClass(NameAddrHeader, null, [{
     key: "parse",
 
     /**
      * Parse the given string and returns a NameAddrHeader instance or undefined if
      * it is an invalid NameAddrHeader.
      */
     value: function parse(name_addr_header) {
       name_addr_header = Grammar.parse(name_addr_header, 'Name_Addr_Header');
 
       if (name_addr_header !== -1) {
         return name_addr_header;
       } else {
         return undefined;
       }
     }
   }]);
 
   function NameAddrHeader(uri, display_name, parameters) {
     _classCallCheck(this, NameAddrHeader);
 
     // Checks.
     if (!uri || !(uri instanceof URI)) {
       throw new TypeError('missing or invalid "uri" parameter');
     } // Initialize parameters.
 
 
     this._uri = uri;
     this._parameters = {};
     this.display_name = display_name;
 
     for (var param in parameters) {
       if (Object.prototype.hasOwnProperty.call(parameters, param)) {
         this.setParam(param, parameters[param]);
       }
     }
   }
 
   _createClass(NameAddrHeader, [{
     key: "setParam",
     value: function setParam(key, value) {
       if (key) {
         this._parameters[key.toLowerCase()] = typeof value === 'undefined' || value === null ? null : value.toString();
       }
     }
   }, {
     key: "getParam",
     value: function getParam(key) {
       if (key) {
         return this._parameters[key.toLowerCase()];
       }
     }
   }, {
     key: "hasParam",
     value: function hasParam(key) {
       if (key) {
         return this._parameters.hasOwnProperty(key.toLowerCase()) && true || false;
       }
     }
   }, {
     key: "deleteParam",
     value: function deleteParam(parameter) {
       parameter = parameter.toLowerCase();
 
       if (this._parameters.hasOwnProperty(parameter)) {
         var value = this._parameters[parameter];
         delete this._parameters[parameter];
         return value;
       }
     }
   }, {
     key: "clearParams",
     value: function clearParams() {
       this._parameters = {};
     }
   }, {
     key: "clone",
     value: function clone() {
       return new NameAddrHeader(this._uri.clone(), this._display_name, JSON.parse(JSON.stringify(this._parameters)));
     }
   }, {
     key: "_quote",
     value: function _quote(str) {
       return str.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
     }
   }, {
     key: "toString",
     value: function toString() {
       var body = this._display_name ? "\"".concat(this._quote(this._display_name), "\" ") : '';
       body += "<".concat(this._uri.toString(), ">");
 
       for (var parameter in this._parameters) {
         if (Object.prototype.hasOwnProperty.call(this._parameters, parameter)) {
           body += ";".concat(parameter);
 
           if (this._parameters[parameter] !== null) {
             body += "=".concat(this._parameters[parameter]);
           }
         }
       }
 
       return body;
     }
   }, {
     key: "uri",
     get: function get() {
       return this._uri;
     }
   }, {
     key: "display_name",
     get: function get() {
       return this._display_name;
     },
     set: function set(value) {
       this._display_name = value === 0 ? '0' : value;
     }
   }]);
 
   return NameAddrHeader;
 }();
 },{"./Grammar":7,"./URI":25}],11:[function(require,module,exports){
 "use strict";
 
 function _createForOfIteratorHelper(o, allowArrayLike) { var it; if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
 
 function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
 
 function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
 
 var Grammar = require('./Grammar');
 
 var SIPMessage = require('./SIPMessage');
 
 var debugerror = require('debug')('JsSIP:ERROR:Parser');
 
 debugerror.log = console.warn.bind(console);
 /**
  * Parse SIP Message
  */
 
 exports.parseMessage = function (data, ua) {
   var message;
   var bodyStart;
   var headerEnd = data.indexOf('\r\n');
 
   if (headerEnd === -1) {
     debugerror('parseMessage() | no CRLF found, not a SIP message');
     return;
   } // Parse first line. Check if it is a Request or a Reply.
 
 
   var firstLine = data.substring(0, headerEnd);
   var parsed = Grammar.parse(firstLine, 'Request_Response');
 
   if (parsed === -1) {
     debugerror("parseMessage() | error parsing first line of SIP message: \"".concat(firstLine, "\""));
     return;
   } else if (!parsed.status_code) {
     message = new SIPMessage.IncomingRequest(ua);
     message.method = parsed.method;
     message.ruri = parsed.uri;
   } else {
     message = new SIPMessage.IncomingResponse();
     message.status_code = parsed.status_code;
     message.reason_phrase = parsed.reason_phrase;
   }
 
   message.data = data;
   var headerStart = headerEnd + 2;
   /* Loop over every line in data. Detect the end of each header and parse
   * it or simply add to the headers collection.
   */
 
   while (true) {
     headerEnd = getHeader(data, headerStart); // The SIP message has normally finished.
 
     if (headerEnd === -2) {
       bodyStart = headerStart + 2;
       break;
     } // Data.indexOf returned -1 due to a malformed message.
     else if (headerEnd === -1) {
         debugerror('parseMessage() | malformed message');
         return;
       }
 
     parsed = parseHeader(message, data, headerStart, headerEnd);
 
     if (parsed !== true) {
       debugerror('parseMessage() |', parsed.error);
       return;
     }
 
     headerStart = headerEnd + 2;
   }
   /* RFC3261 18.3.
    * If there are additional bytes in the transport packet
    * beyond the end of the body, they MUST be discarded.
    */
 
 
   if (message.hasHeader('content-length')) {
     var contentLength = message.getHeader('content-length');
     message.body = data.substr(bodyStart, contentLength);
   } else {
     message.body = data.substring(bodyStart);
   }
 
   return message;
 };
 /**
  * Extract and parse every header of a SIP message.
  */
 
 
 function getHeader(data, headerStart) {
   // 'start' position of the header.
   var start = headerStart; // 'end' position of the header.
 
   var end = 0; // 'partial end' position of the header.
 
   var partialEnd = 0; // End of message.
 
   if (data.substring(start, start + 2).match(/(^\r\n)/)) {
     return -2;
   }
 
   while (end === 0) {
     // Partial End of Header.
     partialEnd = data.indexOf('\r\n', start); // 'indexOf' returns -1 if the value to be found never occurs.
 
     if (partialEnd === -1) {
       return partialEnd;
     }
 
     if (!data.substring(partialEnd + 2, partialEnd + 4).match(/(^\r\n)/) && data.charAt(partialEnd + 2).match(/(^\s+)/)) {
       // Not the end of the message. Continue from the next position.
       start = partialEnd + 2;
     } else {
       end = partialEnd;
     }
   }
 
   return end;
 }
 
 function parseHeader(message, data, headerStart, headerEnd) {
   var parsed;
   var hcolonIndex = data.indexOf(':', headerStart);
   var headerName = data.substring(headerStart, hcolonIndex).trim();
   var headerValue = data.substring(hcolonIndex + 1, headerEnd).trim(); // If header-field is well-known, parse it.
 
   switch (headerName.toLowerCase()) {
     case 'via':
     case 'v':
       message.addHeader('via', headerValue);
 
       if (message.getHeaders('via').length === 1) {
         parsed = message.parseHeader('Via');
 
         if (parsed) {
           message.via = parsed;
           message.via_branch = parsed.branch;
         }
       } else {
         parsed = 0;
       }
 
       break;
 
     case 'from':
     case 'f':
       message.setHeader('from', headerValue);
       parsed = message.parseHeader('from');
 
       if (parsed) {
         message.from = parsed;
         message.from_tag = parsed.getParam('tag');
       }
 
       break;
 
     case 'to':
     case 't':
       message.setHeader('to', headerValue);
       parsed = message.parseHeader('to');
 
       if (parsed) {
         message.to = parsed;
         message.to_tag = parsed.getParam('tag');
       }
 
       break;
 
     case 'record-route':
       parsed = Grammar.parse(headerValue, 'Record_Route');
 
       if (parsed === -1) {
         parsed = undefined;
       } else {
         var _iterator = _createForOfIteratorHelper(parsed),
             _step;
 
         try {
           for (_iterator.s(); !(_step = _iterator.n()).done;) {
             var header = _step.value;
             message.addHeader('record-route', headerValue.substring(header.possition, header.offset));
             message.headers['Record-Route'][message.getHeaders('record-route').length - 1].parsed = header.parsed;
           }
         } catch (err) {
           _iterator.e(err);
         } finally {
           _iterator.f();
         }
       }
 
       break;
 
     case 'call-id':
     case 'i':
       message.setHeader('call-id', headerValue);
       parsed = message.parseHeader('call-id');
 
       if (parsed) {
         message.call_id = headerValue;
       }
 
       break;
 
     case 'contact':
     case 'm':
       parsed = Grammar.parse(headerValue, 'Contact');
 
       if (parsed === -1) {
         parsed = undefined;
       } else {
         var _iterator2 = _createForOfIteratorHelper(parsed),
             _step2;
 
         try {
           for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
             var _header = _step2.value;
             message.addHeader('contact', headerValue.substring(_header.possition, _header.offset));
             message.headers.Contact[message.getHeaders('contact').length - 1].parsed = _header.parsed;
           }
         } catch (err) {
           _iterator2.e(err);
         } finally {
           _iterator2.f();
         }
       }
 
       break;
 
     case 'content-length':
     case 'l':
       message.setHeader('content-length', headerValue);
       parsed = message.parseHeader('content-length');
       break;
 
     case 'content-type':
     case 'c':
       message.setHeader('content-type', headerValue);
       parsed = message.parseHeader('content-type');
       break;
 
     case 'cseq':
       message.setHeader('cseq', headerValue);
       parsed = message.parseHeader('cseq');
 
       if (parsed) {
         message.cseq = parsed.value;
       }
 
       if (message instanceof SIPMessage.IncomingResponse) {
         message.method = parsed.method;
       }
 
       break;
 
     case 'max-forwards':
       message.setHeader('max-forwards', headerValue);
       parsed = message.parseHeader('max-forwards');
       break;
 
     case 'www-authenticate':
       message.setHeader('www-authenticate', headerValue);
       parsed = message.parseHeader('www-authenticate');
       break;
 
     case 'proxy-authenticate':
       message.setHeader('proxy-authenticate', headerValue);
       parsed = message.parseHeader('proxy-authenticate');
       break;
 
     case 'session-expires':
     case 'x':
       message.setHeader('session-expires', headerValue);
       parsed = message.parseHeader('session-expires');
 
       if (parsed) {
         message.session_expires = parsed.expires;
         message.session_expires_refresher = parsed.refresher;
       }
 
       break;
 
     case 'refer-to':
     case 'r':
       message.setHeader('refer-to', headerValue);
       parsed = message.parseHeader('refer-to');
 
       if (parsed) {
         message.refer_to = parsed;
       }
 
       break;
 
     case 'replaces':
       message.setHeader('replaces', headerValue);
       parsed = message.parseHeader('replaces');
 
       if (parsed) {
         message.replaces = parsed;
       }
 
       break;
 
     case 'event':
     case 'o':
       message.setHeader('event', headerValue);
       parsed = message.parseHeader('event');
 
       if (parsed) {
         message.event = parsed;
       }
 
       break;
 
     default:
       // Do not parse this header.
       message.addHeader(headerName, headerValue);
       parsed = 0;
   }
 
   if (parsed === undefined) {
     return {
       error: "error parsing header \"".concat(headerName, "\"")
     };
   } else {
     return true;
   }
 }
 },{"./Grammar":7,"./SIPMessage":19,"debug":30}],12:[function(require,module,exports){
 "use strict";
 
 function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
 
 function _createForOfIteratorHelper(o, allowArrayLike) { var it; if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e2) { throw _e2; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e3) { didErr = true; err = _e3; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
 
 function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
 
 function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
 
 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
 function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
 
 function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
 
 function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
 
 function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
 
 function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
 
 function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
 
 function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
 
 function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }
 
 function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
 
 /* globals RTCPeerConnection: false, RTCSessionDescription: false */
 var EventEmitter = require('events').EventEmitter;
 
 var sdp_transform = require('sdp-transform');
 
 var JsSIP_C = require('./Constants');
 
 var Exceptions = require('./Exceptions');
 
 var Transactions = require('./Transactions');
 
 var Utils = require('./Utils');
 
 var Timers = require('./Timers');
 
 var SIPMessage = require('./SIPMessage');
 
 var Dialog = require('./Dialog');
 
 var RequestSender = require('./RequestSender');
 
 var RTCSession_DTMF = require('./RTCSession/DTMF');
 
 var RTCSession_Info = require('./RTCSession/Info');
 
 var RTCSession_ReferNotifier = require('./RTCSession/ReferNotifier');
 
 var RTCSession_ReferSubscriber = require('./RTCSession/ReferSubscriber');
 
 var URI = require('./URI');
 
 var debug = require('debug')('JsSIP:RTCSession');
 
 var debugerror = require('debug')('JsSIP:ERROR:RTCSession');
 
 debugerror.log = console.warn.bind(console);
 var C = {
   // RTCSession states.
   STATUS_NULL: 0,
   STATUS_INVITE_SENT: 1,
   STATUS_1XX_RECEIVED: 2,
   STATUS_INVITE_RECEIVED: 3,
   STATUS_WAITING_FOR_ANSWER: 4,
   STATUS_ANSWERED: 5,
   STATUS_WAITING_FOR_ACK: 6,
   STATUS_CANCELED: 7,
   STATUS_TERMINATED: 8,
   STATUS_CONFIRMED: 9
 };
 /**
  * Local variables.
  */
 
 var holdMediaTypes = ['audio', 'video'];
 
 module.exports = /*#__PURE__*/function (_EventEmitter) {
   _inherits(RTCSession, _EventEmitter);
 
   var _super = _createSuper(RTCSession);
 
   _createClass(RTCSession, null, [{
     key: "C",
 
     /**
      * Expose C object.
      */
     get: function get() {
       return C;
     }
   }]);
 
   function RTCSession(ua) {
     var _this;
 
     _classCallCheck(this, RTCSession);
 
     debug('new');
     _this = _super.call(this);
     _this._id = null;
     _this._ua = ua;
     _this._status = C.STATUS_NULL;
     _this._dialog = null;
     _this._earlyDialogs = {};
     _this._contact = null;
     _this._from_tag = null;
     _this._to_tag = null; // The RTCPeerConnection instance (public attribute).
 
     _this._connection = null; // Prevent races on serial PeerConnction operations.
 
     _this._connectionPromiseQueue = Promise.resolve(); // Incoming/Outgoing request being currently processed.
 
     _this._request = null; // Cancel state for initial outgoing request.
 
     _this._is_canceled = false;
     _this._cancel_reason = ''; // RTCSession confirmation flag.
 
     _this._is_confirmed = false; // Is late SDP being negotiated.
 
     _this._late_sdp = false; // Default rtcOfferConstraints and rtcAnswerConstrainsts (passed in connect() or answer()).
 
     _this._rtcOfferConstraints = null;
     _this._rtcAnswerConstraints = null; // Local MediaStream.
 
     _this._localMediaStream = null;
     _this._localMediaStreamLocallyGenerated = false; // Flag to indicate PeerConnection ready for new actions.
 
     _this._rtcReady = true; // SIP Timers.
 
     _this._timers = {
       ackTimer: null,
       expiresTimer: null,
       invite2xxTimer: null,
       userNoAnswerTimer: null
     }; // Session info.
 
     _this._direction = null;
     _this._local_identity = null;
     _this._remote_identity = null;
     _this._start_time = null;
     _this._end_time = null;
     _this._tones = null; // Mute/Hold state.
 
     _this._audioMuted = false;
     _this._videoMuted = false;
     _this._localHold = false;
     _this._remoteHold = false; // Session Timers (RFC 4028).
 
     _this._sessionTimers = {
       enabled: _this._ua.configuration.session_timers,
       refreshMethod: _this._ua.configuration.session_timers_refresh_method,
       defaultExpires: JsSIP_C.SESSION_EXPIRES,
       currentExpires: null,
       running: false,
       refresher: false,
       timer: null // A setTimeout.
 
     }; // Map of ReferSubscriber instances indexed by the REFER's CSeq number.
 
     _this._referSubscribers = {}; // Custom session empty object for high level use.
 
     _this._data = {};
     return _this;
   }
   /**
    * User API
    */
   // Expose RTCSession constants as a property of the RTCSession instance.
 
 
   _createClass(RTCSession, [{
     key: "isInProgress",
     value: function isInProgress() {
       switch (this._status) {
         case C.STATUS_NULL:
         case C.STATUS_INVITE_SENT:
         case C.STATUS_1XX_RECEIVED:
         case C.STATUS_INVITE_RECEIVED:
         case C.STATUS_WAITING_FOR_ANSWER:
           return true;
 
         default:
           return false;
       }
     }
   }, {
     key: "isEstablished",
     value: function isEstablished() {
       switch (this._status) {
         case C.STATUS_ANSWERED:
         case C.STATUS_WAITING_FOR_ACK:
         case C.STATUS_CONFIRMED:
           return true;
 
         default:
           return false;
       }
     }
   }, {
     key: "isEnded",
     value: function isEnded() {
       switch (this._status) {
         case C.STATUS_CANCELED:
         case C.STATUS_TERMINATED:
           return true;
 
         default:
           return false;
       }
     }
   }, {
     key: "isMuted",
     value: function isMuted() {
       return {
         audio: this._audioMuted,
         video: this._videoMuted
       };
     }
   }, {
     key: "isOnHold",
     value: function isOnHold() {
       return {
         local: this._localHold,
         remote: this._remoteHold
       };
     }
   }, {
     key: "connect",
     value: function connect(target) {
       var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
       var initCallback = arguments.length > 2 ? arguments[2] : undefined;
       debug('connect()');
       var originalTarget = target;
       var eventHandlers = Utils.cloneObject(options.eventHandlers);
       var extraHeaders = Utils.cloneArray(options.extraHeaders);
       var mediaConstraints = Utils.cloneObject(options.mediaConstraints, {
         audio: true,
         video: true
       });
       var mediaStream = options.mediaStream || null;
       var pcConfig = Utils.cloneObject(options.pcConfig, {
         iceServers: []
       });
       var rtcConstraints = options.rtcConstraints || null;
       var rtcOfferConstraints = options.rtcOfferConstraints || null;
       this._rtcOfferConstraints = rtcOfferConstraints;
       this._rtcAnswerConstraints = options.rtcAnswerConstraints || null;
       this._data = options.data || this._data; // Check target.
 
       if (target === undefined) {
         throw new TypeError('Not enough arguments');
       } // Check Session Status.
 
 
       if (this._status !== C.STATUS_NULL) {
         throw new Exceptions.InvalidStateError(this._status);
       } // Check WebRTC support.
 
 
       if (!window.RTCPeerConnection) {
         throw new Exceptions.NotSupportedError('WebRTC not supported');
       } // Check target validity.
 
 
       target = this._ua.normalizeTarget(target);
 
       if (!target) {
         throw new TypeError("Invalid target: ".concat(originalTarget));
       } // Session Timers.
 
 
       if (this._sessionTimers.enabled) {
         if (Utils.isDecimal(options.sessionTimersExpires)) {
           if (options.sessionTimersExpires >= JsSIP_C.MIN_SESSION_EXPIRES) {
             this._sessionTimers.defaultExpires = options.sessionTimersExpires;
           } else {
             this._sessionTimers.defaultExpires = JsSIP_C.SESSION_EXPIRES;
           }
         }
       } // Set event handlers.
 
 
       for (var event in eventHandlers) {
         if (Object.prototype.hasOwnProperty.call(eventHandlers, event)) {
           this.on(event, eventHandlers[event]);
         }
       } // Session parameter initialization.
 
 
       this._from_tag = Utils.newTag(); // Set anonymous property.
 
       var anonymous = options.anonymous || false;
       var requestParams = {
         from_tag: this._from_tag
       };
       this._contact = this._ua.contact.toString({
         anonymous: anonymous,
         outbound: true
       });
 
       if (anonymous) {
         requestParams.from_display_name = 'Anonymous';
         requestParams.from_uri = new URI('sip', 'anonymous', 'anonymous.invalid');
         extraHeaders.push("P-Preferred-Identity: ".concat(this._ua.configuration.uri.toString()));
         extraHeaders.push('Privacy: id');
       } else if (options.fromUserName) {
         requestParams.from_uri = new URI('sip', options.fromUserName, this._ua.configuration.uri.host);
         extraHeaders.push("P-Preferred-Identity: ".concat(this._ua.configuration.uri.toString()));
       }
 
       if (options.fromDisplayName) {
         requestParams.from_display_name = options.fromDisplayName;
       }
 
       extraHeaders.push("Contact: ".concat(this._contact));
       extraHeaders.push('Content-Type: application/sdp');
 
       if (this._sessionTimers.enabled) {
         extraHeaders.push("Session-Expires: ".concat(this._sessionTimers.defaultExpires).concat(this._ua.configuration.session_timers_force_refresher ? ';refresher=uac' : ''));
       }
 
       this._request = new SIPMessage.InitialOutgoingInviteRequest(target, this._ua, requestParams, extraHeaders);
       this._id = this._request.call_id + this._from_tag; // Create a new RTCPeerConnection instance.
 
       this._createRTCConnection(pcConfig, rtcConstraints); // Set internal properties.
 
 
       this._direction = 'outgoing';
       this._local_identity = this._request.from;
       this._remote_identity = this._request.to; // User explicitly provided a newRTCSession callback for this session.
 
       if (initCallback) {
         initCallback(this);
       }
 
       this._newRTCSession('local', this._request);
 
       this._sendInitialRequest(mediaConstraints, rtcOfferConstraints, mediaStream);
     }
   }, {
     key: "init_incoming",
     value: function init_incoming(request, initCallback) {
       var _this2 = this;
 
       debug('init_incoming()');
       var expires;
       var contentType = request.hasHeader('Content-Type') ? request.getHeader('Content-Type').toLowerCase() : undefined; // Check body and content type.
 
       if (request.body && contentType !== 'application/sdp') {
         request.reply(415);
         return;
       } // Session parameter initialization.
 
 
       this._status = C.STATUS_INVITE_RECEIVED;
       this._from_tag = request.from_tag;
       this._id = request.call_id + this._from_tag;
       this._request = request;
       this._contact = this._ua.contact.toString(); // Get the Expires header value if exists.
 
       if (request.hasHeader('expires')) {
         expires = request.getHeader('expires') * 1000;
       }
       /* Set the to_tag before
        * replying a response code that will create a dialog.
        */
 
 
       request.to_tag = Utils.newTag(); // An error on dialog creation will fire 'failed' event.
 
       if (!this._createDialog(request, 'UAS', true)) {
         request.reply(500, 'Missing Contact header field');
         return;
       }
 
       if (request.body) {
         this._late_sdp = false;
       } else {
         this._late_sdp = true;
       }
 
       this._status = C.STATUS_WAITING_FOR_ANSWER; // Set userNoAnswerTimer.
 
       this._timers.userNoAnswerTimer = setTimeout(function () {
         request.reply(408);
 
         _this2._failed('local', null, JsSIP_C.causes.NO_ANSWER);
       }, this._ua.configuration.no_answer_timeout);
       /* Set expiresTimer
        * RFC3261 13.3.1
        */
 
       if (expires) {
         this._timers.expiresTimer = setTimeout(function () {
           if (_this2._status === C.STATUS_WAITING_FOR_ANSWER) {
             request.reply(487);
 
             _this2._failed('system', null, JsSIP_C.causes.EXPIRES);
           }
         }, expires);
       } // Set internal properties.
 
 
       this._direction = 'incoming';
       this._local_identity = request.to;
       this._remote_identity = request.from; // A init callback was specifically defined.
 
       if (initCallback) {
         initCallback(this);
       } // Fire 'newRTCSession' event.
 
 
       this._newRTCSession('remote', request); // The user may have rejected the call in the 'newRTCSession' event.
 
 
       if (this._status === C.STATUS_TERMINATED) {
         return;
       } // Reply 180.
 
 
       request.reply(180, null, ["Contact: ".concat(this._contact)]); // Fire 'progress' event.
       // TODO: Document that 'response' field in 'progress' event is null for incoming calls.
 
       this._progress('local', null);
     }
     /**
      * Answer the call.
      */
 
   }, {
     key: "answer",
     value: function answer() {
       var _this3 = this;
 
       var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
       debug('answer()');
       var request = this._request;
       var extraHeaders = Utils.cloneArray(options.extraHeaders);
       var mediaConstraints = Utils.cloneObject(options.mediaConstraints);
       var mediaStream = options.mediaStream || null;
       var pcConfig = Utils.cloneObject(options.pcConfig, {
         iceServers: []
       });
       var rtcConstraints = options.rtcConstraints || null;
       var rtcAnswerConstraints = options.rtcAnswerConstraints || null;
       var rtcOfferConstraints = Utils.cloneObject(options.rtcOfferConstraints);
       var tracks;
       var peerHasAudioLine = false;
       var peerHasVideoLine = false;
       var peerOffersFullAudio = false;
       var peerOffersFullVideo = false;
       this._rtcAnswerConstraints = rtcAnswerConstraints;
       this._rtcOfferConstraints = options.rtcOfferConstraints || null;
       this._data = options.data || this._data; // Check Session Direction and Status.
 
       if (this._direction !== 'incoming') {
         throw new Exceptions.NotSupportedError('"answer" not supported for outgoing RTCSession');
       } // Check Session status.
 
 
       if (this._status !== C.STATUS_WAITING_FOR_ANSWER) {
         throw new Exceptions.InvalidStateError(this._status);
       } // Session Timers.
 
 
       if (this._sessionTimers.enabled) {
         if (Utils.isDecimal(options.sessionTimersExpires)) {
           if (options.sessionTimersExpires >= JsSIP_C.MIN_SESSION_EXPIRES) {
             this._sessionTimers.defaultExpires = options.sessionTimersExpires;
           } else {
             this._sessionTimers.defaultExpires = JsSIP_C.SESSION_EXPIRES;
           }
         }
       }
 
       this._status = C.STATUS_ANSWERED; // An error on dialog creation will fire 'failed' event.
 
       if (!this._createDialog(request, 'UAS')) {
         request.reply(500, 'Error creating dialog');
         return;
       }
 
       clearTimeout(this._timers.userNoAnswerTimer);
       extraHeaders.unshift("Contact: ".concat(this._contact)); // Determine incoming media from incoming SDP offer (if any).
 
       var sdp = request.parseSDP(); // Make sure sdp.media is an array, not the case if there is only one media.
 
       if (!Array.isArray(sdp.media)) {
         sdp.media = [sdp.media];
       } // Go through all medias in SDP to find offered capabilities to answer with.
 
 
       var _iterator = _createForOfIteratorHelper(sdp.media),
           _step;
 
       try {
         for (_iterator.s(); !(_step = _iterator.n()).done;) {
           var m = _step.value;
 
           if (m.type === 'audio') {
             peerHasAudioLine = true;
 
             if (!m.direction || m.direction === 'sendrecv') {
               peerOffersFullAudio = true;
             }
           }
 
           if (m.type === 'video') {
             peerHasVideoLine = true;
 
             if (!m.direction || m.direction === 'sendrecv') {
               peerOffersFullVideo = true;
             }
           }
         } // Remove audio from mediaStream if suggested by mediaConstraints.
 
       } catch (err) {
         _iterator.e(err);
       } finally {
         _iterator.f();
       }
 
       if (mediaStream && mediaConstraints.audio === false) {
         tracks = mediaStream.getAudioTracks();
 
         var _iterator2 = _createForOfIteratorHelper(tracks),
             _step2;
 
         try {
           for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
             var track = _step2.value;
             mediaStream.removeTrack(track);
           }
         } catch (err) {
           _iterator2.e(err);
         } finally {
           _iterator2.f();
         }
       } // Remove video from mediaStream if suggested by mediaConstraints.
 
 
       if (mediaStream && mediaConstraints.video === false) {
         tracks = mediaStream.getVideoTracks();
 
         var _iterator3 = _createForOfIteratorHelper(tracks),
             _step3;
 
         try {
           for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
             var _track = _step3.value;
             mediaStream.removeTrack(_track);
           }
         } catch (err) {
           _iterator3.e(err);
         } finally {
           _iterator3.f();
         }
       } // Set audio constraints based on incoming stream if not supplied.
 
 
       if (!mediaStream && mediaConstraints.audio === undefined) {
         mediaConstraints.audio = peerOffersFullAudio;
       } // Set video constraints based on incoming stream if not supplied.
 
 
       if (!mediaStream && mediaConstraints.video === undefined) {
         mediaConstraints.video = peerOffersFullVideo;
       } // Don't ask for audio if the incoming offer has no audio section.
 
 
       if (!mediaStream && !peerHasAudioLine && !rtcOfferConstraints.offerToReceiveAudio) {
         mediaConstraints.audio = false;
       } // Don't ask for video if the incoming offer has no video section.
 
 
       if (!mediaStream && !peerHasVideoLine && !rtcOfferConstraints.offerToReceiveVideo) {
         mediaConstraints.video = false;
       } // Create a new RTCPeerConnection instance.
       // TODO: This may throw an error, should react.
 
 
       this._createRTCConnection(pcConfig, rtcConstraints);
 
       Promise.resolve() // Handle local MediaStream.
       .then(function () {
         // A local MediaStream is given, use it.
         if (mediaStream) {
           return mediaStream;
         } // Audio and/or video requested, prompt getUserMedia.
         else if (mediaConstraints.audio || mediaConstraints.video) {
             _this3._localMediaStreamLocallyGenerated = true;
             return navigator.mediaDevices.getUserMedia(mediaConstraints)["catch"](function (error) {
               if (_this3._status === C.STATUS_TERMINATED) {
                 throw new Error('terminated');
               }
 
               request.reply(480);
 
               _this3._failed('local', null, JsSIP_C.causes.USER_DENIED_MEDIA_ACCESS);
 
               debugerror('emit "getusermediafailed" [error:%o]', error);
 
               _this3.emit('getusermediafailed', error);
 
               throw new Error('getUserMedia() failed');
             });
           }
       }) // Attach MediaStream to RTCPeerconnection.
       .then(function (stream) {
         if (_this3._status === C.STATUS_TERMINATED) {
           throw new Error('terminated');
         }
 
         _this3._localMediaStream = stream;
 
         if (stream) {
           stream.getTracks().forEach(function (track) {
             _this3._connection.addTrack(track, stream);
           });
         }
       }) // Set remote description.
       .then(function () {
         if (_this3._late_sdp) {
           return;
         }
 
         var e = {
           originator: 'remote',
           type: 'offer',
           sdp: request.body
         };
         debug('emit "sdp"');
 
         _this3.emit('sdp', e);
 
         var offer = new RTCSessionDescription({
           type: 'offer',
           sdp: e.sdp
         });
         _this3._connectionPromiseQueue = _this3._connectionPromiseQueue.then(function () {
           return _this3._connection.setRemoteDescription(offer);
         })["catch"](function (error) {
           request.reply(488);
 
           _this3._failed('system', null, JsSIP_C.causes.WEBRTC_ERROR);
 
           debugerror('emit "peerconnection:setremotedescriptionfailed" [error:%o]', error);
 
           _this3.emit('peerconnection:setremotedescriptionfailed', error);
 
           throw new Error('peerconnection.setRemoteDescription() failed');
         });
         return _this3._connectionPromiseQueue;
       }) // Create local description.
       .then(function () {
         if (_this3._status === C.STATUS_TERMINATED) {
           throw new Error('terminated');
         } // TODO: Is this event already useful?
 
 
         _this3._connecting(request);
 
         if (!_this3._late_sdp) {
           return _this3._createLocalDescription('answer', rtcAnswerConstraints)["catch"](function () {
             request.reply(500);
             throw new Error('_createLocalDescription() failed');
           });
         } else {
           return _this3._createLocalDescription('offer', _this3._rtcOfferConstraints)["catch"](function () {
             request.reply(500);
             throw new Error('_createLocalDescription() failed');
           });
         }
       }) // Send reply.
       .then(function (desc) {
         if (_this3._status === C.STATUS_TERMINATED) {
           throw new Error('terminated');
         }
 
         _this3._handleSessionTimersInIncomingRequest(request, extraHeaders);
 
         request.reply(200, null, extraHeaders, desc, function () {
           _this3._status = C.STATUS_WAITING_FOR_ACK;
 
           _this3._setInvite2xxTimer(request, desc);
 
           _this3._setACKTimer();
 
           _this3._accepted('local');
         }, function () {
           _this3._failed('system', null, JsSIP_C.causes.CONNECTION_ERROR);
         });
       })["catch"](function (error) {
         if (_this3._status === C.STATUS_TERMINATED) {
           return;
         }
 
         debugerror(error);
       });
     }
     /**
      * Terminate the call.
      */
 
   }, {
     key: "terminate",
     value: function terminate() {
       var _this4 = this;
 
       var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
       debug('terminate()');
       var cause = options.cause || JsSIP_C.causes.BYE;
       var extraHeaders = Utils.cloneArray(options.extraHeaders);
       var body = options.body;
       var cancel_reason;
       var status_code = options.status_code;
       var reason_phrase = options.reason_phrase; // Check Session Status.
 
       if (this._status === C.STATUS_TERMINATED) {
         throw new Exceptions.InvalidStateError(this._status);
       }
 
       switch (this._status) {
         // - UAC -
         case C.STATUS_NULL:
         case C.STATUS_INVITE_SENT:
         case C.STATUS_1XX_RECEIVED:
           debug('canceling session');
 
           if (status_code && (status_code < 200 || status_code >= 700)) {
             throw new TypeError("Invalid status_code: ".concat(status_code));
           } else if (status_code) {
             reason_phrase = reason_phrase || JsSIP_C.REASON_PHRASE[status_code] || '';
             cancel_reason = "SIP ;cause=".concat(status_code, " ;text=\"").concat(reason_phrase, "\"");
           } // Check Session Status.
 
 
           if (this._status === C.STATUS_NULL || this._status === C.STATUS_INVITE_SENT) {
             this._is_canceled = true;
             this._cancel_reason = cancel_reason;
           } else if (this._status === C.STATUS_1XX_RECEIVED) {
             this._request.cancel(cancel_reason);
           }
 
           this._status = C.STATUS_CANCELED;
 
           this._failed('local', null, JsSIP_C.causes.CANCELED);
 
           break;
         // - UAS -
 
         case C.STATUS_WAITING_FOR_ANSWER:
         case C.STATUS_ANSWERED:
           debug('rejecting session');
           status_code = status_code || 480;
 
           if (status_code < 300 || status_code >= 700) {
             throw new TypeError("Invalid status_code: ".concat(status_code));
           }
 
           this._request.reply(status_code, reason_phrase, extraHeaders, body);
 
           this._failed('local', null, JsSIP_C.causes.REJECTED);
 
           break;
 
         case C.STATUS_WAITING_FOR_ACK:
         case C.STATUS_CONFIRMED:
           debug('terminating session');
           reason_phrase = options.reason_phrase || JsSIP_C.REASON_PHRASE[status_code] || '';
 
           if (status_code && (status_code < 200 || status_code >= 700)) {
             throw new TypeError("Invalid status_code: ".concat(status_code));
           } else if (status_code) {
             extraHeaders.push("Reason: SIP ;cause=".concat(status_code, "; text=\"").concat(reason_phrase, "\""));
           }
           /* RFC 3261 section 15 (Terminating a session):
             *
             * "...the callee's UA MUST NOT send a BYE on a confirmed dialog
             * until it has received an ACK for its 2xx response or until the server
             * transaction times out."
             */
 
 
           if (this._status === C.STATUS_WAITING_FOR_ACK && this._direction === 'incoming' && this._request.server_transaction.state !== Transactions.C.STATUS_TERMINATED) {
             // Save the dialog for later restoration.
             var dialog = this._dialog; // Send the BYE as soon as the ACK is received...
 
             this.receiveRequest = function (_ref) {
               var method = _ref.method;
 
               if (method === JsSIP_C.ACK) {
                 _this4.sendRequest(JsSIP_C.BYE, {
                   extraHeaders: extraHeaders,
                   body: body
                 });
 
                 dialog.terminate();
               }
             }; // .., or when the INVITE transaction times out
 
 
             this._request.server_transaction.on('stateChanged', function () {
               if (_this4._request.server_transaction.state === Transactions.C.STATUS_TERMINATED) {
                 _this4.sendRequest(JsSIP_C.BYE, {
                   extraHeaders: extraHeaders,
                   body: body
                 });
 
                 dialog.terminate();
               }
             });
 
             this._ended('local', null, cause); // Restore the dialog into 'this' in order to be able to send the in-dialog BYE :-).
 
 
             this._dialog = dialog; // Restore the dialog into 'ua' so the ACK can reach 'this' session.
 
             this._ua.newDialog(dialog);
           } else {
             this.sendRequest(JsSIP_C.BYE, {
               extraHeaders: extraHeaders,
               body: body
             });
 
             this._ended('local', null, cause);
           }
 
       }
     }
   }, {
     key: "sendDTMF",
     value: function sendDTMF(tones) {
       var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
       debug('sendDTMF() | tones: %s', tones);
       var position = 0;
       var duration = options.duration || null;
       var interToneGap = options.interToneGap || null;
       var transportType = options.transportType || JsSIP_C.DTMF_TRANSPORT.INFO;
 
       if (tones === undefined) {
         throw new TypeError('Not enough arguments');
       } // Check Session Status.
 
 
       if (this._status !== C.STATUS_CONFIRMED && this._status !== C.STATUS_WAITING_FOR_ACK) {
         throw new Exceptions.InvalidStateError(this._status);
       } // Check Transport type.
 
 
       if (transportType !== JsSIP_C.DTMF_TRANSPORT.INFO && transportType !== JsSIP_C.DTMF_TRANSPORT.RFC2833) {
         throw new TypeError("invalid transportType: ".concat(transportType));
       } // Convert to string.
 
 
       if (typeof tones === 'number') {
         tones = tones.toString();
       } // Check tones.
 
 
       if (!tones || typeof tones !== 'string' || !tones.match(/^[0-9A-DR#*,]+$/i)) {
         throw new TypeError("Invalid tones: ".concat(tones));
       } // Check duration.
 
 
       if (duration && !Utils.isDecimal(duration)) {
         throw new TypeError("Invalid tone duration: ".concat(duration));
       } else if (!duration) {
         duration = RTCSession_DTMF.C.DEFAULT_DURATION;
       } else if (duration < RTCSession_DTMF.C.MIN_DURATION) {
         debug("\"duration\" value is lower than the minimum allowed, setting it to ".concat(RTCSession_DTMF.C.MIN_DURATION, " milliseconds"));
         duration = RTCSession_DTMF.C.MIN_DURATION;
       } else if (duration > RTCSession_DTMF.C.MAX_DURATION) {
         debug("\"duration\" value is greater than the maximum allowed, setting it to ".concat(RTCSession_DTMF.C.MAX_DURATION, " milliseconds"));
         duration = RTCSession_DTMF.C.MAX_DURATION;
       } else {
         duration = Math.abs(duration);
       }
 
       options.duration = duration; // Check interToneGap.
 
       if (interToneGap && !Utils.isDecimal(interToneGap)) {
         throw new TypeError("Invalid interToneGap: ".concat(interToneGap));
       } else if (!interToneGap) {
         interToneGap = RTCSession_DTMF.C.DEFAULT_INTER_TONE_GAP;
       } else if (interToneGap < RTCSession_DTMF.C.MIN_INTER_TONE_GAP) {
         debug("\"interToneGap\" value is lower than the minimum allowed, setting it to ".concat(RTCSession_DTMF.C.MIN_INTER_TONE_GAP, " milliseconds"));
         interToneGap = RTCSession_DTMF.C.MIN_INTER_TONE_GAP;
       } else {
         interToneGap = Math.abs(interToneGap);
       } // RFC2833. Let RTCDTMFSender enqueue the DTMFs.
 
 
       if (transportType === JsSIP_C.DTMF_TRANSPORT.RFC2833) {
         // Send DTMF in current audio RTP stream.
         var sender = this._getDTMFRTPSender();
 
         if (sender) {
           // Add remaining buffered tones.
           tones = sender.toneBuffer + tones; // Insert tones.
 
           sender.insertDTMF(tones, duration, interToneGap);
         }
 
         return;
       }
 
       if (this._tones) {
         // Tones are already queued, just add to the queue.
         this._tones += tones;
         return;
       }
 
       this._tones = tones; // Send the first tone.
 
       _sendDTMF.call(this);
 
       function _sendDTMF() {
         var _this5 = this;
 
         var timeout;
 
         if (this._status === C.STATUS_TERMINATED || !this._tones || position >= this._tones.length) {
           // Stop sending DTMF.
           this._tones = null;
           return;
         }
 
         var tone = this._tones[position];
         position += 1;
 
         if (tone === ',') {
           timeout = 2000;
         } else {
           // Send DTMF via SIP INFO messages.
           var dtmf = new RTCSession_DTMF(this);
           options.eventHandlers = {
             onFailed: function onFailed() {
               _this5._tones = null;
             }
           };
           dtmf.send(tone, options);
           timeout = duration + interToneGap;
         } // Set timeout for the next tone.
 
 
         setTimeout(_sendDTMF.bind(this), timeout);
       }
     }
   }, {
     key: "sendInfo",
     value: function sendInfo(contentType, body) {
       var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
       debug('sendInfo()'); // Check Session Status.
 
       if (this._status !== C.STATUS_CONFIRMED && this._status !== C.STATUS_WAITING_FOR_ACK) {
         throw new Exceptions.InvalidStateError(this._status);
       }
 
       var info = new RTCSession_Info(this);
       info.send(contentType, body, options);
     }
     /**
      * Mute
      */
 
   }, {
     key: "mute",
     value: function mute() {
       var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {
         audio: true,
         video: false
       };
       debug('mute()');
       var audioMuted = false,
           videoMuted = false;
 
       if (this._audioMuted === false && options.audio) {
         audioMuted = true;
         this._audioMuted = true;
 
         this._toggleMuteAudio(true);
       }
 
       if (this._videoMuted === false && options.video) {
         videoMuted = true;
         this._videoMuted = true;
 
         this._toggleMuteVideo(true);
       }
 
       if (audioMuted === true || videoMuted === true) {
         this._onmute({
           audio: audioMuted,
           video: videoMuted
         });
       }
     }
     /**
      * Unmute
      */
 
   }, {
     key: "unmute",
     value: function unmute() {
       var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {
         audio: true,
         video: true
       };
       debug('unmute()');
       var audioUnMuted = false,
           videoUnMuted = false;
 
       if (this._audioMuted === true && options.audio) {
         audioUnMuted = true;
         this._audioMuted = false;
 
         if (this._localHold === false) {
           this._toggleMuteAudio(false);
         }
       }
 
       if (this._videoMuted === true && options.video) {
         videoUnMuted = true;
         this._videoMuted = false;
 
         if (this._localHold === false) {
           this._toggleMuteVideo(false);
         }
       }
 
       if (audioUnMuted === true || videoUnMuted === true) {
         this._onunmute({
           audio: audioUnMuted,
           video: videoUnMuted
         });
       }
     }
     /**
      * Hold
      */
 
   }, {
     key: "hold",
     value: function hold() {
       var _this6 = this;
 
       var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
       var done = arguments.length > 1 ? arguments[1] : undefined;
       debug('hold()');
 
       if (this._status !== C.STATUS_WAITING_FOR_ACK && this._status !== C.STATUS_CONFIRMED) {
         return false;
       }
 
       if (this._localHold === true) {
         return false;
       }
 
       if (!this._isReadyToReOffer()) {
         return false;
       }
 
       this._localHold = true;
 
       this._onhold('local');
 
       var eventHandlers = {
         succeeded: function succeeded() {
           if (done) {
             done();
           }
         },
         failed: function failed() {
           _this6.terminate({
             cause: JsSIP_C.causes.WEBRTC_ERROR,
             status_code: 500,
             reason_phrase: 'Hold Failed'
           });
         }
       };
 
       if (options.useUpdate) {
         this._sendUpdate({
           sdpOffer: true,
           eventHandlers: eventHandlers,
           extraHeaders: options.extraHeaders
         });
       } else {
         this._sendReinvite({
           eventHandlers: eventHandlers,
           extraHeaders: options.extraHeaders
         });
       }
 
       return true;
     }
   }, {
     key: "unhold",
     value: function unhold() {
       var _this7 = this;
 
       var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
       var done = arguments.length > 1 ? arguments[1] : undefined;
       debug('unhold()');
 
       if (this._status !== C.STATUS_WAITING_FOR_ACK && this._status !== C.STATUS_CONFIRMED) {
         return false;
       }
 
       if (this._localHold === false) {
         return false;
       }
 
       if (!this._isReadyToReOffer()) {
         return false;
       }
 
       this._localHold = false;
 
       this._onunhold('local');
 
       var eventHandlers = {
         succeeded: function succeeded() {
           if (done) {
             done();
           }
         },
         failed: function failed() {
           _this7.terminate({
             cause: JsSIP_C.causes.WEBRTC_ERROR,
             status_code: 500,
             reason_phrase: 'Unhold Failed'
           });
         }
       };
 
       if (options.useUpdate) {
         this._sendUpdate({
           sdpOffer: true,
           eventHandlers: eventHandlers,
           extraHeaders: options.extraHeaders
         });
       } else {
         this._sendReinvite({
           eventHandlers: eventHandlers,
           extraHeaders: options.extraHeaders
         });
       }
 
       return true;
     }
   }, {
     key: "renegotiate",
     value: function renegotiate() {
       var _this8 = this;
 
       var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
       var done = arguments.length > 1 ? arguments[1] : undefined;
       debug('renegotiate()');
       var rtcOfferConstraints = options.rtcOfferConstraints || null;
 
       if (this._status !== C.STATUS_WAITING_FOR_ACK && this._status !== C.STATUS_CONFIRMED) {
         return false;
       }
 
       if (!this._isReadyToReOffer()) {
         return false;
       }
 
       var eventHandlers = {
         succeeded: function succeeded() {
           if (done) {
             done();
           }
         },
         failed: function failed() {
           _this8.terminate({
             cause: JsSIP_C.causes.WEBRTC_ERROR,
             status_code: 500,
             reason_phrase: 'Media Renegotiation Failed'
           });
         }
       };
 
       this._setLocalMediaStatus();
 
       if (options.useUpdate) {
         this._sendUpdate({
           sdpOffer: true,
           eventHandlers: eventHandlers,
           rtcOfferConstraints: rtcOfferConstraints,
           extraHeaders: options.extraHeaders
         });
       } else {
         this._sendReinvite({
           eventHandlers: eventHandlers,
           rtcOfferConstraints: rtcOfferConstraints,
           extraHeaders: options.extraHeaders
         });
       }
 
       return true;
     }
     /**
      * Refer
      */
 
   }, {
     key: "refer",
     value: function refer(target, options) {
       var _this9 = this;
 
       debug('refer()');
       var originalTarget = target;
 
       if (this._status !== C.STATUS_WAITING_FOR_ACK && this._status !== C.STATUS_CONFIRMED) {
         return false;
       } // Check target validity.
 
 
       target = this._ua.normalizeTarget(target);
 
       if (!target) {
         throw new TypeError("Invalid target: ".concat(originalTarget));
       }
 
       var referSubscriber = new RTCSession_ReferSubscriber(this);
       referSubscriber.sendRefer(target, options); // Store in the map.
 
       var id = referSubscriber.id;
       this._referSubscribers[id] = referSubscriber; // Listen for ending events so we can remove it from the map.
 
       referSubscriber.on('requestFailed', function () {
         delete _this9._referSubscribers[id];
       });
       referSubscriber.on('accepted', function () {
         delete _this9._referSubscribers[id];
       });
       referSubscriber.on('failed', function () {
         delete _this9._referSubscribers[id];
       });
       return referSubscriber;
     }
     /**
      * Send a generic in-dialog Request
      */
 
   }, {
     key: "sendRequest",
     value: function sendRequest(method, options) {
       debug('sendRequest()');
       return this._dialog.sendRequest(method, options);
     }
     /**
      * In dialog Request Reception
      */
 
   }, {
     key: "receiveRequest",
     value: function receiveRequest(request) {
       var _this10 = this;
 
       debug('receiveRequest()');
 
       if (request.method === JsSIP_C.CANCEL) {
         /* RFC3261 15 States that a UAS may have accepted an invitation while a CANCEL
         * was in progress and that the UAC MAY continue with the session established by
         * any 2xx response, or MAY terminate with BYE. JsSIP does continue with the
         * established session. So the CANCEL is processed only if the session is not yet
         * established.
         */
 
         /*
         * Terminate the whole session in case the user didn't accept (or yet send the answer)
         * nor reject the request opening the session.
         */
         if (this._status === C.STATUS_WAITING_FOR_ANSWER || this._status === C.STATUS_ANSWERED) {
           this._status = C.STATUS_CANCELED;
 
           this._request.reply(487);
 
           this._failed('remote', request, JsSIP_C.causes.CANCELED);
         }
       } else {
         // Requests arriving here are in-dialog requests.
         switch (request.method) {
           case JsSIP_C.ACK:
             if (this._status !== C.STATUS_WAITING_FOR_ACK) {
               return;
             } // Update signaling status.
 
 
             this._status = C.STATUS_CONFIRMED;
             clearTimeout(this._timers.ackTimer);
             clearTimeout(this._timers.invite2xxTimer);
 
             if (this._late_sdp) {
               if (!request.body) {
                 this.terminate({
                   cause: JsSIP_C.causes.MISSING_SDP,
                   status_code: 400
                 });
                 break;
               }
 
               var e = {
                 originator: 'remote',
                 type: 'answer',
                 sdp: request.body
               };
               debug('emit "sdp"');
               this.emit('sdp', e);
               var answer = new RTCSessionDescription({
                 type: 'answer',
                 sdp: e.sdp
               });
               this._connectionPromiseQueue = this._connectionPromiseQueue.then(function () {
                 return _this10._connection.setRemoteDescription(answer);
               }).then(function () {
                 if (!_this10._is_confirmed) {
                   _this10._confirmed('remote', request);
                 }
               })["catch"](function (error) {
                 _this10.terminate({
                   cause: JsSIP_C.causes.BAD_MEDIA_DESCRIPTION,
                   status_code: 488
                 });
 
                 debugerror('emit "peerconnection:setremotedescriptionfailed" [error:%o]', error);
 
                 _this10.emit('peerconnection:setremotedescriptionfailed', error);
               });
             } else if (!this._is_confirmed) {
               this._confirmed('remote', request);
             }
 
             break;
 
           case JsSIP_C.BYE:
             if (this._status === C.STATUS_CONFIRMED || this._status === C.STATUS_WAITING_FOR_ACK) {
               request.reply(200);
 
               this._ended('remote', request, JsSIP_C.causes.BYE);
             } else if (this._status === C.STATUS_INVITE_RECEIVED || this._status === C.STATUS_WAITING_FOR_ANSWER) {
               request.reply(200);
 
               this._request.reply(487, 'BYE Received');
 
               this._ended('remote', request, JsSIP_C.causes.BYE);
             } else {
               request.reply(403, 'Wrong Status');
             }
 
             break;
 
           case JsSIP_C.INVITE:
             if (this._status === C.STATUS_CONFIRMED) {
               if (request.hasHeader('replaces')) {
                 this._receiveReplaces(request);
               } else {
                 this._receiveReinvite(request);
               }
             } else {
               request.reply(403, 'Wrong Status');
             }
 
             break;
 
           case JsSIP_C.INFO:
             if (this._status === C.STATUS_1XX_RECEIVED || this._status === C.STATUS_WAITING_FOR_ANSWER || this._status === C.STATUS_ANSWERED || this._status === C.STATUS_WAITING_FOR_ACK || this._status === C.STATUS_CONFIRMED) {
               var contentType = request.hasHeader('Content-Type') ? request.getHeader('Content-Type').toLowerCase() : undefined;
 
               if (contentType && contentType.match(/^application\/dtmf-relay/i)) {
                 new RTCSession_DTMF(this).init_incoming(request);
               } else if (contentType !== undefined) {
                 new RTCSession_Info(this).init_incoming(request);
               } else {
                 request.reply(415);
               }
             } else {
               request.reply(403, 'Wrong Status');
             }
 
             break;
 
           case JsSIP_C.UPDATE:
             if (this._status === C.STATUS_CONFIRMED) {
               this._receiveUpdate(request);
             } else {
               request.reply(403, 'Wrong Status');
             }
 
             break;
 
           case JsSIP_C.REFER:
             if (this._status === C.STATUS_CONFIRMED) {
               this._receiveRefer(request);
             } else {
               request.reply(403, 'Wrong Status');
             }
 
             break;
 
           case JsSIP_C.NOTIFY:
             if (this._status === C.STATUS_CONFIRMED) {
               this._receiveNotify(request);
             } else {
               request.reply(403, 'Wrong Status');
             }
 
             break;
 
           default:
             request.reply(501);
         }
       }
     }
     /**
      * Session Callbacks
      */
 
   }, {
     key: "onTransportError",
     value: function onTransportError() {
       debugerror('onTransportError()');
 
       if (this._status !== C.STATUS_TERMINATED) {
         this.terminate({
           status_code: 500,
           reason_phrase: JsSIP_C.causes.CONNECTION_ERROR,
           cause: JsSIP_C.causes.CONNECTION_ERROR
         });
       }
     }
   }, {
     key: "onRequestTimeout",
     value: function onRequestTimeout() {
       debugerror('onRequestTimeout()');
 
       if (this._status !== C.STATUS_TERMINATED) {
         this.terminate({
           status_code: 408,
           reason_phrase: JsSIP_C.causes.REQUEST_TIMEOUT,
           cause: JsSIP_C.causes.REQUEST_TIMEOUT
         });
       }
     }
   }, {
     key: "onDialogError",
     value: function onDialogError() {
       debugerror('onDialogError()');
 
       if (this._status !== C.STATUS_TERMINATED) {
         this.terminate({
           status_code: 500,
           reason_phrase: JsSIP_C.causes.DIALOG_ERROR,
           cause: JsSIP_C.causes.DIALOG_ERROR
         });
       }
     } // Called from DTMF handler.
 
   }, {
     key: "newDTMF",
     value: function newDTMF(data) {
       debug('newDTMF()');
       this.emit('newDTMF', data);
     } // Called from Info handler.
 
   }, {
     key: "newInfo",
     value: function newInfo(data) {
       debug('newInfo()');
       this.emit('newInfo', data);
     }
     /**
      * Check if RTCSession is ready for an outgoing re-INVITE or UPDATE with SDP.
      */
 
   }, {
     key: "_isReadyToReOffer",
     value: function _isReadyToReOffer() {
       if (!this._rtcReady) {
         debug('_isReadyToReOffer() | internal WebRTC status not ready');
         return false;
       } // No established yet.
 
 
       if (!this._dialog) {
         debug('_isReadyToReOffer() | session not established yet');
         return false;
       } // Another INVITE transaction is in progress.
 
 
       if (this._dialog.uac_pending_reply === true || this._dialog.uas_pending_reply === true) {
         debug('_isReadyToReOffer() | there is another INVITE/UPDATE transaction in progress');
         return false;
       }
 
       return true;
     }
   }, {
     key: "_close",
     value: function _close() {
       debug('close()');
 
       if (this._status === C.STATUS_TERMINATED) {
         return;
       }
 
       this._status = C.STATUS_TERMINATED; // Terminate RTC.
 
       if (this._connection) {
         try {
           this._connection.close();
         } catch (error) {
           debugerror('close() | error closing the RTCPeerConnection: %o', error);
         }
       } // Close local MediaStream if it was not given by the user.
 
 
       if (this._localMediaStream && this._localMediaStreamLocallyGenerated) {
         debug('close() | closing local MediaStream');
         Utils.closeMediaStream(this._localMediaStream);
       } // Terminate signaling.
       // Clear SIP timers.
 
 
       for (var timer in this._timers) {
         if (Object.prototype.hasOwnProperty.call(this._timers, timer)) {
           clearTimeout(this._timers[timer]);
         }
       } // Clear Session Timers.
 
 
       clearTimeout(this._sessionTimers.timer); // Terminate confirmed dialog.
 
       if (this._dialog) {
         this._dialog.terminate();
 
         delete this._dialog;
       } // Terminate early dialogs.
 
 
       for (var dialog in this._earlyDialogs) {
         if (Object.prototype.hasOwnProperty.call(this._earlyDialogs, dialog)) {
           this._earlyDialogs[dialog].terminate();
 
           delete this._earlyDialogs[dialog];
         }
       } // Terminate REFER subscribers.
 
 
       for (var subscriber in this._referSubscribers) {
         if (Object.prototype.hasOwnProperty.call(this._referSubscribers, subscriber)) {
           delete this._referSubscribers[subscriber];
         }
       }
 
       this._ua.destroyRTCSession(this);
     }
     /**
      * Private API.
      */
 
     /**
      * RFC3261 13.3.1.4
      * Response retransmissions cannot be accomplished by transaction layer
      *  since it is destroyed when receiving the first 2xx answer
      */
 
   }, {
     key: "_setInvite2xxTimer",
     value: function _setInvite2xxTimer(request, body) {
       var timeout = Timers.T1;
 
       function invite2xxRetransmission() {
         if (this._status !== C.STATUS_WAITING_FOR_ACK) {
           return;
         }
 
         request.reply(200, null, ["Contact: ".concat(this._contact)], body);
 
         if (timeout < Timers.T2) {
           timeout = timeout * 2;
 
           if (timeout > Timers.T2) {
             timeout = Timers.T2;
           }
         }
 
         this._timers.invite2xxTimer = setTimeout(invite2xxRetransmission.bind(this), timeout);
       }
 
       this._timers.invite2xxTimer = setTimeout(invite2xxRetransmission.bind(this), timeout);
     }
     /**
      * RFC3261 14.2
      * If a UAS generates a 2xx response and never receives an ACK,
      *  it SHOULD generate a BYE to terminate the dialog.
      */
 
   }, {
     key: "_setACKTimer",
     value: function _setACKTimer() {
       var _this11 = this;
 
       this._timers.ackTimer = setTimeout(function () {
         if (_this11._status === C.STATUS_WAITING_FOR_ACK) {
           debug('no ACK received, terminating the session');
           clearTimeout(_this11._timers.invite2xxTimer);
 
           _this11.sendRequest(JsSIP_C.BYE);
 
           _this11._ended('remote', null, JsSIP_C.causes.NO_ACK);
         }
       }, Timers.TIMER_H);
     }
   }, {
     key: "_createRTCConnection",
     value: function _createRTCConnection(pcConfig, rtcConstraints) {
       var _this12 = this;
 
       this._connection = new RTCPeerConnection(pcConfig, rtcConstraints);
 
       this._connection.addEventListener('iceconnectionstatechange', function () {
         var state = _this12._connection.iceConnectionState; // TODO: Do more with different states.
 
         if (state === 'failed') {
           _this12.terminate({
             cause: JsSIP_C.causes.RTP_TIMEOUT,
             status_code: 408,
             reason_phrase: JsSIP_C.causes.RTP_TIMEOUT
           });
         }
       });
 
       debug('emit "peerconnection"');
       this.emit('peerconnection', {
         peerconnection: this._connection
       });
     }
   }, {
     key: "_createLocalDescription",
     value: function _createLocalDescription(type, constraints) {
       var _this13 = this;
 
       debug('createLocalDescription()');
       if (type !== 'offer' && type !== 'answer') throw new Error("createLocalDescription() | invalid type \"".concat(type, "\""));
       var connection = this._connection;
       this._rtcReady = false;
       return Promise.resolve() // Create Offer or Answer.
       .then(function () {
         if (type === 'offer') {
           return connection.createOffer(constraints)["catch"](function (error) {
             debugerror('emit "peerconnection:createofferfailed" [error:%o]', error);
 
             _this13.emit('peerconnection:createofferfailed', error);
 
             return Promise.reject(error);
           });
         } else {
           return connection.createAnswer(constraints)["catch"](function (error) {
             debugerror('emit "peerconnection:createanswerfailed" [error:%o]', error);
 
             _this13.emit('peerconnection:createanswerfailed', error);
 
             return Promise.reject(error);
           });
         }
       }) // Set local description.
       .then(function (desc) {
         return connection.setLocalDescription(desc)["catch"](function (error) {
           _this13._rtcReady = true;
           debugerror('emit "peerconnection:setlocaldescriptionfailed" [error:%o]', error);
 
           _this13.emit('peerconnection:setlocaldescriptionfailed', error);
 
           return Promise.reject(error);
         });
       }).then(function () {
         // Resolve right away if 'pc.iceGatheringState' is 'complete'.
         if (connection.iceGatheringState === 'complete' && (!constraints || !constraints.iceRestart)) {
           _this13._rtcReady = true;
           var e = {
             originator: 'local',
             type: type,
             sdp: connection.localDescription.sdp
           };
           debug('emit "sdp"');
 
           _this13.emit('sdp', e);
 
           return Promise.resolve(e.sdp);
         } // Add 'pc.onicencandidate' event handler to resolve on last candidate.
 
 
         return new Promise(function (resolve) {
           var finished = false;
           var iceCandidateListener;
           var iceGatheringStateListener;
 
           var ready = function ready() {
             connection.removeEventListener('icecandidate', iceCandidateListener);
             connection.removeEventListener('icegatheringstatechange', iceGatheringStateListener);
             finished = true;
             _this13._rtcReady = true;
             var e = {
               originator: 'local',
               type: type,
               sdp: connection.localDescription.sdp
             };
             debug('emit "sdp"');
 
             _this13.emit('sdp', e);
 
             resolve(e.sdp);
           };
 
           connection.addEventListener('icecandidate', iceCandidateListener = function iceCandidateListener(event) {
             var candidate = event.candidate;
 
             if (candidate) {
               _this13.emit('icecandidate', {
                 candidate: candidate,
                 ready: ready
               });
             } else if (!finished) {
               ready();
             }
           });
           connection.addEventListener('icegatheringstatechange', iceGatheringStateListener = function iceGatheringStateListener() {
             if (connection.iceGatheringState === 'complete' && !finished) {
               ready();
             }
           });
         });
       });
     }
     /**
      * Dialog Management
      */
 
   }, {
     key: "_createDialog",
     value: function _createDialog(message, type, early) {
       var local_tag = type === 'UAS' ? message.to_tag : message.from_tag;
       var remote_tag = type === 'UAS' ? message.from_tag : message.to_tag;
       var id = message.call_id + local_tag + remote_tag;
       var early_dialog = this._earlyDialogs[id]; // Early Dialog.
 
       if (early) {
         if (early_dialog) {
           return true;
         } else {
           early_dialog = new Dialog(this, message, type, Dialog.C.STATUS_EARLY); // Dialog has been successfully created.
 
           if (early_dialog.error) {
             debug(early_dialog.error);
 
             this._failed('remote', message, JsSIP_C.causes.INTERNAL_ERROR);
 
             return false;
           } else {
             this._earlyDialogs[id] = early_dialog;
             return true;
           }
         }
       } // Confirmed Dialog.
       else {
           this._from_tag = message.from_tag;
           this._to_tag = message.to_tag; // In case the dialog is in _early_ state, update it.
 
           if (early_dialog) {
             early_dialog.update(message, type);
             this._dialog = early_dialog;
             delete this._earlyDialogs[id];
             return true;
           } // Otherwise, create a _confirmed_ dialog.
 
 
           var dialog = new Dialog(this, message, type);
 
           if (dialog.error) {
             debug(dialog.error);
 
             this._failed('remote', message, JsSIP_C.causes.INTERNAL_ERROR);
 
             return false;
           } else {
             this._dialog = dialog;
             return true;
           }
         }
     }
     /**
      * In dialog INVITE Reception
      */
 
   }, {
     key: "_receiveReinvite",
     value: function _receiveReinvite(request) {
       var _this14 = this;
 
       debug('receiveReinvite()');
       var contentType = request.hasHeader('Content-Type') ? request.getHeader('Content-Type').toLowerCase() : undefined;
       var data = {
         request: request,
         callback: undefined,
         reject: reject.bind(this)
       };
       var rejected = false;
 
       function reject() {
         var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
         rejected = true;
         var status_code = options.status_code || 403;
         var reason_phrase = options.reason_phrase || '';
         var extraHeaders = Utils.cloneArray(options.extraHeaders);
 
         if (this._status !== C.STATUS_CONFIRMED) {
           return false;
         }
 
         if (status_code < 300 || status_code >= 700) {
           throw new TypeError("Invalid status_code: ".concat(status_code));
         }
 
         request.reply(status_code, reason_phrase, extraHeaders);
       } // Emit 'reinvite'.
 
 
       this.emit('reinvite', data);
 
       if (rejected) {
         return;
       }
 
       this._late_sdp = false; // Request without SDP.
 
       if (!request.body) {
         this._late_sdp = true;
 
         if (this._remoteHold) {
           this._remoteHold = false;
 
           this._onunhold('remote');
         }
 
         this._connectionPromiseQueue = this._connectionPromiseQueue.then(function () {
           return _this14._createLocalDescription('offer', _this14._rtcOfferConstraints);
         }).then(function (sdp) {
           sendAnswer.call(_this14, sdp);
         })["catch"](function () {
           request.reply(500);
         });
         return;
       } // Request with SDP.
 
 
       if (contentType !== 'application/sdp') {
         debug('invalid Content-Type');
         request.reply(415);
         return;
       }
 
       this._processInDialogSdpOffer(request) // Send answer.
       .then(function (desc) {
         if (_this14._status === C.STATUS_TERMINATED) {
           return;
         }
 
         sendAnswer.call(_this14, desc);
       })["catch"](function (error) {
         debugerror(error);
       });
 
       function sendAnswer(desc) {
         var _this15 = this;
 
         var extraHeaders = ["Contact: ".concat(this._contact)];
 
         this._handleSessionTimersInIncomingRequest(request, extraHeaders);
 
         if (this._late_sdp) {
           desc = this._mangleOffer(desc);
         }
 
         request.reply(200, null, extraHeaders, desc, function () {
           _this15._status = C.STATUS_WAITING_FOR_ACK;
 
           _this15._setInvite2xxTimer(request, desc);
 
           _this15._setACKTimer();
         }); // If callback is given execute it.
 
         if (typeof data.callback === 'function') {
           data.callback();
         }
       }
     }
     /**
      * In dialog UPDATE Reception
      */
 
   }, {
     key: "_receiveUpdate",
     value: function _receiveUpdate(request) {
       var _this16 = this;
 
       debug('receiveUpdate()');
       var contentType = request.hasHeader('Content-Type') ? request.getHeader('Content-Type').toLowerCase() : undefined;
       var data = {
         request: request,
         callback: undefined,
         reject: reject.bind(this)
       };
       var rejected = false;
 
       function reject() {
         var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
         rejected = true;
         var status_code = options.status_code || 403;
         var reason_phrase = options.reason_phrase || '';
         var extraHeaders = Utils.cloneArray(options.extraHeaders);
 
         if (this._status !== C.STATUS_CONFIRMED) {
           return false;
         }
 
         if (status_code < 300 || status_code >= 700) {
           throw new TypeError("Invalid status_code: ".concat(status_code));
         }
 
         request.reply(status_code, reason_phrase, extraHeaders);
       } // Emit 'update'.
 
 
       this.emit('update', data);
 
       if (rejected) {
         return;
       }
 
       if (!request.body) {
         sendAnswer.call(this, null);
         return;
       }
 
       if (contentType !== 'application/sdp') {
         debug('invalid Content-Type');
         request.reply(415);
         return;
       }
 
       this._processInDialogSdpOffer(request) // Send answer.
       .then(function (desc) {
         if (_this16._status === C.STATUS_TERMINATED) {
           return;
         }
 
         sendAnswer.call(_this16, desc);
       })["catch"](function (error) {
         debugerror(error);
       });
 
       function sendAnswer(desc) {
         var extraHeaders = ["Contact: ".concat(this._contact)];
 
         this._handleSessionTimersInIncomingRequest(request, extraHeaders);
 
         request.reply(200, null, extraHeaders, desc); // If callback is given execute it.
 
         if (typeof data.callback === 'function') {
           data.callback();
         }
       }
     }
   }, {
     key: "_processInDialogSdpOffer",
     value: function _processInDialogSdpOffer(request) {
       var _this17 = this;
 
       debug('_processInDialogSdpOffer()');
       var sdp = request.parseSDP();
       var hold = false;
 
       var _iterator4 = _createForOfIteratorHelper(sdp.media),
           _step4;
 
       try {
         for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
           var m = _step4.value;
 
           if (holdMediaTypes.indexOf(m.type) === -1) {
             continue;
           }
 
           var direction = m.direction || sdp.direction || 'sendrecv';
 
           if (direction === 'sendonly' || direction === 'inactive') {
             hold = true;
           } // If at least one of the streams is active don't emit 'hold'.
           else {
               hold = false;
               break;
             }
         }
       } catch (err) {
         _iterator4.e(err);
       } finally {
         _iterator4.f();
       }
 
       var e = {
         originator: 'remote',
         type: 'offer',
         sdp: request.body
       };
       debug('emit "sdp"');
       this.emit('sdp', e);
       var offer = new RTCSessionDescription({
         type: 'offer',
         sdp: e.sdp
       });
       this._connectionPromiseQueue = this._connectionPromiseQueue // Set remote description.
       .then(function () {
         if (_this17._status === C.STATUS_TERMINATED) {
           throw new Error('terminated');
         }
 
         return _this17._connection.setRemoteDescription(offer)["catch"](function (error) {
           request.reply(488);
           debugerror('emit "peerconnection:setremotedescriptionfailed" [error:%o]', error);
 
           _this17.emit('peerconnection:setremotedescriptionfailed', error);
 
           throw error;
         });
       }).then(function () {
         if (_this17._status === C.STATUS_TERMINATED) {
           throw new Error('terminated');
         }
 
         if (_this17._remoteHold === true && hold === false) {
           _this17._remoteHold = false;
 
           _this17._onunhold('remote');
         } else if (_this17._remoteHold === false && hold === true) {
           _this17._remoteHold = true;
 
           _this17._onhold('remote');
         }
       }) // Create local description.
       .then(function () {
         if (_this17._status === C.STATUS_TERMINATED) {
           throw new Error('terminated');
         }
 
         return _this17._createLocalDescription('answer', _this17._rtcAnswerConstraints)["catch"](function (error) {
           request.reply(500);
           debugerror('emit "peerconnection:createtelocaldescriptionfailed" [error:%o]', error);
           throw error;
         });
       })["catch"](function (error) {
         debugerror('_processInDialogSdpOffer() failed [error: %o]', error);
       });
       return this._connectionPromiseQueue;
     }
     /**
      * In dialog Refer Reception
      */
 
   }, {
     key: "_receiveRefer",
     value: function _receiveRefer(request) {
       var _this18 = this;
 
       debug('receiveRefer()');
 
       if (!request.refer_to) {
         debug('no Refer-To header field present in REFER');
         request.reply(400);
         return;
       }
 
       if (request.refer_to.uri.scheme !== JsSIP_C.SIP) {
         debug('Refer-To header field points to a non-SIP URI scheme');
         request.reply(416);
         return;
       } // Reply before the transaction timer expires.
 
 
       request.reply(202);
       var notifier = new RTCSession_ReferNotifier(this, request.cseq);
       debug('emit "refer"'); // Emit 'refer'.
 
       this.emit('refer', {
         request: request,
         accept: function accept(initCallback, options) {
           _accept.call(_this18, initCallback, options);
         },
         reject: function reject() {
           _reject.call(_this18);
         }
       });
 
       function _accept(initCallback) {
         var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
         initCallback = typeof initCallback === 'function' ? initCallback : null;
 
         if (this._status !== C.STATUS_WAITING_FOR_ACK && this._status !== C.STATUS_CONFIRMED) {
           return false;
         }
 
         var session = new RTCSession(this._ua);
         session.on('progress', function (_ref2) {
           var response = _ref2.response;
           notifier.notify(response.status_code, response.reason_phrase);
         });
         session.on('accepted', function (_ref3) {
           var response = _ref3.response;
           notifier.notify(response.status_code, response.reason_phrase);
         });
         session.on('_failed', function (_ref4) {
           var message = _ref4.message,
               cause = _ref4.cause;
 
           if (message) {
             notifier.notify(message.status_code, message.reason_phrase);
           } else {
             notifier.notify(487, cause);
           }
         }); // Consider the Replaces header present in the Refer-To URI.
 
         if (request.refer_to.uri.hasHeader('replaces')) {
           var replaces = decodeURIComponent(request.refer_to.uri.getHeader('replaces'));
           options.extraHeaders = Utils.cloneArray(options.extraHeaders);
           options.extraHeaders.push("Replaces: ".concat(replaces));
         }
 
         session.connect(request.refer_to.uri.toAor(), options, initCallback);
       }
 
       function _reject() {
         notifier.notify(603);
       }
     }
     /**
      * In dialog Notify Reception
      */
 
   }, {
     key: "_receiveNotify",
     value: function _receiveNotify(request) {
       debug('receiveNotify()');
 
       if (!request.event) {
         request.reply(400);
       }
 
       switch (request.event.event) {
         case 'refer':
           {
             var id;
             var referSubscriber;
 
             if (request.event.params && request.event.params.id) {
               id = request.event.params.id;
               referSubscriber = this._referSubscribers[id];
             } else if (Object.keys(this._referSubscribers).length === 1) {
               referSubscriber = this._referSubscribers[Object.keys(this._referSubscribers)[0]];
             } else {
               request.reply(400, 'Missing event id parameter');
               return;
             }
 
             if (!referSubscriber) {
               request.reply(481, 'Subscription does not exist');
               return;
             }
 
             referSubscriber.receiveNotify(request);
             request.reply(200);
             break;
           }
 
         default:
           {
             request.reply(489);
           }
       }
     }
     /**
      * INVITE with Replaces Reception
      */
 
   }, {
     key: "_receiveReplaces",
     value: function _receiveReplaces(request) {
       var _this20 = this;
 
       debug('receiveReplaces()');
 
       function _accept2(initCallback) {
         var _this19 = this;
 
         if (this._status !== C.STATUS_WAITING_FOR_ACK && this._status !== C.STATUS_CONFIRMED) {
           return false;
         }
 
         var session = new RTCSession(this._ua); // Terminate the current session when the new one is confirmed.
 
         session.on('confirmed', function () {
           _this19.terminate();
         });
         session.init_incoming(request, initCallback);
       }
 
       function _reject2() {
         debug('Replaced INVITE rejected by the user');
         request.reply(486);
       } // Emit 'replace'.
 
 
       this.emit('replaces', {
         request: request,
         accept: function accept(initCallback) {
           _accept2.call(_this20, initCallback);
         },
         reject: function reject() {
           _reject2.call(_this20);
         }
       });
     }
     /**
      * Initial Request Sender
      */
 
   }, {
     key: "_sendInitialRequest",
     value: function _sendInitialRequest(mediaConstraints, rtcOfferConstraints, mediaStream) {
       var _this21 = this;
 
       var request_sender = new RequestSender(this._ua, this._request, {
         onRequestTimeout: function onRequestTimeout() {
           _this21.onRequestTimeout();
         },
         onTransportError: function onTransportError() {
           _this21.onTransportError();
         },
         // Update the request on authentication.
         onAuthenticated: function onAuthenticated(request) {
           _this21._request = request;
         },
         onReceiveResponse: function onReceiveResponse(response) {
           _this21._receiveInviteResponse(response);
         }
       }); // This Promise is resolved within the next iteration, so the app has now
       // a chance to set events such as 'peerconnection' and 'connecting'.
 
       Promise.resolve() // Get a stream if required.
       .then(function () {
         // A stream is given, let the app set events such as 'peerconnection' and 'connecting'.
         if (mediaStream) {
           return mediaStream;
         } // Request for user media access.
         else if (mediaConstraints.audio || mediaConstraints.video) {
             _this21._localMediaStreamLocallyGenerated = true;
             return navigator.mediaDevices.getUserMedia(mediaConstraints)["catch"](function (error) {
               if (_this21._status === C.STATUS_TERMINATED) {
                 throw new Error('terminated');
               }
 
               _this21._failed('local', null, JsSIP_C.causes.USER_DENIED_MEDIA_ACCESS);
 
               debugerror('emit "getusermediafailed" [error:%o]', error);
 
               _this21.emit('getusermediafailed', error);
 
               throw error;
             });
           }
       }).then(function (stream) {
         if (_this21._status === C.STATUS_TERMINATED) {
           throw new Error('terminated');
         }
 
         _this21._localMediaStream = stream;
 
         if (stream) {
           stream.getTracks().forEach(function (track) {
             _this21._connection.addTrack(track, stream);
           });
         } // TODO: should this be triggered here?
 
 
         _this21._connecting(_this21._request);
 
         return _this21._createLocalDescription('offer', rtcOfferConstraints)["catch"](function (error) {
           _this21._failed('local', null, JsSIP_C.causes.WEBRTC_ERROR);
 
           throw error;
         });
       }).then(function (desc) {
         if (_this21._is_canceled || _this21._status === C.STATUS_TERMINATED) {
           throw new Error('terminated');
         }
 
         _this21._request.body = desc;
         _this21._status = C.STATUS_INVITE_SENT;
         debug('emit "sending" [request:%o]', _this21._request); // Emit 'sending' so the app can mangle the body before the request is sent.
 
         _this21.emit('sending', {
           request: _this21._request
         });
 
         request_sender.send();
       })["catch"](function (error) {
         if (_this21._status === C.STATUS_TERMINATED) {
           return;
         }
 
         debugerror(error);
       });
     }
     /**
      * Get DTMF RTCRtpSender.
      */
 
   }, {
     key: "_getDTMFRTPSender",
     value: function _getDTMFRTPSender() {
       var sender = this._connection.getSenders().find(function (rtpSender) {
         return rtpSender.track && rtpSender.track.kind === 'audio';
       });
 
       if (!(sender && sender.dtmf)) {
         debugerror('sendDTMF() | no local audio track to send DTMF with');
         return;
       }
 
       return sender.dtmf;
     }
     /**
      * Reception of Response for Initial INVITE
      */
 
   }, {
     key: "_receiveInviteResponse",
     value: function _receiveInviteResponse(response) {
       var _this22 = this;
 
       debug('receiveInviteResponse()'); // Handle 2XX retransmissions and responses from forked requests.
 
       if (this._dialog && response.status_code >= 200 && response.status_code <= 299) {
         /*
          * If it is a retransmission from the endpoint that established
          * the dialog, send an ACK
          */
         if (this._dialog.id.call_id === response.call_id && this._dialog.id.local_tag === response.from_tag && this._dialog.id.remote_tag === response.to_tag) {
           this.sendRequest(JsSIP_C.ACK);
           return;
         } // If not, send an ACK  and terminate.
         else {
             var dialog = new Dialog(this, response, 'UAC');
 
             if (dialog.error !== undefined) {
               debug(dialog.error);
               return;
             }
 
             this.sendRequest(JsSIP_C.ACK);
             this.sendRequest(JsSIP_C.BYE);
             return;
           }
       } // Proceed to cancellation if the user requested.
 
 
       if (this._is_canceled) {
         if (response.status_code >= 100 && response.status_code < 200) {
           this._request.cancel(this._cancel_reason);
         } else if (response.status_code >= 200 && response.status_code < 299) {
           this._acceptAndTerminate(response);
         }
 
         return;
       }
 
       if (this._status !== C.STATUS_INVITE_SENT && this._status !== C.STATUS_1XX_RECEIVED) {
         return;
       }
 
       switch (true) {
         case /^100$/.test(response.status_code):
           this._status = C.STATUS_1XX_RECEIVED;
           break;
 
         case /^1[0-9]{2}$/.test(response.status_code):
           {
             // Do nothing with 1xx responses without To tag.
             if (!response.to_tag) {
               debug('1xx response received without to tag');
               break;
             } // Create Early Dialog if 1XX comes with contact.
 
 
             if (response.hasHeader('contact')) {
               // An error on dialog creation will fire 'failed' event.
               if (!this._createDialog(response, 'UAC', true)) {
                 break;
               }
             }
 
             this._status = C.STATUS_1XX_RECEIVED;
 
             if (!response.body) {
               this._progress('remote', response);
 
               break;
             }
 
             var e = {
               originator: 'remote',
               type: 'answer',
               sdp: response.body
             };
             debug('emit "sdp"');
             this.emit('sdp', e);
             var answer = new RTCSessionDescription({
               type: 'answer',
               sdp: e.sdp
             });
             this._connectionPromiseQueue = this._connectionPromiseQueue.then(function () {
               return _this22._connection.setRemoteDescription(answer);
             }).then(function () {
               return _this22._progress('remote', response);
             })["catch"](function (error) {
               debugerror('emit "peerconnection:setremotedescriptionfailed" [error:%o]', error);
 
               _this22.emit('peerconnection:setremotedescriptionfailed', error);
             });
             break;
           }
 
         case /^2[0-9]{2}$/.test(response.status_code):
           {
             this._status = C.STATUS_CONFIRMED;
 
             if (!response.body) {
               this._acceptAndTerminate(response, 400, JsSIP_C.causes.MISSING_SDP);
 
               this._failed('remote', response, JsSIP_C.causes.BAD_MEDIA_DESCRIPTION);
 
               break;
             } // An error on dialog creation will fire 'failed' event.
 
 
             if (!this._createDialog(response, 'UAC')) {
               break;
             }
 
             var _e = {
               originator: 'remote',
               type: 'answer',
               sdp: response.body
             };
             debug('emit "sdp"');
             this.emit('sdp', _e);
 
             var _answer = new RTCSessionDescription({
               type: 'answer',
               sdp: _e.sdp
             });
 
             this._connectionPromiseQueue = this._connectionPromiseQueue.then(function () {
               // Be ready for 200 with SDP after a 180/183 with SDP.
               // We created a SDP 'answer' for it, so check the current signaling state.
               if (_this22._connection.signalingState === 'stable') {
                 return _this22._connection.createOffer(_this22._rtcOfferConstraints).then(function (offer) {
                   return _this22._connection.setLocalDescription(offer);
                 })["catch"](function (error) {
                   _this22._acceptAndTerminate(response, 500, error.toString());
 
                   _this22._failed('local', response, JsSIP_C.causes.WEBRTC_ERROR);
                 });
               }
             }).then(function () {
               _this22._connection.setRemoteDescription(_answer).then(function () {
                 // Handle Session Timers.
                 _this22._handleSessionTimersInIncomingResponse(response);
 
                 _this22._accepted('remote', response);
 
                 _this22.sendRequest(JsSIP_C.ACK);
 
                 _this22._confirmed('local', null);
               })["catch"](function (error) {
                 _this22._acceptAndTerminate(response, 488, 'Not Acceptable Here');
 
                 _this22._failed('remote', response, JsSIP_C.causes.BAD_MEDIA_DESCRIPTION);
 
                 debugerror('emit "peerconnection:setremotedescriptionfailed" [error:%o]', error);
 
                 _this22.emit('peerconnection:setremotedescriptionfailed', error);
               });
             });
             break;
           }
 
         default:
           {
             var cause = Utils.sipErrorCause(response.status_code);
 
             this._failed('remote', response, cause);
           }
       }
     }
     /**
      * Send Re-INVITE
      */
 
   }, {
     key: "_sendReinvite",
     value: function _sendReinvite() {
       var _this23 = this;
 
       var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
       debug('sendReinvite()');
       var extraHeaders = Utils.cloneArray(options.extraHeaders);
       var eventHandlers = Utils.cloneObject(options.eventHandlers);
       var rtcOfferConstraints = options.rtcOfferConstraints || this._rtcOfferConstraints || null;
       var succeeded = false;
       extraHeaders.push("Contact: ".concat(this._contact));
       extraHeaders.push('Content-Type: application/sdp'); // Session Timers.
 
       if (this._sessionTimers.running) {
         extraHeaders.push("Session-Expires: ".concat(this._sessionTimers.currentExpires, ";refresher=").concat(this._sessionTimers.refresher ? 'uac' : 'uas'));
       }
 
       this._connectionPromiseQueue = this._connectionPromiseQueue.then(function () {
         return _this23._createLocalDescription('offer', rtcOfferConstraints);
       }).then(function (sdp) {
         sdp = _this23._mangleOffer(sdp);
         var e = {
           originator: 'local',
           type: 'offer',
           sdp: sdp
         };
         debug('emit "sdp"');
 
         _this23.emit('sdp', e);
 
         _this23.sendRequest(JsSIP_C.INVITE, {
           extraHeaders: extraHeaders,
           body: sdp,
           eventHandlers: {
             onSuccessResponse: function onSuccessResponse(response) {
               onSucceeded.call(_this23, response);
               succeeded = true;
             },
             onErrorResponse: function onErrorResponse(response) {
               onFailed.call(_this23, response);
             },
             onTransportError: function onTransportError() {
               _this23.onTransportError(); // Do nothing because session ends.
 
             },
             onRequestTimeout: function onRequestTimeout() {
               _this23.onRequestTimeout(); // Do nothing because session ends.
 
             },
             onDialogError: function onDialogError() {
               _this23.onDialogError(); // Do nothing because session ends.
 
             }
           }
         });
       })["catch"](function () {
         onFailed();
       });
 
       function onSucceeded(response) {
         var _this24 = this;
 
         if (this._status === C.STATUS_TERMINATED) {
           return;
         }
 
         this.sendRequest(JsSIP_C.ACK); // If it is a 2XX retransmission exit now.
 
         if (succeeded) {
           return;
         } // Handle Session Timers.
 
 
         this._handleSessionTimersInIncomingResponse(response); // Must have SDP answer.
 
 
         if (!response.body) {
           onFailed.call(this);
           return;
         } else if (!response.hasHeader('Content-Type') || response.getHeader('Content-Type').toLowerCase() !== 'application/sdp') {
           onFailed.call(this);
           return;
         }
 
         var e = {
           originator: 'remote',
           type: 'answer',
           sdp: response.body
         };
         debug('emit "sdp"');
         this.emit('sdp', e);
         var answer = new RTCSessionDescription({
           type: 'answer',
           sdp: e.sdp
         });
         this._connectionPromiseQueue = this._connectionPromiseQueue.then(function () {
           return _this24._connection.setRemoteDescription(answer);
         }).then(function () {
           if (eventHandlers.succeeded) {
             eventHandlers.succeeded(response);
           }
         })["catch"](function (error) {
           onFailed.call(_this24);
           debugerror('emit "peerconnection:setremotedescriptionfailed" [error:%o]', error);
 
           _this24.emit('peerconnection:setremotedescriptionfailed', error);
         });
       }
 
       function onFailed(response) {
         if (eventHandlers.failed) {
           eventHandlers.failed(response);
         }
       }
     }
     /**
      * Send UPDATE
      */
 
   }, {
     key: "_sendUpdate",
     value: function _sendUpdate() {
       var _this25 = this;
 
       var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
       debug('sendUpdate()');
       var extraHeaders = Utils.cloneArray(options.extraHeaders);
       var eventHandlers = Utils.cloneObject(options.eventHandlers);
       var rtcOfferConstraints = options.rtcOfferConstraints || this._rtcOfferConstraints || null;
       var sdpOffer = options.sdpOffer || false;
       var succeeded = false;
       extraHeaders.push("Contact: ".concat(this._contact)); // Session Timers.
 
       if (this._sessionTimers.running) {
         extraHeaders.push("Session-Expires: ".concat(this._sessionTimers.currentExpires, ";refresher=").concat(this._sessionTimers.refresher ? 'uac' : 'uas'));
       }
 
       if (sdpOffer) {
         extraHeaders.push('Content-Type: application/sdp');
         this._connectionPromiseQueue = this._connectionPromiseQueue.then(function () {
           return _this25._createLocalDescription('offer', rtcOfferConstraints);
         }).then(function (sdp) {
           sdp = _this25._mangleOffer(sdp);
           var e = {
             originator: 'local',
             type: 'offer',
             sdp: sdp
           };
           debug('emit "sdp"');
 
           _this25.emit('sdp', e);
 
           _this25.sendRequest(JsSIP_C.UPDATE, {
             extraHeaders: extraHeaders,
             body: sdp,
             eventHandlers: {
               onSuccessResponse: function onSuccessResponse(response) {
                 onSucceeded.call(_this25, response);
                 succeeded = true;
               },
               onErrorResponse: function onErrorResponse(response) {
                 onFailed.call(_this25, response);
               },
               onTransportError: function onTransportError() {
                 _this25.onTransportError(); // Do nothing because session ends.
 
               },
               onRequestTimeout: function onRequestTimeout() {
                 _this25.onRequestTimeout(); // Do nothing because session ends.
 
               },
               onDialogError: function onDialogError() {
                 _this25.onDialogError(); // Do nothing because session ends.
 
               }
             }
           });
         })["catch"](function () {
           onFailed.call(_this25);
         });
       } // No SDP.
       else {
           this.sendRequest(JsSIP_C.UPDATE, {
             extraHeaders: extraHeaders,
             eventHandlers: {
               onSuccessResponse: function onSuccessResponse(response) {
                 onSucceeded.call(_this25, response);
               },
               onErrorResponse: function onErrorResponse(response) {
                 onFailed.call(_this25, response);
               },
               onTransportError: function onTransportError() {
                 _this25.onTransportError(); // Do nothing because session ends.
 
               },
               onRequestTimeout: function onRequestTimeout() {
                 _this25.onRequestTimeout(); // Do nothing because session ends.
 
               },
               onDialogError: function onDialogError() {
                 _this25.onDialogError(); // Do nothing because session ends.
 
               }
             }
           });
         }
 
       function onSucceeded(response) {
         var _this26 = this;
 
         if (this._status === C.STATUS_TERMINATED) {
           return;
         } // If it is a 2XX retransmission exit now.
 
 
         if (succeeded) {
           return;
         } // Handle Session Timers.
 
 
         this._handleSessionTimersInIncomingResponse(response); // Must have SDP answer.
 
 
         if (sdpOffer) {
           if (!response.body) {
             onFailed.call(this);
             return;
           } else if (!response.hasHeader('Content-Type') || response.getHeader('Content-Type').toLowerCase() !== 'application/sdp') {
             onFailed.call(this);
             return;
           }
 
           var e = {
             originator: 'remote',
             type: 'answer',
             sdp: response.body
           };
           debug('emit "sdp"');
           this.emit('sdp', e);
           var answer = new RTCSessionDescription({
             type: 'answer',
             sdp: e.sdp
           });
           this._connectionPromiseQueue = this._connectionPromiseQueue.then(function () {
             return _this26._connection.setRemoteDescription(answer);
           }).then(function () {
             if (eventHandlers.succeeded) {
               eventHandlers.succeeded(response);
             }
           })["catch"](function (error) {
             onFailed.call(_this26);
             debugerror('emit "peerconnection:setremotedescriptionfailed" [error:%o]', error);
 
             _this26.emit('peerconnection:setremotedescriptionfailed', error);
           });
         } // No SDP answer.
         else if (eventHandlers.succeeded) {
             eventHandlers.succeeded(response);
           }
       }
 
       function onFailed(response) {
         if (eventHandlers.failed) {
           eventHandlers.failed(response);
         }
       }
     }
   }, {
     key: "_acceptAndTerminate",
     value: function _acceptAndTerminate(response, status_code, reason_phrase) {
       debug('acceptAndTerminate()');
       var extraHeaders = [];
 
       if (status_code) {
         reason_phrase = reason_phrase || JsSIP_C.REASON_PHRASE[status_code] || '';
         extraHeaders.push("Reason: SIP ;cause=".concat(status_code, "; text=\"").concat(reason_phrase, "\""));
       } // An error on dialog creation will fire 'failed' event.
 
 
       if (this._dialog || this._createDialog(response, 'UAC')) {
         this.sendRequest(JsSIP_C.ACK);
         this.sendRequest(JsSIP_C.BYE, {
           extraHeaders: extraHeaders
         });
       } // Update session status.
 
 
       this._status = C.STATUS_TERMINATED;
     }
     /**
      * Correctly set the SDP direction attributes if the call is on local hold
      */
 
   }, {
     key: "_mangleOffer",
     value: function _mangleOffer(sdp) {
       if (!this._localHold && !this._remoteHold) {
         return sdp;
       }
 
       sdp = sdp_transform.parse(sdp); // Local hold.
 
       if (this._localHold && !this._remoteHold) {
         debug('mangleOffer() | me on hold, mangling offer');
 
         var _iterator5 = _createForOfIteratorHelper(sdp.media),
             _step5;
 
         try {
           for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
             var m = _step5.value;
 
             if (holdMediaTypes.indexOf(m.type) === -1) {
               continue;
             }
 
             if (!m.direction) {
               m.direction = 'sendonly';
             } else if (m.direction === 'sendrecv') {
               m.direction = 'sendonly';
             } else if (m.direction === 'recvonly') {
               m.direction = 'inactive';
             }
           }
         } catch (err) {
           _iterator5.e(err);
         } finally {
           _iterator5.f();
         }
       } // Local and remote hold.
       else if (this._localHold && this._remoteHold) {
           debug('mangleOffer() | both on hold, mangling offer');
 
           var _iterator6 = _createForOfIteratorHelper(sdp.media),
               _step6;
 
           try {
             for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
               var _m = _step6.value;
 
               if (holdMediaTypes.indexOf(_m.type) === -1) {
                 continue;
               }
 
               _m.direction = 'inactive';
             }
           } catch (err) {
             _iterator6.e(err);
           } finally {
             _iterator6.f();
           }
         } // Remote hold.
         else if (this._remoteHold) {
             debug('mangleOffer() | remote on hold, mangling offer');
 
             var _iterator7 = _createForOfIteratorHelper(sdp.media),
                 _step7;
 
             try {
               for (_iterator7.s(); !(_step7 = _iterator7.n()).done;) {
                 var _m2 = _step7.value;
 
                 if (holdMediaTypes.indexOf(_m2.type) === -1) {
                   continue;
                 }
 
                 if (!_m2.direction) {
                   _m2.direction = 'recvonly';
                 } else if (_m2.direction === 'sendrecv') {
                   _m2.direction = 'recvonly';
                 } else if (_m2.direction === 'recvonly') {
                   _m2.direction = 'inactive';
                 }
               }
             } catch (err) {
               _iterator7.e(err);
             } finally {
               _iterator7.f();
             }
           }
 
       return sdp_transform.write(sdp);
     }
   }, {
     key: "_setLocalMediaStatus",
     value: function _setLocalMediaStatus() {
       var enableAudio = true,
           enableVideo = true;
 
       if (this._localHold || this._remoteHold) {
         enableAudio = false;
         enableVideo = false;
       }
 
       if (this._audioMuted) {
         enableAudio = false;
       }
 
       if (this._videoMuted) {
         enableVideo = false;
       }
 
       this._toggleMuteAudio(!enableAudio);
 
       this._toggleMuteVideo(!enableVideo);
     }
     /**
      * Handle SessionTimers for an incoming INVITE or UPDATE.
      * @param  {IncomingRequest} request
      * @param  {Array} responseExtraHeaders  Extra headers for the 200 response.
      */
 
   }, {
     key: "_handleSessionTimersInIncomingRequest",
     value: function _handleSessionTimersInIncomingRequest(request, responseExtraHeaders) {
       if (!this._sessionTimers.enabled) {
         return;
       }
 
       var session_expires_refresher;
 
       if (request.session_expires && request.session_expires >= JsSIP_C.MIN_SESSION_EXPIRES) {
         this._sessionTimers.currentExpires = request.session_expires;
         session_expires_refresher = request.session_expires_refresher || 'uas';
       } else {
         this._sessionTimers.currentExpires = this._sessionTimers.defaultExpires;
         session_expires_refresher = 'uas';
       }
 
       responseExtraHeaders.push("Session-Expires: ".concat(this._sessionTimers.currentExpires, ";refresher=").concat(session_expires_refresher));
       this._sessionTimers.refresher = session_expires_refresher === 'uas';
 
       this._runSessionTimer();
     }
     /**
      * Handle SessionTimers for an incoming response to INVITE or UPDATE.
      * @param  {IncomingResponse} response
      */
 
   }, {
     key: "_handleSessionTimersInIncomingResponse",
     value: function _handleSessionTimersInIncomingResponse(response) {
       if (!this._sessionTimers.enabled) {
         return;
       }
 
       var session_expires_refresher;
 
       if (response.session_expires && response.session_expires >= JsSIP_C.MIN_SESSION_EXPIRES) {
         this._sessionTimers.currentExpires = response.session_expires;
         session_expires_refresher = response.session_expires_refresher || 'uac';
       } else {
         this._sessionTimers.currentExpires = this._sessionTimers.defaultExpires;
         session_expires_refresher = 'uac';
       }
 
       this._sessionTimers.refresher = session_expires_refresher === 'uac';
 
       this._runSessionTimer();
     }
   }, {
     key: "_runSessionTimer",
     value: function _runSessionTimer() {
       var _this27 = this;
 
       var expires = this._sessionTimers.currentExpires;
       this._sessionTimers.running = true;
       clearTimeout(this._sessionTimers.timer); // I'm the refresher.
 
       if (this._sessionTimers.refresher) {
         this._sessionTimers.timer = setTimeout(function () {
           if (_this27._status === C.STATUS_TERMINATED) {
             return;
           }
 
           debug('runSessionTimer() | sending session refresh request');
 
           if (_this27._sessionTimers.refreshMethod === JsSIP_C.UPDATE) {
             _this27._sendUpdate();
           } else {
             _this27._sendReinvite();
           }
         }, expires * 500); // Half the given interval (as the RFC states).
       } // I'm not the refresher.
       else {
           this._sessionTimers.timer = setTimeout(function () {
             if (_this27._status === C.STATUS_TERMINATED) {
               return;
             }
 
             debugerror('runSessionTimer() | timer expired, terminating the session');
 
             _this27.terminate({
               cause: JsSIP_C.causes.REQUEST_TIMEOUT,
               status_code: 408,
               reason_phrase: 'Session Timer Expired'
             });
           }, expires * 1100);
         }
     }
   }, {
     key: "_toggleMuteAudio",
     value: function _toggleMuteAudio(mute) {
       var senders = this._connection.getSenders().filter(function (sender) {
         return sender.track && sender.track.kind === 'audio';
       });
 
       var _iterator8 = _createForOfIteratorHelper(senders),
           _step8;
 
       try {
         for (_iterator8.s(); !(_step8 = _iterator8.n()).done;) {
           var sender = _step8.value;
           sender.track.enabled = !mute;
         }
       } catch (err) {
         _iterator8.e(err);
       } finally {
         _iterator8.f();
       }
     }
   }, {
     key: "_toggleMuteVideo",
     value: function _toggleMuteVideo(mute) {
       var senders = this._connection.getSenders().filter(function (sender) {
         return sender.track && sender.track.kind === 'video';
       });
 
       var _iterator9 = _createForOfIteratorHelper(senders),
           _step9;
 
       try {
         for (_iterator9.s(); !(_step9 = _iterator9.n()).done;) {
           var sender = _step9.value;
           sender.track.enabled = !mute;
         }
       } catch (err) {
         _iterator9.e(err);
       } finally {
         _iterator9.f();
       }
     }
   }, {
     key: "_newRTCSession",
     value: function _newRTCSession(originator, request) {
       debug('newRTCSession()');
 
       this._ua.newRTCSession(this, {
         originator: originator,
         session: this,
         request: request
       });
     }
   }, {
     key: "_connecting",
     value: function _connecting(request) {
       debug('session connecting');
       debug('emit "connecting"');
       this.emit('connecting', {
         request: request
       });
     }
   }, {
     key: "_progress",
     value: function _progress(originator, response) {
       debug('session progress');
       debug('emit "progress"');
       this.emit('progress', {
         originator: originator,
         response: response || null
       });
     }
   }, {
     key: "_accepted",
     value: function _accepted(originator, message) {
       debug('session accepted');
       this._start_time = new Date();
       debug('emit "accepted"');
       this.emit('accepted', {
         originator: originator,
         response: message || null
       });
     }
   }, {
     key: "_confirmed",
     value: function _confirmed(originator, ack) {
       debug('session confirmed');
       this._is_confirmed = true;
       debug('emit "confirmed"');
       this.emit('confirmed', {
         originator: originator,
         ack: ack || null
       });
     }
   }, {
     key: "_ended",
     value: function _ended(originator, message, cause) {
       debug('session ended');
       this._end_time = new Date();
 
       this._close();
 
       debug('emit "ended"');
       this.emit('ended', {
         originator: originator,
         message: message || null,
         cause: cause
       });
     }
   }, {
     key: "_failed",
     value: function _failed(originator, message, cause) {
       debug('session failed'); // Emit private '_failed' event first.
 
       debug('emit "_failed"');
       this.emit('_failed', {
         originator: originator,
         message: message || null,
         cause: cause
       });
 
       this._close();
 
       debug('emit "failed"');
       this.emit('failed', {
         originator: originator,
         message: message || null,
         cause: cause
       });
     }
   }, {
     key: "_onhold",
     value: function _onhold(originator) {
       debug('session onhold');
 
       this._setLocalMediaStatus();
 
       debug('emit "hold"');
       this.emit('hold', {
         originator: originator
       });
     }
   }, {
     key: "_onunhold",
     value: function _onunhold(originator) {
       debug('session onunhold');
 
       this._setLocalMediaStatus();
 
       debug('emit "unhold"');
       this.emit('unhold', {
         originator: originator
       });
     }
   }, {
     key: "_onmute",
     value: function _onmute(_ref5) {
       var audio = _ref5.audio,
           video = _ref5.video;
       debug('session onmute');
 
       this._setLocalMediaStatus();
 
       debug('emit "muted"');
       this.emit('muted', {
         audio: audio,
         video: video
       });
     }
   }, {
     key: "_onunmute",
     value: function _onunmute(_ref6) {
       var audio = _ref6.audio,
           video = _ref6.video;
       debug('session onunmute');
 
       this._setLocalMediaStatus();
 
       debug('emit "unmuted"');
       this.emit('unmuted', {
         audio: audio,
         video: video
       });
     }
   }, {
     key: "C",
     get: function get() {
       return C;
     } // Expose session failed/ended causes as a property of the RTCSession instance.
 
   }, {
     key: "causes",
     get: function get() {
       return JsSIP_C.causes;
     }
   }, {
     key: "id",
     get: function get() {
       return this._id;
     }
   }, {
     key: "connection",
     get: function get() {
       return this._connection;
     }
   }, {
     key: "contact",
     get: function get() {
       return this._contact;
     }
   }, {
     key: "direction",
     get: function get() {
       return this._direction;
     }
   }, {
     key: "local_identity",
     get: function get() {
       return this._local_identity;
     }
   }, {
     key: "remote_identity",
     get: function get() {
       return this._remote_identity;
     }
   }, {
     key: "start_time",
     get: function get() {
       return this._start_time;
     }
   }, {
     key: "end_time",
     get: function get() {
       return this._end_time;
     }
   }, {
     key: "data",
     get: function get() {
       return this._data;
     },
     set: function set(_data) {
       this._data = _data;
     }
   }, {
     key: "status",
     get: function get() {
       return this._status;
     }
   }]);
 
   return RTCSession;
 }(EventEmitter);
 },{"./Constants":2,"./Dialog":3,"./Exceptions":6,"./RTCSession/DTMF":13,"./RTCSession/Info":14,"./RTCSession/ReferNotifier":15,"./RTCSession/ReferSubscriber":16,"./RequestSender":18,"./SIPMessage":19,"./Timers":21,"./Transactions":22,"./URI":25,"./Utils":26,"debug":30,"events":29,"sdp-transform":35}],13:[function(require,module,exports){
 "use strict";
 
 function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
 
 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
 function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
 
 function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
 
 function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
 
 function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
 
 function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
 
 function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
 
 function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
 
 function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }
 
 function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
 
 var EventEmitter = require('events').EventEmitter;
 
 var JsSIP_C = require('../Constants');
 
 var Exceptions = require('../Exceptions');
 
 var Utils = require('../Utils');
 
 var debug = require('debug')('JsSIP:RTCSession:DTMF');
 
 var debugerror = require('debug')('JsSIP:ERROR:RTCSession:DTMF');
 
 debugerror.log = console.warn.bind(console);
 var C = {
   MIN_DURATION: 70,
   MAX_DURATION: 6000,
   DEFAULT_DURATION: 100,
   MIN_INTER_TONE_GAP: 50,
   DEFAULT_INTER_TONE_GAP: 500
 };
 
 module.exports = /*#__PURE__*/function (_EventEmitter) {
   _inherits(DTMF, _EventEmitter);
 
   var _super = _createSuper(DTMF);
 
   function DTMF(session) {
     var _this;
 
     _classCallCheck(this, DTMF);
 
     _this = _super.call(this);
     _this._session = session;
     _this._direction = null;
     _this._tone = null;
     _this._duration = null;
     _this._request = null;
     return _this;
   }
 
   _createClass(DTMF, [{
     key: "send",
     value: function send(tone) {
       var _this2 = this;
 
       var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
 
       if (tone === undefined) {
         throw new TypeError('Not enough arguments');
       }
 
       this._direction = 'outgoing'; // Check RTCSession Status.
 
       if (this._session.status !== this._session.C.STATUS_CONFIRMED && this._session.status !== this._session.C.STATUS_WAITING_FOR_ACK) {
         throw new Exceptions.InvalidStateError(this._session.status);
       }
 
       var extraHeaders = Utils.cloneArray(options.extraHeaders);
       this.eventHandlers = Utils.cloneObject(options.eventHandlers); // Check tone type.
 
       if (typeof tone === 'string') {
         tone = tone.toUpperCase();
       } else if (typeof tone === 'number') {
         tone = tone.toString();
       } else {
         throw new TypeError("Invalid tone: ".concat(tone));
       } // Check tone value.
 
 
       if (!tone.match(/^[0-9A-DR#*]$/)) {
         throw new TypeError("Invalid tone: ".concat(tone));
       } else {
         this._tone = tone;
       } // Duration is checked/corrected in RTCSession.
 
 
       this._duration = options.duration;
       extraHeaders.push('Content-Type: application/dtmf-relay');
       var body = "Signal=".concat(this._tone, "\r\n");
       body += "Duration=".concat(this._duration);
 
       this._session.newDTMF({
         originator: 'local',
         dtmf: this,
         request: this._request
       });
 
       this._session.sendRequest(JsSIP_C.INFO, {
         extraHeaders: extraHeaders,
         eventHandlers: {
           onSuccessResponse: function onSuccessResponse(response) {
             _this2.emit('succeeded', {
               originator: 'remote',
               response: response
             });
           },
           onErrorResponse: function onErrorResponse(response) {
             if (_this2.eventHandlers.onFailed) {
               _this2.eventHandlers.onFailed();
             }
 
             _this2.emit('failed', {
               originator: 'remote',
               response: response
             });
           },
           onRequestTimeout: function onRequestTimeout() {
             _this2._session.onRequestTimeout();
           },
           onTransportError: function onTransportError() {
             _this2._session.onTransportError();
           },
           onDialogError: function onDialogError() {
             _this2._session.onDialogError();
           }
         },
         body: body
       });
     }
   }, {
     key: "init_incoming",
     value: function init_incoming(request) {
       var reg_tone = /^(Signal\s*?=\s*?)([0-9A-D#*]{1})(\s)?.*/;
       var reg_duration = /^(Duration\s?=\s?)([0-9]{1,4})(\s)?.*/;
       this._direction = 'incoming';
       this._request = request;
       request.reply(200);
 
       if (request.body) {
         var body = request.body.split('\n');
 
         if (body.length >= 1) {
           if (reg_tone.test(body[0])) {
             this._tone = body[0].replace(reg_tone, '$2');
           }
         }
 
         if (body.length >= 2) {
           if (reg_duration.test(body[1])) {
             this._duration = parseInt(body[1].replace(reg_duration, '$2'), 10);
           }
         }
       }
 
       if (!this._duration) {
         this._duration = C.DEFAULT_DURATION;
       }
 
       if (!this._tone) {
         debug('invalid INFO DTMF received, discarded');
       } else {
         this._session.newDTMF({
           originator: 'remote',
           dtmf: this,
           request: request
         });
       }
     }
   }, {
     key: "tone",
     get: function get() {
       return this._tone;
     }
   }, {
     key: "duration",
     get: function get() {
       return this._duration;
     }
   }]);
 
   return DTMF;
 }(EventEmitter);
 /**
  * Expose C object.
  */
 
 
 module.exports.C = C;
 },{"../Constants":2,"../Exceptions":6,"../Utils":26,"debug":30,"events":29}],14:[function(require,module,exports){
 "use strict";
 
 function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
 
 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
 function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
 
 function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
 
 function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
 
 function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
 
 function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
 
 function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
 
 function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
 
 function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }
 
 function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
 
 var EventEmitter = require('events').EventEmitter;
 
 var debugerror = require('debug')('JsSIP:ERROR:RTCSession:Info');
 
 debugerror.log = console.warn.bind(console);
 
 var JsSIP_C = require('../Constants');
 
 var Exceptions = require('../Exceptions');
 
 var Utils = require('../Utils');
 
 module.exports = /*#__PURE__*/function (_EventEmitter) {
   _inherits(Info, _EventEmitter);
 
   var _super = _createSuper(Info);
 
   function Info(session) {
     var _this;
 
     _classCallCheck(this, Info);
 
     _this = _super.call(this);
     _this._session = session;
     _this._direction = null;
     _this._contentType = null;
     _this._body = null;
     return _this;
   }
 
   _createClass(Info, [{
     key: "send",
     value: function send(contentType, body) {
       var _this2 = this;
 
       var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
       this._direction = 'outgoing';
 
       if (contentType === undefined) {
         throw new TypeError('Not enough arguments');
       } // Check RTCSession Status.
 
 
       if (this._session.status !== this._session.C.STATUS_CONFIRMED && this._session.status !== this._session.C.STATUS_WAITING_FOR_ACK) {
         throw new Exceptions.InvalidStateError(this._session.status);
       }
 
       this._contentType = contentType;
       this._body = body;
       var extraHeaders = Utils.cloneArray(options.extraHeaders);
       extraHeaders.push("Content-Type: ".concat(contentType));
 
       this._session.newInfo({
         originator: 'local',
         info: this,
         request: this.request
       });
 
       this._session.sendRequest(JsSIP_C.INFO, {
         extraHeaders: extraHeaders,
         eventHandlers: {
           onSuccessResponse: function onSuccessResponse(response) {
             _this2.emit('succeeded', {
               originator: 'remote',
               response: response
             });
           },
           onErrorResponse: function onErrorResponse(response) {
             _this2.emit('failed', {
               originator: 'remote',
               response: response
             });
           },
           onTransportError: function onTransportError() {
             _this2._session.onTransportError();
           },
           onRequestTimeout: function onRequestTimeout() {
             _this2._session.onRequestTimeout();
           },
           onDialogError: function onDialogError() {
             _this2._session.onDialogError();
           }
         },
         body: body
       });
     }
   }, {
     key: "init_incoming",
     value: function init_incoming(request) {
       this._direction = 'incoming';
       this.request = request;
       request.reply(200);
       this._contentType = request.hasHeader('Content-Type') ? request.getHeader('Content-Type').toLowerCase() : undefined;
       this._body = request.body;
 
       this._session.newInfo({
         originator: 'remote',
         info: this,
         request: request
       });
     }
   }, {
     key: "contentType",
     get: function get() {
       return this._contentType;
     }
   }, {
     key: "body",
     get: function get() {
       return this._body;
     }
   }]);
 
   return Info;
 }(EventEmitter);
 },{"../Constants":2,"../Exceptions":6,"../Utils":26,"debug":30,"events":29}],15:[function(require,module,exports){
 "use strict";
 
 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
 function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
 
 function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
 
 var JsSIP_C = require('../Constants');
 
 var debug = require('debug')('JsSIP:RTCSession:ReferNotifier');
 
 var C = {
   event_type: 'refer',
   body_type: 'message/sipfrag;version=2.0',
   expires: 300
 };
 
 module.exports = /*#__PURE__*/function () {
   function ReferNotifier(session, id, expires) {
     _classCallCheck(this, ReferNotifier);
 
     this._session = session;
     this._id = id;
     this._expires = expires || C.expires;
     this._active = true; // The creation of a Notifier results in an immediate NOTIFY.
 
     this.notify(100);
   }
 
   _createClass(ReferNotifier, [{
     key: "notify",
     value: function notify(code, reason) {
       debug('notify()');
 
       if (this._active === false) {
         return;
       }
 
       reason = reason || JsSIP_C.REASON_PHRASE[code] || '';
       var state;
 
       if (code >= 200) {
         state = 'terminated;reason=noresource';
       } else {
         state = "active;expires=".concat(this._expires);
       } // Put this in a try/catch block.
 
 
       this._session.sendRequest(JsSIP_C.NOTIFY, {
         extraHeaders: ["Event: ".concat(C.event_type, ";id=").concat(this._id), "Subscription-State: ".concat(state), "Content-Type: ".concat(C.body_type)],
         body: "SIP/2.0 ".concat(code, " ").concat(reason),
         eventHandlers: {
           // If a negative response is received, subscription is canceled.
           onErrorResponse: function onErrorResponse() {
             this._active = false;
           }
         }
       });
     }
   }]);
 
   return ReferNotifier;
 }();
 },{"../Constants":2,"debug":30}],16:[function(require,module,exports){
 "use strict";
 
 function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
 
 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
 function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
 
 function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
 
 function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
 
 function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
 
 function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
 
 function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
 
 function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
 
 function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }
 
 function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
 
 var EventEmitter = require('events').EventEmitter;
 
 var JsSIP_C = require('../Constants');
 
 var Grammar = require('../Grammar');
 
 var Utils = require('../Utils');
 
 var debug = require('debug')('JsSIP:RTCSession:ReferSubscriber');
 
 module.exports = /*#__PURE__*/function (_EventEmitter) {
   _inherits(ReferSubscriber, _EventEmitter);
 
   var _super = _createSuper(ReferSubscriber);
 
   function ReferSubscriber(session) {
     var _this;
 
     _classCallCheck(this, ReferSubscriber);
 
     _this = _super.call(this);
     _this._id = null;
     _this._session = session;
     return _this;
   }
 
   _createClass(ReferSubscriber, [{
     key: "sendRefer",
     value: function sendRefer(target) {
       var _this2 = this;
 
       var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
       debug('sendRefer()');
       var extraHeaders = Utils.cloneArray(options.extraHeaders);
       var eventHandlers = Utils.cloneObject(options.eventHandlers); // Set event handlers.
 
       for (var event in eventHandlers) {
         if (Object.prototype.hasOwnProperty.call(eventHandlers, event)) {
           this.on(event, eventHandlers[event]);
         }
       } // Replaces URI header field.
 
 
       var replaces = null;
 
       if (options.replaces) {
         replaces = options.replaces._request.call_id;
         replaces += ";to-tag=".concat(options.replaces._to_tag);
         replaces += ";from-tag=".concat(options.replaces._from_tag);
         replaces = encodeURIComponent(replaces);
       } // Refer-To header field.
 
 
       var referTo = "Refer-To: <".concat(target).concat(replaces ? "?Replaces=".concat(replaces) : '', ">");
       extraHeaders.push(referTo); // Referred-By header field.
 
       var referredBy = "Referred-By: <".concat(this._session._ua._configuration.uri._scheme, ":").concat(this._session._ua._configuration.uri._user, "@").concat(this._session._ua._configuration.uri._host, ">");
       extraHeaders.push(referredBy);
       extraHeaders.push("Contact: ".concat(this._session.contact));
 
       var request = this._session.sendRequest(JsSIP_C.REFER, {
         extraHeaders: extraHeaders,
         eventHandlers: {
           onSuccessResponse: function onSuccessResponse(response) {
             _this2._requestSucceeded(response);
           },
           onErrorResponse: function onErrorResponse(response) {
             _this2._requestFailed(response, JsSIP_C.causes.REJECTED);
           },
           onTransportError: function onTransportError() {
             _this2._requestFailed(null, JsSIP_C.causes.CONNECTION_ERROR);
           },
           onRequestTimeout: function onRequestTimeout() {
             _this2._requestFailed(null, JsSIP_C.causes.REQUEST_TIMEOUT);
           },
           onDialogError: function onDialogError() {
             _this2._requestFailed(null, JsSIP_C.causes.DIALOG_ERROR);
           }
         }
       });
 
       this._id = request.cseq;
     }
   }, {
     key: "receiveNotify",
     value: function receiveNotify(request) {
       debug('receiveNotify()');
 
       if (!request.body) {
         return;
       }
 
       var status_line = Grammar.parse(request.body.trim(), 'Status_Line');
 
       if (status_line === -1) {
         debug("receiveNotify() | error parsing NOTIFY body: \"".concat(request.body, "\""));
         return;
       }
 
       switch (true) {
         case /^100$/.test(status_line.status_code):
           this.emit('trying', {
             request: request,
             status_line: status_line
           });
           break;
 
         case /^1[0-9]{2}$/.test(status_line.status_code):
           this.emit('progress', {
             request: request,
             status_line: status_line
           });
           break;
 
         case /^2[0-9]{2}$/.test(status_line.status_code):
           this.emit('accepted', {
             request: request,
             status_line: status_line
           });
           break;
 
         default:
           this.emit('failed', {
             request: request,
             status_line: status_line
           });
           break;
       }
     }
   }, {
     key: "_requestSucceeded",
     value: function _requestSucceeded(response) {
       debug('REFER succeeded');
       debug('emit "requestSucceeded"');
       this.emit('requestSucceeded', {
         response: response
       });
     }
   }, {
     key: "_requestFailed",
     value: function _requestFailed(response, cause) {
       debug('REFER failed');
       debug('emit "requestFailed"');
       this.emit('requestFailed', {
         response: response || null,
         cause: cause
       });
     }
   }, {
     key: "id",
     get: function get() {
       return this._id;
     }
   }]);
 
   return ReferSubscriber;
 }(EventEmitter);
 },{"../Constants":2,"../Grammar":7,"../Utils":26,"debug":30,"events":29}],17:[function(require,module,exports){
 "use strict";
 
 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
 function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
 
 function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
 
 var Utils = require('./Utils');
 
 var JsSIP_C = require('./Constants');
 
 var SIPMessage = require('./SIPMessage');
 
 var RequestSender = require('./RequestSender');
 
 var debug = require('debug')('JsSIP:Registrator');
 
 var MIN_REGISTER_EXPIRES = 10; // In seconds.
 
 module.exports = /*#__PURE__*/function () {
   function Registrator(ua, transport) {
     _classCallCheck(this, Registrator);
 
     var reg_id = 1; // Force reg_id to 1.
 
     this._ua = ua;
     this._transport = transport;
     this._registrar = ua.configuration.registrar_server;
     this._expires = ua.configuration.register_expires; // Call-ID and CSeq values RFC3261 10.2.
 
     this._call_id = Utils.createRandomToken(22);
     this._cseq = 0;
     this._to_uri = ua.configuration.uri;
     this._registrationTimer = null; // Ongoing Register request.
 
     this._registering = false; // Set status.
 
     this._registered = false; // Contact header.
 
     this._contact = this._ua.contact.toString(); // Sip.ice media feature tag (RFC 5768).
 
     this._contact += ';+sip.ice'; // Custom headers for REGISTER and un-REGISTER.
 
     this._extraHeaders = []; // Custom Contact header params for REGISTER and un-REGISTER.
 
     this._extraContactParams = '';
 
     if (reg_id) {
       this._contact += ";reg-id=".concat(reg_id);
       this._contact += ";+sip.instance=\"<urn:uuid:".concat(this._ua.configuration.instance_id, ">\"");
     }
   }
 
   _createClass(Registrator, [{
     key: "setExtraHeaders",
     value: function setExtraHeaders(extraHeaders) {
       if (!Array.isArray(extraHeaders)) {
         extraHeaders = [];
       }
 
       this._extraHeaders = extraHeaders.slice();
     }
   }, {
     key: "setExtraContactParams",
     value: function setExtraContactParams(extraContactParams) {
       if (!(extraContactParams instanceof Object)) {
         extraContactParams = {};
       } // Reset it.
 
 
       this._extraContactParams = '';
 
       for (var param_key in extraContactParams) {
         if (Object.prototype.hasOwnProperty.call(extraContactParams, param_key)) {
           var param_value = extraContactParams[param_key];
           this._extraContactParams += ";".concat(param_key);
 
           if (param_value) {
             this._extraContactParams += "=".concat(param_value);
           }
         }
       }
     }
   }, {
     key: "register",
     value: function register() {
       var _this = this;
 
       if (this._registering) {
         debug('Register request in progress...');
         return;
       }
 
       var extraHeaders = this._extraHeaders.slice();
 
       extraHeaders.push("Contact: ".concat(this._contact, ";expires=").concat(this._expires).concat(this._extraContactParams));
       extraHeaders.push("Expires: ".concat(this._expires));
       var request = new SIPMessage.OutgoingRequest(JsSIP_C.REGISTER, this._registrar, this._ua, {
         'to_uri': this._to_uri,
         'call_id': this._call_id,
         'cseq': this._cseq += 1
       }, extraHeaders);
       var request_sender = new RequestSender(this._ua, request, {
         onRequestTimeout: function onRequestTimeout() {
           _this._registrationFailure(null, JsSIP_C.causes.REQUEST_TIMEOUT);
         },
         onTransportError: function onTransportError() {
           _this._registrationFailure(null, JsSIP_C.causes.CONNECTION_ERROR);
         },
         // Increase the CSeq on authentication.
         onAuthenticated: function onAuthenticated() {
           _this._cseq += 1;
         },
         onReceiveResponse: function onReceiveResponse(response) {
           // Discard responses to older REGISTER/un-REGISTER requests.
           if (response.cseq !== _this._cseq) {
             return;
           } // Clear registration timer.
 
 
           if (_this._registrationTimer !== null) {
             clearTimeout(_this._registrationTimer);
             _this._registrationTimer = null;
           }
 
           switch (true) {
             case /^1[0-9]{2}$/.test(response.status_code):
               {
                 // Ignore provisional responses.
                 break;
               }
 
             case /^2[0-9]{2}$/.test(response.status_code):
               {
                 _this._registering = false;
 
                 if (!response.hasHeader('Contact')) {
                   debug('no Contact header in response to REGISTER, response ignored');
                   break;
                 }
 
                 var contacts = response.headers['Contact'].reduce(function (a, b) {
                   return a.concat(b.parsed);
                 }, []); // Get the Contact pointing to us and update the expires value accordingly.
 
                 var contact = contacts.find(function (element) {
                   return element.uri.user === _this._ua.contact.uri.user;
                 });
 
                 if (!contact) {
                   debug('no Contact header pointing to us, response ignored');
                   break;
                 }
 
                 var expires = contact.getParam('expires');
 
                 if (!expires && response.hasHeader('expires')) {
                   expires = response.getHeader('expires');
                 }
 
                 if (!expires) {
                   expires = _this._expires;
                 }
 
                 expires = Number(expires);
                 if (expires < MIN_REGISTER_EXPIRES) expires = MIN_REGISTER_EXPIRES;
                 var timeout = expires > 64 ? expires * 1000 / 2 + Math.floor((expires / 2 - 32) * 1000 * Math.random()) : expires * 1000 - 5000; // Re-Register or emit an event before the expiration interval has elapsed.
                 // For that, decrease the expires value. ie: 3 seconds.
 
                 _this._registrationTimer = setTimeout(function () {
                   _this._registrationTimer = null; // If there are no listeners for registrationExpiring, renew registration.
                   // If there are listeners, let the function listening do the register call.
 
                   if (_this._ua.listeners('registrationExpiring').length === 0) {
                     _this.register();
                   } else {
                     _this._ua.emit('registrationExpiring');
                   }
                 }, timeout); // Save gruu values.
 
                 if (contact.hasParam('temp-gruu')) {
                   _this._ua.contact.temp_gruu = contact.getParam('temp-gruu').replace(/"/g, '');
                 }
 
                 if (contact.hasParam('pub-gruu')) {
                   _this._ua.contact.pub_gruu = contact.getParam('pub-gruu').replace(/"/g, '');
                 }
 
                 if (!_this._registered) {
                   _this._registered = true;
 
                   _this._ua.registered({
                     response: response
                   });
                 }
 
                 break;
               }
             // Interval too brief RFC3261 10.2.8.
 
             case /^423$/.test(response.status_code):
               {
                 if (response.hasHeader('min-expires')) {
                   // Increase our registration interval to the suggested minimum.
                   _this._expires = Number(response.getHeader('min-expires'));
                   if (_this._expires < MIN_REGISTER_EXPIRES) _this._expires = MIN_REGISTER_EXPIRES; // Attempt the registration again immediately.
 
                   _this.register();
                 } else {
                   // This response MUST contain a Min-Expires header field.
                   debug('423 response received for REGISTER without Min-Expires');
 
                   _this._registrationFailure(response, JsSIP_C.causes.SIP_FAILURE_CODE);
                 }
 
                 break;
               }
 
             default:
               {
                 var cause = Utils.sipErrorCause(response.status_code);
 
                 _this._registrationFailure(response, cause);
               }
           }
         }
       });
       this._registering = true;
       request_sender.send();
     }
   }, {
     key: "unregister",
     value: function unregister() {
       var _this2 = this;
 
       var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
 
       if (!this._registered) {
         debug('already unregistered');
         return;
       }
 
       this._registered = false; // Clear the registration timer.
 
       if (this._registrationTimer !== null) {
         clearTimeout(this._registrationTimer);
         this._registrationTimer = null;
       }
 
       var extraHeaders = this._extraHeaders.slice();
 
       if (options.all) {
         extraHeaders.push("Contact: *".concat(this._extraContactParams));
       } else {
         extraHeaders.push("Contact: ".concat(this._contact, ";expires=0").concat(this._extraContactParams));
       }
 
       extraHeaders.push('Expires: 0');
       var request = new SIPMessage.OutgoingRequest(JsSIP_C.REGISTER, this._registrar, this._ua, {
         'to_uri': this._to_uri,
         'call_id': this._call_id,
         'cseq': this._cseq += 1
       }, extraHeaders);
       var request_sender = new RequestSender(this._ua, request, {
         onRequestTimeout: function onRequestTimeout() {
           _this2._unregistered(null, JsSIP_C.causes.REQUEST_TIMEOUT);
         },
         onTransportError: function onTransportError() {
           _this2._unregistered(null, JsSIP_C.causes.CONNECTION_ERROR);
         },
         // Increase the CSeq on authentication.
         onAuthenticated: function onAuthenticated() {
           _this2._cseq += 1;
         },
         onReceiveResponse: function onReceiveResponse(response) {
           switch (true) {
             case /^1[0-9]{2}$/.test(response.status_code):
               // Ignore provisional responses.
               break;
 
             case /^2[0-9]{2}$/.test(response.status_code):
               _this2._unregistered(response);
 
               break;
 
             default:
               {
                 var cause = Utils.sipErrorCause(response.status_code);
 
                 _this2._unregistered(response, cause);
               }
           }
         }
       });
       request_sender.send();
     }
   }, {
     key: "close",
     value: function close() {
       if (this._registered) {
         this.unregister();
       }
     }
   }, {
     key: "onTransportClosed",
     value: function onTransportClosed() {
       this._registering = false;
 
       if (this._registrationTimer !== null) {
         clearTimeout(this._registrationTimer);
         this._registrationTimer = null;
       }
 
       if (this._registered) {
         this._registered = false;
 
         this._ua.unregistered({});
       }
     }
   }, {
     key: "_registrationFailure",
     value: function _registrationFailure(response, cause) {
       this._registering = false;
 
       this._ua.registrationFailed({
         response: response || null,
         cause: cause
       });
 
       if (this._registered) {
         this._registered = false;
 
         this._ua.unregistered({
           response: response || null,
           cause: cause
         });
       }
     }
   }, {
     key: "_unregistered",
     value: function _unregistered(response, cause) {
       this._registering = false;
       this._registered = false;
 
       this._ua.unregistered({
         response: response || null,
         cause: cause || null
       });
     }
   }, {
     key: "registered",
     get: function get() {
       return this._registered;
     }
   }]);
 
   return Registrator;
 }();
 },{"./Constants":2,"./RequestSender":18,"./SIPMessage":19,"./Utils":26,"debug":30}],18:[function(require,module,exports){
 "use strict";
 
 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
 function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
 
 function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
 
 var JsSIP_C = require('./Constants');
 
 var DigestAuthentication = require('./DigestAuthentication');
 
 var Transactions = require('./Transactions');
 
 var debug = require('debug')('JsSIP:RequestSender'); // Default event handlers.
 
 
 var EventHandlers = {
   onRequestTimeout: function onRequestTimeout() {},
   onTransportError: function onTransportError() {},
   onReceiveResponse: function onReceiveResponse() {},
   onAuthenticated: function onAuthenticated() {}
 };
 
 module.exports = /*#__PURE__*/function () {
   function RequestSender(ua, request, eventHandlers) {
     _classCallCheck(this, RequestSender);
 
     this._ua = ua;
     this._eventHandlers = eventHandlers;
     this._method = request.method;
     this._request = request;
     this._auth = null;
     this._challenged = false;
     this._staled = false; // Define the undefined handlers.
 
     for (var handler in EventHandlers) {
       if (Object.prototype.hasOwnProperty.call(EventHandlers, handler)) {
         if (!this._eventHandlers[handler]) {
           this._eventHandlers[handler] = EventHandlers[handler];
         }
       }
     } // If ua is in closing process or even closed just allow sending Bye and ACK.
 
 
     if (ua.status === ua.C.STATUS_USER_CLOSED && (this._method !== JsSIP_C.BYE || this._method !== JsSIP_C.ACK)) {
       this._eventHandlers.onTransportError();
     }
   }
   /**
   * Create the client transaction and send the message.
   */
 
 
   _createClass(RequestSender, [{
     key: "send",
     value: function send() {
       var _this = this;
 
       var eventHandlers = {
         onRequestTimeout: function onRequestTimeout() {
           _this._eventHandlers.onRequestTimeout();
         },
         onTransportError: function onTransportError() {
           _this._eventHandlers.onTransportError();
         },
         onReceiveResponse: function onReceiveResponse(response) {
           _this._receiveResponse(response);
         }
       };
 
       switch (this._method) {
         case 'INVITE':
           this.clientTransaction = new Transactions.InviteClientTransaction(this._ua, this._ua.transport, this._request, eventHandlers);
           break;
 
         case 'ACK':
           this.clientTransaction = new Transactions.AckClientTransaction(this._ua, this._ua.transport, this._request, eventHandlers);
           break;
 
         default:
           this.clientTransaction = new Transactions.NonInviteClientTransaction(this._ua, this._ua.transport, this._request, eventHandlers);
       } // If authorization JWT is present, use it.
 
 
       if (this._ua._configuration.authorization_jwt) {
         this._request.setHeader('Authorization', this._ua._configuration.authorization_jwt);
       }
 
       this.clientTransaction.send();
     }
     /**
     * Called from client transaction when receiving a correct response to the request.
     * Authenticate request if needed or pass the response back to the applicant.
     */
 
   }, {
     key: "_receiveResponse",
     value: function _receiveResponse(response) {
       var challenge;
       var authorization_header_name;
       var status_code = response.status_code;
       /*
       * Authentication
       * Authenticate once. _challenged_ flag used to avoid infinite authentications.
       */
 
       if ((status_code === 401 || status_code === 407) && (this._ua.configuration.password !== null || this._ua.configuration.ha1 !== null)) {
         // Get and parse the appropriate WWW-Authenticate or Proxy-Authenticate header.
         if (response.status_code === 401) {
           challenge = response.parseHeader('www-authenticate');
           authorization_header_name = 'authorization';
         } else {
           challenge = response.parseHeader('proxy-authenticate');
           authorization_header_name = 'proxy-authorization';
         } // Verify it seems a valid challenge.
 
 
         if (!challenge) {
           debug("".concat(response.status_code, " with wrong or missing challenge, cannot authenticate"));
 
           this._eventHandlers.onReceiveResponse(response);
 
           return;
         }
 
         if (!this._challenged || !this._staled && challenge.stale === true) {
           if (!this._auth) {
             this._auth = new DigestAuthentication({
               username: this._ua.configuration.authorization_user,
               password: this._ua.configuration.password,
               realm: this._ua.configuration.realm,
               ha1: this._ua.configuration.ha1
             });
           } // Verify that the challenge is really valid.
 
 
           if (!this._auth.authenticate(this._request, challenge)) {
             this._eventHandlers.onReceiveResponse(response);
 
             return;
           }
 
           this._challenged = true; // Update ha1 and realm in the UA.
 
           this._ua.set('realm', this._auth.get('realm'));
 
           this._ua.set('ha1', this._auth.get('ha1'));
 
           if (challenge.stale) {
             this._staled = true;
           }
 
           this._request = this._request.clone();
           this._request.cseq += 1;
 
           this._request.setHeader('cseq', "".concat(this._request.cseq, " ").concat(this._method));
 
           this._request.setHeader(authorization_header_name, this._auth.toString());
 
           this._eventHandlers.onAuthenticated(this._request);
 
           this.send();
         } else {
           this._eventHandlers.onReceiveResponse(response);
         }
       } else {
         this._eventHandlers.onReceiveResponse(response);
       }
     }
   }]);
 
   return RequestSender;
 }();
 },{"./Constants":2,"./DigestAuthentication":5,"./Transactions":22,"debug":30}],19:[function(require,module,exports){
 "use strict";
 
 function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
 
 function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
 
 function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
 
 function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
 
 function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
 
 function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
 
 function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }
 
 function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
 
 function _createForOfIteratorHelper(o, allowArrayLike) { var it; if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
 
 function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
 
 function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
 
 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
 function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
 
 function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
 
 var sdp_transform = require('sdp-transform');
 
 var JsSIP_C = require('./Constants');
 
 var Utils = require('./Utils');
 
 var NameAddrHeader = require('./NameAddrHeader');
 
 var Grammar = require('./Grammar');
 
 var debug = require('debug')('JsSIP:SIPMessage');
 /**
  * -param {String} method request method
  * -param {String} ruri request uri
  * -param {UA} ua
  * -param {Object} params parameters that will have priority over ua.configuration parameters:
  * <br>
  *  - cseq, call_id, from_tag, from_uri, from_display_name, to_uri, to_tag, route_set
  * -param {Object} [headers] extra headers
  * -param {String} [body]
  */
 
 
 var OutgoingRequest = /*#__PURE__*/function () {
   function OutgoingRequest(method, ruri, ua, params, extraHeaders, body) {
     _classCallCheck(this, OutgoingRequest);
 
     // Mandatory parameters check.
     if (!method || !ruri || !ua) {
       return null;
     }
 
     params = params || {};
     this.ua = ua;
     this.headers = {};
     this.method = method;
     this.ruri = ruri;
     this.body = body;
     this.extraHeaders = Utils.cloneArray(extraHeaders); // Fill the Common SIP Request Headers.
     // Route.
 
     if (params.route_set) {
       this.setHeader('route', params.route_set);
     } else if (ua.configuration.use_preloaded_route) {
       this.setHeader('route', "<".concat(ua.transport.sip_uri, ";lr>"));
     } // Via.
     // Empty Via header. Will be filled by the client transaction.
 
 
     this.setHeader('via', ''); // Max-Forwards.
 
     this.setHeader('max-forwards', JsSIP_C.MAX_FORWARDS); // To
 
     var to_uri = params.to_uri || ruri;
     var to_params = params.to_tag ? {
       tag: params.to_tag
     } : null;
     var to_display_name = typeof params.to_display_name !== 'undefined' ? params.to_display_name : null;
     this.to = new NameAddrHeader(to_uri, to_display_name, to_params);
     this.setHeader('to', this.to.toString()); // From.
 
     var from_uri = params.from_uri || ua.configuration.uri;
     var from_params = {
       tag: params.from_tag || Utils.newTag()
     };
     var display_name;
 
     if (typeof params.from_display_name !== 'undefined') {
       display_name = params.from_display_name;
     } else if (ua.configuration.display_name) {
       display_name = ua.configuration.display_name;
     } else {
       display_name = null;
     }
 
     this.from = new NameAddrHeader(from_uri, display_name, from_params);
     this.setHeader('from', this.from.toString()); // Call-ID.
 
     var call_id = params.call_id || ua.configuration.jssip_id + Utils.createRandomToken(15);
     this.call_id = call_id;
     this.setHeader('call-id', call_id); // CSeq.
 
     var cseq = params.cseq || Math.floor(Math.random() * 10000);
     this.cseq = cseq;
     this.setHeader('cseq', "".concat(cseq, " ").concat(method));
   }
   /**
    * Replace the the given header by the given value.
    * -param {String} name header name
    * -param {String | Array} value header value
    */
 
 
   _createClass(OutgoingRequest, [{
     key: "setHeader",
     value: function setHeader(name, value) {
       // Remove the header from extraHeaders if present.
       var regexp = new RegExp("^\\s*".concat(name, "\\s*:"), 'i');
 
       for (var idx = 0; idx < this.extraHeaders.length; idx++) {
         if (regexp.test(this.extraHeaders[idx])) {
           this.extraHeaders.splice(idx, 1);
         }
       }
 
       this.headers[Utils.headerize(name)] = Array.isArray(value) ? value : [value];
     }
     /**
      * Get the value of the given header name at the given position.
      * -param {String} name header name
      * -returns {String|undefined} Returns the specified header, null if header doesn't exist.
      */
 
   }, {
     key: "getHeader",
     value: function getHeader(name) {
       var headers = this.headers[Utils.headerize(name)];
 
       if (headers) {
         if (headers[0]) {
           return headers[0];
         }
       } else {
         var regexp = new RegExp("^\\s*".concat(name, "\\s*:"), 'i');
 
         var _iterator = _createForOfIteratorHelper(this.extraHeaders),
             _step;
 
         try {
           for (_iterator.s(); !(_step = _iterator.n()).done;) {
             var header = _step.value;
 
             if (regexp.test(header)) {
               return header.substring(header.indexOf(':') + 1).trim();
             }
           }
         } catch (err) {
           _iterator.e(err);
         } finally {
           _iterator.f();
         }
       }
 
       return;
     }
     /**
      * Get the header/s of the given name.
      * -param {String} name header name
      * -returns {Array} Array with all the headers of the specified name.
      */
 
   }, {
     key: "getHeaders",
     value: function getHeaders(name) {
       var headers = this.headers[Utils.headerize(name)];
       var result = [];
 
       if (headers) {
         var _iterator2 = _createForOfIteratorHelper(headers),
             _step2;
 
         try {
           for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
             var header = _step2.value;
             result.push(header);
           }
         } catch (err) {
           _iterator2.e(err);
         } finally {
           _iterator2.f();
         }
 
         return result;
       } else {
         var regexp = new RegExp("^\\s*".concat(name, "\\s*:"), 'i');
 
         var _iterator3 = _createForOfIteratorHelper(this.extraHeaders),
             _step3;
 
         try {
           for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
             var _header = _step3.value;
 
             if (regexp.test(_header)) {
               result.push(_header.substring(_header.indexOf(':') + 1).trim());
             }
           }
         } catch (err) {
           _iterator3.e(err);
         } finally {
           _iterator3.f();
         }
 
         return result;
       }
     }
     /**
      * Verify the existence of the given header.
      * -param {String} name header name
      * -returns {boolean} true if header with given name exists, false otherwise
      */
 
   }, {
     key: "hasHeader",
     value: function hasHeader(name) {
       if (this.headers[Utils.headerize(name)]) {
         return true;
       } else {
         var regexp = new RegExp("^\\s*".concat(name, "\\s*:"), 'i');
 
         var _iterator4 = _createForOfIteratorHelper(this.extraHeaders),
             _step4;
 
         try {
           for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
             var header = _step4.value;
 
             if (regexp.test(header)) {
               return true;
             }
           }
         } catch (err) {
           _iterator4.e(err);
         } finally {
           _iterator4.f();
         }
       }
 
       return false;
     }
     /**
      * Parse the current body as a SDP and store the resulting object
      * into this.sdp.
      * -param {Boolean} force: Parse even if this.sdp already exists.
      *
      * Returns this.sdp.
      */
 
   }, {
     key: "parseSDP",
     value: function parseSDP(force) {
       if (!force && this.sdp) {
         return this.sdp;
       } else {
         this.sdp = sdp_transform.parse(this.body || '');
         return this.sdp;
       }
     }
   }, {
     key: "toString",
     value: function toString() {
       var msg = "".concat(this.method, " ").concat(this.ruri, " SIP/2.0\r\n");
 
       for (var headerName in this.headers) {
         if (Object.prototype.hasOwnProperty.call(this.headers, headerName)) {
           var _iterator5 = _createForOfIteratorHelper(this.headers[headerName]),
               _step5;
 
           try {
             for (_iterator5.s(); !(_step5 = _iterator5.n()).done;) {
               var headerValue = _step5.value;
               msg += "".concat(headerName, ": ").concat(headerValue, "\r\n");
             }
           } catch (err) {
             _iterator5.e(err);
           } finally {
             _iterator5.f();
           }
         }
       }
 
       var _iterator6 = _createForOfIteratorHelper(this.extraHeaders),
           _step6;
 
       try {
         for (_iterator6.s(); !(_step6 = _iterator6.n()).done;) {
           var header = _step6.value;
           msg += "".concat(header.trim(), "\r\n");
         } // Supported.
 
       } catch (err) {
         _iterator6.e(err);
       } finally {
         _iterator6.f();
       }
 
       var supported = [];
 
       switch (this.method) {
         case JsSIP_C.REGISTER:
           supported.push('path', 'gruu');
           break;
 
         case JsSIP_C.INVITE:
           if (this.ua.configuration.session_timers) {
             supported.push('timer');
           }
 
           if (this.ua.contact.pub_gruu || this.ua.contact.temp_gruu) {
             supported.push('gruu');
           }
 
           supported.push('ice', 'replaces');
           break;
 
         case JsSIP_C.UPDATE:
           if (this.ua.configuration.session_timers) {
             supported.push('timer');
           }
 
           supported.push('ice');
           break;
       }
 
       supported.push('outbound');
       var userAgent = this.ua.configuration.user_agent || JsSIP_C.USER_AGENT; // Allow.
 
       msg += "Allow: ".concat(JsSIP_C.ALLOWED_METHODS, "\r\n");
       msg += "Supported: ".concat(supported, "\r\n");
       msg += "User-Agent: ".concat(userAgent, "\r\n");
 
       if (this.body) {
         var length = Utils.str_utf8_length(this.body);
         msg += "Content-Length: ".concat(length, "\r\n\r\n");
         msg += this.body;
       } else {
         msg += 'Content-Length: 0\r\n\r\n';
       }
 
       return msg;
     }
   }, {
     key: "clone",
     value: function clone() {
       var request = new OutgoingRequest(this.method, this.ruri, this.ua);
       Object.keys(this.headers).forEach(function (name) {
         request.headers[name] = this.headers[name].slice();
       }, this);
       request.body = this.body;
       request.extraHeaders = Utils.cloneArray(this.extraHeaders);
       request.to = this.to;
       request.from = this.from;
       request.call_id = this.call_id;
       request.cseq = this.cseq;
       return request;
     }
   }]);
 
   return OutgoingRequest;
 }();
 
 var InitialOutgoingInviteRequest = /*#__PURE__*/function (_OutgoingRequest) {
   _inherits(InitialOutgoingInviteRequest, _OutgoingRequest);
 
   var _super = _createSuper(InitialOutgoingInviteRequest);
 
   function InitialOutgoingInviteRequest(ruri, ua, params, extraHeaders, body) {
     var _this;
 
     _classCallCheck(this, InitialOutgoingInviteRequest);
 
     _this = _super.call(this, JsSIP_C.INVITE, ruri, ua, params, extraHeaders, body);
     _this.transaction = null;
     return _this;
   }
 
   _createClass(InitialOutgoingInviteRequest, [{
     key: "cancel",
     value: function cancel(reason) {
       this.transaction.cancel(reason);
     }
   }, {
     key: "clone",
     value: function clone() {
       var request = new InitialOutgoingInviteRequest(this.ruri, this.ua);
       Object.keys(this.headers).forEach(function (name) {
         request.headers[name] = this.headers[name].slice();
       }, this);
       request.body = this.body;
       request.extraHeaders = Utils.cloneArray(this.extraHeaders);
       request.to = this.to;
       request.from = this.from;
       request.call_id = this.call_id;
       request.cseq = this.cseq;
       request.transaction = this.transaction;
       return request;
     }
   }]);
 
   return InitialOutgoingInviteRequest;
 }(OutgoingRequest);
 
 var IncomingMessage = /*#__PURE__*/function () {
   function IncomingMessage() {
     _classCallCheck(this, IncomingMessage);
 
     this.data = null;
     this.headers = null;
     this.method = null;
     this.via = null;
     this.via_branch = null;
     this.call_id = null;
     this.cseq = null;
     this.from = null;
     this.from_tag = null;
     this.to = null;
     this.to_tag = null;
     this.body = null;
     this.sdp = null;
   }
   /**
   * Insert a header of the given name and value into the last position of the
   * header array.
   */
 
 
   _createClass(IncomingMessage, [{
     key: "addHeader",
     value: function addHeader(name, value) {
       var header = {
         raw: value
       };
       name = Utils.headerize(name);
 
       if (this.headers[name]) {
         this.headers[name].push(header);
       } else {
         this.headers[name] = [header];
       }
     }
     /**
      * Get the value of the given header name at the given position.
      */
 
   }, {
     key: "getHeader",
     value: function getHeader(name) {
       var header = this.headers[Utils.headerize(name)];
 
       if (header) {
         if (header[0]) {
           return header[0].raw;
         }
       } else {
         return;
       }
     }
     /**
      * Get the header/s of the given name.
      */
 
   }, {
     key: "getHeaders",
     value: function getHeaders(name) {
       var headers = this.headers[Utils.headerize(name)];
       var result = [];
 
       if (!headers) {
         return [];
       }
 
       var _iterator7 = _createForOfIteratorHelper(headers),
           _step7;
 
       try {
         for (_iterator7.s(); !(_step7 = _iterator7.n()).done;) {
           var header = _step7.value;
           result.push(header.raw);
         }
       } catch (err) {
         _iterator7.e(err);
       } finally {
         _iterator7.f();
       }
 
       return result;
     }
     /**
      * Verify the existence of the given header.
      */
 
   }, {
     key: "hasHeader",
     value: function hasHeader(name) {
       return this.headers[Utils.headerize(name)] ? true : false;
     }
     /**
     * Parse the given header on the given index.
     * -param {String} name header name
     * -param {Number} [idx=0] header index
     * -returns {Object|undefined} Parsed header object, undefined if the header
     *  is not present or in case of a parsing error.
     */
 
   }, {
     key: "parseHeader",
     value: function parseHeader(name) {
       var idx = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
       name = Utils.headerize(name);
 
       if (!this.headers[name]) {
         debug("header \"".concat(name, "\" not present"));
         return;
       } else if (idx >= this.headers[name].length) {
         debug("not so many \"".concat(name, "\" headers present"));
         return;
       }
 
       var header = this.headers[name][idx];
       var value = header.raw;
 
       if (header.parsed) {
         return header.parsed;
       } // Substitute '-' by '_' for grammar rule matching.
 
 
       var parsed = Grammar.parse(value, name.replace(/-/g, '_'));
 
       if (parsed === -1) {
         this.headers[name].splice(idx, 1); // delete from headers
 
         debug("error parsing \"".concat(name, "\" header field with value \"").concat(value, "\""));
         return;
       } else {
         header.parsed = parsed;
         return parsed;
       }
     }
     /**
      * Message Header attribute selector. Alias of parseHeader.
      * -param {String} name header name
      * -param {Number} [idx=0] header index
      * -returns {Object|undefined} Parsed header object, undefined if the header
      *  is not present or in case of a parsing error.
      *
      * -example
      * message.s('via',3).port
      */
 
   }, {
     key: "s",
     value: function s(name, idx) {
       return this.parseHeader(name, idx);
     }
     /**
     * Replace the value of the given header by the value.
     * -param {String} name header name
     * -param {String} value header value
     */
 
   }, {
     key: "setHeader",
     value: function setHeader(name, value) {
       var header = {
         raw: value
       };
       this.headers[Utils.headerize(name)] = [header];
     }
     /**
      * Parse the current body as a SDP and store the resulting object
      * into this.sdp.
      * -param {Boolean} force: Parse even if this.sdp already exists.
      *
      * Returns this.sdp.
      */
 
   }, {
     key: "parseSDP",
     value: function parseSDP(force) {
       if (!force && this.sdp) {
         return this.sdp;
       } else {
         this.sdp = sdp_transform.parse(this.body || '');
         return this.sdp;
       }
     }
   }, {
     key: "toString",
     value: function toString() {
       return this.data;
     }
   }]);
 
   return IncomingMessage;
 }();
 
 var IncomingRequest = /*#__PURE__*/function (_IncomingMessage) {
   _inherits(IncomingRequest, _IncomingMessage);
 
   var _super2 = _createSuper(IncomingRequest);
 
   function IncomingRequest(ua) {
     var _this2;
 
     _classCallCheck(this, IncomingRequest);
 
     _this2 = _super2.call(this);
     _this2.ua = ua;
     _this2.headers = {};
     _this2.ruri = null;
     _this2.transport = null;
     _this2.server_transaction = null;
     return _this2;
   }
   /**
   * Stateful reply.
   * -param {Number} code status code
   * -param {String} reason reason phrase
   * -param {Object} headers extra headers
   * -param {String} body body
   * -param {Function} [onSuccess] onSuccess callback
   * -param {Function} [onFailure] onFailure callback
   */
 
 
   _createClass(IncomingRequest, [{
     key: "reply",
     value: function reply(code, reason, extraHeaders, body, onSuccess, onFailure) {
       var supported = [];
       var to = this.getHeader('To');
       code = code || null;
       reason = reason || null; // Validate code and reason values.
 
       if (!code || code < 100 || code > 699) {
         throw new TypeError("Invalid status_code: ".concat(code));
       } else if (reason && typeof reason !== 'string' && !(reason instanceof String)) {
         throw new TypeError("Invalid reason_phrase: ".concat(reason));
       }
 
       reason = reason || JsSIP_C.REASON_PHRASE[code] || '';
       extraHeaders = Utils.cloneArray(extraHeaders);
       var response = "SIP/2.0 ".concat(code, " ").concat(reason, "\r\n");
 
       if (this.method === JsSIP_C.INVITE && code > 100 && code <= 200) {
         var headers = this.getHeaders('record-route');
 
         var _iterator8 = _createForOfIteratorHelper(headers),
             _step8;
 
         try {
           for (_iterator8.s(); !(_step8 = _iterator8.n()).done;) {
             var header = _step8.value;
             response += "Record-Route: ".concat(header, "\r\n");
           }
         } catch (err) {
           _iterator8.e(err);
         } finally {
           _iterator8.f();
         }
       }
 
       var vias = this.getHeaders('via');
 
       var _iterator9 = _createForOfIteratorHelper(vias),
           _step9;
 
       try {
         for (_iterator9.s(); !(_step9 = _iterator9.n()).done;) {
           var via = _step9.value;
           response += "Via: ".concat(via, "\r\n");
         }
       } catch (err) {
         _iterator9.e(err);
       } finally {
         _iterator9.f();
       }
 
       if (!this.to_tag && code > 100) {
         to += ";tag=".concat(Utils.newTag());
       } else if (this.to_tag && !this.s('to').hasParam('tag')) {
         to += ";tag=".concat(this.to_tag);
       }
 
       response += "To: ".concat(to, "\r\n");
       response += "From: ".concat(this.getHeader('From'), "\r\n");
       response += "Call-ID: ".concat(this.call_id, "\r\n");
       response += "CSeq: ".concat(this.cseq, " ").concat(this.method, "\r\n");
 
       var _iterator10 = _createForOfIteratorHelper(extraHeaders),
           _step10;
 
       try {
         for (_iterator10.s(); !(_step10 = _iterator10.n()).done;) {
           var _header2 = _step10.value;
           response += "".concat(_header2.trim(), "\r\n");
         } // Supported.
 
       } catch (err) {
         _iterator10.e(err);
       } finally {
         _iterator10.f();
       }
 
       switch (this.method) {
         case JsSIP_C.INVITE:
           if (this.ua.configuration.session_timers) {
             supported.push('timer');
           }
 
           if (this.ua.contact.pub_gruu || this.ua.contact.temp_gruu) {
             supported.push('gruu');
           }
 
           supported.push('ice', 'replaces');
           break;
 
         case JsSIP_C.UPDATE:
           if (this.ua.configuration.session_timers) {
             supported.push('timer');
           }
 
           if (body) {
             supported.push('ice');
           }
 
           supported.push('replaces');
       }
 
       supported.push('outbound'); // Allow and Accept.
 
       if (this.method === JsSIP_C.OPTIONS) {
         response += "Allow: ".concat(JsSIP_C.ALLOWED_METHODS, "\r\n");
         response += "Accept: ".concat(JsSIP_C.ACCEPTED_BODY_TYPES, "\r\n");
       } else if (code === 405) {
         response += "Allow: ".concat(JsSIP_C.ALLOWED_METHODS, "\r\n");
       } else if (code === 415) {
         response += "Accept: ".concat(JsSIP_C.ACCEPTED_BODY_TYPES, "\r\n");
       }
 
       response += "Supported: ".concat(supported, "\r\n");
 
       if (body) {
         var length = Utils.str_utf8_length(body);
         response += 'Content-Type: application/sdp\r\n';
         response += "Content-Length: ".concat(length, "\r\n\r\n");
         response += body;
       } else {
         response += "Content-Length: ".concat(0, "\r\n\r\n");
       }
 
       this.server_transaction.receiveResponse(code, response, onSuccess, onFailure);
     }
     /**
     * Stateless reply.
     * -param {Number} code status code
     * -param {String} reason reason phrase
     */
 
   }, {
     key: "reply_sl",
     value: function reply_sl() {
       var code = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : null;
       var reason = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
       var vias = this.getHeaders('via'); // Validate code and reason values.
 
       if (!code || code < 100 || code > 699) {
         throw new TypeError("Invalid status_code: ".concat(code));
       } else if (reason && typeof reason !== 'string' && !(reason instanceof String)) {
         throw new TypeError("Invalid reason_phrase: ".concat(reason));
       }
 
       reason = reason || JsSIP_C.REASON_PHRASE[code] || '';
       var response = "SIP/2.0 ".concat(code, " ").concat(reason, "\r\n");
 
       var _iterator11 = _createForOfIteratorHelper(vias),
           _step11;
 
       try {
         for (_iterator11.s(); !(_step11 = _iterator11.n()).done;) {
           var via = _step11.value;
           response += "Via: ".concat(via, "\r\n");
         }
       } catch (err) {
         _iterator11.e(err);
       } finally {
         _iterator11.f();
       }
 
       var to = this.getHeader('To');
 
       if (!this.to_tag && code > 100) {
         to += ";tag=".concat(Utils.newTag());
       } else if (this.to_tag && !this.s('to').hasParam('tag')) {
         to += ";tag=".concat(this.to_tag);
       }
 
       response += "To: ".concat(to, "\r\n");
       response += "From: ".concat(this.getHeader('From'), "\r\n");
       response += "Call-ID: ".concat(this.call_id, "\r\n");
       response += "CSeq: ".concat(this.cseq, " ").concat(this.method, "\r\n");
       response += "Content-Length: ".concat(0, "\r\n\r\n");
       this.transport.send(response);
     }
   }]);
 
   return IncomingRequest;
 }(IncomingMessage);
 
 var IncomingResponse = /*#__PURE__*/function (_IncomingMessage2) {
   _inherits(IncomingResponse, _IncomingMessage2);
 
   var _super3 = _createSuper(IncomingResponse);
 
   function IncomingResponse() {
     var _this3;
 
     _classCallCheck(this, IncomingResponse);
 
     _this3 = _super3.call(this);
     _this3.headers = {};
     _this3.status_code = null;
     _this3.reason_phrase = null;
     return _this3;
   }
 
   return IncomingResponse;
 }(IncomingMessage);
 
 module.exports = {
   OutgoingRequest: OutgoingRequest,
   InitialOutgoingInviteRequest: InitialOutgoingInviteRequest,
   IncomingRequest: IncomingRequest,
   IncomingResponse: IncomingResponse
 };
 },{"./Constants":2,"./Grammar":7,"./NameAddrHeader":10,"./Utils":26,"debug":30,"sdp-transform":35}],20:[function(require,module,exports){
 "use strict";
 
 var Utils = require('./Utils');
 
 var Grammar = require('./Grammar');
 
 var debugerror = require('debug')('JsSIP:ERROR:Socket');
 
 debugerror.log = console.warn.bind(console);
 /**
  * Interface documentation: https://jssip.net/documentation/$last_version/api/socket/
  *
  * interface Socket {
  *  attribute String via_transport
  *  attribute String url
  *  attribute String sip_uri
  *
  *  method connect();
  *  method disconnect();
  *  method send(data);
  *
  *  attribute EventHandler onconnect
  *  attribute EventHandler ondisconnect
  *  attribute EventHandler ondata
  * }
  *
  */
 
 exports.isSocket = function (socket) {
   // Ignore if an array is given.
   if (Array.isArray(socket)) {
     return false;
   }
 
   if (typeof socket === 'undefined') {
     debugerror('undefined JsSIP.Socket instance');
     return false;
   } // Check Properties.
 
 
   try {
     if (!Utils.isString(socket.url)) {
       debugerror('missing or invalid JsSIP.Socket url property');
       throw new Error();
     }
 
     if (!Utils.isString(socket.via_transport)) {
       debugerror('missing or invalid JsSIP.Socket via_transport property');
       throw new Error();
     }
 
     if (Grammar.parse(socket.sip_uri, 'SIP_URI') === -1) {
       debugerror('missing or invalid JsSIP.Socket sip_uri property');
       throw new Error();
     }
   } catch (e) {
     return false;
   } // Check Methods.
 
 
   try {
     ['connect', 'disconnect', 'send'].forEach(function (method) {
       if (!Utils.isFunction(socket[method])) {
         debugerror("missing or invalid JsSIP.Socket method: ".concat(method));
         throw new Error();
       }
     });
   } catch (e) {
     return false;
   }
 
   return true;
 };
 },{"./Grammar":7,"./Utils":26,"debug":30}],21:[function(require,module,exports){
 "use strict";
 
 var T1 = 500,
     T2 = 4000,
     T4 = 5000;
 module.exports = {
   T1: T1,
   T2: T2,
   T4: T4,
   TIMER_B: 64 * T1,
   TIMER_D: 0 * T1,
   TIMER_F: 64 * T1,
   TIMER_H: 64 * T1,
   TIMER_I: 0 * T1,
   TIMER_J: 0 * T1,
   TIMER_K: 0 * T4,
   TIMER_L: 64 * T1,
   TIMER_M: 64 * T1,
   PROVISIONAL_RESPONSE_INTERVAL: 60000 // See RFC 3261 Section 13.3.1.1
 
 };
 },{}],22:[function(require,module,exports){
 "use strict";
 
 function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
 
 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
 function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
 
 function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
 
 function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
 
 function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
 
 function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
 
 function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
 
 function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
 
 function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }
 
 function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
 
 var EventEmitter = require('events').EventEmitter;
 
 var JsSIP_C = require('./Constants');
 
 var SIPMessage = require('./SIPMessage');
 
 var Timers = require('./Timers');
 
 var debugnict = require('debug')('JsSIP:NonInviteClientTransaction');
 
 var debugict = require('debug')('JsSIP:InviteClientTransaction');
 
 var debugact = require('debug')('JsSIP:AckClientTransaction');
 
 var debugnist = require('debug')('JsSIP:NonInviteServerTransaction');
 
 var debugist = require('debug')('JsSIP:InviteServerTransaction');
 
 var C = {
   // Transaction states.
   STATUS_TRYING: 1,
   STATUS_PROCEEDING: 2,
   STATUS_CALLING: 3,
   STATUS_ACCEPTED: 4,
   STATUS_COMPLETED: 5,
   STATUS_TERMINATED: 6,
   STATUS_CONFIRMED: 7,
   // Transaction types.
   NON_INVITE_CLIENT: 'nict',
   NON_INVITE_SERVER: 'nist',
   INVITE_CLIENT: 'ict',
   INVITE_SERVER: 'ist'
 };
 
 var NonInviteClientTransaction = /*#__PURE__*/function (_EventEmitter) {
   _inherits(NonInviteClientTransaction, _EventEmitter);
 
   var _super = _createSuper(NonInviteClientTransaction);
 
   function NonInviteClientTransaction(ua, transport, request, eventHandlers) {
     var _this;
 
     _classCallCheck(this, NonInviteClientTransaction);
 
     _this = _super.call(this);
     _this.type = C.NON_INVITE_CLIENT;
     _this.id = "z9hG4bK".concat(Math.floor(Math.random() * 10000000));
     _this.ua = ua;
     _this.transport = transport;
     _this.request = request;
     _this.eventHandlers = eventHandlers;
     var via = "SIP/2.0/".concat(transport.via_transport);
     via += " ".concat(ua.configuration.via_host, ";branch=").concat(_this.id);
 
     _this.request.setHeader('via', via);
 
     _this.ua.newTransaction(_assertThisInitialized(_this));
 
     return _this;
   }
 
   _createClass(NonInviteClientTransaction, [{
     key: "stateChanged",
     value: function stateChanged(state) {
       this.state = state;
       this.emit('stateChanged');
     }
   }, {
     key: "send",
     value: function send() {
       var _this2 = this;
 
       this.stateChanged(C.STATUS_TRYING);
       this.F = setTimeout(function () {
         _this2.timer_F();
       }, Timers.TIMER_F);
 
       if (!this.transport.send(this.request)) {
         this.onTransportError();
       }
     }
   }, {
     key: "onTransportError",
     value: function onTransportError() {
       debugnict("transport error occurred, deleting transaction ".concat(this.id));
       clearTimeout(this.F);
       clearTimeout(this.K);
       this.stateChanged(C.STATUS_TERMINATED);
       this.ua.destroyTransaction(this);
       this.eventHandlers.onTransportError();
     }
   }, {
     key: "timer_F",
     value: function timer_F() {
       debugnict("Timer F expired for transaction ".concat(this.id));
       this.stateChanged(C.STATUS_TERMINATED);
       this.ua.destroyTransaction(this);
       this.eventHandlers.onRequestTimeout();
     }
   }, {
     key: "timer_K",
     value: function timer_K() {
       this.stateChanged(C.STATUS_TERMINATED);
       this.ua.destroyTransaction(this);
     }
   }, {
     key: "receiveResponse",
     value: function receiveResponse(response) {
       var _this3 = this;
 
       var status_code = response.status_code;
 
       if (status_code < 200) {
         switch (this.state) {
           case C.STATUS_TRYING:
           case C.STATUS_PROCEEDING:
             this.stateChanged(C.STATUS_PROCEEDING);
             this.eventHandlers.onReceiveResponse(response);
             break;
         }
       } else {
         switch (this.state) {
           case C.STATUS_TRYING:
           case C.STATUS_PROCEEDING:
             this.stateChanged(C.STATUS_COMPLETED);
             clearTimeout(this.F);
 
             if (status_code === 408) {
               this.eventHandlers.onRequestTimeout();
             } else {
               this.eventHandlers.onReceiveResponse(response);
             }
 
             this.K = setTimeout(function () {
               _this3.timer_K();
             }, Timers.TIMER_K);
             break;
 
           case C.STATUS_COMPLETED:
             break;
         }
       }
     }
   }, {
     key: "C",
     get: function get() {
       return C;
     }
   }]);
 
   return NonInviteClientTransaction;
 }(EventEmitter);
 
 var InviteClientTransaction = /*#__PURE__*/function (_EventEmitter2) {
   _inherits(InviteClientTransaction, _EventEmitter2);
 
   var _super2 = _createSuper(InviteClientTransaction);
 
   function InviteClientTransaction(ua, transport, request, eventHandlers) {
     var _this4;
 
     _classCallCheck(this, InviteClientTransaction);
 
     _this4 = _super2.call(this);
     _this4.type = C.INVITE_CLIENT;
     _this4.id = "z9hG4bK".concat(Math.floor(Math.random() * 10000000));
     _this4.ua = ua;
     _this4.transport = transport;
     _this4.request = request;
     _this4.eventHandlers = eventHandlers;
     request.transaction = _assertThisInitialized(_this4);
     var via = "SIP/2.0/".concat(transport.via_transport);
     via += " ".concat(ua.configuration.via_host, ";branch=").concat(_this4.id);
 
     _this4.request.setHeader('via', via);
 
     _this4.ua.newTransaction(_assertThisInitialized(_this4));
 
     return _this4;
   }
 
   _createClass(InviteClientTransaction, [{
     key: "stateChanged",
     value: function stateChanged(state) {
       this.state = state;
       this.emit('stateChanged');
     }
   }, {
     key: "send",
     value: function send() {
       var _this5 = this;
 
       this.stateChanged(C.STATUS_CALLING);
       this.B = setTimeout(function () {
         _this5.timer_B();
       }, Timers.TIMER_B);
 
       if (!this.transport.send(this.request)) {
         this.onTransportError();
       }
     }
   }, {
     key: "onTransportError",
     value: function onTransportError() {
       clearTimeout(this.B);
       clearTimeout(this.D);
       clearTimeout(this.M);
 
       if (this.state !== C.STATUS_ACCEPTED) {
         debugict("transport error occurred, deleting transaction ".concat(this.id));
         this.eventHandlers.onTransportError();
       }
 
       this.stateChanged(C.STATUS_TERMINATED);
       this.ua.destroyTransaction(this);
     } // RFC 6026 7.2.
 
   }, {
     key: "timer_M",
     value: function timer_M() {
       debugict("Timer M expired for transaction ".concat(this.id));
 
       if (this.state === C.STATUS_ACCEPTED) {
         clearTimeout(this.B);
         this.stateChanged(C.STATUS_TERMINATED);
         this.ua.destroyTransaction(this);
       }
     } // RFC 3261 17.1.1.
 
   }, {
     key: "timer_B",
     value: function timer_B() {
       debugict("Timer B expired for transaction ".concat(this.id));
 
       if (this.state === C.STATUS_CALLING) {
         this.stateChanged(C.STATUS_TERMINATED);
         this.ua.destroyTransaction(this);
         this.eventHandlers.onRequestTimeout();
       }
     }
   }, {
     key: "timer_D",
     value: function timer_D() {
       debugict("Timer D expired for transaction ".concat(this.id));
       clearTimeout(this.B);
       this.stateChanged(C.STATUS_TERMINATED);
       this.ua.destroyTransaction(this);
     }
   }, {
     key: "sendACK",
     value: function sendACK(response) {
       var _this6 = this;
 
       var ack = new SIPMessage.OutgoingRequest(JsSIP_C.ACK, this.request.ruri, this.ua, {
         'route_set': this.request.getHeaders('route'),
         'call_id': this.request.getHeader('call-id'),
         'cseq': this.request.cseq
       });
       ack.setHeader('from', this.request.getHeader('from'));
       ack.setHeader('via', this.request.getHeader('via'));
       ack.setHeader('to', response.getHeader('to'));
       this.D = setTimeout(function () {
         _this6.timer_D();
       }, Timers.TIMER_D);
       this.transport.send(ack);
     }
   }, {
     key: "cancel",
     value: function cancel(reason) {
       // Send only if a provisional response (>100) has been received.
       if (this.state !== C.STATUS_PROCEEDING) {
         return;
       }
 
       var cancel = new SIPMessage.OutgoingRequest(JsSIP_C.CANCEL, this.request.ruri, this.ua, {
         'route_set': this.request.getHeaders('route'),
         'call_id': this.request.getHeader('call-id'),
         'cseq': this.request.cseq
       });
       cancel.setHeader('from', this.request.getHeader('from'));
       cancel.setHeader('via', this.request.getHeader('via'));
       cancel.setHeader('to', this.request.getHeader('to'));
 
       if (reason) {
         cancel.setHeader('reason', reason);
       }
 
       this.transport.send(cancel);
     }
   }, {
     key: "receiveResponse",
     value: function receiveResponse(response) {
       var _this7 = this;
 
       var status_code = response.status_code;
 
       if (status_code >= 100 && status_code <= 199) {
         switch (this.state) {
           case C.STATUS_CALLING:
             this.stateChanged(C.STATUS_PROCEEDING);
             this.eventHandlers.onReceiveResponse(response);
             break;
 
           case C.STATUS_PROCEEDING:
             this.eventHandlers.onReceiveResponse(response);
             break;
         }
       } else if (status_code >= 200 && status_code <= 299) {
         switch (this.state) {
           case C.STATUS_CALLING:
           case C.STATUS_PROCEEDING:
             this.stateChanged(C.STATUS_ACCEPTED);
             this.M = setTimeout(function () {
               _this7.timer_M();
             }, Timers.TIMER_M);
             this.eventHandlers.onReceiveResponse(response);
             break;
 
           case C.STATUS_ACCEPTED:
             this.eventHandlers.onReceiveResponse(response);
             break;
         }
       } else if (status_code >= 300 && status_code <= 699) {
         switch (this.state) {
           case C.STATUS_CALLING:
           case C.STATUS_PROCEEDING:
             this.stateChanged(C.STATUS_COMPLETED);
             this.sendACK(response);
             this.eventHandlers.onReceiveResponse(response);
             break;
 
           case C.STATUS_COMPLETED:
             this.sendACK(response);
             break;
         }
       }
     }
   }, {
     key: "C",
     get: function get() {
       return C;
     }
   }]);
 
   return InviteClientTransaction;
 }(EventEmitter);
 
 var AckClientTransaction = /*#__PURE__*/function (_EventEmitter3) {
   _inherits(AckClientTransaction, _EventEmitter3);
 
   var _super3 = _createSuper(AckClientTransaction);
 
   function AckClientTransaction(ua, transport, request, eventHandlers) {
     var _this8;
 
     _classCallCheck(this, AckClientTransaction);
 
     _this8 = _super3.call(this);
     _this8.id = "z9hG4bK".concat(Math.floor(Math.random() * 10000000));
     _this8.transport = transport;
     _this8.request = request;
     _this8.eventHandlers = eventHandlers;
     var via = "SIP/2.0/".concat(transport.via_transport);
     via += " ".concat(ua.configuration.via_host, ";branch=").concat(_this8.id);
 
     _this8.request.setHeader('via', via);
 
     return _this8;
   }
 
   _createClass(AckClientTransaction, [{
     key: "send",
     value: function send() {
       if (!this.transport.send(this.request)) {
         this.onTransportError();
       }
     }
   }, {
     key: "onTransportError",
     value: function onTransportError() {
       debugact("transport error occurred for transaction ".concat(this.id));
       this.eventHandlers.onTransportError();
     }
   }, {
     key: "C",
     get: function get() {
       return C;
     }
   }]);
 
   return AckClientTransaction;
 }(EventEmitter);
 
 var NonInviteServerTransaction = /*#__PURE__*/function (_EventEmitter4) {
   _inherits(NonInviteServerTransaction, _EventEmitter4);
 
   var _super4 = _createSuper(NonInviteServerTransaction);
 
   function NonInviteServerTransaction(ua, transport, request) {
     var _this9;
 
     _classCallCheck(this, NonInviteServerTransaction);
 
     _this9 = _super4.call(this);
     _this9.type = C.NON_INVITE_SERVER;
     _this9.id = request.via_branch;
     _this9.ua = ua;
     _this9.transport = transport;
     _this9.request = request;
     _this9.last_response = '';
     request.server_transaction = _assertThisInitialized(_this9);
     _this9.state = C.STATUS_TRYING;
     ua.newTransaction(_assertThisInitialized(_this9));
     return _this9;
   }
 
   _createClass(NonInviteServerTransaction, [{
     key: "stateChanged",
     value: function stateChanged(state) {
       this.state = state;
       this.emit('stateChanged');
     }
   }, {
     key: "timer_J",
     value: function timer_J() {
       debugnist("Timer J expired for transaction ".concat(this.id));
       this.stateChanged(C.STATUS_TERMINATED);
       this.ua.destroyTransaction(this);
     }
   }, {
     key: "onTransportError",
     value: function onTransportError() {
       if (!this.transportError) {
         this.transportError = true;
         debugnist("transport error occurred, deleting transaction ".concat(this.id));
         clearTimeout(this.J);
         this.stateChanged(C.STATUS_TERMINATED);
         this.ua.destroyTransaction(this);
       }
     }
   }, {
     key: "receiveResponse",
     value: function receiveResponse(status_code, response, onSuccess, onFailure) {
       var _this10 = this;
 
       if (status_code === 100) {
         /* RFC 4320 4.1
          * 'A SIP element MUST NOT
          * send any provisional response with a
          * Status-Code other than 100 to a non-INVITE request.'
          */
         switch (this.state) {
           case C.STATUS_TRYING:
             this.stateChanged(C.STATUS_PROCEEDING);
 
             if (!this.transport.send(response)) {
               this.onTransportError();
             }
 
             break;
 
           case C.STATUS_PROCEEDING:
             this.last_response = response;
 
             if (!this.transport.send(response)) {
               this.onTransportError();
 
               if (onFailure) {
                 onFailure();
               }
             } else if (onSuccess) {
               onSuccess();
             }
 
             break;
         }
       } else if (status_code >= 200 && status_code <= 699) {
         switch (this.state) {
           case C.STATUS_TRYING:
           case C.STATUS_PROCEEDING:
             this.stateChanged(C.STATUS_COMPLETED);
             this.last_response = response;
             this.J = setTimeout(function () {
               _this10.timer_J();
             }, Timers.TIMER_J);
 
             if (!this.transport.send(response)) {
               this.onTransportError();
 
               if (onFailure) {
                 onFailure();
               }
             } else if (onSuccess) {
               onSuccess();
             }
 
             break;
 
           case C.STATUS_COMPLETED:
             break;
         }
       }
     }
   }, {
     key: "C",
     get: function get() {
       return C;
     }
   }]);
 
   return NonInviteServerTransaction;
 }(EventEmitter);
 
 var InviteServerTransaction = /*#__PURE__*/function (_EventEmitter5) {
   _inherits(InviteServerTransaction, _EventEmitter5);
 
   var _super5 = _createSuper(InviteServerTransaction);
 
   function InviteServerTransaction(ua, transport, request) {
     var _this11;
 
     _classCallCheck(this, InviteServerTransaction);
 
     _this11 = _super5.call(this);
     _this11.type = C.INVITE_SERVER;
     _this11.id = request.via_branch;
     _this11.ua = ua;
     _this11.transport = transport;
     _this11.request = request;
     _this11.last_response = '';
     request.server_transaction = _assertThisInitialized(_this11);
     _this11.state = C.STATUS_PROCEEDING;
     ua.newTransaction(_assertThisInitialized(_this11));
     _this11.resendProvisionalTimer = null;
     request.reply(100);
     return _this11;
   }
 
   _createClass(InviteServerTransaction, [{
     key: "stateChanged",
     value: function stateChanged(state) {
       this.state = state;
       this.emit('stateChanged');
     }
   }, {
     key: "timer_H",
     value: function timer_H() {
       debugist("Timer H expired for transaction ".concat(this.id));
 
       if (this.state === C.STATUS_COMPLETED) {
         debugist('ACK not received, dialog will be terminated');
       }
 
       this.stateChanged(C.STATUS_TERMINATED);
       this.ua.destroyTransaction(this);
     }
   }, {
     key: "timer_I",
     value: function timer_I() {
       this.stateChanged(C.STATUS_TERMINATED);
       this.ua.destroyTransaction(this);
     } // RFC 6026 7.1.
 
   }, {
     key: "timer_L",
     value: function timer_L() {
       debugist("Timer L expired for transaction ".concat(this.id));
 
       if (this.state === C.STATUS_ACCEPTED) {
         this.stateChanged(C.STATUS_TERMINATED);
         this.ua.destroyTransaction(this);
       }
     }
   }, {
     key: "onTransportError",
     value: function onTransportError() {
       if (!this.transportError) {
         this.transportError = true;
         debugist("transport error occurred, deleting transaction ".concat(this.id));
 
         if (this.resendProvisionalTimer !== null) {
           clearInterval(this.resendProvisionalTimer);
           this.resendProvisionalTimer = null;
         }
 
         clearTimeout(this.L);
         clearTimeout(this.H);
         clearTimeout(this.I);
         this.stateChanged(C.STATUS_TERMINATED);
         this.ua.destroyTransaction(this);
       }
     }
   }, {
     key: "resend_provisional",
     value: function resend_provisional() {
       if (!this.transport.send(this.last_response)) {
         this.onTransportError();
       }
     } // INVITE Server Transaction RFC 3261 17.2.1.
 
   }, {
     key: "receiveResponse",
     value: function receiveResponse(status_code, response, onSuccess, onFailure) {
       var _this12 = this;
 
       if (status_code >= 100 && status_code <= 199) {
         switch (this.state) {
           case C.STATUS_PROCEEDING:
             if (!this.transport.send(response)) {
               this.onTransportError();
             }
 
             this.last_response = response;
             break;
         }
       }
 
       if (status_code > 100 && status_code <= 199 && this.state === C.STATUS_PROCEEDING) {
         // Trigger the resendProvisionalTimer only for the first non 100 provisional response.
         if (this.resendProvisionalTimer === null) {
           this.resendProvisionalTimer = setInterval(function () {
             _this12.resend_provisional();
           }, Timers.PROVISIONAL_RESPONSE_INTERVAL);
         }
       } else if (status_code >= 200 && status_code <= 299) {
         switch (this.state) {
           case C.STATUS_PROCEEDING:
             this.stateChanged(C.STATUS_ACCEPTED);
             this.last_response = response;
             this.L = setTimeout(function () {
               _this12.timer_L();
             }, Timers.TIMER_L);
 
             if (this.resendProvisionalTimer !== null) {
               clearInterval(this.resendProvisionalTimer);
               this.resendProvisionalTimer = null;
             }
 
           /* falls through */
 
           case C.STATUS_ACCEPTED:
             // Note that this point will be reached for proceeding this.state also.
             if (!this.transport.send(response)) {
               this.onTransportError();
 
               if (onFailure) {
                 onFailure();
               }
             } else if (onSuccess) {
               onSuccess();
             }
 
             break;
         }
       } else if (status_code >= 300 && status_code <= 699) {
         switch (this.state) {
           case C.STATUS_PROCEEDING:
             if (this.resendProvisionalTimer !== null) {
               clearInterval(this.resendProvisionalTimer);
               this.resendProvisionalTimer = null;
             }
 
             if (!this.transport.send(response)) {
               this.onTransportError();
 
               if (onFailure) {
                 onFailure();
               }
             } else {
               this.stateChanged(C.STATUS_COMPLETED);
               this.H = setTimeout(function () {
                 _this12.timer_H();
               }, Timers.TIMER_H);
 
               if (onSuccess) {
                 onSuccess();
               }
             }
 
             break;
         }
       }
     }
   }, {
     key: "C",
     get: function get() {
       return C;
     }
   }]);
 
   return InviteServerTransaction;
 }(EventEmitter);
 /**
  * INVITE:
  *  _true_ if retransmission
  *  _false_ new request
  *
  * ACK:
  *  _true_  ACK to non2xx response
  *  _false_ ACK must be passed to TU (accepted state)
  *          ACK to 2xx response
  *
  * CANCEL:
  *  _true_  no matching invite transaction
  *  _false_ matching invite transaction and no final response sent
  *
  * OTHER:
  *  _true_  retransmission
  *  _false_ new request
  */
 
 
 function checkTransaction(_ref, request) {
   var _transactions = _ref._transactions;
   var tr;
 
   switch (request.method) {
     case JsSIP_C.INVITE:
       tr = _transactions.ist[request.via_branch];
 
       if (tr) {
         switch (tr.state) {
           case C.STATUS_PROCEEDING:
             tr.transport.send(tr.last_response);
             break;
           // RFC 6026 7.1 Invite retransmission.
           // Received while in C.STATUS_ACCEPTED state. Absorb it.
 
           case C.STATUS_ACCEPTED:
             break;
         }
 
         return true;
       }
 
       break;
 
     case JsSIP_C.ACK:
       tr = _transactions.ist[request.via_branch]; // RFC 6026 7.1.
 
       if (tr) {
         if (tr.state === C.STATUS_ACCEPTED) {
           return false;
         } else if (tr.state === C.STATUS_COMPLETED) {
           tr.state = C.STATUS_CONFIRMED;
           tr.I = setTimeout(function () {
             tr.timer_I();
           }, Timers.TIMER_I);
           return true;
         }
       } // ACK to 2XX Response.
       else {
           return false;
         }
 
       break;
 
     case JsSIP_C.CANCEL:
       tr = _transactions.ist[request.via_branch];
 
       if (tr) {
         request.reply_sl(200);
 
         if (tr.state === C.STATUS_PROCEEDING) {
           return false;
         } else {
           return true;
         }
       } else {
         request.reply_sl(481);
         return true;
       }
 
     default:
       // Non-INVITE Server Transaction RFC 3261 17.2.2.
       tr = _transactions.nist[request.via_branch];
 
       if (tr) {
         switch (tr.state) {
           case C.STATUS_TRYING:
             break;
 
           case C.STATUS_PROCEEDING:
           case C.STATUS_COMPLETED:
             tr.transport.send(tr.last_response);
             break;
         }
 
         return true;
       }
 
       break;
   }
 }
 
 module.exports = {
   C: C,
   NonInviteClientTransaction: NonInviteClientTransaction,
   InviteClientTransaction: InviteClientTransaction,
   AckClientTransaction: AckClientTransaction,
   NonInviteServerTransaction: NonInviteServerTransaction,
   InviteServerTransaction: InviteServerTransaction,
   checkTransaction: checkTransaction
 };
 },{"./Constants":2,"./SIPMessage":19,"./Timers":21,"debug":30,"events":29}],23:[function(require,module,exports){
 "use strict";
 
 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
 function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
 
 function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
 
 var Socket = require('./Socket');
 
 var debug = require('debug')('JsSIP:Transport');
 
 var debugerror = require('debug')('JsSIP:ERROR:Transport');
 
 var JsSIP_C = require('./Constants');
 
 debugerror.log = console.warn.bind(console);
 /**
  * Constants
  */
 
 var C = {
   // Transport status.
   STATUS_CONNECTED: 0,
   STATUS_CONNECTING: 1,
   STATUS_DISCONNECTED: 2,
   // Socket status.
   SOCKET_STATUS_READY: 0,
   SOCKET_STATUS_ERROR: 1,
   // Recovery options.
   recovery_options: {
     // minimum interval in seconds between recover attempts.
     min_interval: JsSIP_C.CONNECTION_RECOVERY_MIN_INTERVAL,
     // maximum interval in seconds between recover attempts.
     max_interval: JsSIP_C.CONNECTION_RECOVERY_MAX_INTERVAL
   }
 };
 /*
  * Manages one or multiple JsSIP.Socket instances.
  * Is reponsible for transport recovery logic among all socket instances.
  *
  * @socket JsSIP::Socket instance
  */
 
 module.exports = /*#__PURE__*/function () {
   function Transport(sockets) {
     var recovery_options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : C.recovery_options;
 
     _classCallCheck(this, Transport);
 
     debug('new()');
     this.status = C.STATUS_DISCONNECTED; // Current socket.
 
     this.socket = null; // Socket collection.
 
     this.sockets = [];
     this.recovery_options = recovery_options;
     this.recover_attempts = 0;
     this.recovery_timer = null;
     this.close_requested = false;
 
     if (typeof sockets === 'undefined') {
       throw new TypeError('Invalid argument.' + ' undefined \'sockets\' argument');
     }
 
     if (!(sockets instanceof Array)) {
       sockets = [sockets];
     }
 
     sockets.forEach(function (socket) {
       if (!Socket.isSocket(socket.socket)) {
         throw new TypeError('Invalid argument.' + ' invalid \'JsSIP.Socket\' instance');
       }
 
       if (socket.weight && !Number(socket.weight)) {
         throw new TypeError('Invalid argument.' + ' \'weight\' attribute is not a number');
       }
 
       this.sockets.push({
         socket: socket.socket,
         weight: socket.weight || 0,
         status: C.SOCKET_STATUS_READY
       });
     }, this); // Get the socket with higher weight.
 
     this._getSocket();
   }
   /**
    * Instance Methods
    */
 
 
   _createClass(Transport, [{
     key: "connect",
     value: function connect() {
       debug('connect()');
 
       if (this.isConnected()) {
         debug('Transport is already connected');
         return;
       } else if (this.isConnecting()) {
         debug('Transport is connecting');
         return;
       }
 
       this.close_requested = false;
       this.status = C.STATUS_CONNECTING;
       this.onconnecting({
         socket: this.socket,
         attempts: this.recover_attempts
       });
 
       if (!this.close_requested) {
         // Bind socket event callbacks.
         this.socket.onconnect = this._onConnect.bind(this);
         this.socket.ondisconnect = this._onDisconnect.bind(this);
         this.socket.ondata = this._onData.bind(this);
         this.socket.connect();
       }
 
       return;
     }
   }, {
     key: "disconnect",
     value: function disconnect() {
       debug('close()');
       this.close_requested = true;
       this.recover_attempts = 0;
       this.status = C.STATUS_DISCONNECTED; // Clear recovery_timer.
 
       if (this.recovery_timer !== null) {
         clearTimeout(this.recovery_timer);
         this.recovery_timer = null;
       } // Unbind socket event callbacks.
 
 
       this.socket.onconnect = function () {};
 
       this.socket.ondisconnect = function () {};
 
       this.socket.ondata = function () {};
 
       this.socket.disconnect();
       this.ondisconnect({
         socket: this.socket,
         error: false
       });
     }
   }, {
     key: "send",
     value: function send(data) {
       debug('send()');
 
       if (!this.isConnected()) {
         debugerror('unable to send message, transport is not connected');
         return false;
       }
 
       var message = data.toString();
       debug("sending message:\n\n".concat(message, "\n"));
       return this.socket.send(message);
     }
   }, {
     key: "isConnected",
     value: function isConnected() {
       return this.status === C.STATUS_CONNECTED;
     }
   }, {
     key: "isConnecting",
     value: function isConnecting() {
       return this.status === C.STATUS_CONNECTING;
     }
     /**
      * Private API.
      */
 
   }, {
     key: "_reconnect",
     value: function _reconnect() {
       var _this = this;
 
       this.recover_attempts += 1;
       var k = Math.floor(Math.random() * Math.pow(2, this.recover_attempts) + 1);
 
       if (k < this.recovery_options.min_interval) {
         k = this.recovery_options.min_interval;
       } else if (k > this.recovery_options.max_interval) {
         k = this.recovery_options.max_interval;
       }
 
       debug("reconnection attempt: ".concat(this.recover_attempts, ". next connection attempt in ").concat(k, " seconds"));
       this.recovery_timer = setTimeout(function () {
         if (!_this.close_requested && !(_this.isConnected() || _this.isConnecting())) {
           // Get the next available socket with higher weight.
           _this._getSocket(); // Connect the socket.
 
 
           _this.connect();
         }
       }, k * 1000);
     }
     /**
      * get the next available socket with higher weight
      */
 
   }, {
     key: "_getSocket",
     value: function _getSocket() {
       var candidates = [];
       this.sockets.forEach(function (socket) {
         if (socket.status === C.SOCKET_STATUS_ERROR) {
           return; // continue the array iteration
         } else if (candidates.length === 0) {
           candidates.push(socket);
         } else if (socket.weight > candidates[0].weight) {
           candidates = [socket];
         } else if (socket.weight === candidates[0].weight) {
           candidates.push(socket);
         }
       });
 
       if (candidates.length === 0) {
         // All sockets have failed. reset sockets status.
         this.sockets.forEach(function (socket) {
           socket.status = C.SOCKET_STATUS_READY;
         }); // Get next available socket.
 
         this._getSocket();
 
         return;
       }
 
       var idx = Math.floor(Math.random() * candidates.length);
       this.socket = candidates[idx].socket;
     }
     /**
      * Socket Event Handlers
      */
 
   }, {
     key: "_onConnect",
     value: function _onConnect() {
       this.recover_attempts = 0;
       this.status = C.STATUS_CONNECTED; // Clear recovery_timer.
 
       if (this.recovery_timer !== null) {
         clearTimeout(this.recovery_timer);
         this.recovery_timer = null;
       }
 
       this.onconnect({
         socket: this
       });
     }
   }, {
     key: "_onDisconnect",
     value: function _onDisconnect(error, code, reason) {
       this.status = C.STATUS_DISCONNECTED;
       this.ondisconnect({
         socket: this.socket,
         error: error,
         code: code,
         reason: reason
       });
 
       if (this.close_requested) {
         return;
       } // Update socket status.
       else {
           this.sockets.forEach(function (socket) {
             if (this.socket === socket.socket) {
               socket.status = C.SOCKET_STATUS_ERROR;
             }
           }, this);
         }
 
       this._reconnect(error);
     }
   }, {
     key: "_onData",
     value: function _onData(data) {
       // CRLF Keep Alive response from server. Ignore it.
       if (data === '\r\n') {
         debug('received message with CRLF Keep Alive response');
         return;
       } // Binary message.
       else if (typeof data !== 'string') {
           try {
             data = String.fromCharCode.apply(null, new Uint8Array(data));
           } catch (evt) {
             debug('received binary message failed to be converted into string,' + ' message discarded');
             return;
           }
 
           debug("received binary message:\n\n".concat(data, "\n"));
         } // Text message.
         else {
             debug("received text message:\n\n".concat(data, "\n"));
           }
 
       this.ondata({
         transport: this,
         message: data
       });
     }
   }, {
     key: "via_transport",
     get: function get() {
       return this.socket.via_transport;
     }
   }, {
     key: "url",
     get: function get() {
       return this.socket.url;
     }
   }, {
     key: "sip_uri",
     get: function get() {
       return this.socket.sip_uri;
     }
   }]);
 
   return Transport;
 }();
 },{"./Constants":2,"./Socket":20,"debug":30}],24:[function(require,module,exports){
 "use strict";
 
 function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
 
 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
 function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
 
 function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
 
 function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
 
 function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
 
 function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
 
 function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
 
 function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
 
 function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }
 
 function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
 
 var EventEmitter = require('events').EventEmitter;
 
 var JsSIP_C = require('./Constants');
 
 var Registrator = require('./Registrator');
 
 var RTCSession = require('./RTCSession');
 
 var Message = require('./Message');
 
 var Transactions = require('./Transactions');
 
 var Transport = require('./Transport');
 
 var Utils = require('./Utils');
 
 var Exceptions = require('./Exceptions');
 
 var URI = require('./URI');
 
 var Parser = require('./Parser');
 
 var SIPMessage = require('./SIPMessage');
 
 var sanityCheck = require('./sanityCheck');
 
 var config = require('./Config');
 
 var debug = require('debug')('JsSIP:UA');
 
 var debugerror = require('debug')('JsSIP:ERROR:UA');
 
 debugerror.log = console.warn.bind(console);
 var C = {
   // UA status codes.
   STATUS_INIT: 0,
   STATUS_READY: 1,
   STATUS_USER_CLOSED: 2,
   STATUS_NOT_READY: 3,
   // UA error codes.
   CONFIGURATION_ERROR: 1,
   NETWORK_ERROR: 2
 };
 /**
  * The User-Agent class.
  * @class JsSIP.UA
  * @param {Object} configuration Configuration parameters.
  * @throws {JsSIP.Exceptions.ConfigurationError} If a configuration parameter is invalid.
  * @throws {TypeError} If no configuration is given.
  */
 
 module.exports = /*#__PURE__*/function (_EventEmitter) {
   _inherits(UA, _EventEmitter);
 
   var _super = _createSuper(UA);
 
   _createClass(UA, null, [{
     key: "C",
     // Expose C object.
     get: function get() {
       return C;
     }
   }]);
 
   function UA(configuration) {
     var _this;
 
     _classCallCheck(this, UA);
 
     debug('new() [configuration:%o]', configuration);
     _this = _super.call(this);
     _this._cache = {
       credentials: {}
     };
     _this._configuration = Object.assign({}, config.settings);
     _this._dynConfiguration = {};
     _this._dialogs = {}; // User actions outside any session/dialog (MESSAGE).
 
     _this._applicants = {};
     _this._sessions = {};
     _this._transport = null;
     _this._contact = null;
     _this._status = C.STATUS_INIT;
     _this._error = null;
     _this._transactions = {
       nist: {},
       nict: {},
       ist: {},
       ict: {}
     }; // Custom UA empty object for high level use.
 
     _this._data = {};
     _this._closeTimer = null; // Check configuration argument.
 
     if (configuration === undefined) {
       throw new TypeError('Not enough arguments');
     } // Load configuration.
 
 
     try {
       _this._loadConfig(configuration);
     } catch (e) {
       _this._status = C.STATUS_NOT_READY;
       _this._error = C.CONFIGURATION_ERROR;
       throw e;
     } // Initialize registrator.
 
 
     _this._registrator = new Registrator(_assertThisInitialized(_this));
     return _this;
   }
 
   _createClass(UA, [{
     key: "start",
     // =================
     //  High Level API
     // =================
 
     /**
      * Connect to the server if status = STATUS_INIT.
      * Resume UA after being closed.
      */
     value: function start() {
       debug('start()');
 
       if (this._status === C.STATUS_INIT) {
         this._transport.connect();
       } else if (this._status === C.STATUS_USER_CLOSED) {
         debug('restarting UA'); // Disconnect.
 
         if (this._closeTimer !== null) {
           clearTimeout(this._closeTimer);
           this._closeTimer = null;
 
           this._transport.disconnect();
         } // Reconnect.
 
 
         this._status = C.STATUS_INIT;
 
         this._transport.connect();
       } else if (this._status === C.STATUS_READY) {
         debug('UA is in READY status, not restarted');
       } else {
         debug('ERROR: connection is down, Auto-Recovery system is trying to reconnect');
       } // Set dynamic configuration.
 
 
       this._dynConfiguration.register = this._configuration.register;
     }
     /**
      * Register.
      */
 
   }, {
     key: "register",
     value: function register() {
       debug('register()');
       this._dynConfiguration.register = true;
 
       this._registrator.register();
     }
     /**
      * Unregister.
      */
 
   }, {
     key: "unregister",
     value: function unregister(options) {
       debug('unregister()');
       this._dynConfiguration.register = false;
 
       this._registrator.unregister(options);
     }
     /**
      * Get the Registrator instance.
      */
 
   }, {
     key: "registrator",
     value: function registrator() {
       return this._registrator;
     }
     /**
      * Registration state.
      */
 
   }, {
     key: "isRegistered",
     value: function isRegistered() {
       return this._registrator.registered;
     }
     /**
      * Connection state.
      */
 
   }, {
     key: "isConnected",
     value: function isConnected() {
       return this._transport.isConnected();
     }
     /**
      * Make an outgoing call.
      *
      * -param {String} target
      * -param {Object} [options]
      *
      * -throws {TypeError}
      *
      */
 
   }, {
     key: "call",
     value: function call(target, options) {
       debug('call()');
       var session = new RTCSession(this);
       session.connect(target, options);
       return session;
     }
     /**
      * Send a message.
      *
      * -param {String} target
      * -param {String} body
      * -param {Object} [options]
      *
      * -throws {TypeError}
      *
      */
 
   }, {
     key: "sendMessage",
     value: function sendMessage(target, body, options) {
       debug('sendMessage()');
       var message = new Message(this);
       message.send(target, body, options);
       return message;
     }
     /**
      * Terminate ongoing sessions.
      */
 
   }, {
     key: "terminateSessions",
     value: function terminateSessions(options) {
       debug('terminateSessions()');
 
       for (var idx in this._sessions) {
         if (!this._sessions[idx].isEnded()) {
           this._sessions[idx].terminate(options);
         }
       }
     }
     /**
      * Gracefully close.
      *
      */
 
   }, {
     key: "stop",
     value: function stop() {
       var _this2 = this;
 
       debug('stop()'); // Remove dynamic settings.
 
       this._dynConfiguration = {};
 
       if (this._status === C.STATUS_USER_CLOSED) {
         debug('UA already closed');
         return;
       } // Close registrator.
 
 
       this._registrator.close(); // If there are session wait a bit so CANCEL/BYE can be sent and their responses received.
 
 
       var num_sessions = Object.keys(this._sessions).length; // Run  _terminate_ on every Session.
 
       for (var session in this._sessions) {
         if (Object.prototype.hasOwnProperty.call(this._sessions, session)) {
           debug("closing session ".concat(session));
 
           try {
             this._sessions[session].terminate();
           } catch (error) {}
         }
       } // Run  _close_ on every applicant.
 
 
       for (var applicant in this._applicants) {
         if (Object.prototype.hasOwnProperty.call(this._applicants, applicant)) try {
           this._applicants[applicant].close();
         } catch (error) {}
       }
 
       this._status = C.STATUS_USER_CLOSED;
       var num_transactions = Object.keys(this._transactions.nict).length + Object.keys(this._transactions.nist).length + Object.keys(this._transactions.ict).length + Object.keys(this._transactions.ist).length;
 
       if (num_transactions === 0 && num_sessions === 0) {
         this._transport.disconnect();
       } else {
         this._closeTimer = setTimeout(function () {
           _this2._closeTimer = null;
 
           _this2._transport.disconnect();
         }, 2000);
       }
     }
     /**
      * Normalice a string into a valid SIP request URI
      * -param {String} target
      * -returns {JsSIP.URI|undefined}
      */
 
   }, {
     key: "normalizeTarget",
     value: function normalizeTarget(target) {
       return Utils.normalizeTarget(target, this._configuration.hostport_params);
     }
     /**
      * Allow retrieving configuration and autogenerated fields in runtime.
      */
 
   }, {
     key: "get",
     value: function get(parameter) {
       switch (parameter) {
         case 'authorization_user':
           return this._configuration.authorization_user;
 
         case 'realm':
           return this._configuration.realm;
 
         case 'ha1':
           return this._configuration.ha1;
 
         case 'authorization_jwt':
           return this._configuration.authorization_jwt;
 
         default:
           debugerror('get() | cannot get "%s" parameter in runtime', parameter);
           return undefined;
       }
     }
     /**
      * Allow configuration changes in runtime.
      * Returns true if the parameter could be set.
      */
 
   }, {
     key: "set",
     value: function set(parameter, value) {
       switch (parameter) {
         case 'authorization_user':
           {
             this._configuration.authorization_user = String(value);
             break;
           }
 
         case 'password':
           {
             this._configuration.password = String(value);
             break;
           }
 
         case 'realm':
           {
             this._configuration.realm = String(value);
             break;
           }
 
         case 'ha1':
           {
             this._configuration.ha1 = String(value); // Delete the plain SIP password.
 
             this._configuration.password = null;
             break;
           }
 
         case 'authorization_jwt':
           {
             this._configuration.authorization_jwt = String(value);
             break;
           }
 
         case 'display_name':
           {
             this._configuration.display_name = value;
             break;
           }
 
         default:
           debugerror('set() | cannot set "%s" parameter in runtime', parameter);
           return false;
       }
 
       return true;
     } // ==========================
     // Event Handlers.
     // ==========================
 
     /**
      * new Transaction
      */
 
   }, {
     key: "newTransaction",
     value: function newTransaction(transaction) {
       this._transactions[transaction.type][transaction.id] = transaction;
       this.emit('newTransaction', {
         transaction: transaction
       });
     }
     /**
      * Transaction destroyed.
      */
 
   }, {
     key: "destroyTransaction",
     value: function destroyTransaction(transaction) {
       delete this._transactions[transaction.type][transaction.id];
       this.emit('transactionDestroyed', {
         transaction: transaction
       });
     }
     /**
      * new Dialog
      */
 
   }, {
     key: "newDialog",
     value: function newDialog(dialog) {
       this._dialogs[dialog.id] = dialog;
     }
     /**
      * Dialog destroyed.
      */
 
   }, {
     key: "destroyDialog",
     value: function destroyDialog(dialog) {
       delete this._dialogs[dialog.id];
     }
     /**
      *  new Message
      */
 
   }, {
     key: "newMessage",
     value: function newMessage(message, data) {
       this._applicants[message] = message;
       this.emit('newMessage', data);
     }
     /**
      *  Message destroyed.
      */
 
   }, {
     key: "destroyMessage",
     value: function destroyMessage(message) {
       delete this._applicants[message];
     }
     /**
      * new RTCSession
      */
 
   }, {
     key: "newRTCSession",
     value: function newRTCSession(session, data) {
       this._sessions[session.id] = session;
       this.emit('newRTCSession', data);
     }
     /**
      * RTCSession destroyed.
      */
 
   }, {
     key: "destroyRTCSession",
     value: function destroyRTCSession(session) {
       delete this._sessions[session.id];
     }
     /**
      * Registered
      */
 
   }, {
     key: "registered",
     value: function registered(data) {
       this.emit('registered', data);
     }
     /**
      * Unregistered
      */
 
   }, {
     key: "unregistered",
     value: function unregistered(data) {
       this.emit('unregistered', data);
     }
     /**
      * Registration Failed
      */
 
   }, {
     key: "registrationFailed",
     value: function registrationFailed(data) {
       this.emit('registrationFailed', data);
     } // =========================
     // ReceiveRequest.
     // =========================
 
     /**
      * Request reception
      */
 
   }, {
     key: "receiveRequest",
     value: function receiveRequest(request) {
       var method = request.method; // Check that request URI points to us.
 
       if (request.ruri.user !== this._configuration.uri.user && request.ruri.user !== this._contact.uri.user) {
         debug('Request-URI does not point to us');
 
         if (request.method !== JsSIP_C.ACK) {
           request.reply_sl(404);
         }
 
         return;
       } // Check request URI scheme.
 
 
       if (request.ruri.scheme === JsSIP_C.SIPS) {
         request.reply_sl(416);
         return;
       } // Check transaction.
 
 
       if (Transactions.checkTransaction(this, request)) {
         return;
       } // Create the server transaction.
 
 
       if (method === JsSIP_C.INVITE) {
         /* eslint-disable no-new */
         new Transactions.InviteServerTransaction(this, this._transport, request);
         /* eslint-enable no-new */
       } else if (method !== JsSIP_C.ACK && method !== JsSIP_C.CANCEL) {
         /* eslint-disable no-new */
         new Transactions.NonInviteServerTransaction(this, this._transport, request);
         /* eslint-enable no-new */
       }
       /* RFC3261 12.2.2
        * Requests that do not change in any way the state of a dialog may be
        * received within a dialog (for example, an OPTIONS request).
        * They are processed as if they had been received outside the dialog.
        */
 
 
       if (method === JsSIP_C.OPTIONS) {
         request.reply(200);
       } else if (method === JsSIP_C.MESSAGE) {
         if (this.listeners('newMessage').length === 0) {
           request.reply(405);
           return;
         }
 
         var message = new Message(this);
         message.init_incoming(request);
       } else if (method === JsSIP_C.INVITE) {
         // Initial INVITE.
         if (!request.to_tag && this.listeners('newRTCSession').length === 0) {
           request.reply(405);
           return;
         }
       }
 
       var dialog;
       var session; // Initial Request.
 
       if (!request.to_tag) {
         switch (method) {
           case JsSIP_C.INVITE:
             if (window.RTCPeerConnection) {
               // TODO
               if (request.hasHeader('replaces')) {
                 var replaces = request.replaces;
                 dialog = this._findDialog(replaces.call_id, replaces.from_tag, replaces.to_tag);
 
                 if (dialog) {
                   session = dialog.owner;
 
                   if (!session.isEnded()) {
                     session.receiveRequest(request);
                   } else {
                     request.reply(603);
                   }
                 } else {
                   request.reply(481);
                 }
               } else {
                 session = new RTCSession(this);
                 session.init_incoming(request);
               }
             } else {
               debugerror('INVITE received but WebRTC is not supported');
               request.reply(488);
             }
 
             break;
 
           case JsSIP_C.BYE:
             // Out of dialog BYE received.
             request.reply(481);
             break;
 
           case JsSIP_C.CANCEL:
             session = this._findSession(request);
 
             if (session) {
               session.receiveRequest(request);
             } else {
               debug('received CANCEL request for a non existent session');
             }
 
             break;
 
           case JsSIP_C.ACK:
             /* Absorb it.
              * ACK request without a corresponding Invite Transaction
              * and without To tag.
              */
             break;
 
           case JsSIP_C.NOTIFY:
             // Receive new sip event.
             this.emit('sipEvent', {
               event: request.event,
               request: request
             });
             request.reply(200);
             break;
 
           default:
             request.reply(405);
             break;
         }
       } // In-dialog request.
       else {
           dialog = this._findDialog(request.call_id, request.from_tag, request.to_tag);
 
           if (dialog) {
             dialog.receiveRequest(request);
           } else if (method === JsSIP_C.NOTIFY) {
             session = this._findSession(request);
 
             if (session) {
               session.receiveRequest(request);
             } else {
               debug('received NOTIFY request for a non existent subscription');
               request.reply(481, 'Subscription does not exist');
             }
           }
           /* RFC3261 12.2.2
            * Request with to tag, but no matching dialog found.
            * Exception: ACK for an Invite request for which a dialog has not
            * been created.
            */
           else if (method !== JsSIP_C.ACK) {
               request.reply(481);
             }
         }
     } // =================
     // Utils.
     // =================
 
     /**
      * Get the session to which the request belongs to, if any.
      */
 
   }, {
     key: "_findSession",
     value: function _findSession(_ref) {
       var call_id = _ref.call_id,
           from_tag = _ref.from_tag,
           to_tag = _ref.to_tag;
       var sessionIDa = call_id + from_tag;
       var sessionA = this._sessions[sessionIDa];
       var sessionIDb = call_id + to_tag;
       var sessionB = this._sessions[sessionIDb];
 
       if (sessionA) {
         return sessionA;
       } else if (sessionB) {
         return sessionB;
       } else {
         return null;
       }
     }
     /**
      * Get the dialog to which the request belongs to, if any.
      */
 
   }, {
     key: "_findDialog",
     value: function _findDialog(call_id, from_tag, to_tag) {
       var id = call_id + from_tag + to_tag;
       var dialog = this._dialogs[id];
 
       if (dialog) {
         return dialog;
       } else {
         id = call_id + to_tag + from_tag;
         dialog = this._dialogs[id];
 
         if (dialog) {
           return dialog;
         } else {
           return null;
         }
       }
     }
   }, {
     key: "_loadConfig",
     value: function _loadConfig(configuration) {
       // Check and load the given configuration.
       try {
         config.load(this._configuration, configuration);
       } catch (e) {
         throw e;
       } // Post Configuration Process.
       // Allow passing 0 number as display_name.
 
 
       if (this._configuration.display_name === 0) {
         this._configuration.display_name = '0';
       } // Instance-id for GRUU.
 
 
       if (!this._configuration.instance_id) {
         this._configuration.instance_id = Utils.newUUID();
       } // Jssip_id instance parameter. Static random tag of length 5.
 
 
       this._configuration.jssip_id = Utils.createRandomToken(5); // String containing this._configuration.uri without scheme and user.
 
       var hostport_params = this._configuration.uri.clone();
 
       hostport_params.user = null;
       this._configuration.hostport_params = hostport_params.toString().replace(/^sip:/i, ''); // Transport.
 
       try {
         this._transport = new Transport(this._configuration.sockets, {
           // Recovery options.
           max_interval: this._configuration.connection_recovery_max_interval,
           min_interval: this._configuration.connection_recovery_min_interval
         }); // Transport event callbacks.
 
         this._transport.onconnecting = onTransportConnecting.bind(this);
         this._transport.onconnect = onTransportConnect.bind(this);
         this._transport.ondisconnect = onTransportDisconnect.bind(this);
         this._transport.ondata = onTransportData.bind(this);
       } catch (e) {
         debugerror(e);
         throw new Exceptions.ConfigurationError('sockets', this._configuration.sockets);
       } // Remove sockets instance from configuration object.
 
 
       delete this._configuration.sockets; // Check whether authorization_user is explicitly defined.
       // Take 'this._configuration.uri.user' value if not.
 
       if (!this._configuration.authorization_user) {
         this._configuration.authorization_user = this._configuration.uri.user;
       } // If no 'registrar_server' is set use the 'uri' value without user portion and
       // without URI params/headers.
 
 
       if (!this._configuration.registrar_server) {
         var registrar_server = this._configuration.uri.clone();
 
         registrar_server.user = null;
         registrar_server.clearParams();
         registrar_server.clearHeaders();
         this._configuration.registrar_server = registrar_server;
       } // User no_answer_timeout.
 
 
       this._configuration.no_answer_timeout *= 1000; // Via Host.
 
       if (this._configuration.contact_uri) {
         this._configuration.via_host = this._configuration.contact_uri.host;
       } // Contact URI.
       else {
           this._configuration.contact_uri = new URI('sip', Utils.createRandomToken(8), this._configuration.via_host, null, {
             transport: 'ws'
           });
         }
 
       this._contact = {
         pub_gruu: null,
         temp_gruu: null,
         uri: this._configuration.contact_uri,
         toString: function toString() {
           var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
           var anonymous = options.anonymous || null;
           var outbound = options.outbound || null;
           var contact = '<';
 
           if (anonymous) {
             contact += this.temp_gruu || 'sip:anonymous@anonymous.invalid;transport=ws';
           } else {
             contact += this.pub_gruu || this.uri.toString();
           }
 
           if (outbound && (anonymous ? !this.temp_gruu : !this.pub_gruu)) {
             contact += ';ob';
           }
 
           contact += '>';
           return contact;
         }
       }; // Seal the configuration.
 
       var writable_parameters = ['authorization_user', 'password', 'realm', 'ha1', 'authorization_jwt', 'display_name', 'register'];
 
       for (var parameter in this._configuration) {
         if (Object.prototype.hasOwnProperty.call(this._configuration, parameter)) {
           if (writable_parameters.indexOf(parameter) !== -1) {
             Object.defineProperty(this._configuration, parameter, {
               writable: true,
               configurable: false
             });
           } else {
             Object.defineProperty(this._configuration, parameter, {
               writable: false,
               configurable: false
             });
           }
         }
       }
 
       debug('configuration parameters after validation:');
 
       for (var _parameter in this._configuration) {
         // Only show the user user configurable parameters.
         if (Object.prototype.hasOwnProperty.call(config.settings, _parameter)) {
           switch (_parameter) {
             case 'uri':
             case 'registrar_server':
               debug("- ".concat(_parameter, ": ").concat(this._configuration[_parameter]));
               break;
 
             case 'password':
             case 'ha1':
             case 'authorization_jwt':
               debug("- ".concat(_parameter, ": NOT SHOWN"));
               break;
 
             default:
               debug("- ".concat(_parameter, ": ").concat(JSON.stringify(this._configuration[_parameter])));
           }
         }
       }
 
       return;
     }
   }, {
     key: "C",
     get: function get() {
       return C;
     }
   }, {
     key: "status",
     get: function get() {
       return this._status;
     }
   }, {
     key: "contact",
     get: function get() {
       return this._contact;
     }
   }, {
     key: "configuration",
     get: function get() {
       return this._configuration;
     }
   }, {
     key: "transport",
     get: function get() {
       return this._transport;
     }
   }]);
 
   return UA;
 }(EventEmitter);
 /**
  * Transport event handlers
  */
 // Transport connecting event.
 
 
 function onTransportConnecting(data) {
   this.emit('connecting', data);
 } // Transport connected event.
 
 
 function onTransportConnect(data) {
   if (this._status === C.STATUS_USER_CLOSED) {
     return;
   }
 
   this._status = C.STATUS_READY;
   this._error = null;
   this.emit('connected', data);
 
   if (this._dynConfiguration.register) {
     this._registrator.register();
   }
 } // Transport disconnected event.
 
 
 function onTransportDisconnect(data) {
   // Run _onTransportError_ callback on every client transaction using _transport_.
   var client_transactions = ['nict', 'ict', 'nist', 'ist'];
 
   for (var _i = 0, _client_transactions = client_transactions; _i < _client_transactions.length; _i++) {
     var type = _client_transactions[_i];
 
     for (var id in this._transactions[type]) {
       if (Object.prototype.hasOwnProperty.call(this._transactions[type], id)) {
         this._transactions[type][id].onTransportError();
       }
     }
   }
 
   this.emit('disconnected', data); // Call registrator _onTransportClosed_.
 
   this._registrator.onTransportClosed();
 
   if (this._status !== C.STATUS_USER_CLOSED) {
     this._status = C.STATUS_NOT_READY;
     this._error = C.NETWORK_ERROR;
   }
 } // Transport data event.
 
 
 function onTransportData(data) {
   var transport = data.transport;
   var message = data.message;
   message = Parser.parseMessage(message, this);
 
   if (!message) {
     return;
   }
 
   if (this._status === C.STATUS_USER_CLOSED && message instanceof SIPMessage.IncomingRequest) {
     return;
   } // Do some sanity check.
 
 
   if (!sanityCheck(message, this, transport)) {
     return;
   }
 
   if (message instanceof SIPMessage.IncomingRequest) {
     message.transport = transport;
     this.receiveRequest(message);
   } else if (message instanceof SIPMessage.IncomingResponse) {
     /* Unike stated in 18.1.2, if a response does not match
     * any transaction, it is discarded here and no passed to the core
     * in order to be discarded there.
     */
     var transaction;
 
     switch (message.method) {
       case JsSIP_C.INVITE:
         transaction = this._transactions.ict[message.via_branch];
 
         if (transaction) {
           transaction.receiveResponse(message);
         }
 
         break;
 
       case JsSIP_C.ACK:
         // Just in case ;-).
         break;
 
       default:
         transaction = this._transactions.nict[message.via_branch];
 
         if (transaction) {
           transaction.receiveResponse(message);
         }
 
         break;
     }
   }
 }
 },{"./Config":1,"./Constants":2,"./Exceptions":6,"./Message":9,"./Parser":11,"./RTCSession":12,"./Registrator":17,"./SIPMessage":19,"./Transactions":22,"./Transport":23,"./URI":25,"./Utils":26,"./sanityCheck":28,"debug":30,"events":29}],25:[function(require,module,exports){
 "use strict";
 
 function _createForOfIteratorHelper(o, allowArrayLike) { var it; if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
 
 function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
 
 function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
 
 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
 function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
 
 function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
 
 var JsSIP_C = require('./Constants');
 
 var Utils = require('./Utils');
 
 var Grammar = require('./Grammar');
 /**
  * -param {String} [scheme]
  * -param {String} [user]
  * -param {String} host
  * -param {String} [port]
  * -param {Object} [parameters]
  * -param {Object} [headers]
  *
  */
 
 
 module.exports = /*#__PURE__*/function () {
   _createClass(URI, null, [{
     key: "parse",
 
     /**
       * Parse the given string and returns a JsSIP.URI instance or undefined if
       * it is an invalid URI.
       */
     value: function parse(uri) {
       uri = Grammar.parse(uri, 'SIP_URI');
 
       if (uri !== -1) {
         return uri;
       } else {
         return undefined;
       }
     }
   }]);
 
   function URI(scheme, user, host, port) {
     var parameters = arguments.length > 4 && arguments[4] !== undefined ? arguments[4] : {};
     var headers = arguments.length > 5 && arguments[5] !== undefined ? arguments[5] : {};
 
     _classCallCheck(this, URI);
 
     // Checks.
     if (!host) {
       throw new TypeError('missing or invalid "host" parameter');
     } // Initialize parameters.
 
 
     this._parameters = {};
     this._headers = {};
     this._scheme = scheme || JsSIP_C.SIP;
     this._user = user;
     this._host = host;
     this._port = port;
 
     for (var param in parameters) {
       if (Object.prototype.hasOwnProperty.call(parameters, param)) {
         this.setParam(param, parameters[param]);
       }
     }
 
     for (var header in headers) {
       if (Object.prototype.hasOwnProperty.call(headers, header)) {
         this.setHeader(header, headers[header]);
       }
     }
   }
 
   _createClass(URI, [{
     key: "setParam",
     value: function setParam(key, value) {
       if (key) {
         this._parameters[key.toLowerCase()] = typeof value === 'undefined' || value === null ? null : value.toString();
       }
     }
   }, {
     key: "getParam",
     value: function getParam(key) {
       if (key) {
         return this._parameters[key.toLowerCase()];
       }
     }
   }, {
     key: "hasParam",
     value: function hasParam(key) {
       if (key) {
         return this._parameters.hasOwnProperty(key.toLowerCase()) && true || false;
       }
     }
   }, {
     key: "deleteParam",
     value: function deleteParam(parameter) {
       parameter = parameter.toLowerCase();
 
       if (this._parameters.hasOwnProperty(parameter)) {
         var value = this._parameters[parameter];
         delete this._parameters[parameter];
         return value;
       }
     }
   }, {
     key: "clearParams",
     value: function clearParams() {
       this._parameters = {};
     }
   }, {
     key: "setHeader",
     value: function setHeader(name, value) {
       this._headers[Utils.headerize(name)] = Array.isArray(value) ? value : [value];
     }
   }, {
     key: "getHeader",
     value: function getHeader(name) {
       if (name) {
         return this._headers[Utils.headerize(name)];
       }
     }
   }, {
     key: "hasHeader",
     value: function hasHeader(name) {
       if (name) {
         return this._headers.hasOwnProperty(Utils.headerize(name)) && true || false;
       }
     }
   }, {
     key: "deleteHeader",
     value: function deleteHeader(header) {
       header = Utils.headerize(header);
 
       if (this._headers.hasOwnProperty(header)) {
         var value = this._headers[header];
         delete this._headers[header];
         return value;
       }
     }
   }, {
     key: "clearHeaders",
     value: function clearHeaders() {
       this._headers = {};
     }
   }, {
     key: "clone",
     value: function clone() {
       return new URI(this._scheme, this._user, this._host, this._port, JSON.parse(JSON.stringify(this._parameters)), JSON.parse(JSON.stringify(this._headers)));
     }
   }, {
     key: "toString",
     value: function toString() {
       var headers = [];
       var uri = "".concat(this._scheme, ":");
 
       if (this._user) {
         uri += "".concat(Utils.escapeUser(this._user), "@");
       }
 
       uri += this._host;
 
       if (this._port || this._port === 0) {
         uri += ":".concat(this._port);
       }
 
       for (var parameter in this._parameters) {
         if (Object.prototype.hasOwnProperty.call(this._parameters, parameter)) {
           uri += ";".concat(parameter);
 
           if (this._parameters[parameter] !== null) {
             uri += "=".concat(this._parameters[parameter]);
           }
         }
       }
 
       for (var header in this._headers) {
         if (Object.prototype.hasOwnProperty.call(this._headers, header)) {
           var _iterator = _createForOfIteratorHelper(this._headers[header]),
               _step;
 
           try {
             for (_iterator.s(); !(_step = _iterator.n()).done;) {
               var item = _step.value;
               headers.push("".concat(header, "=").concat(item));
             }
           } catch (err) {
             _iterator.e(err);
           } finally {
             _iterator.f();
           }
         }
       }
 
       if (headers.length > 0) {
         uri += "?".concat(headers.join('&'));
       }
 
       return uri;
     }
   }, {
     key: "toAor",
     value: function toAor(show_port) {
       var aor = "".concat(this._scheme, ":");
 
       if (this._user) {
         aor += "".concat(Utils.escapeUser(this._user), "@");
       }
 
       aor += this._host;
 
       if (show_port && (this._port || this._port === 0)) {
         aor += ":".concat(this._port);
       }
 
       return aor;
     }
   }, {
     key: "scheme",
     get: function get() {
       return this._scheme;
     },
     set: function set(value) {
       this._scheme = value.toLowerCase();
     }
   }, {
     key: "user",
     get: function get() {
       return this._user;
     },
     set: function set(value) {
       this._user = value;
     }
   }, {
     key: "host",
     get: function get() {
       return this._host;
     },
     set: function set(value) {
       this._host = value.toLowerCase();
     }
   }, {
     key: "port",
     get: function get() {
       return this._port;
     },
     set: function set(value) {
       this._port = value === 0 ? value : parseInt(value, 10) || null;
     }
   }]);
 
   return URI;
 }();
 },{"./Constants":2,"./Grammar":7,"./Utils":26}],26:[function(require,module,exports){
 "use strict";
 
 function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
 
 function _createForOfIteratorHelper(o, allowArrayLike) { var it; if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
 
 function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
 
 function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
 
 var JsSIP_C = require('./Constants');
 
 var URI = require('./URI');
 
 var Grammar = require('./Grammar');
 
 exports.str_utf8_length = function (string) {
   return unescape(encodeURIComponent(string)).length;
 }; // Used by 'hasMethods'.
 
 
 var isFunction = exports.isFunction = function (fn) {
   if (fn !== undefined) {
     return Object.prototype.toString.call(fn) === '[object Function]' ? true : false;
   } else {
     return false;
   }
 };
 
 exports.isString = function (str) {
   if (str !== undefined) {
     return Object.prototype.toString.call(str) === '[object String]' ? true : false;
   } else {
     return false;
   }
 };
 
 exports.isDecimal = function (num) {
   return !isNaN(num) && parseFloat(num) === parseInt(num, 10);
 };
 
 exports.isEmpty = function (value) {
   return value === null || value === '' || value === undefined || Array.isArray(value) && value.length === 0 || typeof value === 'number' && isNaN(value);
 };
 
 exports.hasMethods = function (obj) {
   for (var _len = arguments.length, methodNames = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
     methodNames[_key - 1] = arguments[_key];
   }
 
   for (var _i = 0, _methodNames = methodNames; _i < _methodNames.length; _i++) {
     var methodName = _methodNames[_i];
 
     if (isFunction(obj[methodName])) {
       return false;
     }
   }
 
   return true;
 }; // Used by 'newTag'.
 
 
 var createRandomToken = exports.createRandomToken = function (size) {
   var base = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 32;
   var i,
       r,
       token = '';
 
   for (i = 0; i < size; i++) {
     r = Math.random() * base | 0;
     token += r.toString(base);
   }
 
   return token;
 };
 
 exports.newTag = function () {
   return createRandomToken(10);
 }; // https://stackoverflow.com/users/109538/broofa.
 
 
 exports.newUUID = function () {
   var UUID = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
     var r = Math.random() * 16 | 0,
         v = c === 'x' ? r : r & 0x3 | 0x8;
     return v.toString(16);
   });
   return UUID;
 };
 
 exports.hostType = function (host) {
   if (!host) {
     return;
   } else {
     host = Grammar.parse(host, 'host');
 
     if (host !== -1) {
       return host.host_type;
     }
   }
 };
 /**
 * Hex-escape a SIP URI user.
 * Don't hex-escape ':' (%3A), '+' (%2B), '?' (%3F"), '/' (%2F).
 *
 * Used by 'normalizeTarget'.
 */
 
 
 var escapeUser = exports.escapeUser = function (user) {
   return encodeURIComponent(decodeURIComponent(user)).replace(/%3A/ig, ':').replace(/%2B/ig, '+').replace(/%3F/ig, '?').replace(/%2F/ig, '/');
 };
 /**
 * Normalize SIP URI.
 * NOTE: It does not allow a SIP URI without username.
 * Accepts 'sip', 'sips' and 'tel' URIs and convert them into 'sip'.
 * Detects the domain part (if given) and properly hex-escapes the user portion.
 * If the user portion has only 'tel' number symbols the user portion is clean of 'tel' visual separators.
 */
 
 
 exports.normalizeTarget = function (target, domain) {
   // If no target is given then raise an error.
   if (!target) {
     return; // If a URI instance is given then return it.
   } else if (target instanceof URI) {
     return target; // If a string is given split it by '@':
     // - Last fragment is the desired domain.
     // - Otherwise append the given domain argument.
   } else if (typeof target === 'string') {
     var target_array = target.split('@');
     var target_user;
     var target_domain;
 
     switch (target_array.length) {
       case 1:
         if (!domain) {
           return;
         }
 
         target_user = target;
         target_domain = domain;
         break;
 
       case 2:
         target_user = target_array[0];
         target_domain = target_array[1];
         break;
 
       default:
         target_user = target_array.slice(0, target_array.length - 1).join('@');
         target_domain = target_array[target_array.length - 1];
     } // Remove the URI scheme (if present).
 
 
     target_user = target_user.replace(/^(sips?|tel):/i, ''); // Remove 'tel' visual separators if the user portion just contains 'tel' number symbols.
 
     if (/^[-.()]*\+?[0-9\-.()]+$/.test(target_user)) {
       target_user = target_user.replace(/[-.()]/g, '');
     } // Build the complete SIP URI.
 
 
     target = "".concat(JsSIP_C.SIP, ":").concat(escapeUser(target_user), "@").concat(target_domain); // Finally parse the resulting URI.
 
     var uri;
 
     if (uri = URI.parse(target)) {
       return uri;
     } else {
       return;
     }
   } else {
     return;
   }
 };
 
 exports.headerize = function (string) {
   var exceptions = {
     'Call-Id': 'Call-ID',
     'Cseq': 'CSeq',
     'Www-Authenticate': 'WWW-Authenticate'
   };
   var name = string.toLowerCase().replace(/_/g, '-').split('-');
   var hname = '';
   var parts = name.length;
   var part;
 
   for (part = 0; part < parts; part++) {
     if (part !== 0) {
       hname += '-';
     }
 
     hname += name[part].charAt(0).toUpperCase() + name[part].substring(1);
   }
 
   if (exceptions[hname]) {
     hname = exceptions[hname];
   }
 
   return hname;
 };
 
 exports.sipErrorCause = function (status_code) {
   for (var cause in JsSIP_C.SIP_ERROR_CAUSES) {
     if (JsSIP_C.SIP_ERROR_CAUSES[cause].indexOf(status_code) !== -1) {
       return JsSIP_C.causes[cause];
     }
   }
 
   return JsSIP_C.causes.SIP_FAILURE_CODE;
 };
 /**
 * Generate a random Test-Net IP (https://tools.ietf.org/html/rfc5735)
 */
 
 
 exports.getRandomTestNetIP = function () {
   function getOctet(from, to) {
     return Math.floor(Math.random() * (to - from + 1) + from);
   }
 
   return "192.0.2.".concat(getOctet(1, 254));
 }; // MD5 (Message-Digest Algorithm) https://www.webtoolkit.info.
 
 
 exports.calculateMD5 = function (string) {
   function rotateLeft(lValue, iShiftBits) {
     return lValue << iShiftBits | lValue >>> 32 - iShiftBits;
   }
 
   function addUnsigned(lX, lY) {
     var lX8 = lX & 0x80000000;
     var lY8 = lY & 0x80000000;
     var lX4 = lX & 0x40000000;
     var lY4 = lY & 0x40000000;
     var lResult = (lX & 0x3FFFFFFF) + (lY & 0x3FFFFFFF);
 
     if (lX4 & lY4) {
       return lResult ^ 0x80000000 ^ lX8 ^ lY8;
     }
 
     if (lX4 | lY4) {
       if (lResult & 0x40000000) {
         return lResult ^ 0xC0000000 ^ lX8 ^ lY8;
       } else {
         return lResult ^ 0x40000000 ^ lX8 ^ lY8;
       }
     } else {
       return lResult ^ lX8 ^ lY8;
     }
   }
 
   function doF(x, y, z) {
     return x & y | ~x & z;
   }
 
   function doG(x, y, z) {
     return x & z | y & ~z;
   }
 
   function doH(x, y, z) {
     return x ^ y ^ z;
   }
 
   function doI(x, y, z) {
     return y ^ (x | ~z);
   }
 
   function doFF(a, b, c, d, x, s, ac) {
     a = addUnsigned(a, addUnsigned(addUnsigned(doF(b, c, d), x), ac));
     return addUnsigned(rotateLeft(a, s), b);
   }
 
   function doGG(a, b, c, d, x, s, ac) {
     a = addUnsigned(a, addUnsigned(addUnsigned(doG(b, c, d), x), ac));
     return addUnsigned(rotateLeft(a, s), b);
   }
 
   function doHH(a, b, c, d, x, s, ac) {
     a = addUnsigned(a, addUnsigned(addUnsigned(doH(b, c, d), x), ac));
     return addUnsigned(rotateLeft(a, s), b);
   }
 
   function doII(a, b, c, d, x, s, ac) {
     a = addUnsigned(a, addUnsigned(addUnsigned(doI(b, c, d), x), ac));
     return addUnsigned(rotateLeft(a, s), b);
   }
 
   function convertToWordArray(str) {
     var lWordCount;
     var lMessageLength = str.length;
     var lNumberOfWords_temp1 = lMessageLength + 8;
     var lNumberOfWords_temp2 = (lNumberOfWords_temp1 - lNumberOfWords_temp1 % 64) / 64;
     var lNumberOfWords = (lNumberOfWords_temp2 + 1) * 16;
     var lWordArray = new Array(lNumberOfWords - 1);
     var lBytePosition = 0;
     var lByteCount = 0;
 
     while (lByteCount < lMessageLength) {
       lWordCount = (lByteCount - lByteCount % 4) / 4;
       lBytePosition = lByteCount % 4 * 8;
       lWordArray[lWordCount] = lWordArray[lWordCount] | str.charCodeAt(lByteCount) << lBytePosition;
       lByteCount++;
     }
 
     lWordCount = (lByteCount - lByteCount % 4) / 4;
     lBytePosition = lByteCount % 4 * 8;
     lWordArray[lWordCount] = lWordArray[lWordCount] | 0x80 << lBytePosition;
     lWordArray[lNumberOfWords - 2] = lMessageLength << 3;
     lWordArray[lNumberOfWords - 1] = lMessageLength >>> 29;
     return lWordArray;
   }
 
   function wordToHex(lValue) {
     var wordToHexValue = '',
         wordToHexValue_temp = '',
         lByte,
         lCount;
 
     for (lCount = 0; lCount <= 3; lCount++) {
       lByte = lValue >>> lCount * 8 & 255;
       wordToHexValue_temp = "0".concat(lByte.toString(16));
       wordToHexValue = wordToHexValue + wordToHexValue_temp.substr(wordToHexValue_temp.length - 2, 2);
     }
 
     return wordToHexValue;
   }
 
   function utf8Encode(str) {
     str = str.replace(/\r\n/g, '\n');
     var utftext = '';
 
     for (var n = 0; n < str.length; n++) {
       var _c = str.charCodeAt(n);
 
       if (_c < 128) {
         utftext += String.fromCharCode(_c);
       } else if (_c > 127 && _c < 2048) {
         utftext += String.fromCharCode(_c >> 6 | 192);
         utftext += String.fromCharCode(_c & 63 | 128);
       } else {
         utftext += String.fromCharCode(_c >> 12 | 224);
         utftext += String.fromCharCode(_c >> 6 & 63 | 128);
         utftext += String.fromCharCode(_c & 63 | 128);
       }
     }
 
     return utftext;
   }
 
   var x = [];
   var k, AA, BB, CC, DD, a, b, c, d;
   var S11 = 7,
       S12 = 12,
       S13 = 17,
       S14 = 22;
   var S21 = 5,
       S22 = 9,
       S23 = 14,
       S24 = 20;
   var S31 = 4,
       S32 = 11,
       S33 = 16,
       S34 = 23;
   var S41 = 6,
       S42 = 10,
       S43 = 15,
       S44 = 21;
   string = utf8Encode(string);
   x = convertToWordArray(string);
   a = 0x67452301;
   b = 0xEFCDAB89;
   c = 0x98BADCFE;
   d = 0x10325476;
 
   for (k = 0; k < x.length; k += 16) {
     AA = a;
     BB = b;
     CC = c;
     DD = d;
     a = doFF(a, b, c, d, x[k + 0], S11, 0xD76AA478);
     d = doFF(d, a, b, c, x[k + 1], S12, 0xE8C7B756);
     c = doFF(c, d, a, b, x[k + 2], S13, 0x242070DB);
     b = doFF(b, c, d, a, x[k + 3], S14, 0xC1BDCEEE);
     a = doFF(a, b, c, d, x[k + 4], S11, 0xF57C0FAF);
     d = doFF(d, a, b, c, x[k + 5], S12, 0x4787C62A);
     c = doFF(c, d, a, b, x[k + 6], S13, 0xA8304613);
     b = doFF(b, c, d, a, x[k + 7], S14, 0xFD469501);
     a = doFF(a, b, c, d, x[k + 8], S11, 0x698098D8);
     d = doFF(d, a, b, c, x[k + 9], S12, 0x8B44F7AF);
     c = doFF(c, d, a, b, x[k + 10], S13, 0xFFFF5BB1);
     b = doFF(b, c, d, a, x[k + 11], S14, 0x895CD7BE);
     a = doFF(a, b, c, d, x[k + 12], S11, 0x6B901122);
     d = doFF(d, a, b, c, x[k + 13], S12, 0xFD987193);
     c = doFF(c, d, a, b, x[k + 14], S13, 0xA679438E);
     b = doFF(b, c, d, a, x[k + 15], S14, 0x49B40821);
     a = doGG(a, b, c, d, x[k + 1], S21, 0xF61E2562);
     d = doGG(d, a, b, c, x[k + 6], S22, 0xC040B340);
     c = doGG(c, d, a, b, x[k + 11], S23, 0x265E5A51);
     b = doGG(b, c, d, a, x[k + 0], S24, 0xE9B6C7AA);
     a = doGG(a, b, c, d, x[k + 5], S21, 0xD62F105D);
     d = doGG(d, a, b, c, x[k + 10], S22, 0x2441453);
     c = doGG(c, d, a, b, x[k + 15], S23, 0xD8A1E681);
     b = doGG(b, c, d, a, x[k + 4], S24, 0xE7D3FBC8);
     a = doGG(a, b, c, d, x[k + 9], S21, 0x21E1CDE6);
     d = doGG(d, a, b, c, x[k + 14], S22, 0xC33707D6);
     c = doGG(c, d, a, b, x[k + 3], S23, 0xF4D50D87);
     b = doGG(b, c, d, a, x[k + 8], S24, 0x455A14ED);
     a = doGG(a, b, c, d, x[k + 13], S21, 0xA9E3E905);
     d = doGG(d, a, b, c, x[k + 2], S22, 0xFCEFA3F8);
     c = doGG(c, d, a, b, x[k + 7], S23, 0x676F02D9);
     b = doGG(b, c, d, a, x[k + 12], S24, 0x8D2A4C8A);
     a = doHH(a, b, c, d, x[k + 5], S31, 0xFFFA3942);
     d = doHH(d, a, b, c, x[k + 8], S32, 0x8771F681);
     c = doHH(c, d, a, b, x[k + 11], S33, 0x6D9D6122);
     b = doHH(b, c, d, a, x[k + 14], S34, 0xFDE5380C);
     a = doHH(a, b, c, d, x[k + 1], S31, 0xA4BEEA44);
     d = doHH(d, a, b, c, x[k + 4], S32, 0x4BDECFA9);
     c = doHH(c, d, a, b, x[k + 7], S33, 0xF6BB4B60);
     b = doHH(b, c, d, a, x[k + 10], S34, 0xBEBFBC70);
     a = doHH(a, b, c, d, x[k + 13], S31, 0x289B7EC6);
     d = doHH(d, a, b, c, x[k + 0], S32, 0xEAA127FA);
     c = doHH(c, d, a, b, x[k + 3], S33, 0xD4EF3085);
     b = doHH(b, c, d, a, x[k + 6], S34, 0x4881D05);
     a = doHH(a, b, c, d, x[k + 9], S31, 0xD9D4D039);
     d = doHH(d, a, b, c, x[k + 12], S32, 0xE6DB99E5);
     c = doHH(c, d, a, b, x[k + 15], S33, 0x1FA27CF8);
     b = doHH(b, c, d, a, x[k + 2], S34, 0xC4AC5665);
     a = doII(a, b, c, d, x[k + 0], S41, 0xF4292244);
     d = doII(d, a, b, c, x[k + 7], S42, 0x432AFF97);
     c = doII(c, d, a, b, x[k + 14], S43, 0xAB9423A7);
     b = doII(b, c, d, a, x[k + 5], S44, 0xFC93A039);
     a = doII(a, b, c, d, x[k + 12], S41, 0x655B59C3);
     d = doII(d, a, b, c, x[k + 3], S42, 0x8F0CCC92);
     c = doII(c, d, a, b, x[k + 10], S43, 0xFFEFF47D);
     b = doII(b, c, d, a, x[k + 1], S44, 0x85845DD1);
     a = doII(a, b, c, d, x[k + 8], S41, 0x6FA87E4F);
     d = doII(d, a, b, c, x[k + 15], S42, 0xFE2CE6E0);
     c = doII(c, d, a, b, x[k + 6], S43, 0xA3014314);
     b = doII(b, c, d, a, x[k + 13], S44, 0x4E0811A1);
     a = doII(a, b, c, d, x[k + 4], S41, 0xF7537E82);
     d = doII(d, a, b, c, x[k + 11], S42, 0xBD3AF235);
     c = doII(c, d, a, b, x[k + 2], S43, 0x2AD7D2BB);
     b = doII(b, c, d, a, x[k + 9], S44, 0xEB86D391);
     a = addUnsigned(a, AA);
     b = addUnsigned(b, BB);
     c = addUnsigned(c, CC);
     d = addUnsigned(d, DD);
   }
 
   var temp = wordToHex(a) + wordToHex(b) + wordToHex(c) + wordToHex(d);
   return temp.toLowerCase();
 };
 
 exports.closeMediaStream = function (stream) {
   if (!stream) {
     return;
   } // Latest spec states that MediaStream has no stop() method and instead must
   // call stop() on every MediaStreamTrack.
 
 
   try {
     var tracks;
 
     if (stream.getTracks) {
       tracks = stream.getTracks();
 
       var _iterator = _createForOfIteratorHelper(tracks),
           _step;
 
       try {
         for (_iterator.s(); !(_step = _iterator.n()).done;) {
           var track = _step.value;
           track.stop();
         }
       } catch (err) {
         _iterator.e(err);
       } finally {
         _iterator.f();
       }
     } else {
       tracks = stream.getAudioTracks();
 
       var _iterator2 = _createForOfIteratorHelper(tracks),
           _step2;
 
       try {
         for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
           var _track = _step2.value;
 
           _track.stop();
         }
       } catch (err) {
         _iterator2.e(err);
       } finally {
         _iterator2.f();
       }
 
       tracks = stream.getVideoTracks();
 
       var _iterator3 = _createForOfIteratorHelper(tracks),
           _step3;
 
       try {
         for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
           var _track2 = _step3.value;
 
           _track2.stop();
         }
       } catch (err) {
         _iterator3.e(err);
       } finally {
         _iterator3.f();
       }
     }
   } catch (error) {
     // Deprecated by the spec, but still in use.
     // NOTE: In Temasys IE plugin stream.stop is a callable 'object'.
     if (typeof stream.stop === 'function' || _typeof(stream.stop) === 'object') {
       stream.stop();
     }
   }
 };
 
 exports.cloneArray = function (array) {
   return array && array.slice() || [];
 };
 
 exports.cloneObject = function (obj) {
   var fallback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
   return obj && Object.assign({}, obj) || fallback;
 };
 },{"./Constants":2,"./Grammar":7,"./URI":25}],27:[function(require,module,exports){
 "use strict";
 
 function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
 
 function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
 
 function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
 
 var Grammar = require('./Grammar');
 
 var debug = require('debug')('JsSIP:WebSocketInterface');
 
 var debugerror = require('debug')('JsSIP:ERROR:WebSocketInterface');
 
 debugerror.log = console.warn.bind(console);
 
 module.exports = /*#__PURE__*/function () {
   function WebSocketInterface(url) {
     _classCallCheck(this, WebSocketInterface);
 
     debug('new() [url:"%s"]', url);
     this._url = url;
     this._sip_uri = null;
     this._via_transport = null;
     this._ws = null;
     var parsed_url = Grammar.parse(url, 'absoluteURI');
 
     if (parsed_url === -1) {
       debugerror("invalid WebSocket URI: ".concat(url));
       throw new TypeError("Invalid argument: ".concat(url));
     } else if (parsed_url.scheme !== 'wss' && parsed_url.scheme !== 'ws') {
       debugerror("invalid WebSocket URI scheme: ".concat(parsed_url.scheme));
       throw new TypeError("Invalid argument: ".concat(url));
     } else {
       this._sip_uri = "sip:".concat(parsed_url.host).concat(parsed_url.port ? ":".concat(parsed_url.port) : '', ";transport=ws");
       this._via_transport = parsed_url.scheme.toUpperCase();
     }
   }
 
   _createClass(WebSocketInterface, [{
     key: "connect",
     value: function connect() {
       debug('connect()');
 
       if (this.isConnected()) {
         debug("WebSocket ".concat(this._url, " is already connected"));
         return;
       } else if (this.isConnecting()) {
         debug("WebSocket ".concat(this._url, " is connecting"));
         return;
       }
 
       if (this._ws) {
         this.disconnect();
       }
 
       debug("connecting to WebSocket ".concat(this._url));
 
       try {
         this._ws = new WebSocket(this._url, 'sip');
         this._ws.binaryType = 'arraybuffer';
         this._ws.onopen = this._onOpen.bind(this);
         this._ws.onclose = this._onClose.bind(this);
         this._ws.onmessage = this._onMessage.bind(this);
         this._ws.onerror = this._onError.bind(this);
       } catch (e) {
         this._onError(e);
       }
     }
   }, {
     key: "disconnect",
     value: function disconnect() {
       debug('disconnect()');
 
       if (this._ws) {
         // Unbind websocket event callbacks.
         this._ws.onopen = function () {};
 
         this._ws.onclose = function () {};
 
         this._ws.onmessage = function () {};
 
         this._ws.onerror = function () {};
 
         this._ws.close();
 
         this._ws = null;
       }
     }
   }, {
     key: "send",
     value: function send(message) {
       debug('send()');
 
       if (this.isConnected()) {
         this._ws.send(message);
 
         return true;
       } else {
         debugerror('unable to send message, WebSocket is not open');
         return false;
       }
     }
   }, {
     key: "isConnected",
     value: function isConnected() {
       return this._ws && this._ws.readyState === this._ws.OPEN;
     }
   }, {
     key: "isConnecting",
     value: function isConnecting() {
       return this._ws && this._ws.readyState === this._ws.CONNECTING;
     }
     /**
      * WebSocket Event Handlers
      */
 
   }, {
     key: "_onOpen",
     value: function _onOpen() {
       debug("WebSocket ".concat(this._url, " connected"));
       this.onconnect();
     }
   }, {
     key: "_onClose",
     value: function _onClose(_ref) {
       var wasClean = _ref.wasClean,
           code = _ref.code,
           reason = _ref.reason;
       debug("WebSocket ".concat(this._url, " closed"));
 
       if (wasClean === false) {
         debug('WebSocket abrupt disconnection');
       }
 
       var data = {
         socket: this,
         error: !wasClean,
         code: code,
         reason: reason
       };
       this.ondisconnect(data);
     }
   }, {
     key: "_onMessage",
     value: function _onMessage(_ref2) {
       var data = _ref2.data;
       debug('received WebSocket message');
       this.ondata(data);
     }
   }, {
     key: "_onError",
     value: function _onError(e) {
       debugerror("WebSocket ".concat(this._url, " error: ").concat(e));
     }
   }, {
     key: "via_transport",
     get: function get() {
       return this._via_transport;
     },
     set: function set(value) {
       this._via_transport = value.toUpperCase();
     }
   }, {
     key: "sip_uri",
     get: function get() {
       return this._sip_uri;
     }
   }, {
     key: "url",
     get: function get() {
       return this._url;
     }
   }]);
 
   return WebSocketInterface;
 }();
 },{"./Grammar":7,"debug":30}],28:[function(require,module,exports){
 "use strict";
 
 function _createForOfIteratorHelper(o, allowArrayLike) { var it; if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
 
 function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
 
 function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
 
 var JsSIP_C = require('./Constants');
 
 var SIPMessage = require('./SIPMessage');
 
 var Utils = require('./Utils');
 
 var debug = require('debug')('JsSIP:sanityCheck'); // Checks for requests and responses.
 
 
 var all = [minimumHeaders]; // Checks for requests.
 
 var requests = [rfc3261_8_2_2_1, rfc3261_16_3_4, rfc3261_18_3_request, rfc3261_8_2_2_2]; // Checks for responses.
 
 var responses = [rfc3261_8_1_3_3, rfc3261_18_3_response]; // local variables.
 
 var message;
 var ua;
 var transport;
 
 module.exports = function (m, u, t) {
   message = m;
   ua = u;
   transport = t;
 
   var _iterator = _createForOfIteratorHelper(all),
       _step;
 
   try {
     for (_iterator.s(); !(_step = _iterator.n()).done;) {
       var _check2 = _step.value;
 
       if (_check2() === false) {
         return false;
       }
     }
   } catch (err) {
     _iterator.e(err);
   } finally {
     _iterator.f();
   }
 
   if (message instanceof SIPMessage.IncomingRequest) {
     var _iterator2 = _createForOfIteratorHelper(requests),
         _step2;
 
     try {
       for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
         var check = _step2.value;
 
         if (check() === false) {
           return false;
         }
       }
     } catch (err) {
       _iterator2.e(err);
     } finally {
       _iterator2.f();
     }
   } else if (message instanceof SIPMessage.IncomingResponse) {
     var _iterator3 = _createForOfIteratorHelper(responses),
         _step3;
 
     try {
       for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {
         var _check = _step3.value;
 
         if (_check() === false) {
           return false;
         }
       }
     } catch (err) {
       _iterator3.e(err);
     } finally {
       _iterator3.f();
     }
   } // Everything is OK.
 
 
   return true;
 };
 /*
  * Sanity Check for incoming Messages
  *
  * Requests:
  *  - _rfc3261_8_2_2_1_ Receive a Request with a non supported URI scheme
  *  - _rfc3261_16_3_4_ Receive a Request already sent by us
  *   Does not look at via sent-by but at jssip_id, which is inserted as
  *   a prefix in all initial requests generated by the ua
  *  - _rfc3261_18_3_request_ Body Content-Length
  *  - _rfc3261_8_2_2_2_ Merged Requests
  *
  * Responses:
  *  - _rfc3261_8_1_3_3_ Multiple Via headers
  *  - _rfc3261_18_3_response_ Body Content-Length
  *
  * All:
  *  - Minimum headers in a SIP message
  */
 // Sanity Check functions for requests.
 
 
 function rfc3261_8_2_2_1() {
   if (message.s('to').uri.scheme !== 'sip') {
     reply(416);
     return false;
   }
 }
 
 function rfc3261_16_3_4() {
   if (!message.to_tag) {
     if (message.call_id.substr(0, 5) === ua.configuration.jssip_id) {
       reply(482);
       return false;
     }
   }
 }
 
 function rfc3261_18_3_request() {
   var len = Utils.str_utf8_length(message.body);
   var contentLength = message.getHeader('content-length');
 
   if (len < contentLength) {
     reply(400);
     return false;
   }
 }
 
 function rfc3261_8_2_2_2() {
   var fromTag = message.from_tag;
   var call_id = message.call_id;
   var cseq = message.cseq;
   var tr; // Accept any in-dialog request.
 
   if (message.to_tag) {
     return;
   } // INVITE request.
 
 
   if (message.method === JsSIP_C.INVITE) {
     // If the branch matches the key of any IST then assume it is a retransmission
     // and ignore the INVITE.
     // TODO: we should reply the last response.
     if (ua._transactions.ist[message.via_branch]) {
       return false;
     } // Otherwise check whether it is a merged request.
     else {
         for (var transaction in ua._transactions.ist) {
           if (Object.prototype.hasOwnProperty.call(ua._transactions.ist, transaction)) {
             tr = ua._transactions.ist[transaction];
 
             if (tr.request.from_tag === fromTag && tr.request.call_id === call_id && tr.request.cseq === cseq) {
               reply(482);
               return false;
             }
           }
         }
       }
   } // Non INVITE request.
   // If the branch matches the key of any NIST then assume it is a retransmission
   // and ignore the request.
   // TODO: we should reply the last response.
   else if (ua._transactions.nist[message.via_branch]) {
       return false;
     } // Otherwise check whether it is a merged request.
     else {
         for (var _transaction in ua._transactions.nist) {
           if (Object.prototype.hasOwnProperty.call(ua._transactions.nist, _transaction)) {
             tr = ua._transactions.nist[_transaction];
 
             if (tr.request.from_tag === fromTag && tr.request.call_id === call_id && tr.request.cseq === cseq) {
               reply(482);
               return false;
             }
           }
         }
       }
 } // Sanity Check functions for responses.
 
 
 function rfc3261_8_1_3_3() {
   if (message.getHeaders('via').length > 1) {
     debug('more than one Via header field present in the response, dropping the response');
     return false;
   }
 }
 
 function rfc3261_18_3_response() {
   var len = Utils.str_utf8_length(message.body),
       contentLength = message.getHeader('content-length');
 
   if (len < contentLength) {
     debug('message body length is lower than the value in Content-Length header field, dropping the response');
     return false;
   }
 } // Sanity Check functions for requests and responses.
 
 
 function minimumHeaders() {
   var mandatoryHeaders = ['from', 'to', 'call_id', 'cseq', 'via'];
 
   for (var _i = 0, _mandatoryHeaders = mandatoryHeaders; _i < _mandatoryHeaders.length; _i++) {
     var header = _mandatoryHeaders[_i];
 
     if (!message.hasHeader(header)) {
       debug("missing mandatory header field : ".concat(header, ", dropping the response"));
       return false;
     }
   }
 } // Reply.
 
 
 function reply(status_code) {
   var vias = message.getHeaders('via');
   var to;
   var response = "SIP/2.0 ".concat(status_code, " ").concat(JsSIP_C.REASON_PHRASE[status_code], "\r\n");
 
   var _iterator4 = _createForOfIteratorHelper(vias),
       _step4;
 
   try {
     for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {
       var via = _step4.value;
       response += "Via: ".concat(via, "\r\n");
     }
   } catch (err) {
     _iterator4.e(err);
   } finally {
     _iterator4.f();
   }
 
   to = message.getHeader('To');
 
   if (!message.to_tag) {
     to += ";tag=".concat(Utils.newTag());
   }
 
   response += "To: ".concat(to, "\r\n");
   response += "From: ".concat(message.getHeader('From'), "\r\n");
   response += "Call-ID: ".concat(message.call_id, "\r\n");
   response += "CSeq: ".concat(message.cseq, " ").concat(message.method, "\r\n");
   response += '\r\n';
   transport.send(response);
 }
 },{"./Constants":2,"./SIPMessage":19,"./Utils":26,"debug":30}],29:[function(require,module,exports){
 // Copyright Joyent, Inc. and other Node contributors.
 //
 // Permission is hereby granted, free of charge, to any person obtaining a
 // copy of this software and associated documentation files (the
 // "Software"), to deal in the Software without restriction, including
 // without limitation the rights to use, copy, modify, merge, publish,
 // distribute, sublicense, and/or sell copies of the Software, and to permit
 // persons to whom the Software is furnished to do so, subject to the
 // following conditions:
 //
 // The above copyright notice and this permission notice shall be included
 // in all copies or substantial portions of the Software.
 //
 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
 // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
 // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
 // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
 // USE OR OTHER DEALINGS IN THE SOFTWARE.
 
 var objectCreate = Object.create || objectCreatePolyfill
 var objectKeys = Object.keys || objectKeysPolyfill
 var bind = Function.prototype.bind || functionBindPolyfill
 
 function EventEmitter() {
   if (!this._events || !Object.prototype.hasOwnProperty.call(this, '_events')) {
     this._events = objectCreate(null);
     this._eventsCount = 0;
   }
 
   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.
 var defaultMaxListeners = 10;
 
 var hasDefineProperty;
 try {
   var o = {};
   if (Object.defineProperty) Object.defineProperty(o, 'x', { value: 0 });
   hasDefineProperty = o.x === 0;
 } catch (err) { hasDefineProperty = false }
 if (hasDefineProperty) {
   Object.defineProperty(EventEmitter, 'defaultMaxListeners', {
     enumerable: true,
     get: function() {
       return defaultMaxListeners;
     },
     set: function(arg) {
       // check whether the input is a positive number (whose value is zero or
       // greater and not a NaN).
       if (typeof arg !== 'number' || arg < 0 || arg !== arg)
         throw new TypeError('"defaultMaxListeners" must be a positive number');
       defaultMaxListeners = arg;
     }
   });
 } else {
   EventEmitter.defaultMaxListeners = defaultMaxListeners;
 }
 
 // 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 setMaxListeners(n) {
   if (typeof n !== 'number' || n < 0 || isNaN(n))
     throw new TypeError('"n" argument must be a positive number');
   this._maxListeners = n;
   return this;
 };
 
 function $getMaxListeners(that) {
   if (that._maxListeners === undefined)
     return EventEmitter.defaultMaxListeners;
   return that._maxListeners;
 }
 
 EventEmitter.prototype.getMaxListeners = function getMaxListeners() {
   return $getMaxListeners(this);
 };
 
 // These standalone emit* functions are used to optimize calling of event
 // handlers for fast cases because emit() itself often has a variable number of
 // arguments and can be deoptimized because of that. These functions always have
 // the same number of arguments and thus do not get deoptimized, so the code
 // inside them can execute faster.
 function emitNone(handler, isFn, self) {
   if (isFn)
     handler.call(self);
   else {
     var len = handler.length;
     var listeners = arrayClone(handler, len);
     for (var i = 0; i < len; ++i)
       listeners[i].call(self);
   }
 }
 function emitOne(handler, isFn, self, arg1) {
   if (isFn)
     handler.call(self, arg1);
   else {
     var len = handler.length;
     var listeners = arrayClone(handler, len);
     for (var i = 0; i < len; ++i)
       listeners[i].call(self, arg1);
   }
 }
 function emitTwo(handler, isFn, self, arg1, arg2) {
   if (isFn)
     handler.call(self, arg1, arg2);
   else {
     var len = handler.length;
     var listeners = arrayClone(handler, len);
     for (var i = 0; i < len; ++i)
       listeners[i].call(self, arg1, arg2);
   }
 }
 function emitThree(handler, isFn, self, arg1, arg2, arg3) {
   if (isFn)
     handler.call(self, arg1, arg2, arg3);
   else {
     var len = handler.length;
     var listeners = arrayClone(handler, len);
     for (var i = 0; i < len; ++i)
       listeners[i].call(self, arg1, arg2, arg3);
   }
 }
 
 function emitMany(handler, isFn, self, args) {
   if (isFn)
     handler.apply(self, args);
   else {
     var len = handler.length;
     var listeners = arrayClone(handler, len);
     for (var i = 0; i < len; ++i)
       listeners[i].apply(self, args);
   }
 }
 
 EventEmitter.prototype.emit = function emit(type) {
   var er, handler, len, args, i, events;
   var doError = (type === 'error');
 
   events = this._events;
   if (events)
     doError = (doError && events.error == null);
   else if (!doError)
     return false;
 
   // If there is no 'error' event listener then throw.
   if (doError) {
     if (arguments.length > 1)
       er = arguments[1];
     if (er instanceof Error) {
       throw er; // Unhandled 'error' event
     } else {
       // At least give some kind of context to the user
       var err = new Error('Unhandled "error" event. (' + er + ')');
       err.context = er;
       throw err;
     }
     return false;
   }
 
   handler = events[type];
 
   if (!handler)
     return false;
 
   var isFn = typeof handler === 'function';
   len = arguments.length;
   switch (len) {
       // fast cases
     case 1:
       emitNone(handler, isFn, this);
       break;
     case 2:
       emitOne(handler, isFn, this, arguments[1]);
       break;
     case 3:
       emitTwo(handler, isFn, this, arguments[1], arguments[2]);
       break;
     case 4:
       emitThree(handler, isFn, this, arguments[1], arguments[2], arguments[3]);
       break;
       // slower
     default:
       args = new Array(len - 1);
       for (i = 1; i < len; i++)
         args[i - 1] = arguments[i];
       emitMany(handler, isFn, this, args);
   }
 
   return true;
 };
 
 function _addListener(target, type, listener, prepend) {
   var m;
   var events;
   var existing;
 
   if (typeof listener !== 'function')
     throw new TypeError('"listener" argument must be a function');
 
   events = target._events;
   if (!events) {
     events = target._events = objectCreate(null);
     target._eventsCount = 0;
   } else {
     // To avoid recursion in the case that type === "newListener"! Before
     // adding it to the listeners, first emit "newListener".
     if (events.newListener) {
       target.emit('newListener', type,
           listener.listener ? listener.listener : listener);
 
       // Re-assign `events` because a newListener handler could have caused the
       // this._events to be assigned to a new object
       events = target._events;
     }
     existing = events[type];
   }
 
   if (!existing) {
     // Optimize the case of one listener. Don't need the extra array object.
     existing = events[type] = listener;
     ++target._eventsCount;
   } else {
     if (typeof existing === 'function') {
       // Adding the second element, need to change to array.
       existing = events[type] =
           prepend ? [listener, existing] : [existing, listener];
     } else {
       // If we've already got an array, just append.
       if (prepend) {
         existing.unshift(listener);
       } else {
         existing.push(listener);
       }
     }
 
     // Check for listener leak
     if (!existing.warned) {
       m = $getMaxListeners(target);
       if (m && m > 0 && existing.length > m) {
         existing.warned = true;
         var w = new Error('Possible EventEmitter memory leak detected. ' +
             existing.length + ' "' + String(type) + '" listeners ' +
             'added. Use emitter.setMaxListeners() to ' +
             'increase limit.');
         w.name = 'MaxListenersExceededWarning';
         w.emitter = target;
         w.type = type;
         w.count = existing.length;
         if (typeof console === 'object' && console.warn) {
           console.warn('%s: %s', w.name, w.message);
         }
       }
     }
   }
 
   return target;
 }
 
 EventEmitter.prototype.addListener = function addListener(type, listener) {
   return _addListener(this, type, listener, false);
 };
 
 EventEmitter.prototype.on = EventEmitter.prototype.addListener;
 
 EventEmitter.prototype.prependListener =
     function prependListener(type, listener) {
       return _addListener(this, type, listener, true);
     };
 
 function onceWrapper() {
   if (!this.fired) {
     this.target.removeListener(this.type, this.wrapFn);
     this.fired = true;
     switch (arguments.length) {
       case 0:
         return this.listener.call(this.target);
       case 1:
         return this.listener.call(this.target, arguments[0]);
       case 2:
         return this.listener.call(this.target, arguments[0], arguments[1]);
       case 3:
         return this.listener.call(this.target, arguments[0], arguments[1],
             arguments[2]);
       default:
         var args = new Array(arguments.length);
         for (var i = 0; i < args.length; ++i)
           args[i] = arguments[i];
         this.listener.apply(this.target, args);
     }
   }
 }
 
 function _onceWrap(target, type, listener) {
   var state = { fired: false, wrapFn: undefined, target: target, type: type, listener: listener };
   var wrapped = bind.call(onceWrapper, state);
   wrapped.listener = listener;
   state.wrapFn = wrapped;
   return wrapped;
 }
 
 EventEmitter.prototype.once = function once(type, listener) {
   if (typeof listener !== 'function')
     throw new TypeError('"listener" argument must be a function');
   this.on(type, _onceWrap(this, type, listener));
   return this;
 };
 
 EventEmitter.prototype.prependOnceListener =
     function prependOnceListener(type, listener) {
       if (typeof listener !== 'function')
         throw new TypeError('"listener" argument must be a function');
       this.prependListener(type, _onceWrap(this, type, listener));
       return this;
     };
 
 // Emits a 'removeListener' event if and only if the listener was removed.
 EventEmitter.prototype.removeListener =
     function removeListener(type, listener) {
       var list, events, position, i, originalListener;
 
       if (typeof listener !== 'function')
         throw new TypeError('"listener" argument must be a function');
 
       events = this._events;
       if (!events)
         return this;
 
       list = events[type];
       if (!list)
         return this;
 
       if (list === listener || list.listener === listener) {
         if (--this._eventsCount === 0)
           this._events = objectCreate(null);
         else {
           delete events[type];
           if (events.removeListener)
             this.emit('removeListener', type, list.listener || listener);
         }
       } else if (typeof list !== 'function') {
         position = -1;
 
         for (i = list.length - 1; i >= 0; i--) {
           if (list[i] === listener || list[i].listener === listener) {
             originalListener = list[i].listener;
             position = i;
             break;
           }
         }
 
         if (position < 0)
           return this;
 
         if (position === 0)
           list.shift();
         else
           spliceOne(list, position);
 
         if (list.length === 1)
           events[type] = list[0];
 
         if (events.removeListener)
           this.emit('removeListener', type, originalListener || listener);
       }
 
       return this;
     };
 
 EventEmitter.prototype.removeAllListeners =
     function removeAllListeners(type) {
       var listeners, events, i;
 
       events = this._events;
       if (!events)
         return this;
 
       // not listening for removeListener, no need to emit
       if (!events.removeListener) {
         if (arguments.length === 0) {
           this._events = objectCreate(null);
           this._eventsCount = 0;
         } else if (events[type]) {
           if (--this._eventsCount === 0)
             this._events = objectCreate(null);
           else
             delete events[type];
         }
         return this;
       }
 
       // emit removeListener for all listeners on all events
       if (arguments.length === 0) {
         var keys = objectKeys(events);
         var key;
         for (i = 0; i < keys.length; ++i) {
           key = keys[i];
           if (key === 'removeListener') continue;
           this.removeAllListeners(key);
         }
         this.removeAllListeners('removeListener');
         this._events = objectCreate(null);
         this._eventsCount = 0;
         return this;
       }
 
       listeners = events[type];
 
       if (typeof listeners === 'function') {
         this.removeListener(type, listeners);
       } else if (listeners) {
         // LIFO order
         for (i = listeners.length - 1; i >= 0; i--) {
           this.removeListener(type, listeners[i]);
         }
       }
 
       return this;
     };
 
 function _listeners(target, type, unwrap) {
   var events = target._events;
 
   if (!events)
     return [];
 
   var evlistener = events[type];
   if (!evlistener)
     return [];
 
   if (typeof evlistener === 'function')
     return unwrap ? [evlistener.listener || evlistener] : [evlistener];
 
   return unwrap ? unwrapListeners(evlistener) : arrayClone(evlistener, evlistener.length);
 }
 
 EventEmitter.prototype.listeners = function listeners(type) {
   return _listeners(this, type, true);
 };
 
 EventEmitter.prototype.rawListeners = function rawListeners(type) {
   return _listeners(this, type, false);
 };
 
 EventEmitter.listenerCount = function(emitter, type) {
   if (typeof emitter.listenerCount === 'function') {
     return emitter.listenerCount(type);
   } else {
     return listenerCount.call(emitter, type);
   }
 };
 
 EventEmitter.prototype.listenerCount = listenerCount;
 function listenerCount(type) {
   var events = this._events;
 
   if (events) {
     var evlistener = events[type];
 
     if (typeof evlistener === 'function') {
       return 1;
     } else if (evlistener) {
       return evlistener.length;
     }
   }
 
   return 0;
 }
 
 EventEmitter.prototype.eventNames = function eventNames() {
   return this._eventsCount > 0 ? Reflect.ownKeys(this._events) : [];
 };
 
 // About 1.5x faster than the two-arg version of Array#splice().
 function spliceOne(list, index) {
   for (var i = index, k = i + 1, n = list.length; k < n; i += 1, k += 1)
     list[i] = list[k];
   list.pop();
 }
 
 function arrayClone(arr, n) {
   var copy = new Array(n);
   for (var i = 0; i < n; ++i)
     copy[i] = arr[i];
   return copy;
 }
 
 function unwrapListeners(arr) {
   var ret = new Array(arr.length);
   for (var i = 0; i < ret.length; ++i) {
     ret[i] = arr[i].listener || arr[i];
   }
   return ret;
 }
 
 function objectCreatePolyfill(proto) {
   var F = function() {};
   F.prototype = proto;
   return new F;
 }
 function objectKeysPolyfill(obj) {
   var keys = [];
   for (var k in obj) if (Object.prototype.hasOwnProperty.call(obj, k)) {
     keys.push(k);
   }
   return k;
 }
 function functionBindPolyfill(context) {
   var fn = this;
   return function () {
     return fn.apply(context, arguments);
   };
 }
 
 },{}],30:[function(require,module,exports){
 (function (process){
 /* eslint-env browser */
 
 /**
  * This is the web browser implementation of `debug()`.
  */
 
 exports.log = log;
 exports.formatArgs = formatArgs;
 exports.save = save;
 exports.load = load;
 exports.useColors = useColors;
 exports.storage = localstorage();
 
 /**
  * Colors.
  */
 
 exports.colors = [
 	'#0000CC',
 	'#0000FF',
 	'#0033CC',
 	'#0033FF',
 	'#0066CC',
 	'#0066FF',
 	'#0099CC',
 	'#0099FF',
 	'#00CC00',
 	'#00CC33',
 	'#00CC66',
 	'#00CC99',
 	'#00CCCC',
 	'#00CCFF',
 	'#3300CC',
 	'#3300FF',
 	'#3333CC',
 	'#3333FF',
 	'#3366CC',
 	'#3366FF',
 	'#3399CC',
 	'#3399FF',
 	'#33CC00',
 	'#33CC33',
 	'#33CC66',
 	'#33CC99',
 	'#33CCCC',
 	'#33CCFF',
 	'#6600CC',
 	'#6600FF',
 	'#6633CC',
 	'#6633FF',
 	'#66CC00',
 	'#66CC33',
 	'#9900CC',
 	'#9900FF',
 	'#9933CC',
 	'#9933FF',
 	'#99CC00',
 	'#99CC33',
 	'#CC0000',
 	'#CC0033',
 	'#CC0066',
 	'#CC0099',
 	'#CC00CC',
 	'#CC00FF',
 	'#CC3300',
 	'#CC3333',
 	'#CC3366',
 	'#CC3399',
 	'#CC33CC',
 	'#CC33FF',
 	'#CC6600',
 	'#CC6633',
 	'#CC9900',
 	'#CC9933',
 	'#CCCC00',
 	'#CCCC33',
 	'#FF0000',
 	'#FF0033',
 	'#FF0066',
 	'#FF0099',
 	'#FF00CC',
 	'#FF00FF',
 	'#FF3300',
 	'#FF3333',
 	'#FF3366',
 	'#FF3399',
 	'#FF33CC',
 	'#FF33FF',
 	'#FF6600',
 	'#FF6633',
 	'#FF9900',
 	'#FF9933',
 	'#FFCC00',
 	'#FFCC33'
 ];
 
 /**
  * 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
  */
 
 // eslint-disable-next-line complexity
 function useColors() {
 	// NB: In an Electron preload script, document will be defined but not fully
 	// initialized. Since we know we're in Chrome, we'll just detect this case
 	// explicitly
 	if (typeof window !== 'undefined' && window.process && (window.process.type === 'renderer' || window.process.__nwjs)) {
 		return true;
 	}
 
 	// Internet Explorer and Edge do not support colors.
 	if (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/)) {
 		return false;
 	}
 
 	// Is webkit? http://stackoverflow.com/a/16459606/376773
 	// document is undefined in react-native: https://github.com/facebook/react-native/pull/1632
 	return (typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance) ||
 		// Is firebug? http://stackoverflow.com/a/398120/376773
 		(typeof window !== 'undefined' && window.console && (window.console.firebug || (window.console.exception && window.console.table))) ||
 		// Is firefox >= v31?
 		// https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages
 		(typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31) ||
 		// Double check webkit in userAgent just in case we are in a worker
 		(typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/));
 }
 
 /**
  * Colorize log arguments if enabled.
  *
  * @api public
  */
 
 function formatArgs(args) {
 	args[0] = (this.useColors ? '%c' : '') +
 		this.namespace +
 		(this.useColors ? ' %c' : ' ') +
 		args[0] +
 		(this.useColors ? '%c ' : ' ') +
 		'+' + module.exports.humanize(this.diff);
 
 	if (!this.useColors) {
 		return;
 	}
 
 	const c = 'color: ' + this.color;
 	args.splice(1, 0, c, 'color: inherit');
 
 	// 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
 	let index = 0;
 	let lastC = 0;
 	args[0].replace(/%[a-zA-Z%]/g, match => {
 		if (match === '%%') {
 			return;
 		}
 		index++;
 		if (match === '%c') {
 			// We only are interested in the *last* %c
 			// (the user may have provided their own)
 			lastC = index;
 		}
 	});
 
 	args.splice(lastC, 0, c);
 }
 
 /**
  * Invokes `console.log()` when available.
  * No-op when `console.log` is not a "function".
  *
  * @api public
  */
 function log(...args) {
 	// This hackery is required for IE8/9, where
 	// the `console.log` function doesn't have 'apply'
 	return typeof console === 'object' &&
 		console.log &&
 		console.log(...args);
 }
 
 /**
  * Save `namespaces`.
  *
  * @param {String} namespaces
  * @api private
  */
 function save(namespaces) {
 	try {
 		if (namespaces) {
 			exports.storage.setItem('debug', namespaces);
 		} else {
 			exports.storage.removeItem('debug');
 		}
 	} catch (error) {
 		// Swallow
 		// XXX (@Qix-) should we be logging these?
 	}
 }
 
 /**
  * Load `namespaces`.
  *
  * @return {String} returns the previously persisted debug modes
  * @api private
  */
 function load() {
 	let r;
 	try {
 		r = exports.storage.getItem('debug');
 	} catch (error) {
 		// Swallow
 		// XXX (@Qix-) should we be logging these?
 	}
 
 	// If debug isn't set in LS, and we're in Electron, try to load $DEBUG
 	if (!r && typeof process !== 'undefined' && 'env' in process) {
 		r = process.env.DEBUG;
 	}
 
 	return r;
 }
 
 /**
  * Localstorage attempts to return the localstorage.
  *
  * This is necessary because safari throws
  * when a user disables cookies/localstorage
  * and you attempt to access it.
  *
  * @return {LocalStorage}
  * @api private
  */
 
 function localstorage() {
 	try {
 		// TVMLKit (Apple TV JS Runtime) does not have a window object, just localStorage in the global context
 		// The Browser also has localStorage in the global context.
 		return localStorage;
 	} catch (error) {
 		// Swallow
 		// XXX (@Qix-) should we be logging these?
 	}
 }
 
 module.exports = require('./common')(exports);
 
 const {formatters} = module.exports;
 
 /**
  * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default.
  */
 
 formatters.j = function (v) {
 	try {
 		return JSON.stringify(v);
 	} catch (error) {
 		return '[UnexpectedJSONParseError]: ' + error.message;
 	}
 };
 
 }).call(this,require('_process'))
 },{"./common":31,"_process":33}],31:[function(require,module,exports){
 
 /**
  * This is the common logic for both the Node.js and web browser
  * implementations of `debug()`.
  */
 
 function setup(env) {
 	createDebug.debug = createDebug;
 	createDebug.default = createDebug;
 	createDebug.coerce = coerce;
 	createDebug.disable = disable;
 	createDebug.enable = enable;
 	createDebug.enabled = enabled;
 	createDebug.humanize = require('ms');
 
 	Object.keys(env).forEach(key => {
 		createDebug[key] = env[key];
 	});
 
 	/**
 	* Active `debug` instances.
 	*/
 	createDebug.instances = [];
 
 	/**
 	* The currently active debug mode names, and names to skip.
 	*/
 
 	createDebug.names = [];
 	createDebug.skips = [];
 
 	/**
 	* Map of special "%n" handling functions, for the debug "format" argument.
 	*
 	* Valid key names are a single, lower or upper-case letter, i.e. "n" and "N".
 	*/
 	createDebug.formatters = {};
 
 	/**
 	* Selects a color for a debug namespace
 	* @param {String} namespace The namespace string for the for the debug instance to be colored
 	* @return {Number|String} An ANSI color code for the given namespace
 	* @api private
 	*/
 	function selectColor(namespace) {
 		let hash = 0;
 
 		for (let i = 0; i < namespace.length; i++) {
 			hash = ((hash << 5) - hash) + namespace.charCodeAt(i);
 			hash |= 0; // Convert to 32bit integer
 		}
 
 		return createDebug.colors[Math.abs(hash) % createDebug.colors.length];
 	}
 	createDebug.selectColor = selectColor;
 
 	/**
 	* Create a debugger with the given `namespace`.
 	*
 	* @param {String} namespace
 	* @return {Function}
 	* @api public
 	*/
 	function createDebug(namespace) {
 		let prevTime;
 
 		function debug(...args) {
 			// Disabled?
 			if (!debug.enabled) {
 				return;
 			}
 
 			const self = debug;
 
 			// Set `diff` timestamp
 			const curr = Number(new Date());
 			const ms = curr - (prevTime || curr);
 			self.diff = ms;
 			self.prev = prevTime;
 			self.curr = curr;
 			prevTime = curr;
 
 			args[0] = createDebug.coerce(args[0]);
 
 			if (typeof args[0] !== 'string') {
 				// Anything else let's inspect with %O
 				args.unshift('%O');
 			}
 
 			// Apply any `formatters` transformations
 			let index = 0;
 			args[0] = args[0].replace(/%([a-zA-Z%])/g, (match, format) => {
 				// If we encounter an escaped % then don't increase the array index
 				if (match === '%%') {
 					return match;
 				}
 				index++;
 				const formatter = createDebug.formatters[format];
 				if (typeof formatter === 'function') {
 					const 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;
 			});
 
 			// Apply env-specific formatting (colors, etc.)
 			createDebug.formatArgs.call(self, args);
 
 			const logFn = self.log || createDebug.log;
 			logFn.apply(self, args);
 		}
 
 		debug.namespace = namespace;
 		debug.enabled = createDebug.enabled(namespace);
 		debug.useColors = createDebug.useColors();
 		debug.color = selectColor(namespace);
 		debug.destroy = destroy;
 		debug.extend = extend;
 		// Debug.formatArgs = formatArgs;
 		// debug.rawLog = rawLog;
 
 		// env-specific initialization logic for debug instances
 		if (typeof createDebug.init === 'function') {
 			createDebug.init(debug);
 		}
 
 		createDebug.instances.push(debug);
 
 		return debug;
 	}
 
 	function destroy() {
 		const index = createDebug.instances.indexOf(this);
 		if (index !== -1) {
 			createDebug.instances.splice(index, 1);
 			return true;
 		}
 		return false;
 	}
 
 	function extend(namespace, delimiter) {
 		const newDebug = createDebug(this.namespace + (typeof delimiter === 'undefined' ? ':' : delimiter) + namespace);
 		newDebug.log = this.log;
 		return newDebug;
 	}
 
 	/**
 	* Enables a debug mode by namespaces. This can include modes
 	* separated by a colon and wildcards.
 	*
 	* @param {String} namespaces
 	* @api public
 	*/
 	function enable(namespaces) {
 		createDebug.save(namespaces);
 
 		createDebug.names = [];
 		createDebug.skips = [];
 
 		let i;
 		const split = (typeof namespaces === 'string' ? namespaces : '').split(/[\s,]+/);
 		const len = split.length;
 
 		for (i = 0; i < len; i++) {
 			if (!split[i]) {
 				// ignore empty strings
 				continue;
 			}
 
 			namespaces = split[i].replace(/\*/g, '.*?');
 
 			if (namespaces[0] === '-') {
 				createDebug.skips.push(new RegExp('^' + namespaces.substr(1) + '$'));
 			} else {
 				createDebug.names.push(new RegExp('^' + namespaces + '$'));
 			}
 		}
 
 		for (i = 0; i < createDebug.instances.length; i++) {
 			const instance = createDebug.instances[i];
 			instance.enabled = createDebug.enabled(instance.namespace);
 		}
 	}
 
 	/**
 	* Disable debug output.
 	*
 	* @return {String} namespaces
 	* @api public
 	*/
 	function disable() {
 		const namespaces = [
 			...createDebug.names.map(toNamespace),
 			...createDebug.skips.map(toNamespace).map(namespace => '-' + namespace)
 		].join(',');
 		createDebug.enable('');
 		return namespaces;
 	}
 
 	/**
 	* Returns true if the given mode name is enabled, false otherwise.
 	*
 	* @param {String} name
 	* @return {Boolean}
 	* @api public
 	*/
 	function enabled(name) {
 		if (name[name.length - 1] === '*') {
 			return true;
 		}
 
 		let i;
 		let len;
 
 		for (i = 0, len = createDebug.skips.length; i < len; i++) {
 			if (createDebug.skips[i].test(name)) {
 				return false;
 			}
 		}
 
 		for (i = 0, len = createDebug.names.length; i < len; i++) {
 			if (createDebug.names[i].test(name)) {
 				return true;
 			}
 		}
 
 		return false;
 	}
 
 	/**
 	* Convert regexp to namespace
 	*
 	* @param {RegExp} regxep
 	* @return {String} namespace
 	* @api private
 	*/
 	function toNamespace(regexp) {
 		return regexp.toString()
 			.substring(2, regexp.toString().length - 2)
 			.replace(/\.\*\?$/, '*');
 	}
 
 	/**
 	* Coerce `val`.
 	*
 	* @param {Mixed} val
 	* @return {Mixed}
 	* @api private
 	*/
 	function coerce(val) {
 		if (val instanceof Error) {
 			return val.stack || val.message;
 		}
 		return val;
 	}
 
 	createDebug.enable(createDebug.load());
 
 	return createDebug;
 }
 
 module.exports = setup;
 
 },{"ms":32}],32:[function(require,module,exports){
 /**
  * Helpers.
  */
 
 var s = 1000;
 var m = s * 60;
 var h = m * 60;
 var d = h * 24;
 var w = d * 7;
 var y = d * 365.25;
 
 /**
  * Parse or format the given `val`.
  *
  * Options:
  *
  *  - `long` verbose formatting [false]
  *
  * @param {String|Number} val
  * @param {Object} [options]
  * @throws {Error} throw an error if val is not a non-empty string or a number
  * @return {String|Number}
  * @api public
  */
 
 module.exports = function(val, options) {
   options = options || {};
   var type = typeof val;
   if (type === 'string' && val.length > 0) {
     return parse(val);
   } else if (type === 'number' && isFinite(val)) {
     return options.long ? fmtLong(val) : fmtShort(val);
   }
   throw new Error(
     'val is not a non-empty string or a valid number. val=' +
       JSON.stringify(val)
   );
 };
 
 /**
  * Parse the given `str` and return milliseconds.
  *
  * @param {String} str
  * @return {Number}
  * @api private
  */
 
 function parse(str) {
   str = String(str);
   if (str.length > 100) {
     return;
   }
   var match = /^(-?(?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|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 'yrs':
     case 'yr':
     case 'y':
       return n * y;
     case 'weeks':
     case 'week':
     case 'w':
       return n * w;
     case 'days':
     case 'day':
     case 'd':
       return n * d;
     case 'hours':
     case 'hour':
     case 'hrs':
     case 'hr':
     case 'h':
       return n * h;
     case 'minutes':
     case 'minute':
     case 'mins':
     case 'min':
     case 'm':
       return n * m;
     case 'seconds':
     case 'second':
     case 'secs':
     case 'sec':
     case 's':
       return n * s;
     case 'milliseconds':
     case 'millisecond':
     case 'msecs':
     case 'msec':
     case 'ms':
       return n;
     default:
       return undefined;
   }
 }
 
 /**
  * Short format for `ms`.
  *
  * @param {Number} ms
  * @return {String}
  * @api private
  */
 
 function fmtShort(ms) {
   var msAbs = Math.abs(ms);
   if (msAbs >= d) {
     return Math.round(ms / d) + 'd';
   }
   if (msAbs >= h) {
     return Math.round(ms / h) + 'h';
   }
   if (msAbs >= m) {
     return Math.round(ms / m) + 'm';
   }
   if (msAbs >= s) {
     return Math.round(ms / s) + 's';
   }
   return ms + 'ms';
 }
 
 /**
  * Long format for `ms`.
  *
  * @param {Number} ms
  * @return {String}
  * @api private
  */
 
 function fmtLong(ms) {
   var msAbs = Math.abs(ms);
   if (msAbs >= d) {
     return plural(ms, msAbs, d, 'day');
   }
   if (msAbs >= h) {
     return plural(ms, msAbs, h, 'hour');
   }
   if (msAbs >= m) {
     return plural(ms, msAbs, m, 'minute');
   }
   if (msAbs >= s) {
     return plural(ms, msAbs, s, 'second');
   }
   return ms + ' ms';
 }
 
 /**
  * Pluralization helper.
  */
 
 function plural(ms, msAbs, n, name) {
   var isPlural = msAbs >= n * 1.5;
   return Math.round(ms / n) + ' ' + name + (isPlural ? 's' : '');
 }
 
 },{}],33:[function(require,module,exports){
 // shim for using process in browser
 var process = module.exports = {};
 
 // cached from whatever global is present so that test runners that stub it
 // don't break things.  But we need to wrap it in a try catch in case it is
 // wrapped in strict mode code which doesn't define any globals.  It's inside a
 // function because try/catches deoptimize in certain engines.
 
 var cachedSetTimeout;
 var cachedClearTimeout;
 
 function defaultSetTimout() {
     throw new Error('setTimeout has not been defined');
 }
 function defaultClearTimeout () {
     throw new Error('clearTimeout has not been defined');
 }
 (function () {
     try {
         if (typeof setTimeout === 'function') {
             cachedSetTimeout = setTimeout;
         } else {
             cachedSetTimeout = defaultSetTimout;
         }
     } catch (e) {
         cachedSetTimeout = defaultSetTimout;
     }
     try {
         if (typeof clearTimeout === 'function') {
             cachedClearTimeout = clearTimeout;
         } else {
             cachedClearTimeout = defaultClearTimeout;
         }
     } catch (e) {
         cachedClearTimeout = defaultClearTimeout;
     }
 } ())
 function runTimeout(fun) {
     if (cachedSetTimeout === setTimeout) {
         //normal enviroments in sane situations
         return setTimeout(fun, 0);
     }
     // if setTimeout wasn't available but was latter defined
     if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) {
         cachedSetTimeout = setTimeout;
         return setTimeout(fun, 0);
     }
     try {
         // when when somebody has screwed with setTimeout but no I.E. maddness
         return cachedSetTimeout(fun, 0);
     } catch(e){
         try {
             // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally
             return cachedSetTimeout.call(null, fun, 0);
         } catch(e){
             // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error
             return cachedSetTimeout.call(this, fun, 0);
         }
     }
 
 
 }
 function runClearTimeout(marker) {
     if (cachedClearTimeout === clearTimeout) {
         //normal enviroments in sane situations
         return clearTimeout(marker);
     }
     // if clearTimeout wasn't available but was latter defined
     if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) {
         cachedClearTimeout = clearTimeout;
         return clearTimeout(marker);
     }
     try {
         // when when somebody has screwed with setTimeout but no I.E. maddness
         return cachedClearTimeout(marker);
     } catch (e){
         try {
             // When we are in I.E. but the script has been evaled so I.E. doesn't  trust the global object when called normally
             return cachedClearTimeout.call(null, marker);
         } catch (e){
             // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error.
             // Some versions of I.E. have different rules for clearTimeout vs setTimeout
             return cachedClearTimeout.call(this, marker);
         }
     }
 
 
 
 }
 var queue = [];
 var draining = false;
 var currentQueue;
 var queueIndex = -1;
 
 function cleanUpNextTick() {
     if (!draining || !currentQueue) {
         return;
     }
     draining = false;
     if (currentQueue.length) {
         queue = currentQueue.concat(queue);
     } else {
         queueIndex = -1;
     }
     if (queue.length) {
         drainQueue();
     }
 }
 
 function drainQueue() {
     if (draining) {
         return;
     }
     var timeout = runTimeout(cleanUpNextTick);
     draining = true;
 
     var len = queue.length;
     while(len) {
         currentQueue = queue;
         queue = [];
         while (++queueIndex < len) {
             if (currentQueue) {
                 currentQueue[queueIndex].run();
             }
         }
         queueIndex = -1;
         len = queue.length;
     }
     currentQueue = null;
     draining = false;
     runClearTimeout(timeout);
 }
 
 process.nextTick = function (fun) {
     var args = new Array(arguments.length - 1);
     if (arguments.length > 1) {
         for (var i = 1; i < arguments.length; i++) {
             args[i - 1] = arguments[i];
         }
     }
     queue.push(new Item(fun, args));
     if (queue.length === 1 && !draining) {
         runTimeout(drainQueue);
     }
 };
 
 // v8 likes predictible objects
 function Item(fun, array) {
     this.fun = fun;
     this.array = array;
 }
 Item.prototype.run = function () {
     this.fun.apply(null, this.array);
 };
 process.title = 'browser';
 process.browser = true;
 process.env = {};
 process.argv = [];
 process.version = ''; // empty string to avoid regexp issues
 process.versions = {};
 
 function noop() {}
 
 process.on = noop;
 process.addListener = noop;
 process.once = noop;
 process.off = noop;
 process.removeListener = noop;
 process.removeAllListeners = noop;
 process.emit = noop;
 process.prependListener = noop;
 process.prependOnceListener = noop;
 
 process.listeners = function (name) { return [] }
 
 process.binding = function (name) {
     throw new Error('process.binding is not supported');
 };
 
 process.cwd = function () { return '/' };
 process.chdir = function (dir) {
     throw new Error('process.chdir is not supported');
 };
 process.umask = function() { return 0; };
 
 },{}],34:[function(require,module,exports){
 var grammar = module.exports = {
   v: [{
     name: 'version',
     reg: /^(\d*)$/
   }],
   o: [{
     // o=- 20518 0 IN IP4 203.0.113.1
     // NB: sessionId will be a String in most cases because it is huge
     name: 'origin',
     reg: /^(\S*) (\d*) (\d*) (\S*) IP(\d) (\S*)/,
     names: ['username', 'sessionId', 'sessionVersion', 'netType', 'ipVer', 'address'],
     format: '%s %s %d %s IP%d %s'
   }],
   // default parsing of these only (though some of these feel outdated)
   s: [{ name: 'name' }],
   i: [{ name: 'description' }],
   u: [{ name: 'uri' }],
   e: [{ name: 'email' }],
   p: [{ name: 'phone' }],
   z: [{ name: 'timezones' }], // TODO: this one can actually be parsed properly...
   r: [{ name: 'repeats' }],   // TODO: this one can also be parsed properly
   // k: [{}], // outdated thing ignored
   t: [{
     // t=0 0
     name: 'timing',
     reg: /^(\d*) (\d*)/,
     names: ['start', 'stop'],
     format: '%d %d'
   }],
   c: [{
     // c=IN IP4 10.47.197.26
     name: 'connection',
     reg: /^IN IP(\d) (\S*)/,
     names: ['version', 'ip'],
     format: 'IN IP%d %s'
   }],
   b: [{
     // b=AS:4000
     push: 'bandwidth',
     reg: /^(TIAS|AS|CT|RR|RS):(\d*)/,
     names: ['type', 'limit'],
     format: '%s:%s'
   }],
   m: [{
     // m=video 51744 RTP/AVP 126 97 98 34 31
     // NB: special - pushes to session
     // TODO: rtp/fmtp should be filtered by the payloads found here?
     reg: /^(\w*) (\d*) ([\w/]*)(?: (.*))?/,
     names: ['type', 'port', 'protocol', 'payloads'],
     format: '%s %d %s %s'
   }],
   a: [
     {
       // a=rtpmap:110 opus/48000/2
       push: 'rtp',
       reg: /^rtpmap:(\d*) ([\w\-.]*)(?:\s*\/(\d*)(?:\s*\/(\S*))?)?/,
       names: ['payload', 'codec', 'rate', 'encoding'],
       format: function (o) {
         return (o.encoding)
           ? 'rtpmap:%d %s/%s/%s'
           : o.rate
             ? 'rtpmap:%d %s/%s'
             : 'rtpmap:%d %s';
       }
     },
     {
       // a=fmtp:108 profile-level-id=24;object=23;bitrate=64000
       // a=fmtp:111 minptime=10; useinbandfec=1
       push: 'fmtp',
       reg: /^fmtp:(\d*) ([\S| ]*)/,
       names: ['payload', 'config'],
       format: 'fmtp:%d %s'
     },
     {
       // a=control:streamid=0
       name: 'control',
       reg: /^control:(.*)/,
       format: 'control:%s'
     },
     {
       // a=rtcp:65179 IN IP4 193.84.77.194
       name: 'rtcp',
       reg: /^rtcp:(\d*)(?: (\S*) IP(\d) (\S*))?/,
       names: ['port', 'netType', 'ipVer', 'address'],
       format: function (o) {
         return (o.address != null)
           ? 'rtcp:%d %s IP%d %s'
           : 'rtcp:%d';
       }
     },
     {
       // a=rtcp-fb:98 trr-int 100
       push: 'rtcpFbTrrInt',
       reg: /^rtcp-fb:(\*|\d*) trr-int (\d*)/,
       names: ['payload', 'value'],
       format: 'rtcp-fb:%d trr-int %d'
     },
     {
       // a=rtcp-fb:98 nack rpsi
       push: 'rtcpFb',
       reg: /^rtcp-fb:(\*|\d*) ([\w-_]*)(?: ([\w-_]*))?/,
       names: ['payload', 'type', 'subtype'],
       format: function (o) {
         return (o.subtype != null)
           ? 'rtcp-fb:%s %s %s'
           : 'rtcp-fb:%s %s';
       }
     },
     {
       // a=extmap:2 urn:ietf:params:rtp-hdrext:toffset
       // a=extmap:1/recvonly URI-gps-string
       // a=extmap:3 urn:ietf:params:rtp-hdrext:encrypt urn:ietf:params:rtp-hdrext:smpte-tc 25@600/24
       push: 'ext',
       reg: /^extmap:(\d+)(?:\/(\w+))?(?: (urn:ietf:params:rtp-hdrext:encrypt))? (\S*)(?: (\S*))?/,
       names: ['value', 'direction', 'encrypt-uri', 'uri', 'config'],
       format: function (o) {
         return (
           'extmap:%d' +
           (o.direction ? '/%s' : '%v') +
           (o['encrypt-uri'] ? ' %s' : '%v') +
           ' %s' +
           (o.config ? ' %s' : '')
         );
       }
     },
     {
       // a=extmap-allow-mixed
       name: 'extmapAllowMixed',
       reg: /^(extmap-allow-mixed)/
     },
     {
       // a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:PS1uQCVeeCFCanVmcjkpPywjNWhcYD0mXXtxaVBR|2^20|1:32
       push: 'crypto',
       reg: /^crypto:(\d*) ([\w_]*) (\S*)(?: (\S*))?/,
       names: ['id', 'suite', 'config', 'sessionConfig'],
       format: function (o) {
         return (o.sessionConfig != null)
           ? 'crypto:%d %s %s %s'
           : 'crypto:%d %s %s';
       }
     },
     {
       // a=setup:actpass
       name: 'setup',
       reg: /^setup:(\w*)/,
       format: 'setup:%s'
     },
     {
       // a=connection:new
       name: 'connectionType',
       reg: /^connection:(new|existing)/,
       format: 'connection:%s'
     },
     {
       // a=mid:1
       name: 'mid',
       reg: /^mid:([^\s]*)/,
       format: 'mid:%s'
     },
     {
       // a=msid:0c8b064d-d807-43b4-b434-f92a889d8587 98178685-d409-46e0-8e16-7ef0db0db64a
       name: 'msid',
       reg: /^msid:(.*)/,
       format: 'msid:%s'
     },
     {
       // a=ptime:20
       name: 'ptime',
       reg: /^ptime:(\d*(?:\.\d*)*)/,
       format: 'ptime:%d'
     },
     {
       // a=maxptime:60
       name: 'maxptime',
       reg: /^maxptime:(\d*(?:\.\d*)*)/,
       format: 'maxptime:%d'
     },
     {
       // a=sendrecv
       name: 'direction',
       reg: /^(sendrecv|recvonly|sendonly|inactive)/
     },
     {
       // a=ice-lite
       name: 'icelite',
       reg: /^(ice-lite)/
     },
     {
       // a=ice-ufrag:F7gI
       name: 'iceUfrag',
       reg: /^ice-ufrag:(\S*)/,
       format: 'ice-ufrag:%s'
     },
     {
       // a=ice-pwd:x9cml/YzichV2+XlhiMu8g
       name: 'icePwd',
       reg: /^ice-pwd:(\S*)/,
       format: 'ice-pwd:%s'
     },
     {
       // a=fingerprint:SHA-1 00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD:EE:FF:00:11:22:33
       name: 'fingerprint',
       reg: /^fingerprint:(\S*) (\S*)/,
       names: ['type', 'hash'],
       format: 'fingerprint:%s %s'
     },
     {
       // a=candidate:0 1 UDP 2113667327 203.0.113.1 54400 typ host
       // a=candidate:1162875081 1 udp 2113937151 192.168.34.75 60017 typ host generation 0 network-id 3 network-cost 10
       // a=candidate:3289912957 2 udp 1845501695 193.84.77.194 60017 typ srflx raddr 192.168.34.75 rport 60017 generation 0 network-id 3 network-cost 10
       // a=candidate:229815620 1 tcp 1518280447 192.168.150.19 60017 typ host tcptype active generation 0 network-id 3 network-cost 10
       // a=candidate:3289912957 2 tcp 1845501695 193.84.77.194 60017 typ srflx raddr 192.168.34.75 rport 60017 tcptype passive generation 0 network-id 3 network-cost 10
       push:'candidates',
       reg: /^candidate:(\S*) (\d*) (\S*) (\d*) (\S*) (\d*) typ (\S*)(?: raddr (\S*) rport (\d*))?(?: tcptype (\S*))?(?: generation (\d*))?(?: network-id (\d*))?(?: network-cost (\d*))?/,
       names: ['foundation', 'component', 'transport', 'priority', 'ip', 'port', 'type', 'raddr', 'rport', 'tcptype', 'generation', 'network-id', 'network-cost'],
       format: function (o) {
         var str = 'candidate:%s %d %s %d %s %d typ %s';
 
         str += (o.raddr != null) ? ' raddr %s rport %d' : '%v%v';
 
         // NB: candidate has three optional chunks, so %void middles one if it's missing
         str += (o.tcptype != null) ? ' tcptype %s' : '%v';
 
         if (o.generation != null) {
           str += ' generation %d';
         }
 
         str += (o['network-id'] != null) ? ' network-id %d' : '%v';
         str += (o['network-cost'] != null) ? ' network-cost %d' : '%v';
         return str;
       }
     },
     {
       // a=end-of-candidates (keep after the candidates line for readability)
       name: 'endOfCandidates',
       reg: /^(end-of-candidates)/
     },
     {
       // a=remote-candidates:1 203.0.113.1 54400 2 203.0.113.1 54401 ...
       name: 'remoteCandidates',
       reg: /^remote-candidates:(.*)/,
       format: 'remote-candidates:%s'
     },
     {
       // a=ice-options:google-ice
       name: 'iceOptions',
       reg: /^ice-options:(\S*)/,
       format: 'ice-options:%s'
     },
     {
       // a=ssrc:2566107569 cname:t9YU8M1UxTF8Y1A1
       push: 'ssrcs',
       reg: /^ssrc:(\d*) ([\w_-]*)(?::(.*))?/,
       names: ['id', 'attribute', 'value'],
       format: function (o) {
         var str = 'ssrc:%d';
         if (o.attribute != null) {
           str += ' %s';
           if (o.value != null) {
             str += ':%s';
           }
         }
         return str;
       }
     },
     {
       // a=ssrc-group:FEC 1 2
       // a=ssrc-group:FEC-FR 3004364195 1080772241
       push: 'ssrcGroups',
       // token-char = %x21 / %x23-27 / %x2A-2B / %x2D-2E / %x30-39 / %x41-5A / %x5E-7E
       reg: /^ssrc-group:([\x21\x23\x24\x25\x26\x27\x2A\x2B\x2D\x2E\w]*) (.*)/,
       names: ['semantics', 'ssrcs'],
       format: 'ssrc-group:%s %s'
     },
     {
       // a=msid-semantic: WMS Jvlam5X3SX1OP6pn20zWogvaKJz5Hjf9OnlV
       name: 'msidSemantic',
       reg: /^msid-semantic:\s?(\w*) (\S*)/,
       names: ['semantic', 'token'],
       format: 'msid-semantic: %s %s' // space after ':' is not accidental
     },
     {
       // a=group:BUNDLE audio video
       push: 'groups',
       reg: /^group:(\w*) (.*)/,
       names: ['type', 'mids'],
       format: 'group:%s %s'
     },
     {
       // a=rtcp-mux
       name: 'rtcpMux',
       reg: /^(rtcp-mux)/
     },
     {
       // a=rtcp-rsize
       name: 'rtcpRsize',
       reg: /^(rtcp-rsize)/
     },
     {
       // a=sctpmap:5000 webrtc-datachannel 1024
       name: 'sctpmap',
       reg: /^sctpmap:([\w_/]*) (\S*)(?: (\S*))?/,
       names: ['sctpmapNumber', 'app', 'maxMessageSize'],
       format: function (o) {
         return (o.maxMessageSize != null)
           ? 'sctpmap:%s %s %s'
           : 'sctpmap:%s %s';
       }
     },
     {
       // a=x-google-flag:conference
       name: 'xGoogleFlag',
       reg: /^x-google-flag:([^\s]*)/,
       format: 'x-google-flag:%s'
     },
     {
       // a=rid:1 send max-width=1280;max-height=720;max-fps=30;depend=0
       push: 'rids',
       reg: /^rid:([\d\w]+) (\w+)(?: ([\S| ]*))?/,
       names: ['id', 'direction', 'params'],
       format: function (o) {
         return (o.params) ? 'rid:%s %s %s' : 'rid:%s %s';
       }
     },
     {
       // a=imageattr:97 send [x=800,y=640,sar=1.1,q=0.6] [x=480,y=320] recv [x=330,y=250]
       // a=imageattr:* send [x=800,y=640] recv *
       // a=imageattr:100 recv [x=320,y=240]
       push: 'imageattrs',
       reg: new RegExp(
         // a=imageattr:97
         '^imageattr:(\\d+|\\*)' +
         // send [x=800,y=640,sar=1.1,q=0.6] [x=480,y=320]
         '[\\s\\t]+(send|recv)[\\s\\t]+(\\*|\\[\\S+\\](?:[\\s\\t]+\\[\\S+\\])*)' +
         // recv [x=330,y=250]
         '(?:[\\s\\t]+(recv|send)[\\s\\t]+(\\*|\\[\\S+\\](?:[\\s\\t]+\\[\\S+\\])*))?'
       ),
       names: ['pt', 'dir1', 'attrs1', 'dir2', 'attrs2'],
       format: function (o) {
         return 'imageattr:%s %s %s' + (o.dir2 ? ' %s %s' : '');
       }
     },
     {
       // a=simulcast:send 1,2,3;~4,~5 recv 6;~7,~8
       // a=simulcast:recv 1;4,5 send 6;7
       name: 'simulcast',
       reg: new RegExp(
         // a=simulcast:
         '^simulcast:' +
         // send 1,2,3;~4,~5
         '(send|recv) ([a-zA-Z0-9\\-_~;,]+)' +
         // space + recv 6;~7,~8
         '(?:\\s?(send|recv) ([a-zA-Z0-9\\-_~;,]+))?' +
         // end
         '$'
       ),
       names: ['dir1', 'list1', 'dir2', 'list2'],
       format: function (o) {
         return 'simulcast:%s %s' + (o.dir2 ? ' %s %s' : '');
       }
     },
     {
       // old simulcast draft 03 (implemented by Firefox)
       //   https://tools.ietf.org/html/draft-ietf-mmusic-sdp-simulcast-03
       // a=simulcast: recv pt=97;98 send pt=97
       // a=simulcast: send rid=5;6;7 paused=6,7
       name: 'simulcast_03',
       reg: /^simulcast:[\s\t]+([\S+\s\t]+)$/,
       names: ['value'],
       format: 'simulcast: %s'
     },
     {
       // a=framerate:25
       // a=framerate:29.97
       name: 'framerate',
       reg: /^framerate:(\d+(?:$|\.\d+))/,
       format: 'framerate:%s'
     },
     {
       // RFC4570
       // a=source-filter: incl IN IP4 239.5.2.31 10.1.15.5
       name: 'sourceFilter',
       reg: /^source-filter: *(excl|incl) (\S*) (IP4|IP6|\*) (\S*) (.*)/,
       names: ['filterMode', 'netType', 'addressTypes', 'destAddress', 'srcList'],
       format: 'source-filter: %s %s %s %s %s'
     },
     {
       // a=bundle-only
       name: 'bundleOnly',
       reg: /^(bundle-only)/
     },
     {
       // a=label:1
       name: 'label',
       reg: /^label:(.+)/,
       format: 'label:%s'
     },
     {
       // RFC version 26 for SCTP over DTLS
       // https://tools.ietf.org/html/draft-ietf-mmusic-sctp-sdp-26#section-5
       name: 'sctpPort',
       reg: /^sctp-port:(\d+)$/,
       format: 'sctp-port:%s'
     },
     {
       // RFC version 26 for SCTP over DTLS
       // https://tools.ietf.org/html/draft-ietf-mmusic-sctp-sdp-26#section-6
       name: 'maxMessageSize',
       reg: /^max-message-size:(\d+)$/,
       format: 'max-message-size:%s'
     },
     {
       // RFC7273
       // a=ts-refclk:ptp=IEEE1588-2008:39-A7-94-FF-FE-07-CB-D0:37
       push:'tsRefClocks',
       reg: /^ts-refclk:([^\s=]*)(?:=(\S*))?/,
       names: ['clksrc', 'clksrcExt'],
       format: function (o) {
         return 'ts-refclk:%s' + (o.clksrcExt != null ? '=%s' : '');
       }
     },
     {
       // RFC7273
       // a=mediaclk:direct=963214424
       name:'mediaClk',
       reg: /^mediaclk:(?:id=(\S*))? *([^\s=]*)(?:=(\S*))?(?: *rate=(\d+)\/(\d+))?/,
       names: ['id', 'mediaClockName', 'mediaClockValue', 'rateNumerator', 'rateDenominator'],
       format: function (o) {
         var str = 'mediaclk:';
         str += (o.id != null ? 'id=%s %s' : '%v%s');
         str += (o.mediaClockValue != null ? '=%s' : '');
         str += (o.rateNumerator != null ? ' rate=%s' : '');
         str += (o.rateDenominator != null ? '/%s' : '');
         return str;
       }
     },
     {
       // a=keywds:keywords
       name: 'keywords',
       reg: /^keywds:(.+)$/,
       format: 'keywds:%s'
     },
     {
       // a=content:main
       name: 'content',
       reg: /^content:(.+)/,
       format: 'content:%s'
     },
     // BFCP https://tools.ietf.org/html/rfc4583
     {
       // a=floorctrl:c-s
       name: 'bfcpFloorCtrl',
       reg: /^floorctrl:(c-only|s-only|c-s)/,
       format: 'floorctrl:%s'
     },
     {
       // a=confid:1
       name: 'bfcpConfId',
       reg: /^confid:(\d+)/,
       format: 'confid:%s'
     },
     {
       // a=userid:1
       name: 'bfcpUserId',
       reg: /^userid:(\d+)/,
       format: 'userid:%s'
     },
     {
       // a=floorid:1
       name: 'bfcpFloorId',
       reg: /^floorid:(.+) (?:m-stream|mstrm):(.+)/,
       names: ['id', 'mStream'],
       format: 'floorid:%s mstrm:%s'
     },
     {
       // any a= that we don't understand is kept verbatim on media.invalid
       push: 'invalid',
       names: ['value']
     }
   ]
 };
 
 // set sensible defaults to avoid polluting the grammar with boring details
 Object.keys(grammar).forEach(function (key) {
   var objs = grammar[key];
   objs.forEach(function (obj) {
     if (!obj.reg) {
       obj.reg = /(.*)/;
     }
     if (!obj.format) {
       obj.format = '%s';
     }
   });
 });
 
 },{}],35:[function(require,module,exports){
 var parser = require('./parser');
 var writer = require('./writer');
 
 exports.write = writer;
 exports.parse = parser.parse;
 exports.parseParams = parser.parseParams;
 exports.parseFmtpConfig = parser.parseFmtpConfig; // Alias of parseParams().
 exports.parsePayloads = parser.parsePayloads;
 exports.parseRemoteCandidates = parser.parseRemoteCandidates;
 exports.parseImageAttributes = parser.parseImageAttributes;
 exports.parseSimulcastStreamList = parser.parseSimulcastStreamList;
 
 },{"./parser":36,"./writer":37}],36:[function(require,module,exports){
 var toIntIfInt = function (v) {
   return String(Number(v)) === v ? Number(v) : v;
 };
 
 var attachProperties = function (match, location, names, rawName) {
   if (rawName && !names) {
     location[rawName] = toIntIfInt(match[1]);
   }
   else {
     for (var i = 0; i < names.length; i += 1) {
       if (match[i+1] != null) {
         location[names[i]] = toIntIfInt(match[i+1]);
       }
     }
   }
 };
 
 var parseReg = function (obj, location, content) {
   var needsBlank = obj.name && obj.names;
   if (obj.push && !location[obj.push]) {
     location[obj.push] = [];
   }
   else if (needsBlank && !location[obj.name]) {
     location[obj.name] = {};
   }
   var keyLocation = obj.push ?
     {} :  // blank object that will be pushed
     needsBlank ? location[obj.name] : location; // otherwise, named location or root
 
   attachProperties(content.match(obj.reg), keyLocation, obj.names, obj.name);
 
   if (obj.push) {
     location[obj.push].push(keyLocation);
   }
 };
 
 var grammar = require('./grammar');
 var validLine = RegExp.prototype.test.bind(/^([a-z])=(.*)/);
 
 exports.parse = function (sdp) {
   var session = {}
     , media = []
     , location = session; // points at where properties go under (one of the above)
 
   // parse lines we understand
   sdp.split(/(\r\n|\r|\n)/).filter(validLine).forEach(function (l) {
     var type = l[0];
     var content = l.slice(2);
     if (type === 'm') {
       media.push({rtp: [], fmtp: []});
       location = media[media.length-1]; // point at latest media line
     }
 
     for (var j = 0; j < (grammar[type] || []).length; j += 1) {
       var obj = grammar[type][j];
       if (obj.reg.test(content)) {
         return parseReg(obj, location, content);
       }
     }
   });
 
   session.media = media; // link it up
   return session;
 };
 
 var paramReducer = function (acc, expr) {
   var s = expr.split(/=(.+)/, 2);
   if (s.length === 2) {
     acc[s[0]] = toIntIfInt(s[1]);
   } else if (s.length === 1 && expr.length > 1) {
     acc[s[0]] = undefined;
   }
   return acc;
 };
 
 exports.parseParams = function (str) {
   return str.split(/;\s?/).reduce(paramReducer, {});
 };
 
 // For backward compatibility - alias will be removed in 3.0.0
 exports.parseFmtpConfig = exports.parseParams;
 
 exports.parsePayloads = function (str) {
   return str.toString().split(' ').map(Number);
 };
 
 exports.parseRemoteCandidates = function (str) {
   var candidates = [];
   var parts = str.split(' ').map(toIntIfInt);
   for (var i = 0; i < parts.length; i += 3) {
     candidates.push({
       component: parts[i],
       ip: parts[i + 1],
       port: parts[i + 2]
     });
   }
   return candidates;
 };
 
 exports.parseImageAttributes = function (str) {
   return str.split(' ').map(function (item) {
     return item.substring(1, item.length-1).split(',').reduce(paramReducer, {});
   });
 };
 
 exports.parseSimulcastStreamList = function (str) {
   return str.split(';').map(function (stream) {
     return stream.split(',').map(function (format) {
       var scid, paused = false;
 
       if (format[0] !== '~') {
         scid = toIntIfInt(format);
       } else {
         scid = toIntIfInt(format.substring(1, format.length));
         paused = true;
       }
 
       return {
         scid: scid,
         paused: paused
       };
     });
   });
 };
 
 },{"./grammar":34}],37:[function(require,module,exports){
 var grammar = require('./grammar');
 
 // customized util.format - discards excess arguments and can void middle ones
 var formatRegExp = /%[sdv%]/g;
 var format = function (formatStr) {
   var i = 1;
   var args = arguments;
   var len = args.length;
   return formatStr.replace(formatRegExp, function (x) {
     if (i >= len) {
       return x; // missing argument
     }
     var arg = args[i];
     i += 1;
     switch (x) {
     case '%%':
       return '%';
     case '%s':
       return String(arg);
     case '%d':
       return Number(arg);
     case '%v':
       return '';
     }
   });
   // NB: we discard excess arguments - they are typically undefined from makeLine
 };
 
 var makeLine = function (type, obj, location) {
   var str = obj.format instanceof Function ?
     (obj.format(obj.push ? location : location[obj.name])) :
     obj.format;
 
   var args = [type + '=' + str];
   if (obj.names) {
     for (var i = 0; i < obj.names.length; i += 1) {
       var n = obj.names[i];
       if (obj.name) {
         args.push(location[obj.name][n]);
       }
       else { // for mLine and push attributes
         args.push(location[obj.names[i]]);
       }
     }
   }
   else {
     args.push(location[obj.name]);
   }
   return format.apply(null, args);
 };
 
 // RFC specified order
 // TODO: extend this with all the rest
 var defaultOuterOrder = [
   'v', 'o', 's', 'i',
   'u', 'e', 'p', 'c',
   'b', 't', 'r', 'z', 'a'
 ];
 var defaultInnerOrder = ['i', 'c', 'b', 'a'];
 
 
 module.exports = function (session, opts) {
   opts = opts || {};
   // ensure certain properties exist
   if (session.version == null) {
     session.version = 0; // 'v=0' must be there (only defined version atm)
   }
   if (session.name == null) {
     session.name = ' '; // 's= ' must be there if no meaningful name set
   }
   session.media.forEach(function (mLine) {
     if (mLine.payloads == null) {
       mLine.payloads = '';
     }
   });
 
   var outerOrder = opts.outerOrder || defaultOuterOrder;
   var innerOrder = opts.innerOrder || defaultInnerOrder;
   var sdp = [];
 
   // loop through outerOrder for matching properties on session
   outerOrder.forEach(function (type) {
     grammar[type].forEach(function (obj) {
       if (obj.name in session && session[obj.name] != null) {
         sdp.push(makeLine(type, obj, session));
       }
       else if (obj.push in session && session[obj.push] != null) {
         session[obj.push].forEach(function (el) {
           sdp.push(makeLine(type, obj, el));
         });
       }
     });
   });
 
   // then for each media line, follow the innerOrder
   session.media.forEach(function (mLine) {
     sdp.push(makeLine('m', grammar.m[0], mLine));
 
     innerOrder.forEach(function (type) {
       grammar[type].forEach(function (obj) {
         if (obj.name in mLine && mLine[obj.name] != null) {
           sdp.push(makeLine(type, obj, mLine));
         }
         else if (obj.push in mLine && mLine[obj.push] != null) {
           mLine[obj.push].forEach(function (el) {
             sdp.push(makeLine(type, obj, el));
           });
         }
       });
     });
   });
 
   return sdp.join('\r\n') + '\r\n';
 };
 
 },{"./grammar":34}],38:[function(require,module,exports){
 module.exports={
   "name": "jssip",
   "title": "JsSIP",
   "description": "the Javascript SIP library",
   "version": "3.7.0",
   "homepage": "https://jssip.net",
   "author": "José Luis Millán <jmillan@aliax.net> (https://github.com/jmillan)",
   "contributors": [
     "Iñaki Baz Castillo <ibc@aliax.net> (https://github.com/ibc)"
   ],
   "types": "lib/JsSIP.d.ts",
   "main": "lib-es5/JsSIP.js",
   "keywords": [
     "sip",
     "websocket",
     "webrtc",
     "node",
     "browser",
     "library"
   ],
   "license": "MIT",
   "repository": {
     "type": "git",
     "url": "https://github.com/versatica/JsSIP.git"
   },
   "bugs": {
     "url": "https://github.com/versatica/JsSIP/issues"
   },
   "dependencies": {
     "@types/debug": "^4.1.5",
     "@types/node": "^14.14.13",
     "debug": "^4.3.1",
     "events": "^3.2.0",
     "sdp-transform": "^2.14.1"
   },
   "devDependencies": {
     "@babel/core": "^7.12.10",
     "@babel/preset-env": "^7.12.10",
     "ansi-colors": "^3.2.4",
     "browserify": "^16.5.1",
     "eslint": "^5.16.0",
     "fancy-log": "^1.3.3",
     "gulp": "^4.0.2",
     "gulp-babel": "^8.0.0",
     "gulp-eslint": "^5.0.0",
     "gulp-expect-file": "^1.0.2",
     "gulp-header": "^2.0.9",
     "gulp-nodeunit-runner": "^0.2.2",
     "gulp-plumber": "^1.2.1",
     "gulp-rename": "^1.4.0",
     "gulp-uglify-es": "^1.0.4",
     "pegjs": "^0.7.0",
     "vinyl-buffer": "^1.0.1",
     "vinyl-source-stream": "^2.0.0"
   },
   "scripts": {
     "lint": "gulp lint",
     "test": "gulp test",
     "prepublishOnly": "gulp babel"
   }
 }
 
 },{}]},{},[8])(8)
 });