/*
 * JsSIP v3.10.0
 * the Javascript SIP library
 * Copyright: 2012-2022 
 * 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,
      // Global extra headers, to be added to every request and response
      extra_headers: null,
    
      /*
       * 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;
          }
        },
        extra_headers: function extra_headers(_extra_headers) {
          var _extraHeaders = [];
    
          if (Array.isArray(_extra_headers) && _extra_headers.length) {
            var _iterator2 = _createForOfIteratorHelper(_extra_headers),
                _step2;
    
            try {
              for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
                var header = _step2.value;
    
                if (typeof header === 'string') {
                  _extraHeaders.push(header);
                }
              }
            } catch (err) {
              _iterator2.e(err);
            } finally {
              _iterator2.f();
            }
          } else {
            return;
          }
    
          return _extraHeaders;
        }
      }
    };
    
    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":22,"./URI":27,"./Utils":28}],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: 120,
      MIN_SESSION_EXPIRES: 60,
      CONNECTION_RECOVERY_MAX_INTERVAL: 30,
      CONNECTION_RECOVERY_MIN_INTERVAL: 2
    };
    },{"../package.json":40}],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 Logger = require('./Logger');
    
    var SIPMessage = require('./SIPMessage');
    
    var JsSIP_C = require('./Constants');
    
    var Transactions = require('./Transactions');
    
    var Dialog_RequestSender = require('./Dialog/RequestSender');
    
    var Utils = require('./Utils');
    
    var logger = new Logger('Dialog');
    var C = {
      // Dialog states.
      STATUS_EARLY: 1,
      STATUS_CONFIRMED: 2,
      STATUS_TERMINATED: 3
    }; // 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);
    
        logger.debug("new ".concat(type, " dialog created with status ").concat(this._state === C.STATUS_EARLY ? 'EARLY' : 'CONFIRMED'));
      }
    
      _createClass(Dialog, [{
        key: "isTerminated",
        value: function isTerminated() {
          return this._status === C.STATUS_TERMINATED;
        }
      }, {
        key: "update",
        value: function update(message, type) {
          this._state = C.STATUS_CONFIRMED;
          logger.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() {
          logger.debug("dialog ".concat(this._id.toString(), " deleted"));
    
          this._ua.destroyDialog(this);
    
          this._state = C.STATUS_TERMINATED;
        }
      }, {
        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,"./Logger":9,"./SIPMessage":21,"./Transactions":24,"./Utils":28}],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 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 () {
                if (!_this2._dialog.isTerminated()) {
                  _this2._reattempt = true;
    
                  _this2.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,"../RequestSender":20,"../Transactions":24}],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 Logger = require('./Logger');
    
    var Utils = require('./Utils');
    
    var logger = new Logger('DigestAuthentication');
    
    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:
              logger.warn('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') {
              logger.warn('authenticate() | challenge with Digest algorithm different than "MD5", authentication aborted');
              return false;
            }
          } else {
            this._algorithm = 'MD5';
          }
    
          if (!this._nonce) {
            logger.warn('authenticate() | challenge without Digest nonce, authentication aborted');
            return false;
          }
    
          if (!this._realm) {
            logger.warn('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) {
              logger.warn('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) {
              logger.warn('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.
              logger.warn('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);
            logger.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);
            logger.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);
            logger.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));
          }
    
          logger.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;
    }();
    },{"./Logger":9,"./Utils":28}],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":11,"./URI":27}],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":40,"./Constants":2,"./Exceptions":6,"./Grammar":7,"./NameAddrHeader":11,"./UA":26,"./URI":27,"./Utils":28,"./WebSocketInterface":29,"debug":32}],9:[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 debug = require('debug');
    
    var APP_NAME = 'JsSIP';
    
    module.exports = /*#__PURE__*/function () {
      function Logger(prefix) {
        _classCallCheck(this, Logger);
    
        if (prefix) {
          this._debug = debug["default"]("".concat(APP_NAME, ":").concat(prefix));
          this._warn = debug["default"]("".concat(APP_NAME, ":WARN:").concat(prefix));
          this._error = debug["default"]("".concat(APP_NAME, ":ERROR:").concat(prefix));
        } else {
          this._debug = debug["default"](APP_NAME);
          this._warn = debug["default"]("".concat(APP_NAME, ":WARN"));
          this._error = debug["default"]("".concat(APP_NAME, ":ERROR"));
        }
        /* eslint-disable no-console */
    
    
        this._debug.log = console.info.bind(console);
        this._warn.log = console.warn.bind(console);
        this._error.log = console.error.bind(console);
        /* eslint-enable no-console */
      }
    
      _createClass(Logger, [{
        key: "debug",
        get: function get() {
          return this._debug;
        }
      }, {
        key: "warn",
        get: function get() {
          return this._warn;
        }
      }, {
        key: "error",
        get: function get() {
          return this._error;
        }
      }]);
    
      return Logger;
    }();
    },{"debug":32}],10:[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 Logger = require('./Logger');
    
    var JsSIP_C = require('./Constants');
    
    var SIPMessage = require('./SIPMessage');
    
    var Utils = require('./Utils');
    
    var RequestSender = require('./RequestSender');
    
    var Exceptions = require('./Exceptions');
    
    var URI = require('./URI');
    
    var logger = new Logger('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';
          var requestParams = {};
    
          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;
          } // 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, requestParams, 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) {
          logger.debug('MESSAGE failed');
    
          this._close();
    
          logger.debug('emit "failed"');
          this.emit('failed', {
            originator: originator,
            response: response || null,
            cause: cause
          });
        }
      }, {
        key: "_succeeded",
        value: function _succeeded(originator, response) {
          logger.debug('MESSAGE succeeded');
    
          this._close();
    
          logger.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,"./Logger":9,"./RequestSender":20,"./SIPMessage":21,"./URI":27,"./Utils":28,"events":31}],11:[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":27}],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 _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 Logger = require('./Logger');
    
    var JsSIP_C = require('./Constants');
    
    var SIPMessage = require('./SIPMessage');
    
    var Utils = require('./Utils');
    
    var RequestSender = require('./RequestSender');
    
    var Exceptions = require('./Exceptions');
    
    var logger = new Logger('Options');
    
    module.exports = /*#__PURE__*/function (_EventEmitter) {
      _inherits(Options, _EventEmitter);
    
      var _super = _createSuper(Options);
    
      function Options(ua) {
        var _this;
    
        _classCallCheck(this, Options);
    
        _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(Options, [{
        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) {
            throw new TypeError('A target is required for OPTIONS');
          } // 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 || 'application/sdp'; // 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.OPTIONS, 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._newOptions('local', this._request);
    
          request_sender.send();
        }
      }, {
        key: "init_incoming",
        value: function init_incoming(request) {
          this._request = request;
    
          this._newOptions('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 Options
         * Only valid for incoming Options
         */
    
      }, {
        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 Options');
          }
    
          if (this._is_replied) {
            throw new Error('incoming Options already replied');
          }
    
          this._is_replied = true;
    
          this._request.reply(200, null, extraHeaders, body);
        }
        /**
         * Reject the incoming Options
         * Only valid for incoming Options
         */
    
      }, {
        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 Options');
          }
    
          if (this._is_replied) {
            throw new Error('incoming Options 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: "_newOptions",
        value: function _newOptions(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.newOptions(this, {
            originator: originator,
            message: this,
            request: request
          });
        }
      }, {
        key: "_failed",
        value: function _failed(originator, response, cause) {
          logger.debug('OPTIONS failed');
    
          this._close();
    
          logger.debug('emit "failed"');
          this.emit('failed', {
            originator: originator,
            response: response || null,
            cause: cause
          });
        }
      }, {
        key: "_succeeded",
        value: function _succeeded(originator, response) {
          logger.debug('OPTIONS succeeded');
    
          this._close();
    
          logger.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 Options;
    }(EventEmitter);
    },{"./Constants":2,"./Exceptions":6,"./Logger":9,"./RequestSender":20,"./SIPMessage":21,"./Utils":28,"events":31}],13:[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 Logger = require('./Logger');
    
    var Grammar = require('./Grammar');
    
    var SIPMessage = require('./SIPMessage');
    
    var logger = new Logger('Parser');
    /**
     * Parse SIP Message
     */
    
    exports.parseMessage = function (data, ua) {
      var message;
      var bodyStart;
      var headerEnd = data.indexOf('\r\n');
    
      if (headerEnd === -1) {
        logger.warn('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) {
        logger.warn("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) {
            logger.warn('parseMessage() | malformed message');
            return;
          }
    
        parsed = parseHeader(message, data, headerStart, headerEnd);
    
        if (parsed !== true) {
          logger.warn('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,"./Logger":9,"./SIPMessage":21}],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 _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 Logger = require('./Logger');
    
    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 logger = new Logger('RTCSession');
    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);
    
        logger.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; // Flag to indicate ICE candidate gathering is finished even if iceGatheringState is not yet 'complete'.
    
        _this._iceReady = false; // 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;
          logger.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;
    
          logger.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] : {};
          logger.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 (window.getStreamError){
                    getStreamError(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);
    
                  logger.warn('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
            };
            logger.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);
    
              logger.warn('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;
            }
    
            logger.warn(error);
          });
        }
        /**
         * Terminate the call.
         */
    
      }, {
        key: "terminate",
        value: function terminate() {
          var _this4 = this;
    
          var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
          logger.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:
              logger.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:
              logger.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:
              logger.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] : {};
          logger.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 && this._status !== C.STATUS_1XX_RECEIVED) {
            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) {
            logger.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) {
            logger.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) {
            logger.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] : {};
          logger.debug('sendInfo()'); // Check Session Status.
    
          if (this._status !== C.STATUS_CONFIRMED && this._status !== C.STATUS_WAITING_FOR_ACK && this._status !== C.STATUS_1XX_RECEIVED) {
            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
          };
          logger.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
          };
          logger.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;
          logger.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;
          logger.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;
          logger.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;
    
          logger.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) {
          logger.debug('sendRequest()');
          return this._dialog.sendRequest(method, options);
        }
        /**
         * In dialog Request Reception
         */
    
      }, {
        key: "receiveRequest",
        value: function receiveRequest(request) {
          var _this10 = this;
    
          logger.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
                  };
                  logger.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
                    });
    
                    logger.warn('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 {
                    // 音视频切换逻辑
                    var that = this
                    if (request.body.indexOf('m=video 0 RTP/SAVPF 19') > -1 || request.body.indexOf('m=video') < 0){
                      hasVideo = false
                    } else {
                      hasVideo = true
                    }
                    navigator.mediaDevices.getUserMedia({ video: hasVideo,audio:true }).then((stream)=>{
                      Utils.closeMediaStream(that._localMediaStream);
                      that._connection.close()
                      that._connection = null
                      that._createRTCConnection({iceServers: []}, null);
                      stream.getTracks().forEach(function (track) {
                        that._connection.addTrack(track, stream);
                      });
                      that._connection.onaddstream = function(e) {
                        switch_video()
                      };
                      that._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() {
          logger.warn('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() {
          logger.warn('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() {
          logger.warn('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) {
          logger.debug('newDTMF()');
          this.emit('newDTMF', data);
        } // Called from Info handler.
    
      }, {
        key: "newInfo",
        value: function newInfo(data) {
          logger.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) {
            logger.debug('_isReadyToReOffer() | internal WebRTC status not ready');
            return false;
          } // No established yet.
    
    
          if (!this._dialog) {
            logger.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) {
            logger.debug('_isReadyToReOffer() | there is another INVITE/UPDATE transaction in progress');
            return false;
          }
    
          return true;
        }
      }, {
        key: "_close",
        value: function _close() {
          logger.debug('close()'); // Close local MediaStream if it was not given by the user.
    
          if (this._localMediaStream && this._localMediaStreamLocallyGenerated) {
            logger.debug('close() | closing local MediaStream');
            Utils.closeMediaStream(this._localMediaStream);
          }
    
          if (this._status === C.STATUS_TERMINATED) {
            return;
          }
    
          this._status = C.STATUS_TERMINATED; // Terminate RTC.
    
          if (this._connection) {
            try {
              this._connection.close();
            } catch (error) {
              logger.warn('close() | error closing the RTCPeerConnection: %o', error);
            }
          } // 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) {
              logger.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
              });
            }
          });
    
          logger.debug('emit "peerconnection"');
          this.emit('peerconnection', {
            peerconnection: this._connection
          });
        }
      }, {
        key: "_createLocalDescription",
        value: function _createLocalDescription(type, constraints) {
          var _this13 = this;
    
          logger.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) {
                logger.warn('emit "peerconnection:createofferfailed" [error:%o]', error);
    
                _this13.emit('peerconnection:createofferfailed', error);
    
                return Promise.reject(error);
              });
            } else {
              return connection.createAnswer(constraints)["catch"](function (error) {
                logger.warn('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;
              logger.warn('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'.
    
            /**
             * Resolve right away if:
             * - 'connection.iceGatheringState' is 'complete' and no 'iceRestart' constraint is set.
             * - 'connection.iceGatheringState' is 'gathering' and 'iceReady' is true.
             */
            var iceRestart = constraints && constraints.iceRestart;
            // 切换
            if (connection.iceGatheringState === 'complete' && !iceRestart || connection.iceGatheringState === 'gathering' && _this13._iceReady) {
              _this13._rtcReady = true;
              var e = {
                originator: 'local',
                type: type,
                sdp: connection.localDescription.sdp
              };
              logger.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;
              _this13._iceReady = false;
    
              var ready = function ready() {
                connection.removeEventListener('icecandidate', iceCandidateListener);
                connection.removeEventListener('icegatheringstatechange', iceGatheringStateListener);
                finished = true;
                _this13._rtcReady = true; // connection.iceGatheringState will still indicate 'gathering' and thus be blocking.
    
                _this13._iceReady = true;
                var e = {
                  originator: 'local',
                  type: type,
                  sdp: connection.localDescription.sdp
                };
                logger.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) {
                logger.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) {
                logger.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;
    
          logger.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') {
            logger.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) {
            logger.warn(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;
    
          logger.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') {
            logger.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) {
            logger.warn(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;
    
          logger.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
          };
          logger.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);
              logger.warn('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);
              logger.warn('emit "peerconnection:createtelocaldescriptionfailed" [error:%o]', error);
              throw error;
            });
          })["catch"](function (error) {
            logger.warn('_processInDialogSdpOffer() failed [error: %o]', error);
          });
          return this._connectionPromiseQueue;
        }
        /**
         * In dialog Refer Reception
         */
    
      }, {
        key: "_receiveRefer",
        value: function _receiveRefer(request) {
          var _this18 = this;
    
          logger.debug('receiveRefer()');
    
          if (!request.refer_to) {
            logger.debug('no Refer-To header field present in REFER');
            request.reply(400);
            return;
          }
    
          if (request.refer_to.uri.scheme !== JsSIP_C.SIP) {
            logger.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);
          logger.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) {
          logger.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;
    
          logger.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() {
            logger.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);
    
                  logger.warn('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;
            logger.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;
            }
    
            logger.warn(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)) {
            logger.warn('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;
    
          logger.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) {
                  logger.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) {
                  logger.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
                };
                logger.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) {
                  logger.warn('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
                };
                logger.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);
    
                    logger.warn('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] : {};
          logger.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
            };
            logger.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
            };
            logger.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);
              logger.warn('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] : {};
          logger.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
              };
              logger.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
              };
              logger.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);
                logger.warn('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) {
          logger.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) {
            logger.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) {
              logger.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) {
                logger.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;
              }
    
              if (!_this27._isReadyToReOffer()) {
                return;
              }
    
              logger.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;
                }
    
                logger.warn('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) {
          logger.debug('newRTCSession()');
    
          this._ua.newRTCSession(this, {
            originator: originator,
            session: this,
            request: request
          });
        }
      }, {
        key: "_connecting",
        value: function _connecting(request) {
          logger.debug('session connecting');
          logger.debug('emit "connecting"');
          this.emit('connecting', {
            request: request
          });
        }
      }, {
        key: "_progress",
        value: function _progress(originator, response) {
          logger.debug('session progress');
          logger.debug('emit "progress"');
          this.emit('progress', {
            originator: originator,
            response: response || null
          });
        }
      }, {
        key: "_accepted",
        value: function _accepted(originator, message) {
          logger.debug('session accepted');
          this._start_time = new Date();
          logger.debug('emit "accepted"');
          this.emit('accepted', {
            originator: originator,
            response: message || null
          });
        }
      }, {
        key: "_confirmed",
        value: function _confirmed(originator, ack) {
          logger.debug('session confirmed');
          this._is_confirmed = true;
          logger.debug('emit "confirmed"');
          this.emit('confirmed', {
            originator: originator,
            ack: ack || null
          });
        }
      }, {
        key: "_ended",
        value: function _ended(originator, message, cause) {
          logger.debug('session ended');
          this._end_time = new Date();
    
          this._close();
    
          logger.debug('emit "ended"');
          this.emit('ended', {
            originator: originator,
            message: message || null,
            cause: cause
          });
        }
      }, {
        key: "_failed",
        value: function _failed(originator, message, cause) {
          logger.debug('session failed'); // Emit private '_failed' event first.
    
          logger.debug('emit "_failed"');
          this.emit('_failed', {
            originator: originator,
            message: message || null,
            cause: cause
          });
    
          this._close();
    
          logger.debug('emit "failed"');
          this.emit('failed', {
            originator: originator,
            message: message || null,
            cause: cause
          });
        }
      }, {
        key: "_onhold",
        value: function _onhold(originator) {
          logger.debug('session onhold');
    
          this._setLocalMediaStatus();
    
          logger.debug('emit "hold"');
          this.emit('hold', {
            originator: originator
          });
        }
      }, {
        key: "_onunhold",
        value: function _onunhold(originator) {
          logger.debug('session onunhold');
    
          this._setLocalMediaStatus();
    
          logger.debug('emit "unhold"');
          this.emit('unhold', {
            originator: originator
          });
        }
      }, {
        key: "_onmute",
        value: function _onmute(_ref5) {
          var audio = _ref5.audio,
              video = _ref5.video;
          logger.debug('session onmute');
    
          this._setLocalMediaStatus();
    
          logger.debug('emit "muted"');
          this.emit('muted', {
            audio: audio,
            video: video
          });
        }
      }, {
        key: "_onunmute",
        value: function _onunmute(_ref6) {
          var audio = _ref6.audio,
              video = _ref6.video;
          logger.debug('session onunmute');
    
          this._setLocalMediaStatus();
    
          logger.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,"./Logger":9,"./RTCSession/DTMF":15,"./RTCSession/Info":16,"./RTCSession/ReferNotifier":17,"./RTCSession/ReferSubscriber":18,"./RequestSender":20,"./SIPMessage":21,"./Timers":23,"./Transactions":24,"./URI":27,"./Utils":28,"events":31,"sdp-transform":37}],15:[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 Logger = require('../Logger');
    
    var JsSIP_C = require('../Constants');
    
    var Exceptions = require('../Exceptions');
    
    var Utils = require('../Utils');
    
    var logger = new Logger('RTCSession:DTMF');
    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) {
            logger.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,"../Logger":9,"../Utils":28,"events":31}],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 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":28,"events":31}],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 Logger = require('../Logger');
    
    var JsSIP_C = require('../Constants');
    
    var logger = new Logger('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) {
          logger.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,"../Logger":9}],18:[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 Logger = require('../Logger');
    
    var JsSIP_C = require('../Constants');
    
    var Grammar = require('../Grammar');
    
    var Utils = require('../Utils');
    
    var logger = new Logger('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] : {};
          logger.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 (if not already present).
    
          if (!extraHeaders.some(function (header) {
            return header.toLowerCase().startsWith('referred-by:');
          })) {
            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) {
          logger.debug('receiveNotify()');
    
          if (!request.body) {
            return;
          }
    
          var status_line = Grammar.parse(request.body.trim().split('\r\n', 1)[0], 'Status_Line');
    
          if (status_line === -1) {
            logger.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) {
          logger.debug('REFER succeeded');
          logger.debug('emit "requestSucceeded"');
          this.emit('requestSucceeded', {
            response: response
          });
        }
      }, {
        key: "_requestFailed",
        value: function _requestFailed(response, cause) {
          logger.debug('REFER failed');
          logger.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,"../Logger":9,"../Utils":28,"events":31}],19:[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 Logger = require('./Logger');
    
    var Utils = require('./Utils');
    
    var JsSIP_C = require('./Constants');
    
    var SIPMessage = require('./SIPMessage');
    
    var RequestSender = require('./RequestSender');
    
    var logger = new Logger('Registrator');
    var MIN_REGISTER_EXPIRES = 10; // In seconds.
    
    module.exports = /*#__PURE__*/function () {
      function Registrator(ua, transport) {
        _classCallCheck(this, Registrator);
    
        // Force reg_id to 1.
        this._reg_id = 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 = ''; // Contents of the sip.instance Contact header parameter.
    
        this._sipInstance = "\"<urn:uuid:".concat(this._ua.configuration.instance_id, ">\"");
        this._contact += ";reg-id=".concat(this._reg_id);
        this._contact += ";+sip.instance=".concat(this._sipInstance);
      }
    
      _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) {
            logger.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')) {
                      logger.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.
                    // Try to find a matching Contact using sip.instance and reg-id.
    
                    var contact = contacts.find(function (element) {
                      return _this._sipInstance === element.getParam('+sip.instance') && _this._reg_id === parseInt(element.getParam('reg-id'));
                    }); // If no match was found using the sip.instance try comparing the URIs.
    
                    if (!contact) {
                      contact = contacts.find(function (element) {
                        return element.uri.user === _this._ua.contact.uri.user;
                      });
                    }
    
                    if (!contact) {
                      logger.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.
                    var timeout = 60000
                    // 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.
                      logger.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) {
            logger.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,"./Logger":9,"./RequestSender":20,"./SIPMessage":21,"./Utils":28}],20:[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 Logger = require('./Logger');
    
    var JsSIP_C = require('./Constants');
    
    var DigestAuthentication = require('./DigestAuthentication');
    
    var Transactions = require('./Transactions');
    
    var logger = new Logger('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) {
              logger.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,"./Logger":9,"./Transactions":24}],21:[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 Logger = require('./Logger');
    
    var JsSIP_C = require('./Constants');
    
    var Utils = require('./Utils');
    
    var NameAddrHeader = require('./NameAddrHeader');
    
    var Grammar = require('./Grammar');
    
    var logger = new Logger('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);
    
        if (this.ua.configuration.extra_headers) {
          this.extraHeaders = this.extraHeaders.concat(this.ua.configuration.extra_headers);
        } // 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]) {
            logger.debug("header \"".concat(name, "\" not present"));
            return;
          } else if (idx >= this.headers[name].length) {
            logger.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
    
            logger.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);
    
          if (this.ua.configuration.extra_headers) {
            extraHeaders = extraHeaders.concat(this.ua.configuration.extra_headers);
          }
    
          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");
    
          if (this.ua.configuration.extra_headers) {
            var _iterator12 = _createForOfIteratorHelper(this.ua.configuration.extra_headers),
                _step12;
    
            try {
              for (_iterator12.s(); !(_step12 = _iterator12.n()).done;) {
                var header = _step12.value;
                response += "".concat(header.trim(), "\r\n");
              }
            } catch (err) {
              _iterator12.e(err);
            } finally {
              _iterator12.f();
            }
          }
    
          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,"./Logger":9,"./NameAddrHeader":11,"./Utils":28,"sdp-transform":37}],22:[function(require,module,exports){
    "use strict";
    
    var Logger = require('./Logger');
    
    var Utils = require('./Utils');
    
    var Grammar = require('./Grammar');
    
    var logger = new Logger('Socket');
    /**
     * 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') {
        logger.warn('undefined JsSIP.Socket instance');
        return false;
      } // Check Properties.
    
    
      try {
        if (!Utils.isString(socket.url)) {
          logger.warn('missing or invalid JsSIP.Socket url property');
          throw new Error('Missing or invalid JsSIP.Socket url property');
        }
    
        if (!Utils.isString(socket.via_transport)) {
          logger.warn('missing or invalid JsSIP.Socket via_transport property');
          throw new Error('Missing or invalid JsSIP.Socket via_transport property');
        }
    
        if (Grammar.parse(socket.sip_uri, 'SIP_URI') === -1) {
          logger.warn('missing or invalid JsSIP.Socket sip_uri property');
          throw new Error('missing or invalid JsSIP.Socket sip_uri property');
        }
      } catch (e) {
        return false;
      } // Check Methods.
    
    
      try {
        ['connect', 'disconnect', 'send'].forEach(function (method) {
          if (!Utils.isFunction(socket[method])) {
            logger.warn("missing or invalid JsSIP.Socket method: ".concat(method));
            throw new Error("Missing or invalid JsSIP.Socket method: ".concat(method));
          }
        });
      } catch (e) {
        return false;
      }
    
      return true;
    };
    },{"./Grammar":7,"./Logger":9,"./Utils":28}],23:[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
    
    };
    },{}],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 Logger = require('./Logger');
    
    var JsSIP_C = require('./Constants');
    
    var SIPMessage = require('./SIPMessage');
    
    var Timers = require('./Timers');
    
    var loggernict = new Logger('NonInviteClientTransaction');
    var loggerict = new Logger('InviteClientTransaction');
    var loggeract = new Logger('AckClientTransaction');
    var loggernist = new Logger('NonInviteServerTransaction');
    var loggerist = new Logger('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() {
          loggernict.debug("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() {
          loggernict.debug("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) {
            loggerict.debug("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() {
          loggerict.debug("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() {
          loggerict.debug("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() {
          loggerict.debug("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() {
          loggeract.debug("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() {
          loggernist.debug("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;
            loggernist.debug("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() {
          loggerist.debug("Timer H expired for transaction ".concat(this.id));
    
          if (this.state === C.STATUS_COMPLETED) {
            loggerist.debug('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() {
          loggerist.debug("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;
            loggerist.debug("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,"./Logger":9,"./SIPMessage":21,"./Timers":23,"events":31}],25:[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 Logger = require('./Logger');
    
    var Socket = require('./Socket');
    
    var JsSIP_C = require('./Constants');
    
    var logger = new Logger('Transport');
    /**
     * 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);
    
        logger.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; // It seems that TextDecoder is not available in some versions of React-Native.
        // See https://github.com/versatica/JsSIP/issues/695
    
        try {
          this.textDecoder = new TextDecoder('utf8');
        } catch (error) {
          logger.warn("cannot use TextDecoder: ".concat(error));
        }
    
        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() {
          logger.debug('connect()');
    
          if (this.isConnected()) {
            logger.debug('Transport is already connected');
            return;
          } else if (this.isConnecting()) {
            logger.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() {
          logger.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) {
          logger.debug('send()');
    
          if (!this.isConnected()) {
            logger.warn('unable to send message, transport is not connected');
            return false;
          }
    
          var message = data.toString();
          logger.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;
          }
    
          logger.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') {
            logger.debug('received message with CRLF Keep Alive response');
            return;
          } // Binary message.
          else if (typeof data !== 'string') {
              try {
                if (this.textDecoder) data = this.textDecoder.decode(data);else data = String.fromCharCode.apply(null, new Uint8Array(data));
              } catch (evt) {
                logger.debug('received binary message failed to be converted into string,' + ' message discarded');
                return;
              }
    
              logger.debug("received binary message:\n\n".concat(data, "\n"));
            } // Text message.
            else {
                logger.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,"./Logger":9,"./Socket":22}],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 _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 Logger = require('./Logger');
    
    var JsSIP_C = require('./Constants');
    
    var Registrator = require('./Registrator');
    
    var RTCSession = require('./RTCSession');
    
    var Message = require('./Message');
    
    var Options = require('./Options');
    
    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 logger = new Logger('UA');
    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);
    
        logger.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/OPTIONS).
    
        _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() {
          logger.debug('start()');
    
          if (this._status === C.STATUS_INIT) {
            this._transport.connect();
          } else if (this._status === C.STATUS_USER_CLOSED) {
            logger.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) {
            logger.debug('UA is in READY status, not restarted');
          } else {
            logger.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() {
          logger.debug('register()');
          this._dynConfiguration.register = true;
    
          this._registrator.register();
        }
        /**
         * Unregister.
         */
    
      }, {
        key: "unregister",
        value: function unregister(options) {
          logger.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) {
          logger.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) {
          logger.debug('sendMessage()');
          var message = new Message(this);
          message.send(target, body, options);
          return message;
        }
        /**
         * Send a SIP OPTIONS.
         *
         * -param {String} target
         * -param {String} [body]
         * -param {Object} [options]
         *
         * -throws {TypeError}
         *
         */
    
      }, {
        key: "sendOptions",
        value: function sendOptions(target, body, options) {
          logger.debug('sendOptions()');
          var message = new Options(this);
          message.send(target, body, options);
          return message;
        }
        /**
         * Terminate ongoing sessions.
         */
    
      }, {
        key: "terminateSessions",
        value: function terminateSessions(options) {
          logger.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;
    
          logger.debug('stop()'); // Remove dynamic settings.
    
          this._dynConfiguration = {};
    
          if (this._status === C.STATUS_USER_CLOSED) {
            logger.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)) {
              logger.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:
              logger.warn('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:
              logger.warn('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);
        }
        /**
         *  new Options
         */
    
      }, {
        key: "newOptions",
        value: function newOptions(message, data) {
          this._applicants[message] = message;
          this.emit('newOptions', 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) {
            logger.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) {
            if (this.listeners('newOptions').length === 0) {
              request.reply(200);
              return;
            }
    
            var message = new Options(this);
            message.init_incoming(request);
          } 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 {
                  logger.warn('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 {
                  logger.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 {
                  logger.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) {
            logger.warn(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
                });
              }
            }
          }
    
          logger.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':
                  logger.debug("- ".concat(_parameter, ": ").concat(this._configuration[_parameter]));
                  break;
    
                case 'password':
                case 'ha1':
                case 'authorization_jwt':
                  logger.debug("- ".concat(_parameter, ": NOT SHOWN"));
                  break;
    
                default:
                  logger.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,"./Logger":9,"./Message":10,"./Options":12,"./Parser":13,"./RTCSession":14,"./Registrator":19,"./SIPMessage":21,"./Transactions":24,"./Transport":25,"./URI":27,"./Utils":28,"./sanityCheck":30,"events":31}],27:[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":28}],28:[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) {
        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":27}],29:[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 Logger = require('./Logger');
    
    var Grammar = require('./Grammar');
    
    var logger = new Logger('WebSocketInterface');
    
    module.exports = /*#__PURE__*/function () {
      function WebSocketInterface(url) {
        _classCallCheck(this, WebSocketInterface);
    
        logger.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) {
          logger.warn("invalid WebSocket URI: ".concat(url));
          throw new TypeError("Invalid argument: ".concat(url));
        } else if (parsed_url.scheme !== 'wss' && parsed_url.scheme !== 'ws') {
          logger.warn("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() {
          logger.debug('connect()');
    
          if (this.isConnected()) {
            logger.debug("WebSocket ".concat(this._url, " is already connected"));
            return;
          } else if (this.isConnecting()) {
            logger.debug("WebSocket ".concat(this._url, " is connecting"));
            return;
          }
    
          if (this._ws) {
            this.disconnect();
          }
    
          logger.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() {
          logger.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) {
          logger.debug('send()');
    
          if (this.isConnected()) {
            this._ws.send(message);
    
            return true;
          } else {
            logger.warn('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() {
          logger.debug("WebSocket ".concat(this._url, " connected"));
          this.onconnect();
        }
      }, {
        key: "_onClose",
        value: function _onClose(_ref) {
          var wasClean = _ref.wasClean,
              code = _ref.code,
              reason = _ref.reason;
          logger.debug("WebSocket ".concat(this._url, " closed"));
    
          if (wasClean === false) {
            logger.debug('WebSocket abrupt disconnection');
          }
    
          this.ondisconnect(!wasClean, code, reason);
        }
      }, {
        key: "_onMessage",
        value: function _onMessage(_ref2) {
          var data = _ref2.data;
          logger.debug('received WebSocket message');
          this.ondata(data);
        }
      }, {
        key: "_onError",
        value: function _onError(e) {
          logger.warn("WebSocket ".concat(this._url, " error: "), 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,"./Logger":9}],30:[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 Logger = require('./Logger');
    
    var JsSIP_C = require('./Constants');
    
    var SIPMessage = require('./SIPMessage');
    
    var Utils = require('./Utils');
    
    var logger = new Logger('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) {
        logger.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) {
        logger.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)) {
          logger.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,"./Logger":9,"./SIPMessage":21,"./Utils":28}],31:[function(require,module,exports){
    // Copyright Joyent, Inc. and other Node contributors.
    //
    // Permission is hereby granted, free of charge, to any person obtaining a
    // copy of this software and associated documentation files (the
    // "Software"), to deal in the Software without restriction, including
    // without limitation the rights to use, copy, modify, merge, publish,
    // distribute, sublicense, and/or sell copies of the Software, and to permit
    // persons to whom the Software is furnished to do so, subject to the
    // following conditions:
    //
    // The above copyright notice and this permission notice shall be included
    // in all copies or substantial portions of the Software.
    //
    // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
    // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
    // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
    // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
    // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
    // USE OR OTHER DEALINGS IN THE SOFTWARE.
    
    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);
      };
    }
    
    },{}],32:[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":33,"_process":35}],33:[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":34}],34:[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' : '');
    }
    
    },{}],35:[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; };
    
    },{}],36:[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';
        }
      });
    });
    
    },{}],37:[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":38,"./writer":39}],38:[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":36}],39:[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":36}],40:[function(require,module,exports){
    module.exports={
      "name": "jssip",
      "title": "JsSIP",
      "description": "the Javascript SIP library",
      "version": "3.10.0",
      "homepage": "https://jssip.net",
      "contributors": [
        "José Luis Millán <jmillan@aliax.net> (https://github.com/jmillan)",
        "Iñaki Baz Castillo <ibc@aliax.net> (https://inakibaz.me)"
      ],
      "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/events": "^3.0.0",
        "@types/debug": "^4.1.7",
        "debug": "^4.3.1",
        "events": "^3.3.0",
        "sdp-transform": "^2.14.1"
      },
      "devDependencies": {
        "@babel/core": "^7.19.6",
        "@babel/preset-env": "^7.19.4",
        "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": "node npm-scripts.js lint",
        "test": "node npm-scripts.js test",
        "prepublish": "node npm-scripts.js prepublish",
        "release": "node npm-scripts.js release"
      }
    }
    
    },{}]},{},[8])(8)
    });
    