/*!
 * 
 *  SIP version 0.13.8
 *  Copyright (c) 2014-2019 Junction Networks, Inc <http://www.onsip.com>
 *  Homepage: https://sipjs.com
 *  License: https://sipjs.com/license/
 * 
 * 
 *  ~~~SIP.js contains substantial portions of JsSIP under the following license~~~
 *  Homepage: http://jssip.net
 *  Copyright (c) 2012-2013 José Luis Millán - Versatica <http://www.versatica.com>
 * 
 *  Permission is hereby granted, free of charge, to any person obtaining
 *  a copy of this software and associated documentation files (the
 *  "Software"), to deal in the Software without restriction, including
 *  without limitation the rights to use, copy, modify, merge, publish,
 *  distribute, sublicense, and/or sell copies of the Software, and to
 *  permit persons to whom the Software is furnished to do so, subject to
 *  the following conditions:
 * 
 *  The above copyright notice and this permission notice shall be
 *  included in all copies or substantial portions of the Software.
 * 
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS 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.
 * 
 *  ~~~ end JsSIP license ~~~
 * 
 * 
 * 
 * 
 */
(function webpackUniversalModuleDefinition(root, factory) {
	if(typeof exports === 'object' && typeof module === 'object')
		module.exports = factory();
	else if(typeof define === 'function' && define.amd)
		define([], factory);
	else if(typeof exports === 'object')
		exports["SIP"] = factory();
	else
		root["SIP"] = factory();
})(this, function() {
return /******/ (function(modules) { // webpackBootstrap
/******/ 	// The module cache
/******/ 	var installedModules = {};
/******/
/******/ 	// The require function
/******/ 	function __webpack_require__(moduleId) {
/******/
/******/ 		// Check if module is in cache
/******/ 		if(installedModules[moduleId]) {
/******/ 			return installedModules[moduleId].exports;
/******/ 		}
/******/ 		// Create a new module (and put it into the cache)
/******/ 		var module = installedModules[moduleId] = {
/******/ 			i: moduleId,
/******/ 			l: false,
/******/ 			exports: {}
/******/ 		};
/******/
/******/ 		// Execute the module function
/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ 		// Flag the module as loaded
/******/ 		module.l = true;
/******/
/******/ 		// Return the exports of the module
/******/ 		return module.exports;
/******/ 	}
/******/
/******/
/******/ 	// expose the modules object (__webpack_modules__)
/******/ 	__webpack_require__.m = modules;
/******/
/******/ 	// expose the module cache
/******/ 	__webpack_require__.c = installedModules;
/******/
/******/ 	// define getter function for harmony exports
/******/ 	__webpack_require__.d = function(exports, name, getter) {
/******/ 		if(!__webpack_require__.o(exports, name)) {
/******/ 			Object.defineProperty(exports, name, { enumerable: true, get: getter });
/******/ 		}
/******/ 	};
/******/
/******/ 	// define __esModule on exports
/******/ 	__webpack_require__.r = function(exports) {
/******/ 		if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ 			Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ 		}
/******/ 		Object.defineProperty(exports, '__esModule', { value: true });
/******/ 	};
/******/
/******/ 	// create a fake namespace object
/******/ 	// mode & 1: value is a module id, require it
/******/ 	// mode & 2: merge all properties of value into the ns
/******/ 	// mode & 4: return value when already ns object
/******/ 	// mode & 8|1: behave like require
/******/ 	__webpack_require__.t = function(value, mode) {
/******/ 		if(mode & 1) value = __webpack_require__(value);
/******/ 		if(mode & 8) return value;
/******/ 		if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
/******/ 		var ns = Object.create(null);
/******/ 		__webpack_require__.r(ns);
/******/ 		Object.defineProperty(ns, 'default', { enumerable: true, value: value });
/******/ 		if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
/******/ 		return ns;
/******/ 	};
/******/
/******/ 	// getDefaultExport function for compatibility with non-harmony modules
/******/ 	__webpack_require__.n = function(module) {
/******/ 		var getter = module && module.__esModule ?
/******/ 			function getDefault() { return module['default']; } :
/******/ 			function getModuleExports() { return module; };
/******/ 		__webpack_require__.d(getter, 'a', getter);
/******/ 		return getter;
/******/ 	};
/******/
/******/ 	// Object.prototype.hasOwnProperty.call
/******/ 	__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ 	// __webpack_public_path__
/******/ 	__webpack_require__.p = "";
/******/
/******/
/******/ 	// Load entry module and return exports
/******/ 	return __webpack_require__(__webpack_require__.s = 0);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";

Object.defineProperty(exports, "__esModule", { value: true });
var ClientContext_1 = __webpack_require__(1);
exports.ClientContext = ClientContext_1.ClientContext;
var Constants_1 = __webpack_require__(3);
exports.C = Constants_1.C;
var Dialogs_1 = __webpack_require__(16);
exports.Dialog = Dialogs_1.Dialog;
var DigestAuthentication_1 = __webpack_require__(17);
exports.DigestAuthentication = DigestAuthentication_1.DigestAuthentication;
var Enums_1 = __webpack_require__(5);
exports.DialogStatus = Enums_1.DialogStatus;
exports.SessionStatus = Enums_1.SessionStatus;
exports.TypeStrings = Enums_1.TypeStrings;
exports.UAStatus = Enums_1.UAStatus;
var Exceptions_1 = __webpack_require__(8);
exports.Exceptions = Exceptions_1.Exceptions;
var Grammar_1 = __webpack_require__(11);
exports.Grammar = Grammar_1.Grammar;
var LoggerFactory_1 = __webpack_require__(20);
exports.LoggerFactory = LoggerFactory_1.LoggerFactory;
var NameAddrHeader_1 = __webpack_require__(13);
exports.NameAddrHeader = NameAddrHeader_1.NameAddrHeader;
var Parser_1 = __webpack_require__(21);
exports.Parser = Parser_1.Parser;
var PublishContext_1 = __webpack_require__(22);
exports.PublishContext = PublishContext_1.PublishContext;
var RegisterContext_1 = __webpack_require__(23);
exports.RegisterContext = RegisterContext_1.RegisterContext;
var RequestSender_1 = __webpack_require__(6);
exports.RequestSender = RequestSender_1.RequestSender;
var SanityCheck_1 = __webpack_require__(24);
var sanityCheck = SanityCheck_1.SanityCheck.sanityCheck;
exports.sanityCheck = sanityCheck;
var ServerContext_1 = __webpack_require__(25);
exports.ServerContext = ServerContext_1.ServerContext;
var Session_1 = __webpack_require__(26);
exports.InviteClientContext = Session_1.InviteClientContext;
exports.InviteServerContext = Session_1.InviteServerContext;
exports.ReferClientContext = Session_1.ReferClientContext;
exports.ReferServerContext = Session_1.ReferServerContext;
exports.Session = Session_1.Session;
var SIPMessage_1 = __webpack_require__(10);
exports.IncomingRequest = SIPMessage_1.IncomingRequest;
exports.IncomingResponse = SIPMessage_1.IncomingResponse;
exports.OutgoingRequest = SIPMessage_1.OutgoingRequest;
var Subscription_1 = __webpack_require__(28);
exports.Subscription = Subscription_1.Subscription;
var Timers_1 = __webpack_require__(9);
exports.Timers = Timers_1.Timers;
var Transactions_1 = __webpack_require__(7);
var Transactions = {
    InviteClientTransaction: Transactions_1.InviteClientTransaction,
    InviteServerTransaction: Transactions_1.InviteServerTransaction,
    NonInviteClientTransaction: Transactions_1.NonInviteClientTransaction,
    NonInviteServerTransaction: Transactions_1.NonInviteServerTransaction
};
exports.Transactions = Transactions;
var Transport_1 = __webpack_require__(29);
exports.Transport = Transport_1.Transport;
var UA_1 = __webpack_require__(30);
exports.UA = UA_1.UA;
var URI_1 = __webpack_require__(14);
exports.URI = URI_1.URI;
var Utils_1 = __webpack_require__(15);
exports.Utils = Utils_1.Utils;
var Web = __webpack_require__(36);
exports.Web = Web;
// tslint:disable-next-line:no-var-requires
var pkg = __webpack_require__(4);
var name = pkg.title;
exports.name = name;
var version = pkg.version;
exports.version = version;


/***/ }),
/* 1 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";

var __extends = (this && this.__extends) || (function () {
    var extendStatics = function (d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
var events_1 = __webpack_require__(2);
var Constants_1 = __webpack_require__(3);
var Enums_1 = __webpack_require__(5);
var RequestSender_1 = __webpack_require__(6);
var SIPMessage_1 = __webpack_require__(10);
var Utils_1 = __webpack_require__(15);
var ClientContext = /** @class */ (function (_super) {
    __extends(ClientContext, _super);
    function ClientContext(ua, method, target, options) {
        var _this = _super.call(this) || this;
        _this.data = {};
        ClientContext.initializer(_this, ua, method, target, options);
        return _this;
    }
    ClientContext.initializer = function (objToConstruct, ua, method, originalTarget, options) {
        objToConstruct.type = Enums_1.TypeStrings.ClientContext;
        // Validate arguments
        if (originalTarget === undefined) {
            throw new TypeError("Not enough arguments");
        }
        objToConstruct.ua = ua;
        objToConstruct.logger = ua.getLogger("sip.clientcontext");
        objToConstruct.method = method;
        var target = ua.normalizeTarget(originalTarget);
        if (!target) {
            throw new TypeError("Invalid target: " + originalTarget);
        }
        /* Options
        * - extraHeaders
        * - params
        * - contentType
        * - body
        */
        options = Object.create(options || Object.prototype);
        options.extraHeaders = (options.extraHeaders || []).slice();
        // Build the request
        objToConstruct.request = new SIPMessage_1.OutgoingRequest(objToConstruct.method, target, objToConstruct.ua, options.params, options.extraHeaders);
        if (options.body) {
            objToConstruct.body = {};
            objToConstruct.body.body = options.body;
            if (options.contentType) {
                objToConstruct.body.contentType = options.contentType;
            }
            objToConstruct.request.body = objToConstruct.body;
        }
        /* Set other properties from the request */
        if (objToConstruct.request.from) {
            objToConstruct.localIdentity = objToConstruct.request.from;
        }
        if (objToConstruct.request.to) {
            objToConstruct.remoteIdentity = objToConstruct.request.to;
        }
    };
    ClientContext.prototype.send = function () {
        var sender = new RequestSender_1.RequestSender(this, this.ua);
        sender.send();
        return this;
    };
    ClientContext.prototype.receiveResponse = function (response) {
        var statusCode = response.statusCode || 0;
        var cause = Utils_1.Utils.getReasonPhrase(statusCode);
        switch (true) {
            case /^1[0-9]{2}$/.test(statusCode.toString()):
                this.emit("progress", response, cause);
                break;
            case /^2[0-9]{2}$/.test(statusCode.toString()):
                if (this.ua.applicants[this.toString()]) {
                    delete this.ua.applicants[this.toString()];
                }
                this.emit("accepted", response, cause);
                break;
            default:
                if (this.ua.applicants[this.toString()]) {
                    delete this.ua.applicants[this.toString()];
                }
                this.emit("rejected", response, cause);
                this.emit("failed", response, cause);
                break;
        }
    };
    ClientContext.prototype.onRequestTimeout = function () {
        this.emit("failed", undefined, Constants_1.C.causes.REQUEST_TIMEOUT);
    };
    ClientContext.prototype.onTransportError = function () {
        this.emit("failed", undefined, Constants_1.C.causes.CONNECTION_ERROR);
    };
    return ClientContext;
}(events_1.EventEmitter));
exports.ClientContext = ClientContext;


/***/ }),
/* 2 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
// 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 R = typeof Reflect === 'object' ? Reflect : null
var ReflectApply = R && typeof R.apply === 'function'
  ? R.apply
  : function ReflectApply(target, receiver, args) {
    return Function.prototype.apply.call(target, receiver, args);
  }

var ReflectOwnKeys
if (R && typeof R.ownKeys === 'function') {
  ReflectOwnKeys = R.ownKeys
} else if (Object.getOwnPropertySymbols) {
  ReflectOwnKeys = function ReflectOwnKeys(target) {
    return Object.getOwnPropertyNames(target)
      .concat(Object.getOwnPropertySymbols(target));
  };
} else {
  ReflectOwnKeys = function ReflectOwnKeys(target) {
    return Object.getOwnPropertyNames(target);
  };
}

function ProcessEmitWarning(warning) {
  if (console && console.warn) console.warn(warning);
}

var NumberIsNaN = Number.isNaN || function NumberIsNaN(value) {
  return value !== value;
}

function EventEmitter() {
  EventEmitter.init.call(this);
}
module.exports = EventEmitter;

// Backwards-compat with node 0.10.x
EventEmitter.EventEmitter = EventEmitter;

EventEmitter.prototype._events = undefined;
EventEmitter.prototype._eventsCount = 0;
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;

Object.defineProperty(EventEmitter, 'defaultMaxListeners', {
  enumerable: true,
  get: function() {
    return defaultMaxListeners;
  },
  set: function(arg) {
    if (typeof arg !== 'number' || arg < 0 || NumberIsNaN(arg)) {
      throw new RangeError('The value of "defaultMaxListeners" is out of range. It must be a non-negative number. Received ' + arg + '.');
    }
    defaultMaxListeners = arg;
  }
});

EventEmitter.init = function() {

  if (this._events === undefined ||
      this._events === Object.getPrototypeOf(this)._events) {
    this._events = Object.create(null);
    this._eventsCount = 0;
  }

  this._maxListeners = this._maxListeners || undefined;
};

// 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 || NumberIsNaN(n)) {
    throw new RangeError('The value of "n" is out of range. It must be a non-negative number. Received ' + n + '.');
  }
  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);
};

EventEmitter.prototype.emit = function emit(type) {
  var args = [];
  for (var i = 1; i < arguments.length; i++) args.push(arguments[i]);
  var doError = (type === 'error');

  var events = this._events;
  if (events !== undefined)
    doError = (doError && events.error === undefined);
  else if (!doError)
    return false;

  // If there is no 'error' event listener then throw.
  if (doError) {
    var er;
    if (args.length > 0)
      er = args[0];
    if (er instanceof Error) {
      // Note: The comments on the `throw` lines are intentional, they show
      // up in Node's output if this results in an unhandled exception.
      throw er; // Unhandled 'error' event
    }
    // At least give some kind of context to the user
    var err = new Error('Unhandled error.' + (er ? ' (' + er.message + ')' : ''));
    err.context = er;
    throw err; // Unhandled 'error' event
  }

  var handler = events[type];

  if (handler === undefined)
    return false;

  if (typeof handler === 'function') {
    ReflectApply(handler, this, args);
  } else {
    var len = handler.length;
    var listeners = arrayClone(handler, len);
    for (var i = 0; i < len; ++i)
      ReflectApply(listeners[i], this, args);
  }

  return true;
};

function _addListener(target, type, listener, prepend) {
  var m;
  var events;
  var existing;

  if (typeof listener !== 'function') {
    throw new TypeError('The "listener" argument must be of type Function. Received type ' + typeof listener);
  }

  events = target._events;
  if (events === undefined) {
    events = target._events = Object.create(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 !== undefined) {
      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 === undefined) {
    // 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];
      // If we've already got an array, just append.
    } else if (prepend) {
      existing.unshift(listener);
    } else {
      existing.push(listener);
    }

    // Check for listener leak
    m = $getMaxListeners(target);
    if (m > 0 && existing.length > m && !existing.warned) {
      existing.warned = true;
      // No error code for this since it is a Warning
      // eslint-disable-next-line no-restricted-syntax
      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;
      ProcessEmitWarning(w);
    }
  }

  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() {
  var args = [];
  for (var i = 0; i < arguments.length; i++) args.push(arguments[i]);
  if (!this.fired) {
    this.target.removeListener(this.type, this.wrapFn);
    this.fired = true;
    ReflectApply(this.listener, this.target, args);
  }
}

function _onceWrap(target, type, listener) {
  var state = { fired: false, wrapFn: undefined, target: target, type: type, listener: listener };
  var wrapped = onceWrapper.bind(state);
  wrapped.listener = listener;
  state.wrapFn = wrapped;
  return wrapped;
}

EventEmitter.prototype.once = function once(type, listener) {
  if (typeof listener !== 'function') {
    throw new TypeError('The "listener" argument must be of type Function. Received type ' + typeof listener);
  }
  this.on(type, _onceWrap(this, type, listener));
  return this;
};

EventEmitter.prototype.prependOnceListener =
    function prependOnceListener(type, listener) {
      if (typeof listener !== 'function') {
        throw new TypeError('The "listener" argument must be of type Function. Received type ' + typeof listener);
      }
      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('The "listener" argument must be of type Function. Received type ' + typeof listener);
      }

      events = this._events;
      if (events === undefined)
        return this;

      list = events[type];
      if (list === undefined)
        return this;

      if (list === listener || list.listener === listener) {
        if (--this._eventsCount === 0)
          this._events = Object.create(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 !== undefined)
          this.emit('removeListener', type, originalListener || listener);
      }

      return this;
    };

EventEmitter.prototype.off = EventEmitter.prototype.removeListener;

EventEmitter.prototype.removeAllListeners =
    function removeAllListeners(type) {
      var listeners, events, i;

      events = this._events;
      if (events === undefined)
        return this;

      // not listening for removeListener, no need to emit
      if (events.removeListener === undefined) {
        if (arguments.length === 0) {
          this._events = Object.create(null);
          this._eventsCount = 0;
        } else if (events[type] !== undefined) {
          if (--this._eventsCount === 0)
            this._events = Object.create(null);
          else
            delete events[type];
        }
        return this;
      }

      // emit removeListener for all listeners on all events
      if (arguments.length === 0) {
        var keys = Object.keys(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 = Object.create(null);
        this._eventsCount = 0;
        return this;
      }

      listeners = events[type];

      if (typeof listeners === 'function') {
        this.removeListener(type, listeners);
      } else if (listeners !== undefined) {
        // 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 === undefined)
    return [];

  var evlistener = events[type];
  if (evlistener === undefined)
    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 !== undefined) {
    var evlistener = events[type];

    if (typeof evlistener === 'function') {
      return 1;
    } else if (evlistener !== undefined) {
      return evlistener.length;
    }
  }

  return 0;
}

EventEmitter.prototype.eventNames = function eventNames() {
  return this._eventsCount > 0 ? ReflectOwnKeys(this._events) : [];
};

function arrayClone(arr, n) {
  var copy = new Array(n);
  for (var i = 0; i < n; ++i)
    copy[i] = arr[i];
  return copy;
}

function spliceOne(list, index) {
  for (; index + 1 < list.length; index++)
    list[index] = list[index + 1];
  list.pop();
}

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;
}


/***/ }),
/* 3 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";

Object.defineProperty(exports, "__esModule", { value: true });
// tslint:disable-next-line:no-var-requires
var pkg = __webpack_require__(4);
var C;
(function (C) {
    C.USER_AGENT = pkg.title + "/" + pkg.version;
    // SIP scheme
    C.SIP = "sip";
    C.SIPS = "sips";
    // End and Failure causes
    var causes;
    (function (causes) {
        // Generic error causes
        causes["CONNECTION_ERROR"] = "Connection Error";
        causes["INTERNAL_ERROR"] = "Internal Error";
        causes["REQUEST_TIMEOUT"] = "Request Timeout";
        causes["SIP_FAILURE_CODE"] = "SIP Failure Code";
        // SIP error causes
        causes["ADDRESS_INCOMPLETE"] = "Address Incomplete";
        causes["AUTHENTICATION_ERROR"] = "Authentication Error";
        causes["BUSY"] = "Busy";
        causes["DIALOG_ERROR"] = "Dialog Error";
        causes["INCOMPATIBLE_SDP"] = "Incompatible SDP";
        causes["NOT_FOUND"] = "Not Found";
        causes["REDIRECTED"] = "Redirected";
        causes["REJECTED"] = "Rejected";
        causes["UNAVAILABLE"] = "Unavailable";
        // Session error causes
        causes["BAD_MEDIA_DESCRIPTION"] = "Bad Media Description";
        causes["CANCELED"] = "Canceled";
        causes["EXPIRES"] = "Expires";
        causes["NO_ACK"] = "No ACK";
        causes["NO_ANSWER"] = "No Answer";
        causes["NO_PRACK"] = "No PRACK";
        causes["RTP_TIMEOUT"] = "RTP Timeout";
        causes["USER_DENIED_MEDIA_ACCESS"] = "User Denied Media Access";
        causes["WEBRTC_ERROR"] = "WebRTC Error";
        causes["WEBRTC_NOT_SUPPORTED"] = "WebRTC Not Supported";
    })(causes = C.causes || (C.causes = {}));
    var supported;
    (function (supported) {
        supported["REQUIRED"] = "required";
        supported["SUPPORTED"] = "supported";
        supported["UNSUPPORTED"] = "none";
    })(supported = C.supported || (C.supported = {}));
    C.SIP_ERROR_CAUSES = {
        ADDRESS_INCOMPLETE: [484],
        AUTHENTICATION_ERROR: [401, 407],
        BUSY: [486, 600],
        INCOMPATIBLE_SDP: [488, 606],
        NOT_FOUND: [404, 604],
        REDIRECTED: [300, 301, 302, 305, 380],
        REJECTED: [403, 603],
        UNAVAILABLE: [480, 410, 408, 430]
    };
    // SIP Methods
    C.ACK = "ACK";
    C.BYE = "BYE";
    C.CANCEL = "CANCEL";
    C.INFO = "INFO";
    C.INVITE = "INVITE";
    C.MESSAGE = "MESSAGE";
    C.NOTIFY = "NOTIFY";
    C.OPTIONS = "OPTIONS";
    C.REGISTER = "REGISTER";
    C.UPDATE = "UPDATE";
    C.SUBSCRIBE = "SUBSCRIBE";
    C.PUBLISH = "PUBLISH";
    C.REFER = "REFER";
    C.PRACK = "PRACK";
    /* SIP Response Reasons
     * DOC: http://www.iana.org/assignments/sip-parameters
     * Copied from https://github.com/versatica/OverSIP/blob/master/lib/oversip/sip/constants.rb#L7
     */
    C.REASON_PHRASE = {
        100: "Trying",
        180: "Ringing",
        181: "Call Is Being Forwarded",
        182: "Queued",
        183: "Session Progress",
        199: "Early Dialog Terminated",
        200: "OK",
        202: "Accepted",
        204: "No Notification",
        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",
        413: "Request Entity Too Large",
        414: "Request-URI Too Long",
        415: "Unsupported Media Type",
        416: "Unsupported URI Scheme",
        417: "Unknown Resource-Priority",
        420: "Bad Extension",
        421: "Extension Required",
        422: "Session Interval Too Small",
        423: "Interval Too Brief",
        428: "Use Identity Header",
        429: "Provide Referrer Identity",
        430: "Flow Failed",
        433: "Anonymity Disallowed",
        436: "Bad Identity-Info",
        437: "Unsupported Certificate",
        438: "Invalid Identity Header",
        439: "First Hop Lacks Outbound Support",
        440: "Max-Breadth Exceeded",
        469: "Bad Info Package",
        470: "Consent Needed",
        478: "Unresolvable Destination",
        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",
        491: "Request Pending",
        493: "Undecipherable",
        494: "Security Agreement Required",
        500: "Internal Server 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",
        600: "Busy Everywhere",
        603: "Decline",
        604: "Does Not Exist Anywhere",
        606: "Not Acceptable"
    };
    /* SIP Option Tags
     * DOC: http://www.iana.org/assignments/sip-parameters/sip-parameters.xhtml#sip-parameters-4
     */
    C.OPTION_TAGS = {
        "100rel": true,
        "199": true,
        "answermode": true,
        "early-session": true,
        "eventlist": true,
        "explicitsub": true,
        "from-change": true,
        "geolocation-http": true,
        "geolocation-sip": true,
        "gin": true,
        "gruu": true,
        "histinfo": true,
        "ice": true,
        "join": true,
        "multiple-refer": true,
        "norefersub": true,
        "nosub": true,
        "outbound": true,
        "path": true,
        "policy": true,
        "precondition": true,
        "pref": true,
        "privacy": true,
        "recipient-list-invite": true,
        "recipient-list-message": true,
        "recipient-list-subscribe": true,
        "replaces": true,
        "resource-priority": true,
        "sdp-anat": false,
        "sec-agree": true,
        "tdialog": true,
        "timer": true,
        "uui": true // RFC 7433
    };
    var dtmfType;
    (function (dtmfType) {
        dtmfType["INFO"] = "info";
        dtmfType["RTP"] = "rtp";
    })(dtmfType = C.dtmfType || (C.dtmfType = {}));
})(C = exports.C || (exports.C = {}));


/***/ }),
/* 4 */
/***/ (function(module) {

module.exports = {"name":"sip.js","title":"SIP.js","description":"A simple, intuitive, and powerful JavaScript signaling library","version":"0.13.8","license":"MIT","main":"./lib/index.js","types":"./lib/index.d.ts","homepage":"https://sipjs.com","author":"OnSIP <developer@onsip.com> (https://sipjs.com/aboutus/)","contributors":[{"url":"https://github.com/onsip/SIP.js/blob/master/THANKS.md"}],"repository":{"type":"git","url":"https://github.com/onsip/SIP.js.git"},"keywords":["sip","webrtc","library","websocket","javascript","typescript"],"dependencies":{"crypto-js":"^3.1.9-1"},"devDependencies":{"@types/jasmine":"^3.3.11","@types/node":"^11.11.6","circular-dependency-plugin":"^5.0.2","jasmine-core":"^3.3.0","karma":"^4.0.1","karma-chrome-launcher":"^2.2.0","karma-cli":"^2.0.0","karma-jasmine":"^2.0.1","karma-jasmine-html-reporter":"^1.4.0","karma-mocha-reporter":"^2.2.5","karma-sourcemap-loader":"^0.3.7","karma-webpack":"^3.0.5","pegjs":"^0.10.0","ts-loader":"^5.3.3","ts-pegjs":"0.2.2","tslint":"^5.14.0","typescript":"^3.3.4000","webpack":"^4.29.6","webpack-cli":"^3.3.0"},"engines":{"node":">=8.0"},"scripts":{"prebuild":"tslint -p tsconfig-base.json -c tslint.json","generate-grammar":"node build/grammarGenerator.js","build-reg-bundle":"webpack --progress --config build/webpack.config.js --env.buildType reg","build-min-bundle":"webpack --progress --config build/webpack.config.js --env.buildType min","build-bundles":"npm run build-reg-bundle && npm run build-min-bundle","build-lib":"tsc -p src","build-test":"tsc -p test","copy-dist-files":"cp dist/sip.js dist/sip-$npm_package_version.js && cp dist/sip.min.js dist/sip-$npm_package_version.min.js","build":"npm run generate-grammar && npm run build-lib && npm run build-reg-bundle && npm run build-min-bundle && npm run copy-dist-files","browserTest":"npm run build-test && sleep 2 && open http://0.0.0.0:9876/debug.html & karma start --reporters kjhtml --no-single-run","commandLineTest":"npm run build-test && karma start --reporters mocha --browsers ChromeHeadless --single-run","buildAndTest":"npm run build && npm run commandLineTest","buildAndBrowserTest":"npm run build && npm run browserTest"}};

/***/ }),
/* 5 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";

// enums can't really be declared, so they are set here.
// pulled out of individual files to avoid circular dependencies
Object.defineProperty(exports, "__esModule", { value: true });
var DialogStatus;
(function (DialogStatus) {
    DialogStatus[DialogStatus["STATUS_EARLY"] = 1] = "STATUS_EARLY";
    DialogStatus[DialogStatus["STATUS_CONFIRMED"] = 2] = "STATUS_CONFIRMED";
})(DialogStatus = exports.DialogStatus || (exports.DialogStatus = {}));
var SessionStatus;
(function (SessionStatus) {
    // Session states
    SessionStatus[SessionStatus["STATUS_NULL"] = 0] = "STATUS_NULL";
    SessionStatus[SessionStatus["STATUS_INVITE_SENT"] = 1] = "STATUS_INVITE_SENT";
    SessionStatus[SessionStatus["STATUS_1XX_RECEIVED"] = 2] = "STATUS_1XX_RECEIVED";
    SessionStatus[SessionStatus["STATUS_INVITE_RECEIVED"] = 3] = "STATUS_INVITE_RECEIVED";
    SessionStatus[SessionStatus["STATUS_WAITING_FOR_ANSWER"] = 4] = "STATUS_WAITING_FOR_ANSWER";
    SessionStatus[SessionStatus["STATUS_ANSWERED"] = 5] = "STATUS_ANSWERED";
    SessionStatus[SessionStatus["STATUS_WAITING_FOR_PRACK"] = 6] = "STATUS_WAITING_FOR_PRACK";
    SessionStatus[SessionStatus["STATUS_WAITING_FOR_ACK"] = 7] = "STATUS_WAITING_FOR_ACK";
    SessionStatus[SessionStatus["STATUS_CANCELED"] = 8] = "STATUS_CANCELED";
    SessionStatus[SessionStatus["STATUS_TERMINATED"] = 9] = "STATUS_TERMINATED";
    SessionStatus[SessionStatus["STATUS_ANSWERED_WAITING_FOR_PRACK"] = 10] = "STATUS_ANSWERED_WAITING_FOR_PRACK";
    SessionStatus[SessionStatus["STATUS_EARLY_MEDIA"] = 11] = "STATUS_EARLY_MEDIA";
    SessionStatus[SessionStatus["STATUS_CONFIRMED"] = 12] = "STATUS_CONFIRMED";
})(SessionStatus = exports.SessionStatus || (exports.SessionStatus = {}));
var TypeStrings;
(function (TypeStrings) {
    TypeStrings[TypeStrings["ClientContext"] = 0] = "ClientContext";
    TypeStrings[TypeStrings["ConfigurationError"] = 1] = "ConfigurationError";
    TypeStrings[TypeStrings["Dialog"] = 2] = "Dialog";
    TypeStrings[TypeStrings["DigestAuthentication"] = 3] = "DigestAuthentication";
    TypeStrings[TypeStrings["DTMF"] = 4] = "DTMF";
    TypeStrings[TypeStrings["IncomingMessage"] = 5] = "IncomingMessage";
    TypeStrings[TypeStrings["IncomingRequest"] = 6] = "IncomingRequest";
    TypeStrings[TypeStrings["IncomingResponse"] = 7] = "IncomingResponse";
    TypeStrings[TypeStrings["InvalidStateError"] = 8] = "InvalidStateError";
    TypeStrings[TypeStrings["InviteClientContext"] = 9] = "InviteClientContext";
    TypeStrings[TypeStrings["InviteServerContext"] = 10] = "InviteServerContext";
    TypeStrings[TypeStrings["Logger"] = 11] = "Logger";
    TypeStrings[TypeStrings["LoggerFactory"] = 12] = "LoggerFactory";
    TypeStrings[TypeStrings["MethodParameterError"] = 13] = "MethodParameterError";
    TypeStrings[TypeStrings["NameAddrHeader"] = 14] = "NameAddrHeader";
    TypeStrings[TypeStrings["NotSupportedError"] = 15] = "NotSupportedError";
    TypeStrings[TypeStrings["OutgoingRequest"] = 16] = "OutgoingRequest";
    TypeStrings[TypeStrings["Parameters"] = 17] = "Parameters";
    TypeStrings[TypeStrings["PublishContext"] = 18] = "PublishContext";
    TypeStrings[TypeStrings["ReferClientContext"] = 19] = "ReferClientContext";
    TypeStrings[TypeStrings["ReferServerContext"] = 20] = "ReferServerContext";
    TypeStrings[TypeStrings["RegisterContext"] = 21] = "RegisterContext";
    TypeStrings[TypeStrings["RenegotiationError"] = 22] = "RenegotiationError";
    TypeStrings[TypeStrings["RequestSender"] = 23] = "RequestSender";
    TypeStrings[TypeStrings["ServerContext"] = 24] = "ServerContext";
    TypeStrings[TypeStrings["Session"] = 25] = "Session";
    TypeStrings[TypeStrings["SessionDescriptionHandler"] = 26] = "SessionDescriptionHandler";
    TypeStrings[TypeStrings["SessionDescriptionHandlerError"] = 27] = "SessionDescriptionHandlerError";
    TypeStrings[TypeStrings["SessionDescriptionHandlerObserver"] = 28] = "SessionDescriptionHandlerObserver";
    TypeStrings[TypeStrings["Subscription"] = 29] = "Subscription";
    TypeStrings[TypeStrings["Transport"] = 30] = "Transport";
    TypeStrings[TypeStrings["UA"] = 31] = "UA";
    TypeStrings[TypeStrings["URI"] = 32] = "URI";
})(TypeStrings = exports.TypeStrings || (exports.TypeStrings = {}));
// UA status codes
var UAStatus;
(function (UAStatus) {
    UAStatus[UAStatus["STATUS_INIT"] = 0] = "STATUS_INIT";
    UAStatus[UAStatus["STATUS_STARTING"] = 1] = "STATUS_STARTING";
    UAStatus[UAStatus["STATUS_READY"] = 2] = "STATUS_READY";
    UAStatus[UAStatus["STATUS_USER_CLOSED"] = 3] = "STATUS_USER_CLOSED";
    UAStatus[UAStatus["STATUS_NOT_READY"] = 4] = "STATUS_NOT_READY";
})(UAStatus = exports.UAStatus || (exports.UAStatus = {}));


/***/ }),
/* 6 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";

Object.defineProperty(exports, "__esModule", { value: true });
var Constants_1 = __webpack_require__(3);
var Enums_1 = __webpack_require__(5);
var Transactions_1 = __webpack_require__(7);
/**
 * @class Class creating a request sender.
 * @param {Object} applicant
 * @param {SIP.UA} ua
 */
var RequestSender = /** @class */ (function () {
    function RequestSender(applicant, ua) {
        this.type = Enums_1.TypeStrings.RequestSender;
        this.logger = ua.getLogger("sip.requestsender");
        this.loggerFactory = ua.getLoggerFactory();
        this.ua = ua;
        this.applicant = applicant;
        this.method = applicant.request.method;
        this.request = applicant.request;
        this.credentials = undefined;
        this.challenged = false;
        this.staled = false;
        // If ua is in closing process or even closed just allow sending Bye and ACK
        if (ua.status === Enums_1.UAStatus.STATUS_USER_CLOSED && (this.method !== Constants_1.C.BYE && this.method !== Constants_1.C.ACK)) {
            this.onTransportError();
        }
    }
    /**
     * Create the client transaction and send the message.
     */
    RequestSender.prototype.send = function () {
        var _this = this;
        var transport = this.ua.transport;
        if (!transport) {
            throw new Error("Transport undefined.");
        }
        var user = {
            loggerFactory: this.ua.getLoggerFactory(),
            onRequestTimeout: function () { return _this.onRequestTimeout(); },
            onStateChange: function (newState) {
                if (newState === Transactions_1.TransactionState.Terminated) {
                    _this.ua.destroyTransaction(clientTransaction);
                }
            },
            onTransportError: function (error) { return _this.onTransportError(); },
            receiveResponse: function (response) { return _this.receiveResponse(response); }
        };
        var clientTransaction;
        switch (this.method) {
            case "INVITE":
                clientTransaction = new Transactions_1.InviteClientTransaction(this.request, transport, user);
                break;
            case "ACK":
                throw new Error("Cannot make client transaction for ACK method.");
            default:
                clientTransaction = new Transactions_1.NonInviteClientTransaction(this.request, transport, user);
        }
        this.clientTransaction = clientTransaction;
        this.ua.newTransaction(clientTransaction);
        return clientTransaction;
    };
    /**
     * Callback fired when receiving a request timeout error from the client transaction.
     * To be re-defined by the applicant.
     * @event
     */
    RequestSender.prototype.onRequestTimeout = function () {
        this.applicant.onRequestTimeout();
    };
    /**
     * Callback fired when receiving a transport error from the client transaction.
     * To be re-defined by the applicant.
     * @event
     */
    RequestSender.prototype.onTransportError = function () {
        this.applicant.onTransportError();
    };
    /**
     * Called from client transaction when receiving a correct response to the request.
     * Authenticate request if needed or pass the response back to the applicant.
     * @param {SIP.IncomingResponse} response
     */
    RequestSender.prototype.receiveResponse = function (response) {
        var statusCode = response && response.statusCode ? response.statusCode : 0;
        /*
        * Authentication
        * Authenticate once. _challenged_ flag used to avoid infinite authentications.
        */
        if (statusCode === 401 || statusCode === 407) {
            var challenge = void 0;
            var authorizationHeaderName = void 0;
            // Get and parse the appropriate WWW-Authenticate or Proxy-Authenticate header.
            if (statusCode === 401) {
                challenge = response.parseHeader("www-authenticate");
                authorizationHeaderName = "authorization";
            }
            else {
                challenge = response.parseHeader("proxy-authenticate");
                authorizationHeaderName = "proxy-authorization";
            }
            // Verify it seems a valid challenge.
            if (!challenge) {
                this.logger.warn(statusCode + " with wrong or missing challenge, cannot authenticate");
                this.applicant.receiveResponse(response);
                return;
            }
            if (!this.challenged || (!this.staled && challenge.stale === true)) {
                if (!this.credentials && this.ua.configuration.authenticationFactory) {
                    this.credentials = this.ua.configuration.authenticationFactory(this.ua);
                }
                // Verify that the challenge is really valid.
                if (!this.credentials.authenticate(this.request, challenge)) {
                    this.applicant.receiveResponse(response);
                    return;
                }
                this.challenged = true;
                if (challenge.stale) {
                    this.staled = true;
                }
                var cseq = void 0;
                if (response.method === Constants_1.C.REGISTER) {
                    cseq = this.applicant.cseq += 1;
                }
                else if (this.request.dialog) {
                    cseq = this.request.dialog.localSeqnum += 1;
                }
                else {
                    cseq = (this.request.cseq || 0) + 1;
                    this.request.cseq = cseq;
                }
                this.request.setHeader("cseq", cseq + " " + this.method);
                this.request.setHeader(authorizationHeaderName, this.credentials.toString());
                this.send();
            }
            else {
                this.applicant.receiveResponse(response);
            }
        }
        else {
            this.applicant.receiveResponse(response);
        }
    };
    return RequestSender;
}());
exports.RequestSender = RequestSender;


/***/ }),
/* 7 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";

var __extends = (this && this.__extends) || (function () {
    var extendStatics = function (d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
var events_1 = __webpack_require__(2);
var Constants_1 = __webpack_require__(3);
var Exceptions_1 = __webpack_require__(8);
var Timers_1 = __webpack_require__(9);
// tslint:disable:max-classes-per-file
// tslint:disable:no-empty-interface
// FIXME & TODO Issues
// - Unreliable transports are not supported; timers missing/wrong, IP address/port, other?
// - UAS Provisional Retransmission Timer. See RFC 3261 Section 13.3.1.1. Per spec, should be handled by the UAS.
// - 2xx response and ACK handling is not to spec. It works, but arguably should be handled by UAC.
// - Transaction ID is currently the branch parameter value - not completely sufficient for transaction matching.
// - Relationship between Request/Response/Message Classes and Transaction could be refactored/reworked.
/** Transaction state. */
var TransactionState;
(function (TransactionState) {
    TransactionState["Accepted"] = "Accepted";
    TransactionState["Calling"] = "Calling";
    TransactionState["Completed"] = "Completed";
    TransactionState["Confirmed"] = "Confirmed";
    TransactionState["Proceeding"] = "Proceeding";
    TransactionState["Terminated"] = "Terminated";
    TransactionState["Trying"] = "Trying";
})(TransactionState = exports.TransactionState || (exports.TransactionState = {}));
/**
 * Transaction
 *
 * SIP is a transactional protocol: interactions between components take
 * place in a series of independent message exchanges.  Specifically, a
 * SIP transaction consists of a single request and any responses to
 * that request, which include zero or more provisional responses and
 * one or more final responses.  In the case of a transaction where the
 * request was an INVITE (known as an INVITE transaction), the
 * transaction also includes the ACK only if the final response was not
 * a 2xx response.  If the response was a 2xx, the ACK is not considered
 * part of the transaction.
 * https://tools.ietf.org/html/rfc3261#section-17
 */
var Transaction = /** @class */ (function (_super) {
    __extends(Transaction, _super);
    function Transaction(_transport, _user, _id, _state, loggerCategory) {
        var _this = _super.call(this) || this;
        _this._transport = _transport;
        _this._user = _user;
        _this._id = _id;
        _this._state = _state;
        _this.logger = _user.loggerFactory.getLogger(loggerCategory, _id);
        _this.logger.debug("Constructing " + _this.typeToString() + " with id " + _this.id + ".");
        return _this;
    }
    /**
     * Destructor.
     * Once the transaction is in the "terminated" state, it is destroyed
     * immediately and there is no need to call `dispose`. However, if a
     * transaction needs to be ended prematurely, the transaction user may
     * do so by calling this method (for example, perhaps the UA is shutting down).
     * No state transition will occur upon calling this method, all outstanding
     * transmission timers will be cancelled, and use of the transaction after
     * calling `dispose` is undefined.
     */
    Transaction.prototype.dispose = function () {
        this.logger.debug("Destroyed " + this.typeToString() + " with id " + this.id + ".");
    };
    Object.defineProperty(Transaction.prototype, "id", {
        /** Transaction id. */
        get: function () {
            return this._id;
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(Transaction.prototype, "kind", {
        /** Transaction kind. Deprecated. */
        get: function () {
            if (this instanceof InviteClientTransaction) {
                return "ict";
            }
            else if (this instanceof NonInviteClientTransaction) {
                return "nict";
            }
            else if (this instanceof InviteServerTransaction) {
                return "ist";
            }
            else if (this instanceof NonInviteServerTransaction) {
                return "nist";
            }
            throw new Error("Invalid kind.");
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(Transaction.prototype, "state", {
        /** Transaction state. */
        get: function () {
            return this._state;
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(Transaction.prototype, "transport", {
        /** Transaction transport. */
        get: function () {
            return this._transport;
        },
        enumerable: true,
        configurable: true
    });
    Transaction.prototype.on = function (name, callback) { return _super.prototype.on.call(this, name, callback); };
    Transaction.prototype.logTransportError = function (error, message) {
        this.logger.error(error.message);
        this.logger.error("Transport error occurred in " + this.typeToString() + " with id " + this.id + ".");
        this.logger.error(message);
    };
    /**
     * Pass message to transport for transmission. If transport fails,
     * the transaction user is notified by callback to onTransportError().
     * @throws {TransportError} If transport fails.
     */
    Transaction.prototype.send = function (message) {
        var _this = this;
        return this.transport.send(message).catch(function (error) {
            // FIXME: Transport is not, yet, typed and it is not clear
            // yet what send() may or may not send our way. So for now,
            // make sure we convert it to a TransportError if need be.
            if (error instanceof Exceptions_1.Exceptions.TransportError) {
                _this.onTransportError(error);
                return;
            }
            var transportError;
            if (error && typeof error.message === "string") {
                transportError = new Exceptions_1.Exceptions.TransportError(error.message);
            }
            else {
                transportError = new Exceptions_1.Exceptions.TransportError();
            }
            _this.onTransportError(transportError);
            throw transportError;
        });
    };
    Transaction.prototype.setState = function (state) {
        this.logger.debug("State change to \"" + state + "\" on " + this.typeToString() + " with id " + this.id + ".");
        this._state = state;
        if (this._user.onStateChange) {
            this._user.onStateChange(state);
        }
        this.emit("stateChanged");
    };
    Transaction.prototype.typeToString = function () {
        var type = "UnknownType";
        if (this instanceof InviteClientTransaction) {
            type = "INVITE client transaction";
        }
        else if (this instanceof NonInviteClientTransaction) {
            type = "non-INVITE client transaction";
        }
        else if (this instanceof InviteServerTransaction) {
            type = "INVITE server transaction";
        }
        else if (this instanceof NonInviteServerTransaction) {
            type = "non-INVITE server transaction";
        }
        return type;
    };
    return Transaction;
}(events_1.EventEmitter));
exports.Transaction = Transaction;
/**
 * Client Transaction
 *
 * The client transaction provides its functionality through the
 * maintenance of a state machine.
 *
 * The TU communicates with the client transaction through a simple
 * interface.  When the TU wishes to initiate a new transaction, it
 * creates a client transaction and passes it the SIP request to send
 * and an IP address, port, and transport to which to send it.  The
 * client transaction begins execution of its state machine.  Valid
 * responses are passed up to the TU from the client transaction.
 * https://tools.ietf.org/html/rfc3261#section-17.1
 */
var ClientTransaction = /** @class */ (function (_super) {
    __extends(ClientTransaction, _super);
    function ClientTransaction(_request, transport, user, state, loggerCategory) {
        var _this = _super.call(this, transport, user, ClientTransaction.makeId(_request), state, loggerCategory) || this;
        _this._request = _request;
        _this.user = user;
        // The Via header field indicates the transport used for the transaction
        // and identifies the location where the response is to be sent.  A Via
        // header field value is added only after the transport that will be
        // used to reach the next hop has been selected (which may involve the
        // usage of the procedures in [4]).
        // https://tools.ietf.org/html/rfc3261#section-8.1.1.7
        _request.setViaHeader(_this.id, transport);
        // FIXME: Bad hack. Potentially creating circular dependency. SIPMessage needs refactor.
        // Set OutgoingRequest's transaction.
        _request.transaction = _this;
        return _this;
    }
    ClientTransaction.makeId = function (request) {
        if (request.method === "CANCEL") {
            if (!request.branch) {
                throw new Error("Outgoing CANCEL request without a branch.");
            }
            return request.branch;
        }
        else {
            return "z9hG4bK" + Math.floor(Math.random() * 10000000);
        }
    };
    Object.defineProperty(ClientTransaction.prototype, "request", {
        /** The outgoing request the transaction handling. */
        get: function () {
            return this._request;
        },
        enumerable: true,
        configurable: true
    });
    /**
     * A 408 to non-INVITE will always arrive too late to be useful ([3]),
     * The client already has full knowledge of the timeout. The only
     * information this message would convey is whether or not the server
     * believed the transaction timed out. However, with the current design
     * of the NIT, a client cannot do anything with this knowledge. Thus,
     * the 408 is simply wasting network resources and contributes to the
     * response bombardment illustrated in [3].
     * https://tools.ietf.org/html/rfc4320#section-4.1
     */
    ClientTransaction.prototype.onRequestTimeout = function () {
        if (this.user.onRequestTimeout) {
            this.user.onRequestTimeout();
        }
    };
    return ClientTransaction;
}(Transaction));
exports.ClientTransaction = ClientTransaction;
/**
 * INVITE Client Transaction
 *
 * The INVITE transaction consists of a three-way handshake.  The client
 * transaction sends an INVITE, the server transaction sends responses,
 * and the client transaction sends an ACK.
 * https://tools.ietf.org/html/rfc3261#section-17.1.1
 */
var InviteClientTransaction = /** @class */ (function (_super) {
    __extends(InviteClientTransaction, _super);
    /**
     * Constructor.
     * Upon construction, the outgoing request's Via header is updated by calling `setViaHeader`.
     * Then `toString` is called on the outgoing request and the message is sent via the transport.
     * After construction the transaction will be in the "calling" state and the transaction id
     * will equal the branch parameter set in the Via header of the outgoing request.
     * https://tools.ietf.org/html/rfc3261#section-17.1.1
     * @param request The outgoing INVITE request.
     * @param transport The transport.
     * @param user The transaction user.
     */
    function InviteClientTransaction(request, transport, user) {
        var _this = _super.call(this, request, transport, user, TransactionState.Calling, "sip.transaction.ict") || this;
        /**
         * Map of 2xx to-tag => ACK.
         * If value is not undefined, value is the ACK which was sent.
         * If key exists but value is undefined, a 2xx was received but the ACK not yet sent.
         * Otherwise, a 2xx was not (yet) received for this transaction.
         */
        _this.ackRetransmissionCache = new Map();
        // FIXME: Timer A for unreliable transport not implemented
        //
        // If an unreliable transport is being used, the client transaction
        // MUST start timer A with a value of T1. If a reliable transport is being used,
        // the client transaction SHOULD NOT start timer A (Timer A controls request retransmissions).
        // For any transport, the client transaction MUST start timer B with a value
        // of 64*T1 seconds (Timer B controls transaction timeouts).
        // https://tools.ietf.org/html/rfc3261#section-17.1.1.2
        //
        // While not spelled out in the RFC, Timer B is the maximum amount of time that a sender
        // will wait for an INVITE message to be acknowledged (a SIP response message is received).
        // So Timer B should be cleared when the transaction state proceeds from "Calling".
        _this.B = setTimeout(function () { return _this.timer_B(); }, Timers_1.Timers.TIMER_B);
        _this.send(request.toString()).catch(function (error) {
            _this.logTransportError(error, "Failed to send initial outgoing request.");
        });
        return _this;
    }
    /**
     * Destructor.
     */
    InviteClientTransaction.prototype.dispose = function () {
        if (this.B) {
            clearTimeout(this.B);
            this.B = undefined;
        }
        if (this.D) {
            clearTimeout(this.D);
            this.D = undefined;
        }
        if (this.M) {
            clearTimeout(this.M);
            this.M = undefined;
        }
        _super.prototype.dispose.call(this);
    };
    /**
     * ACK a 2xx final response.
     *
     * The transaction includes the ACK only if the final response was not a 2xx response (the
     * transaction will generate and send the ACK to the transport automagically). If the
     * final response was a 2xx, the ACK is not considered part of the transaction (the
     * transaction user needs to generate and send the ACK).
     *
     * This library is not strictly RFC compliant with regard to ACK handling for 2xx final
     * responses. Specifically, retransmissions of ACKs to a 2xx final responses is handled
     * by the transaction layer (instead of the UAC core). The "standard" approach is for
     * the UAC core to receive all 2xx responses and manage sending ACK retransmissions to
     * the transport directly. Herein the transaction layer manages sending ACKs to 2xx responses
     * and any retransmissions of those ACKs as needed.
     *
     * @param ack The outgoing ACK request.
     */
    InviteClientTransaction.prototype.ackResponse = function (ack) {
        var _this = this;
        var toTag = ack.toTag;
        if (!toTag) {
            throw new Error("To tag undefined.");
        }
        var id = "z9hG4bK" + Math.floor(Math.random() * 10000000);
        ack.setViaHeader(id, this.transport);
        this.ackRetransmissionCache.set(toTag, ack); // Add to ACK retransmission cache
        this.send(ack.toString()).catch(function (error) {
            _this.logTransportError(error, "Failed to send ACK to 2xx response.");
        });
    };
    /**
     * Handler for incoming responses from the transport which match this transaction.
     * @param response The incoming response.
     */
    InviteClientTransaction.prototype.receiveResponse = function (response) {
        var _this = this;
        var statusCode = response.statusCode;
        if (!statusCode || statusCode < 100 || statusCode > 699) {
            throw new Error("Invalid status code " + statusCode);
        }
        switch (this.state) {
            case TransactionState.Calling:
                // If the client transaction receives a provisional response while in
                // the "Calling" state, it transitions to the "Proceeding" state. In the
                // "Proceeding" state, the client transaction SHOULD NOT retransmit the
                // request any longer. Furthermore, the provisional response MUST be
                // passed to the TU.  Any further provisional responses MUST be passed
                // up to the TU while in the "Proceeding" state.
                // https://tools.ietf.org/html/rfc3261#section-17.1.1.2
                if (statusCode >= 100 && statusCode <= 199) {
                    this.stateTransition(TransactionState.Proceeding);
                    if (this.user.receiveResponse) {
                        this.user.receiveResponse(response);
                    }
                    return;
                }
                // When a 2xx response is received while in either the "Calling" or
                // "Proceeding" states, the client transaction MUST transition to
                // the "Accepted" state... The 2xx response MUST be passed up to the TU.
                // The client transaction MUST NOT generate an ACK to the 2xx response -- its
                // handling is delegated to the TU. A UAC core will send an ACK to
                // the 2xx response using a new transaction.
                // https://tools.ietf.org/html/rfc6026#section-8.4
                if (statusCode >= 200 && statusCode <= 299) {
                    this.ackRetransmissionCache.set(response.toTag, undefined); // Prime the ACK cache
                    this.stateTransition(TransactionState.Accepted);
                    if (this.user.receiveResponse) {
                        this.user.receiveResponse(response);
                    }
                    return;
                }
                // When in either the "Calling" or "Proceeding" states, reception of
                // a response with status code from 300-699 MUST cause the client
                // transaction to transition to "Completed". The client transaction
                // MUST pass the received response up to the TU, and the client
                // transaction MUST generate an ACK request, even if the transport is
                // reliable (guidelines for constructing the ACK from the response
                // are given in Section 17.1.1.3), and then pass the ACK to the
                // transport layer for transmission. The ACK MUST be sent to the
                // same address, port, and transport to which the original request was sent.
                // https://tools.ietf.org/html/rfc6026#section-8.4
                if (statusCode >= 300 && statusCode <= 699) {
                    this.stateTransition(TransactionState.Completed);
                    this.ack(response);
                    if (this.user.receiveResponse) {
                        this.user.receiveResponse(response);
                    }
                    return;
                }
                break;
            case TransactionState.Proceeding:
                // In the "Proceeding" state, the client transaction SHOULD NOT retransmit the
                // request any longer. Furthermore, the provisional response MUST be
                // passed to the TU.  Any further provisional responses MUST be passed
                // up to the TU while in the "Proceeding" state.
                // https://tools.ietf.org/html/rfc3261#section-17.1.1.2
                if (statusCode >= 100 && statusCode <= 199) {
                    if (this.user.receiveResponse) {
                        this.user.receiveResponse(response);
                    }
                    return;
                }
                // When a 2xx response is received while in either the "Calling" or "Proceeding" states,
                // the client transaction MUST transition to the "Accepted" state...
                // The 2xx response MUST be passed up to the TU. The client
                // transaction MUST NOT generate an ACK to the 2xx response -- its
                // handling is delegated to the TU. A UAC core will send an ACK to
                // the 2xx response using a new transaction.
                // https://tools.ietf.org/html/rfc6026#section-8.4
                if (statusCode >= 200 && statusCode <= 299) {
                    this.ackRetransmissionCache.set(response.toTag, undefined); // Prime the ACK cache
                    this.stateTransition(TransactionState.Accepted);
                    if (this.user.receiveResponse) {
                        this.user.receiveResponse(response);
                    }
                    return;
                }
                // When in either the "Calling" or "Proceeding" states, reception of
                // a response with status code from 300-699 MUST cause the client
                // transaction to transition to "Completed". The client transaction
                // MUST pass the received response up to the TU, and the client
                // transaction MUST generate an ACK request, even if the transport is
                // reliable (guidelines for constructing the ACK from the response
                // are given in Section 17.1.1.3), and then pass the ACK to the
                // transport layer for transmission. The ACK MUST be sent to the
                // same address, port, and transport to which the original request was sent.
                // https://tools.ietf.org/html/rfc6026#section-8.4
                if (statusCode >= 300 && statusCode <= 699) {
                    this.stateTransition(TransactionState.Completed);
                    this.ack(response);
                    if (this.user.receiveResponse) {
                        this.user.receiveResponse(response);
                    }
                    return;
                }
                break;
            case TransactionState.Accepted:
                // The purpose of the "Accepted" state is to allow the client
                // transaction to continue to exist to receive, and pass to the TU,
                // any retransmissions of the 2xx response and any additional 2xx
                // responses from other branches of the INVITE if it forked
                // downstream. Timer M reflects the amount of time that the
                // transaction user will wait for such messages.
                //
                // Any 2xx responses that match this client transaction and that are
                // received while in the "Accepted" state MUST be passed up to the
                // TU. The client transaction MUST NOT generate an ACK to the 2xx
                // response. The client transaction takes no further action.
                // https://tools.ietf.org/html/rfc6026#section-8.4
                if (statusCode >= 200 && statusCode <= 299) {
                    // NOTE: This implementation herein is intentionally not RFC compliant.
                    // While the first 2xx response for a given branch is passed up to the TU,
                    // retransmissions of 2xx responses are absorbed and the ACK associated
                    // with the original response is resent. This approach is taken because
                    // our current transaction users are not currently in a good position to
                    // deal with 2xx retransmission. This SHOULD NOT cause any compliance issues - ;)
                    //
                    // If we don't have a cache hit, pass the response to the TU.
                    if (!this.ackRetransmissionCache.has(response.toTag)) {
                        this.ackRetransmissionCache.set(response.toTag, undefined); // Prime the ACK cache
                        if (this.user.receiveResponse) {
                            this.user.receiveResponse(response);
                        }
                        return;
                    }
                    // If we have a cache hit, try pulling the ACK from cache and retransmitting it.
                    var ack = this.ackRetransmissionCache.get(response.toTag);
                    if (ack) {
                        this.send(ack.toString()).catch(function (error) {
                            _this.logTransportError(error, "Failed to send retransmission of ACK to 2xx response.");
                        });
                        return;
                    }
                    // If an ACK was not found in cache then we have received a retransmitted 2xx
                    // response before the TU responded to the original response (we don't have an ACK yet).
                    // So discard this response under the assumption that the TU will eventually
                    // get us a ACK for the original response.
                    return;
                }
                break;
            case TransactionState.Completed:
                // Any retransmissions of a response with status code 300-699 that
                // are received while in the "Completed" state MUST cause the ACK to
                // be re-passed to the transport layer for retransmission, but the
                // newly received response MUST NOT be passed up to the TU.
                // https://tools.ietf.org/html/rfc6026#section-8.4
                if (statusCode >= 300 && statusCode <= 699) {
                    this.ack(response);
                    return;
                }
                break;
            case TransactionState.Terminated:
                break;
            default:
                throw new Error("Invalid state " + this.state);
        }
        // Any response received that does not match an existing client
        // transaction state machine is simply dropped. (Implementations are,
        // of course, free to log or do other implementation-specific things
        // with such responses, but the implementer should be sure to consider
        // the impact of large numbers of malicious stray responses.)
        // https://tools.ietf.org/html/rfc6026#section-7.2
        var message = "Received unexpected " + statusCode + " response while in state " + this.state + ".";
        this.logger.warn(message);
        return;
    };
    /**
     * The client transaction SHOULD inform the TU that a transport failure
     * has occurred, and the client transaction SHOULD transition directly
     * to the "Terminated" state.  The TU will handle the failover
     * mechanisms described in [4].
     * https://tools.ietf.org/html/rfc3261#section-17.1.4
     * @param error The error.
     */
    InviteClientTransaction.prototype.onTransportError = function (error) {
        if (this.user.onTransportError) {
            this.user.onTransportError(error);
        }
        this.stateTransition(TransactionState.Terminated, true);
    };
    InviteClientTransaction.prototype.ack = function (response) {
        var _this = this;
        // The ACK request constructed by the client transaction MUST contain
        // values for the Call-ID, From, and Request-URI that are equal to the
        // values of those header fields in the request passed to the transport
        // by the client transaction (call this the "original request"). The To
        // header field in the ACK MUST equal the To header field in the
        // response being acknowledged, and therefore will usually differ from
        // the To header field in the original request by the addition of the
        // tag parameter. The ACK MUST contain a single Via header field, and
        // this MUST be equal to the top Via header field of the original
        // request. The CSeq header field in the ACK MUST contain the same
        // value for the sequence number as was present in the original request,
        // but the method parameter MUST be equal to "ACK".
        //
        // If the INVITE request whose response is being acknowledged had Route
        // header fields, those header fields MUST appear in the ACK. This is
        // to ensure that the ACK can be routed properly through any downstream
        // stateless proxies.
        // https://tools.ietf.org/html/rfc3261#section-17.1.1.3
        var ruri = this.request.ruri;
        var callId = this.request.callId;
        var cseq = this.request.cseq;
        var from = this.request.getHeader("from");
        var to = response.getHeader("to");
        var via = this.request.getHeader("via");
        var route = this.request.getHeader("route");
        if (!from) {
            throw new Error("From undefined.");
        }
        if (!to) {
            throw new Error("To undefined.");
        }
        if (!via) {
            throw new Error("Via undefined.");
        }
        var ack = "ACK " + ruri + " SIP/2.0\r\n";
        if (route) {
            ack += "Route: " + route + "\r\n";
        }
        ack += "Via: " + via + "\r\n";
        ack += "To: " + to + "\r\n";
        ack += "From: " + from + "\r\n";
        ack += "Call-ID: " + callId + "\r\n";
        ack += "CSeq: " + cseq + " ACK\r\n";
        ack += "Max-Forwards: 70\r\n";
        ack += "Content-Length: 0\r\n\r\n";
        // TOOO: "User-Agent" header
        this.send(ack).catch(function (error) {
            _this.logTransportError(error, "Failed to send ACK to non-2xx response.");
        });
        return;
    };
    /**
     * Execute a state transition.
     * @param newState New state.
     */
    InviteClientTransaction.prototype.stateTransition = function (newState, dueToTransportError) {
        var _this = this;
        if (dueToTransportError === void 0) { dueToTransportError = false; }
        // Assert valid state transitions.
        var invalidStateTransition = function () {
            throw new Error("Invalid state transition from " + _this.state + " to " + newState);
        };
        switch (newState) {
            case TransactionState.Calling:
                invalidStateTransition();
                break;
            case TransactionState.Proceeding:
                if (this.state !== TransactionState.Calling) {
                    invalidStateTransition();
                }
                break;
            case TransactionState.Accepted:
            case TransactionState.Completed:
                if (this.state !== TransactionState.Calling &&
                    this.state !== TransactionState.Proceeding) {
                    invalidStateTransition();
                }
                break;
            case TransactionState.Terminated:
                if (this.state !== TransactionState.Calling &&
                    this.state !== TransactionState.Accepted &&
                    this.state !== TransactionState.Completed) {
                    if (!dueToTransportError) {
                        invalidStateTransition();
                    }
                }
                break;
            default:
                invalidStateTransition();
        }
        // While not spelled out in the RFC, Timer B is the maximum amount of time that a sender
        // will wait for an INVITE message to be acknowledged (a SIP response message is received).
        // So Timer B should be cleared when the transaction state proceeds from "Calling".
        if (this.B) {
            clearTimeout(this.B);
            this.B = undefined;
        }
        if (newState === TransactionState.Proceeding) {
            // Timers have no effect on "Proceeding" state.
            // In the "Proceeding" state, the client transaction
            // SHOULD NOT retransmit the request any longer.
            // https://tools.ietf.org/html/rfc3261#section-17.1.1.2
        }
        // The client transaction MUST start Timer D when it enters the "Completed" state
        // for any reason, with a value of at least 32 seconds for unreliable transports,
        // and a value of zero seconds for reliable transports.
        // https://tools.ietf.org/html/rfc6026#section-8.4
        if (newState === TransactionState.Completed) {
            this.D = setTimeout(function () { return _this.timer_D(); }, Timers_1.Timers.TIMER_D);
        }
        // The client transaction MUST transition to the "Accepted" state,
        // and Timer M MUST be started with a value of 64*T1.
        // https://tools.ietf.org/html/rfc6026#section-8.4
        if (newState === TransactionState.Accepted) {
            this.M = setTimeout(function () { return _this.timer_M(); }, Timers_1.Timers.TIMER_M);
        }
        // Once the transaction is in the "Terminated" state, it MUST be destroyed immediately.
        // https://tools.ietf.org/html/rfc6026#section-8.7
        if (newState === TransactionState.Terminated) {
            this.dispose();
        }
        // Update state.
        this.setState(newState);
    };
    /**
     * When timer A fires, the client transaction MUST retransmit the
     * request by passing it to the transport layer, and MUST reset the
     * timer with a value of 2*T1.
     * When timer A fires 2*T1 seconds later, the request MUST be
     * retransmitted again (assuming the client transaction is still in this
     * state). This process MUST continue so that the request is
     * retransmitted with intervals that double after each transmission.
     * These retransmissions SHOULD only be done while the client
     * transaction is in the "Calling" state.
     * https://tools.ietf.org/html/rfc3261#section-17.1.1.2
     */
    InviteClientTransaction.prototype.timer_A = function () {
        // TODO
    };
    /**
     * If the client transaction is still in the "Calling" state when timer
     * B fires, the client transaction SHOULD inform the TU that a timeout
     * has occurred.  The client transaction MUST NOT generate an ACK.
     * https://tools.ietf.org/html/rfc3261#section-17.1.1.2
     */
    InviteClientTransaction.prototype.timer_B = function () {
        this.logger.debug("Timer B expired for INVITE client transaction " + this.id + ".");
        if (this.state === TransactionState.Calling) {
            this.onRequestTimeout();
            this.stateTransition(TransactionState.Terminated);
        }
    };
    /**
     * If Timer D fires while the client transaction is in the "Completed" state,
     * the client transaction MUST move to the "Terminated" state.
     * https://tools.ietf.org/html/rfc6026#section-8.4
     */
    InviteClientTransaction.prototype.timer_D = function () {
        this.logger.debug("Timer D expired for INVITE client transaction " + this.id + ".");
        if (this.state === TransactionState.Completed) {
            this.stateTransition(TransactionState.Terminated);
        }
    };
    /**
     * If Timer M fires while the client transaction is in the "Accepted"
     * state, the client transaction MUST move to the "Terminated" state.
     * https://tools.ietf.org/html/rfc6026#section-8.4
     */
    InviteClientTransaction.prototype.timer_M = function () {
        this.logger.debug("Timer M expired for INVITE client transaction " + this.id + ".");
        if (this.state === TransactionState.Accepted) {
            this.stateTransition(TransactionState.Terminated);
        }
    };
    return InviteClientTransaction;
}(ClientTransaction));
exports.InviteClientTransaction = InviteClientTransaction;
/**
 * Non-INVITE Client Transaction
 *
 * Non-INVITE transactions do not make use of ACK.
 * They are simple request-response interactions.
 * https://tools.ietf.org/html/rfc3261#section-17.1.2
 */
var NonInviteClientTransaction = /** @class */ (function (_super) {
    __extends(NonInviteClientTransaction, _super);
    /**
     * Constructor
     * Upon construction, the outgoing request's Via header is updated by calling `setViaHeader`.
     * Then `toString` is called on the outgoing request and the message is sent via the transport.
     * After construction the transaction will be in the "calling" state and the transaction id
     * will equal the branch parameter set in the Via header of the outgoing request.
     * https://tools.ietf.org/html/rfc3261#section-17.1.2
     * @param request The outgoing Non-INVITE request.
     * @param transport The transport.
     * @param user The transaction user.
     */
    function NonInviteClientTransaction(request, transport, user) {
        var _this = _super.call(this, request, transport, user, TransactionState.Trying, "sip.transaction.nict") || this;
        // FIXME: Timer E for unreliable transports not implemented.
        //
        // The "Trying" state is entered when the TU initiates a new client
        // transaction with a request.  When entering this state, the client
        // transaction SHOULD set timer F to fire in 64*T1 seconds. The request
        // MUST be passed to the transport layer for transmission.
        // https://tools.ietf.org/html/rfc3261#section-17.1.2.2
        _this.F = setTimeout(function () { return _this.timer_F(); }, Timers_1.Timers.TIMER_F);
        _this.send(request.toString()).catch(function (error) {
            _this.logTransportError(error, "Failed to send initial outgoing request.");
        });
        return _this;
    }
    /**
     * Destructor.
     */
    NonInviteClientTransaction.prototype.dispose = function () {
        if (this.F) {
            clearTimeout(this.F);
            this.F = undefined;
        }
        if (this.K) {
            clearTimeout(this.K);
            this.K = undefined;
        }
        _super.prototype.dispose.call(this);
    };
    /**
     * Handler for incoming responses from the transport which match this transaction.
     * @param response The incoming response.
     */
    NonInviteClientTransaction.prototype.receiveResponse = function (response) {
        var statusCode = response.statusCode;
        if (!statusCode || statusCode < 100 || statusCode > 699) {
            throw new Error("Invalid status code " + statusCode);
        }
        switch (this.state) {
            case TransactionState.Trying:
                // If a provisional response is received while in the "Trying" state, the
                // response MUST be passed to the TU, and then the client transaction
                // SHOULD move to the "Proceeding" state.
                // https://tools.ietf.org/html/rfc3261#section-17.1.2.2
                if (statusCode >= 100 && statusCode <= 199) {
                    this.stateTransition(TransactionState.Proceeding);
                    if (this.user.receiveResponse) {
                        this.user.receiveResponse(response);
                    }
                    return;
                }
                // If a final response (status codes 200-699) is received while in the
                // "Trying" state, the response MUST be passed to the TU, and the
                // client transaction MUST transition to the "Completed" state.
                // https://tools.ietf.org/html/rfc3261#section-17.1.2.2
                if (statusCode >= 200 && statusCode <= 699) {
                    this.stateTransition(TransactionState.Completed);
                    if (statusCode === 408) {
                        this.onRequestTimeout();
                        return;
                    }
                    if (this.user.receiveResponse) {
                        this.user.receiveResponse(response);
                    }
                    return;
                }
                break;
            case TransactionState.Proceeding:
                // If a provisional response is received while in the "Proceeding" state,
                // the response MUST be passed to the TU. (From Figure 6)
                // https://tools.ietf.org/html/rfc3261#section-17.1.2.2
                if (statusCode >= 100 && statusCode <= 199) {
                    if (this.user.receiveResponse) {
                        return this.user.receiveResponse(response);
                    }
                }
                // If a final response (status codes 200-699) is received while in the
                // "Proceeding" state, the response MUST be passed to the TU, and the
                // client transaction MUST transition to the "Completed" state.
                // https://tools.ietf.org/html/rfc3261#section-17.1.2.2
                if (statusCode >= 200 && statusCode <= 699) {
                    this.stateTransition(TransactionState.Completed);
                    if (statusCode === 408) {
                        this.onRequestTimeout();
                        return;
                    }
                    if (this.user.receiveResponse) {
                        this.user.receiveResponse(response);
                    }
                    return;
                }
            case TransactionState.Completed:
                // The "Completed" state exists to buffer any additional response
                // retransmissions that may be received (which is why the client
                // transaction remains there only for unreliable transports).
                // https://tools.ietf.org/html/rfc3261#section-17.1.2.2
                return;
            case TransactionState.Terminated:
                // For good measure just absorb additional response retransmissions.
                return;
            default:
                throw new Error("Invalid state " + this.state);
        }
        var message = "Non-INVITE client transaction received unexpected " + statusCode + " response while in state " + this.state + ".";
        this.logger.warn(message);
        return;
    };
    /**
     * The client transaction SHOULD inform the TU that a transport failure has occurred,
     * and the client transaction SHOULD transition directly to the "Terminated" state.
     * The TU will handle the failover mechanisms described in [4].
     * https://tools.ietf.org/html/rfc3261#section-17.1.4
     * @param error Trasnsport error
     */
    NonInviteClientTransaction.prototype.onTransportError = function (error) {
        if (this.user.onTransportError) {
            this.user.onTransportError(error);
        }
        this.stateTransition(TransactionState.Terminated, true);
    };
    /**
     * Execute a state transition.
     * @param newState New state.
     */
    NonInviteClientTransaction.prototype.stateTransition = function (newState, dueToTransportError) {
        var _this = this;
        if (dueToTransportError === void 0) { dueToTransportError = false; }
        // Assert valid state transitions.
        var invalidStateTransition = function () {
            throw new Error("Invalid state transition from " + _this.state + " to " + newState);
        };
        switch (newState) {
            case TransactionState.Trying:
                invalidStateTransition();
                break;
            case TransactionState.Proceeding:
                if (this.state !== TransactionState.Trying) {
                    invalidStateTransition();
                }
                break;
            case TransactionState.Completed:
                if (this.state !== TransactionState.Trying &&
                    this.state !== TransactionState.Proceeding) {
                    invalidStateTransition();
                }
                break;
            case TransactionState.Terminated:
                if (this.state !== TransactionState.Trying &&
                    this.state !== TransactionState.Proceeding &&
                    this.state !== TransactionState.Completed) {
                    if (!dueToTransportError) {
                        invalidStateTransition();
                    }
                }
                break;
            default:
                invalidStateTransition();
        }
        // Once the client transaction enters the "Completed" state, it MUST set
        // Timer K to fire in T4 seconds for unreliable transports, and zero
        // seconds for reliable transports  The "Completed" state exists to
        // buffer any additional response retransmissions that may be received
        // (which is why the client transaction remains there only for unreliable transports).
        // https://tools.ietf.org/html/rfc3261#section-17.1.2.2
        if (newState === TransactionState.Completed) {
            if (this.F) {
                clearTimeout(this.F);
                this.F = undefined;
            }
            this.K = setTimeout(function () { return _this.timer_K(); }, Timers_1.Timers.TIMER_K);
        }
        // Once the transaction is in the terminated state, it MUST be destroyed immediately.
        // https://tools.ietf.org/html/rfc3261#section-17.1.2.2
        if (newState === TransactionState.Terminated) {
            this.dispose();
        }
        // Update state.
        this.setState(newState);
    };
    /**
     * If Timer F fires while the client transaction is still in the
     * "Trying" state, the client transaction SHOULD inform the TU about the
     * timeout, and then it SHOULD enter the "Terminated" state.
     * If timer F fires while in the "Proceeding" state, the TU MUST be informed of
     * a timeout, and the client transaction MUST transition to the terminated state.
     * https://tools.ietf.org/html/rfc3261#section-17.1.2.2
     */
    NonInviteClientTransaction.prototype.timer_F = function () {
        this.logger.debug("Timer F expired for non-INVITE client transaction " + this.id + ".");
        if (this.state === TransactionState.Trying || this.state === TransactionState.Proceeding) {
            this.onRequestTimeout();
            this.stateTransition(TransactionState.Terminated);
        }
    };
    /**
     * If Timer K fires while in this (COMPLETED) state, the client transaction
     * MUST transition to the "Terminated" state.
     * https://tools.ietf.org/html/rfc3261#section-17.1.2.2
     */
    NonInviteClientTransaction.prototype.timer_K = function () {
        if (this.state === TransactionState.Completed) {
            this.stateTransition(TransactionState.Terminated);
        }
    };
    return NonInviteClientTransaction;
}(ClientTransaction));
exports.NonInviteClientTransaction = NonInviteClientTransaction;
/**
 * Server Transaction
 * The server transaction is responsible for the delivery of requests to
 * the TU and the reliable transmission of responses.  It accomplishes
 * this through a state machine.  Server transactions are created by the
 * core when a request is received, and transaction handling is desired
 * for that request (this is not always the case).
 * https://tools.ietf.org/html/rfc3261#section-17.2
 */
var ServerTransaction = /** @class */ (function (_super) {
    __extends(ServerTransaction, _super);
    function ServerTransaction(_request, transport, user, state, loggerCategory) {
        var _this = _super.call(this, transport, user, _request.viaBranch, state, loggerCategory) || this;
        _this._request = _request;
        _this.user = user;
        // FIXME: Bad hack. Potentially creating circular dependency. SIPMessage needs refactor.
        // Set IncomingRequest's transaction.
        _request.transaction = _this;
        return _this;
    }
    Object.defineProperty(ServerTransaction.prototype, "request", {
        /** The incoming request the transaction handling. */
        get: function () {
            return this._request;
        },
        enumerable: true,
        configurable: true
    });
    return ServerTransaction;
}(Transaction));
exports.ServerTransaction = ServerTransaction;
/**
 * INVITE Server Transaction
 * https://tools.ietf.org/html/rfc3261#section-17.2.1
 */
var InviteServerTransaction = /** @class */ (function (_super) {
    __extends(InviteServerTransaction, _super);
    /**
     * Constructor.
     * Upon construction, a "100 Trying" reply will be immediately sent.
     * After construction the transaction will be in the "proceeding" state and the transaction
     * `id` will equal the branch parameter set in the Via header of the incoming request.
     * https://tools.ietf.org/html/rfc3261#section-17.2.1
     * @param request Incoming INVITE request from the transport.
     * @param transport The transport.
     * @param user The transaction user.
     */
    function InviteServerTransaction(request, transport, user) {
        var _this = _super.call(this, request, transport, user, TransactionState.Proceeding, "sip.transaction.ist") || this;
        // FIXME: This is in the wrong place - UAS should trigger it.
        // Results in this this.receiveResponse() being called.
        // FIXME: Should be configurable. Only required if TU will not respond in 200ms.
        // https://tools.ietf.org/html/rfc3261#section-17.2.1
        request.reply(100);
        return _this;
    }
    /**
     * Destructor.
     */
    InviteServerTransaction.prototype.dispose = function () {
        this.stopProgressExtensionTimer();
        if (this.H) {
            clearTimeout(this.H);
            this.H = undefined;
        }
        if (this.I) {
            clearTimeout(this.I);
            this.I = undefined;
        }
        if (this.L) {
            clearTimeout(this.L);
            this.L = undefined;
        }
        _super.prototype.dispose.call(this);
    };
    /**
     * Receive requests from transport matching this transaction.
     * @param request Request matching this transaction.
     */
    InviteServerTransaction.prototype.receiveRequest = function (request) {
        var _this = this;
        switch (this.state) {
            case TransactionState.Proceeding:
                // If a request retransmission is received while in the "Proceeding" state, the most
                // recent provisional response that was received from the TU MUST be passed to the
                // transport layer for retransmission.
                // https://tools.ietf.org/html/rfc3261#section-17.2.1
                if (request.method === Constants_1.C.INVITE) {
                    if (this.lastProvisionalResponse) {
                        this.send(this.lastProvisionalResponse).catch(function (error) {
                            _this.logTransportError(error, "Failed to send retransmission of provisional response.");
                        });
                    }
                    return;
                }
                break;
            case TransactionState.Accepted:
                // While in the "Accepted" state, any retransmissions of the INVITE
                // received will match this transaction state machine and will be
                // absorbed by the machine without changing its state. These
                // retransmissions are not passed onto the TU.
                // https://tools.ietf.org/html/rfc6026#section-7.1
                if (request.method === Constants_1.C.INVITE) {
                    return;
                }
                break;
            case TransactionState.Completed:
                // Furthermore, while in the "Completed" state, if a request retransmission is
                // received, the server SHOULD pass the response to the transport for retransmission.
                // https://tools.ietf.org/html/rfc3261#section-17.2.1
                if (request.method === Constants_1.C.INVITE) {
                    if (!this.lastFinalResponse) {
                        throw new Error("Last final response undefined.");
                    }
                    this.send(this.lastFinalResponse).catch(function (error) {
                        _this.logTransportError(error, "Failed to send retransmission of final response.");
                    });
                    return;
                }
                // If an ACK is received while the server transaction is in the "Completed" state,
                // the server transaction MUST transition to the "Confirmed" state.
                // https://tools.ietf.org/html/rfc3261#section-17.2.1
                if (request.method === Constants_1.C.ACK) {
                    this.stateTransition(TransactionState.Confirmed);
                    return;
                }
                break;
            case TransactionState.Confirmed:
                // The purpose of the "Confirmed" state is to absorb any additional ACK messages that arrive,
                // triggered from retransmissions of the final response.
                // https://tools.ietf.org/html/rfc3261#section-17.2.1
                if (request.method === Constants_1.C.INVITE || request.method === Constants_1.C.ACK) {
                    return;
                }
                break;
            case TransactionState.Terminated:
                // For good measure absorb any additional messages that arrive (should not happen).
                if (request.method === Constants_1.C.INVITE || request.method === Constants_1.C.ACK) {
                    return;
                }
                break;
            default:
                throw new Error("Invalid state " + this.state);
        }
        var message = "INVITE server transaction received unexpected " + request.method + " request while in state " + this.state + ".";
        this.logger.warn(message);
        return;
    };
    /**
     * Receive responses from TU for this transaction.
     * @param statusCode Status code of response.
     * @param response Response.
     */
    InviteServerTransaction.prototype.receiveResponse = function (statusCode, response) {
        var _this = this;
        if (statusCode < 100 || statusCode > 699) {
            throw new Error("Invalid status code " + statusCode);
        }
        switch (this.state) {
            case TransactionState.Proceeding:
                // The TU passes any number of provisional responses to the server
                // transaction. So long as the server transaction is in the
                // "Proceeding" state, each of these MUST be passed to the transport
                // layer for transmission. They are not sent reliably by the
                // transaction layer (they are not retransmitted by it) and do not cause
                // a change in the state of the server transaction.
                // https://tools.ietf.org/html/rfc3261#section-17.2.1
                if (statusCode >= 100 && statusCode <= 199) {
                    this.lastProvisionalResponse = response;
                    // Start the progress extension timer only for a non-100 provisional response.
                    if (statusCode > 100) {
                        this.startProgressExtensionTimer(); // FIXME: remove
                    }
                    this.send(response).catch(function (error) {
                        _this.logTransportError(error, "Failed to send 1xx response.");
                    });
                    return;
                }
                // If, while in the "Proceeding" state, the TU passes a 2xx response
                // to the server transaction, the server transaction MUST pass this
                // response to the transport layer for transmission. It is not
                // retransmitted by the server transaction; retransmissions of 2xx
                // responses are handled by the TU. The server transaction MUST then
                // transition to the "Accepted" state.
                // https://tools.ietf.org/html/rfc6026#section-8.5
                if (statusCode >= 200 && statusCode <= 299) {
                    this.lastFinalResponse = response;
                    this.stateTransition(TransactionState.Accepted);
                    this.send(response).catch(function (error) {
                        _this.logTransportError(error, "Failed to send 2xx response.");
                    });
                    return;
                }
                // While in the "Proceeding" state, if the TU passes a response with
                // status code from 300 to 699 to the server transaction, the response
                // MUST be passed to the transport layer for transmission, and the state
                // machine MUST enter the "Completed" state.
                // https://tools.ietf.org/html/rfc3261#section-17.2.1
                if (statusCode >= 300 && statusCode <= 699) {
                    this.lastFinalResponse = response;
                    this.stateTransition(TransactionState.Completed);
                    this.send(response).catch(function (error) {
                        _this.logTransportError(error, "Failed to send non-2xx final response.");
                    });
                    return;
                }
                break;
            case TransactionState.Accepted:
                // While in the "Accepted" state, if the TU passes a 2xx response,
                // the server transaction MUST pass the response to the transport layer for transmission.
                // https://tools.ietf.org/html/rfc6026#section-8.7
                if (statusCode >= 200 && statusCode <= 299) {
                    this.send(response).catch(function (error) {
                        _this.logTransportError(error, "Failed to send 2xx response.");
                    });
                    return;
                }
                break;
            case TransactionState.Completed:
                break;
            case TransactionState.Confirmed:
                break;
            case TransactionState.Terminated:
                break;
            default:
                throw new Error("Invalid state " + this.state);
        }
        var message = "INVITE server transaction received unexpected " + statusCode + " response from TU while in state " + this.state + ".";
        this.logger.error(message);
        throw new Error(message);
    };
    /**
     * First, the procedures in [4] are followed, which attempt to deliver the response to a backup.
     * If those should all fail, based on the definition of failure in [4], the server transaction SHOULD
     * inform the TU that a failure has occurred, and MUST remain in the current state.
     * https://tools.ietf.org/html/rfc6026#section-8.8
     */
    InviteServerTransaction.prototype.onTransportError = function (error) {
        if (this.user.onTransportError) {
            this.user.onTransportError(error);
        }
    };
    /**
     * Execute a state transition.
     * @param newState New state.
     */
    InviteServerTransaction.prototype.stateTransition = function (newState) {
        var _this = this;
        // Assert valid state transitions.
        var invalidStateTransition = function () {
            throw new Error("Invalid state transition from " + _this.state + " to " + newState);
        };
        switch (newState) {
            case TransactionState.Proceeding:
                invalidStateTransition();
                break;
            case TransactionState.Accepted:
            case TransactionState.Completed:
                if (this.state !== TransactionState.Proceeding) {
                    invalidStateTransition();
                }
                break;
            case TransactionState.Confirmed:
                if (this.state !== TransactionState.Completed) {
                    invalidStateTransition();
                }
                break;
            case TransactionState.Terminated:
                if (this.state !== TransactionState.Accepted &&
                    this.state !== TransactionState.Completed &&
                    this.state !== TransactionState.Confirmed) {
                    invalidStateTransition();
                }
                break;
            default:
                invalidStateTransition();
        }
        // On any state transition, stop resending provisonal responses
        this.stopProgressExtensionTimer();
        // The purpose of the "Accepted" state is to absorb retransmissions of an accepted INVITE request.
        // Any such retransmissions are absorbed entirely within the server transaction.
        // They are not passed up to the TU since any downstream UAS cores that accepted the request have
        // taken responsibility for reliability and will already retransmit their 2xx responses if necessary.
        // https://tools.ietf.org/html/rfc6026#section-8.7
        if (newState === TransactionState.Accepted) {
            this.L = setTimeout(function () { return _this.timer_L(); }, Timers_1.Timers.TIMER_L);
        }
        // When the "Completed" state is entered, timer H MUST be set to fire in 64*T1 seconds for all transports.
        // Timer H determines when the server transaction abandons retransmitting the response.
        // If an ACK is received while the server transaction is in the "Completed" state,
        // the server transaction MUST transition to the "Confirmed" state.
        // https://tools.ietf.org/html/rfc3261#section-17.2.1
        if (newState === TransactionState.Completed) {
            // FIXME: Missing timer G for unreliable transports.
            this.H = setTimeout(function () { return _this.timer_H(); }, Timers_1.Timers.TIMER_H);
        }
        // The purpose of the "Confirmed" state is to absorb any additional ACK messages that arrive,
        // triggered from retransmissions of the final response. When this state is entered, timer I
        // is set to fire in T4 seconds for unreliable transports, and zero seconds for reliable
        // transports. Once timer I fires, the server MUST transition to the "Terminated" state.
        // https://tools.ietf.org/html/rfc3261#section-17.2.1
        if (newState === TransactionState.Confirmed) {
            // FIXME: This timer is not getting set correctly for unreliable transports.
            this.I = setTimeout(function () { return _this.timer_I(); }, Timers_1.Timers.TIMER_I);
        }
        // Once the transaction is in the "Terminated" state, it MUST be destroyed immediately.
        // https://tools.ietf.org/html/rfc6026#section-8.7
        if (newState === TransactionState.Terminated) {
            this.dispose();
        }
        // Update state.
        this.setState(newState);
    };
    /**
     * FIXME: UAS Provisional Retransmission Timer. See RFC 3261 Section 13.3.1.1
     * This is in the wrong place. This is not a transaction level thing. It's a UAS level thing.
     */
    InviteServerTransaction.prototype.startProgressExtensionTimer = function () {
        var _this = this;
        // Start the progress extension timer only for the first non-100 provisional response.
        if (this.progressExtensionTimer === undefined) {
            this.progressExtensionTimer = setInterval(function () {
                _this.logger.debug("Progress extension timer expired for INVITE server transaction " + _this.id + ".");
                if (!_this.lastProvisionalResponse) {
                    throw new Error("Last provisional response undefined.");
                }
                _this.send(_this.lastProvisionalResponse).catch(function (error) {
                    _this.logTransportError(error, "Failed to send retransmission of provisional response.");
                });
            }, Timers_1.Timers.PROVISIONAL_RESPONSE_INTERVAL);
        }
    };
    /**
     * FIXME: UAS Provisional Retransmission Timer id. See RFC 3261 Section 13.3.1.1
     * This is in the wrong place. This is not a transaction level thing. It's a UAS level thing.
     */
    InviteServerTransaction.prototype.stopProgressExtensionTimer = function () {
        if (this.progressExtensionTimer !== undefined) {
            clearInterval(this.progressExtensionTimer);
            this.progressExtensionTimer = undefined;
        }
    };
    /**
     * While in the "Proceeding" state, if the TU passes a response with status code
     * from 300 to 699 to the server transaction, the response MUST be passed to the
     * transport layer for transmission, and the state machine MUST enter the "Completed" state.
     * For unreliable transports, timer G is set to fire in T1 seconds, and is not set to fire for
     * reliable transports. If timer G fires, the response is passed to the transport layer once
     * more for retransmission, and timer G is set to fire in MIN(2*T1, T2) seconds. From then on,
     * when timer G fires, the response is passed to the transport again for transmission, and
     * timer G is reset with a value that doubles, unless that value exceeds T2, in which case
     * it is reset with the value of T2.
     * https://tools.ietf.org/html/rfc3261#section-17.2.1
     */
    InviteServerTransaction.prototype.timer_G = function () {
        // TODO
    };
    /**
     * If timer H fires while in the "Completed" state, it implies that the ACK was never received.
     * In this case, the server transaction MUST transition to the "Terminated" state, and MUST
     * indicate to the TU that a transaction failure has occurred.
     * https://tools.ietf.org/html/rfc3261#section-17.2.1
     */
    InviteServerTransaction.prototype.timer_H = function () {
        this.logger.debug("Timer H expired for INVITE server transaction " + this.id + ".");
        if (this.state === TransactionState.Completed) {
            this.logger.warn("ACK to negative final response was never received, terminating transaction.");
            this.stateTransition(TransactionState.Terminated);
        }
    };
    /**
     * Once timer I fires, the server MUST transition to the "Terminated" state.
     * https://tools.ietf.org/html/rfc3261#section-17.2.1
     */
    InviteServerTransaction.prototype.timer_I = function () {
        this.logger.debug("Timer I expired for INVITE server transaction " + this.id + ".");
        this.stateTransition(TransactionState.Terminated);
    };
    /**
     * When Timer L fires and the state machine is in the "Accepted" state, the machine MUST
     * transition to the "Terminated" state. Once the transaction is in the "Terminated" state,
     * it MUST be destroyed immediately. Timer L reflects the amount of time the server
     * transaction could receive 2xx responses for retransmission from the
     * TU while it is waiting to receive an ACK.
     * https://tools.ietf.org/html/rfc6026#section-7.1
     * https://tools.ietf.org/html/rfc6026#section-8.7
     */
    InviteServerTransaction.prototype.timer_L = function () {
        this.logger.debug("Timer L expired for INVITE server transaction " + this.id + ".");
        if (this.state === TransactionState.Accepted) {
            this.stateTransition(TransactionState.Terminated);
        }
    };
    return InviteServerTransaction;
}(ServerTransaction));
exports.InviteServerTransaction = InviteServerTransaction;
/**
 * Non-INVITE Server Transaction
 * https://tools.ietf.org/html/rfc3261#section-17.2.2
 */
var NonInviteServerTransaction = /** @class */ (function (_super) {
    __extends(NonInviteServerTransaction, _super);
    /**
     * Constructor.
     * After construction the transaction will be in the "trying": state and the transaction
     * `id` will equal the branch parameter set in the Via header of the incoming request.
     * https://tools.ietf.org/html/rfc3261#section-17.2.2
     * @param request Incoming Non-INVITE request from the transport.
     * @param transport The transport.
     * @param user The transaction user.
     */
    function NonInviteServerTransaction(request, transport, user) {
        return _super.call(this, request, transport, user, TransactionState.Trying, "sip.transaction.nist") || this;
    }
    /**
     * Destructor.
     */
    NonInviteServerTransaction.prototype.dispose = function () {
        if (this.J) {
            clearTimeout(this.J);
            this.J = undefined;
        }
        _super.prototype.dispose.call(this);
    };
    /**
     * Receive requests from transport matching this transaction.
     * @param request Request matching this transaction.
     */
    NonInviteServerTransaction.prototype.receiveRequest = function (request) {
        var _this = this;
        switch (this.state) {
            case TransactionState.Trying:
                // Once in the "Trying" state, any further request retransmissions are discarded.
                // https://tools.ietf.org/html/rfc3261#section-17.2.2
                break;
            case TransactionState.Proceeding:
                // If a retransmission of the request is received while in the "Proceeding" state,
                // the most recently sent provisional response MUST be passed to the transport layer for retransmission.
                // https://tools.ietf.org/html/rfc3261#section-17.2.2
                if (!this.lastResponse) {
                    throw new Error("Last response undefined.");
                }
                this.send(this.lastResponse).catch(function (error) {
                    _this.logTransportError(error, "Failed to send retransmission of provisional response.");
                });
                break;
            case TransactionState.Completed:
                // While in the "Completed" state, the server transaction MUST pass the final response to the transport
                // layer for retransmission whenever a retransmission of the request is received. Any other final responses
                // passed by the TU to the server transaction MUST be discarded while in the "Completed" state.
                // https://tools.ietf.org/html/rfc3261#section-17.2.2
                if (!this.lastResponse) {
                    throw new Error("Last response undefined.");
                }
                this.send(this.lastResponse).catch(function (error) {
                    _this.logTransportError(error, "Failed to send retransmission of final response.");
                });
                break;
            case TransactionState.Terminated:
                break;
            default:
                throw new Error("Invalid state " + this.state);
        }
    };
    /**
     * Receive responses from TU for this transaction.
     * @param statusCode Status code of repsonse. 101-199 not allowed per RFC 4320.
     * @param response Response to send.
     */
    NonInviteServerTransaction.prototype.receiveResponse = function (statusCode, response) {
        var _this = this;
        if (statusCode < 100 || statusCode > 699) {
            throw new Error("Invalid status code " + statusCode);
        }
        // An SIP element MUST NOT send any provisional response with a
        // Status-Code other than 100 to a non-INVITE request.
        // An SIP element MUST NOT respond to a non-INVITE request with a
        // Status-Code of 100 over any unreliable transport, such as UDP,
        // before the amount of time it takes a client transaction's Timer E to be reset to T2.
        // An SIP element MAY respond to a non-INVITE request with a
        // Status-Code of 100 over a reliable transport at any time.
        // https://tools.ietf.org/html/rfc4320#section-4.1
        if (statusCode > 100 && statusCode <= 199) {
            throw new Error("Provisional response other than 100 not allowed.");
        }
        switch (this.state) {
            case TransactionState.Trying:
                // While in the "Trying" state, if the TU passes a provisional response
                // to the server transaction, the server transaction MUST enter the "Proceeding" state.
                // The response MUST be passed to the transport layer for transmission.
                // https://tools.ietf.org/html/rfc3261#section-17.2.2
                this.lastResponse = response;
                if (statusCode >= 100 && statusCode < 200) {
                    this.stateTransition(TransactionState.Proceeding);
                    this.send(response).catch(function (error) {
                        _this.logTransportError(error, "Failed to send provisional response.");
                    });
                    return;
                }
                if (statusCode >= 200 && statusCode <= 699) {
                    this.stateTransition(TransactionState.Completed);
                    this.send(response).catch(function (error) {
                        _this.logTransportError(error, "Failed to send final response.");
                    });
                    return;
                }
                break;
            case TransactionState.Proceeding:
                // Any further provisional responses that are received from the TU while
                // in the "Proceeding" state MUST be passed to the transport layer for transmission.
                // If the TU passes a final response (status codes 200-699) to the server while in
                // the "Proceeding" state, the transaction MUST enter the "Completed" state, and
                // the response MUST be passed to the transport layer for transmission.
                // https://tools.ietf.org/html/rfc3261#section-17.2.2
                this.lastResponse = response;
                if (statusCode >= 200 && statusCode <= 699) {
                    this.stateTransition(TransactionState.Completed);
                    this.send(response).catch(function (error) {
                        _this.logTransportError(error, "Failed to send final response.");
                    });
                    return;
                }
                break;
            case TransactionState.Completed:
                // Any other final responses passed by the TU to the server
                // transaction MUST be discarded while in the "Completed" state.
                // https://tools.ietf.org/html/rfc3261#section-17.2.2
                return;
            case TransactionState.Terminated:
                break;
            default:
                throw new Error("Invalid state " + this.state);
        }
        var message = "Non-INVITE server transaction received unexpected " + statusCode + " response from TU while in state " + this.state + ".";
        this.logger.error(message);
        throw new Error(message);
    };
    /**
     * First, the procedures in [4] are followed, which attempt to deliver the response to a backup.
     * If those should all fail, based on the definition of failure in [4], the server transaction SHOULD
     * inform the TU that a failure has occurred, and SHOULD transition to the terminated state.
     * https://tools.ietf.org/html/rfc3261#section-17.2.4
     */
    NonInviteServerTransaction.prototype.onTransportError = function (error) {
        if (this.user.onTransportError) {
            this.user.onTransportError(error);
        }
        this.stateTransition(TransactionState.Terminated, true);
    };
    NonInviteServerTransaction.prototype.stateTransition = function (newState, dueToTransportError) {
        var _this = this;
        if (dueToTransportError === void 0) { dueToTransportError = false; }
        // Assert valid state transitions.
        var invalidStateTransition = function () {
            throw new Error("Invalid state transition from " + _this.state + " to " + newState);
        };
        switch (newState) {
            case TransactionState.Trying:
                invalidStateTransition();
                break;
            case TransactionState.Proceeding:
                if (this.state !== TransactionState.Trying) {
                    invalidStateTransition();
                }
                break;
            case TransactionState.Completed:
                if (this.state !== TransactionState.Trying && this.state !== TransactionState.Proceeding) {
                    invalidStateTransition();
                }
                break;
            case TransactionState.Terminated:
                if (this.state !== TransactionState.Proceeding && this.state !== TransactionState.Completed) {
                    if (!dueToTransportError) {
                        invalidStateTransition();
                    }
                }
                break;
            default:
                invalidStateTransition();
        }
        // When the server transaction enters the "Completed" state, it MUST set Timer J to fire
        // in 64*T1 seconds for unreliable transports, and zero seconds for reliable transports.
        // https://tools.ietf.org/html/rfc3261#section-17.2.2
        if (newState === TransactionState.Completed) {
            this.J = setTimeout(function () { return _this.timer_J(); }, Timers_1.Timers.TIMER_J);
        }
        // The server transaction MUST be destroyed the instant it enters the "Terminated" state.
        // https://tools.ietf.org/html/rfc3261#section-17.2.2
        if (newState === TransactionState.Terminated) {
            this.dispose();
        }
        this.setState(newState);
    };
    /**
     * The server transaction remains in this state until Timer J fires,
     * at which point it MUST transition to the "Terminated" state.
     * https://tools.ietf.org/html/rfc3261#section-17.2.2
     */
    NonInviteServerTransaction.prototype.timer_J = function () {
        this.logger.debug("Timer J expired for NON-INVITE server transaction " + this.id + ".");
        if (this.state === TransactionState.Completed) {
            this.stateTransition(TransactionState.Terminated);
        }
    };
    return NonInviteServerTransaction;
}(ServerTransaction));
exports.NonInviteServerTransaction = NonInviteServerTransaction;


/***/ }),
/* 8 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";

var __extends = (this && this.__extends) || (function () {
    var extendStatics = function (d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
var Enums_1 = __webpack_require__(5);
// tslint:disable:max-classes-per-file
/**
 * An Exception is considered a condition that a reasonable application may wish to catch.
 * An Error indicates serious problems that a reasonable application should not try to catch.
 */
var Exception = /** @class */ (function (_super) {
    __extends(Exception, _super);
    function Exception(message) {
        var _newTarget = this.constructor;
        var _this = _super.call(this, message) || this;
        Object.setPrototypeOf(_this, _newTarget.prototype); // restore prototype chain
        return _this;
    }
    return Exception;
}(Error));
exports.Exception = Exception;
var Exceptions;
(function (Exceptions) {
    /**
     * Transport error.
     */
    var TransportError = /** @class */ (function (_super) {
        __extends(TransportError, _super);
        function TransportError(message) {
            return _super.call(this, message ? message : "Unspecified transport error.") || this;
        }
        return TransportError;
    }(Exception));
    Exceptions.TransportError = TransportError;
})(Exceptions = exports.Exceptions || (exports.Exceptions = {}));
/**
 * DEPRECATED: The original implementation of exceptions in this library attempted to
 * deal with the lack of type checking in JavaScript by adding a "type" attribute
 * to objects and using that to discriminate. On top of that it layered allcoated
 * "code" numbers and constant "name" strings. All of that is unnecessary when using
 * TypeScript, inheriting from Error and properly setting up the prototype chain...
 */
var LegacyException = /** @class */ (function (_super) {
    __extends(LegacyException, _super);
    function LegacyException(code, name, message) {
        var _this = _super.call(this, message) || this;
        _this.code = code;
        _this.name = name;
        _this.message = message;
        return _this;
    }
    return LegacyException;
}(Exception));
(function (Exceptions) {
    var ConfigurationError = /** @class */ (function (_super) {
        __extends(ConfigurationError, _super);
        function ConfigurationError(parameter, value) {
            var _this = _super.call(this, 1, "CONFIGURATION_ERROR", (!value) ? "Missing parameter: " + parameter :
                "Invalid value " + JSON.stringify(value) + " for parameter '" + parameter + "'") || this;
            _this.type = Enums_1.TypeStrings.ConfigurationError;
            _this.parameter = parameter;
            _this.value = value;
            return _this;
        }
        return ConfigurationError;
    }(LegacyException));
    Exceptions.ConfigurationError = ConfigurationError;
    var InvalidStateError = /** @class */ (function (_super) {
        __extends(InvalidStateError, _super);
        function InvalidStateError(status) {
            var _this = _super.call(this, 2, "INVALID_STATE_ERROR", "Invalid status: " + status) || this;
            _this.type = Enums_1.TypeStrings.InvalidStateError;
            _this.status = status;
            return _this;
        }
        return InvalidStateError;
    }(LegacyException));
    Exceptions.InvalidStateError = InvalidStateError;
    var NotSupportedError = /** @class */ (function (_super) {
        __extends(NotSupportedError, _super);
        function NotSupportedError(message) {
            var _this = _super.call(this, 3, "NOT_SUPPORTED_ERROR", message) || this;
            _this.type = Enums_1.TypeStrings.NotSupportedError;
            return _this;
        }
        return NotSupportedError;
    }(LegacyException));
    Exceptions.NotSupportedError = NotSupportedError;
    // 4 was GetDescriptionError, which was deprecated and now removed
    var RenegotiationError = /** @class */ (function (_super) {
        __extends(RenegotiationError, _super);
        function RenegotiationError(message) {
            var _this = _super.call(this, 5, "RENEGOTIATION_ERROR", message) || this;
            _this.type = Enums_1.TypeStrings.RenegotiationError;
            return _this;
        }
        return RenegotiationError;
    }(LegacyException));
    Exceptions.RenegotiationError = RenegotiationError;
    var MethodParameterError = /** @class */ (function (_super) {
        __extends(MethodParameterError, _super);
        function MethodParameterError(method, parameter, value) {
            var _this = _super.call(this, 6, "METHOD_PARAMETER_ERROR", (!value) ?
                "Missing parameter: " + parameter :
                "Invalid value " + JSON.stringify(value) + " for parameter '" + parameter + "'") || this;
            _this.type = Enums_1.TypeStrings.MethodParameterError;
            _this.method = method;
            _this.parameter = parameter;
            _this.value = value;
            return _this;
        }
        return MethodParameterError;
    }(LegacyException));
    Exceptions.MethodParameterError = MethodParameterError;
    // 7 was TransportError, which was replaced
    var SessionDescriptionHandlerError = /** @class */ (function (_super) {
        __extends(SessionDescriptionHandlerError, _super);
        function SessionDescriptionHandlerError(method, error, message) {
            var _this = _super.call(this, 8, "SESSION_DESCRIPTION_HANDLER_ERROR", message || "Error with Session Description Handler") || this;
            _this.type = Enums_1.TypeStrings.SessionDescriptionHandlerError;
            _this.method = method;
            _this.error = error;
            return _this;
        }
        return SessionDescriptionHandlerError;
    }(LegacyException));
    Exceptions.SessionDescriptionHandlerError = SessionDescriptionHandlerError;
})(Exceptions = exports.Exceptions || (exports.Exceptions = {}));


/***/ }),
/* 9 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";

Object.defineProperty(exports, "__esModule", { value: true });
var T1 = 500;
var T2 = 4000;
var T4 = 5000;
exports.Timers = {
    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 * T4,
    TIMER_J: 0 * T1,
    TIMER_K: 0 * T4,
    TIMER_L: 64 * T1,
    TIMER_M: 64 * T1,
    TIMER_N: 64 * T1,
    PROVISIONAL_RESPONSE_INTERVAL: 60000 // See RFC 3261 Section 13.3.1.1
};


/***/ }),
/* 10 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";

var __extends = (this && this.__extends) || (function () {
    var extendStatics = function (d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
var Constants_1 = __webpack_require__(3);
var Enums_1 = __webpack_require__(5);
var Grammar_1 = __webpack_require__(11);
var Transactions_1 = __webpack_require__(7);
var Utils_1 = __webpack_require__(15);
exports.getSupportedHeader = function (request) {
    var optionTags = [];
    if (request.method === Constants_1.C.REGISTER) {
        optionTags.push("path", "gruu");
    }
    else if (request.method === Constants_1.C.INVITE &&
        (request.ua.contact.pubGruu || request.ua.contact.tempGruu)) {
        optionTags.push("gruu");
    }
    if (request.ua.configuration.rel100 === Constants_1.C.supported.SUPPORTED) {
        optionTags.push("100rel");
    }
    if (request.ua.configuration.replaces === Constants_1.C.supported.SUPPORTED) {
        optionTags.push("replaces");
    }
    optionTags.push("outbound");
    optionTags = optionTags.concat(request.ua.configuration.extraSupported || []);
    var allowUnregistered = request.ua.configuration.hackAllowUnregisteredOptionTags || false;
    var optionTagSet = {};
    optionTags = optionTags.filter(function (optionTag) {
        var registered = Constants_1.C.OPTION_TAGS[optionTag];
        var unique = !optionTagSet[optionTag];
        optionTagSet[optionTag] = true;
        return (registered || allowUnregistered) && unique;
    });
    return "Supported: " + optionTags.join(", ") + "\r\n";
};
/**
 * @class Class for outgoing SIP request.
 * @param {String} method request method
 * @param {String} ruri request uri
 * @param {SIP.UA} ua
 * @param {Object} params parameters that will have priority over ua.configuration parameters:
 * <br>
 *  - cseq, callId, fromTag, fromUri, fromDisplayName, toUri, toTag, routeSet
 * @param {Object} [headers] extra headers
 * @param {String} [body]
 */
var OutgoingRequest = /** @class */ (function () {
    function OutgoingRequest(method, ruri, ua, params, extraHeaders, body) {
        if (params === void 0) { params = {}; }
        this.type = Enums_1.TypeStrings.OutgoingRequest;
        this.logger = ua.getLogger("sip.sipmessage");
        this.ua = ua;
        this.headers = {};
        this.method = method;
        this.ruri = ruri;
        this.body = body;
        this.extraHeaders = (extraHeaders || []).slice();
        // FIXME: Why are response properties on a Request class?
        this.statusCode = params.statusCode;
        this.reasonPhrase = params.reasonPhrase;
        // Fill the Common SIP Request Headers
        // Route
        if (params.routeSet) {
            this.setHeader("route", params.routeSet);
        }
        else if (ua.configuration.usePreloadedRoute && ua.transport) {
            this.setHeader("route", ua.transport.server.sipUri);
        }
        // Via
        // Empty Via header. Will be filled by the client transaction.
        this.setHeader("via", "");
        // Max-Forwards
        // is a constant on ua.c, removed for circular dependency
        this.setHeader("max-forwards", "70");
        // To
        var toUri = params.toUri || ruri;
        this.toTag = params.toTag;
        var to = (params.toDisplayName || params.toDisplayName === 0) ? '"' + params.toDisplayName + '" ' : "";
        to += "<" + (toUri.type === Enums_1.TypeStrings.URI ? toUri.toRaw() : toUri) + ">";
        to += this.toTag ? ";tag=" + this.toTag : "";
        this.to = Grammar_1.Grammar.nameAddrHeaderParse(to);
        this.setHeader("to", to);
        // From
        var fromUri = params.fromUri || ua.configuration.uri || "";
        this.fromTag = params.fromTag || Utils_1.Utils.newTag();
        var from;
        if (params.fromDisplayName || params.fromDisplayName === 0) {
            from = '"' + params.fromDisplayName + '" ';
        }
        else if (ua.configuration.displayName) {
            from = '"' + ua.configuration.displayName + '" ';
        }
        else {
            from = "";
        }
        from += "<" + (fromUri.type === Enums_1.TypeStrings.URI ? fromUri.toRaw() : fromUri) + ">;tag=";
        from += this.fromTag;
        this.from = Grammar_1.Grammar.nameAddrHeaderParse(from);
        this.setHeader("from", from);
        // Call-ID
        this.callId = params.callId || (ua.configuration.sipjsId + Utils_1.Utils.createRandomToken(15));
        this.setHeader("call-id", this.callId);
        // CSeq
        // Why not make this a "1" if not provided? See: https://tools.ietf.org/html/rfc3261#section-8.1.1.5
        this.cseq = params.cseq || Math.floor(Math.random() * 10000);
        this.setHeader("cseq", this.cseq + " " + method);
    }
    /**
     * Get the value of the given header name at the given position.
     * @param {String} name header name
     * @returns {String|undefined} Returns the specified header, undefined if header doesn't exist.
     */
    OutgoingRequest.prototype.getHeader = function (name) {
        var header = this.headers[Utils_1.Utils.headerize(name)];
        if (header) {
            if (header[0]) {
                return header[0];
            }
        }
        else {
            var regexp = new RegExp("^\\s*" + name + "\\s*:", "i");
            for (var _i = 0, _a = this.extraHeaders; _i < _a.length; _i++) {
                var exHeader = _a[_i];
                if (regexp.test(exHeader)) {
                    return exHeader.substring(exHeader.indexOf(":") + 1).trim();
                }
            }
        }
        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.
     */
    OutgoingRequest.prototype.getHeaders = function (name) {
        var result = [];
        var headerArray = this.headers[Utils_1.Utils.headerize(name)];
        if (headerArray) {
            for (var _i = 0, headerArray_1 = headerArray; _i < headerArray_1.length; _i++) {
                var headerPart = headerArray_1[_i];
                result.push(headerPart);
            }
        }
        else {
            var regexp = new RegExp("^\\s*" + name + "\\s*:", "i");
            for (var _a = 0, _b = this.extraHeaders; _a < _b.length; _a++) {
                var exHeader = _b[_a];
                if (regexp.test(exHeader)) {
                    result.push(exHeader.substring(exHeader.indexOf(":") + 1).trim());
                }
            }
        }
        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
     */
    OutgoingRequest.prototype.hasHeader = function (name) {
        if (this.headers[Utils_1.Utils.headerize(name)]) {
            return true;
        }
        else {
            var regexp = new RegExp("^\\s*" + name + "\\s*:", "i");
            for (var _i = 0, _a = this.extraHeaders; _i < _a.length; _i++) {
                var extraHeader = _a[_i];
                if (regexp.test(extraHeader)) {
                    return true;
                }
            }
        }
        return false;
    };
    /**
     * Replace the the given header by the given value.
     * @param {String} name header name
     * @param {String | Array} value header value
     */
    OutgoingRequest.prototype.setHeader = function (name, value) {
        this.headers[Utils_1.Utils.headerize(name)] = (value instanceof Array) ? value : [value];
    };
    /**
     * The Via header field indicates the transport used for the transaction
     * and identifies the location where the response is to be sent.  A Via
     * header field value is added only after the transport that will be
     * used to reach the next hop has been selected (which may involve the
     * usage of the procedures in [4]).
     *
     * When the UAC creates a request, it MUST insert a Via into that
     * request.  The protocol name and protocol version in the header field
     * MUST be SIP and 2.0, respectively.  The Via header field value MUST
     * contain a branch parameter.  This parameter is used to identify the
     * transaction created by that request.  This parameter is used by both
     * the client and the server.
     * https://tools.ietf.org/html/rfc3261#section-8.1.1.7
     * @param branchParameter The branch parameter.
     * @param transport The transport.
     */
    OutgoingRequest.prototype.setViaHeader = function (branch, transport) {
        // FIXME: Default scheme to "WSS"
        // This should go away once transport is typed and we can be sure
        // we are getting the something valid from there transport.
        var scheme = "WSS";
        // FIXME: Transport's server property is not typed (as of writing this).
        if (transport.server && transport.server.scheme) {
            scheme = transport.server.scheme;
        }
        // FIXME: Hack
        if (this.ua.configuration.hackViaTcp) {
            scheme = "TCP";
        }
        var via = "SIP/2.0/" + scheme;
        via += " " + this.ua.configuration.viaHost + ";branch=" + branch;
        if (this.ua.configuration.forceRport) {
            via += ";rport";
        }
        this.setHeader("via", via);
        this.branch = branch;
    };
    /**
     * Cancel this request.
     * If this is not an INVITE request, a no-op.
     * @param reason Reason phrase.
     * @param extraHeaders Extra headers.
     */
    OutgoingRequest.prototype.cancel = function (reason, extraHeaders) {
        var _this = this;
        if (!this.transaction) {
            throw new Error("Transaction undefined.");
        }
        var sendCancel = function () {
            if (!_this.transaction) {
                throw new Error("Transaction undefined.");
            }
            if (!_this.to) {
                throw new Error("To undefined.");
            }
            if (!_this.from) {
                throw new Error("From undefined.");
            }
            // The following procedures are used to construct a CANCEL request.  The
            // Request-URI, Call-ID, To, the numeric part of CSeq, and From header
            // fields in the CANCEL request MUST be identical to those in the
            // request being cancelled, including tags.  A CANCEL constructed by a
            // client MUST have only a single Via header field value matching the
            // top Via value in the request being cancelled.  Using the same values
            // for these header fields allows the CANCEL to be matched with the
            // request it cancels (Section 9.2 indicates how such matching occurs).
            // However, the method part of the CSeq header field MUST have a value
            // of CANCEL.  This allows it to be identified and processed as a
            // transaction in its own right (See Section 17).
            // https://tools.ietf.org/html/rfc3261#section-9.1
            var cancel = new OutgoingRequest(Constants_1.C.CANCEL, _this.ruri, _this.ua, {
                toUri: _this.to.uri,
                toTag: _this.toTag,
                fromUri: _this.from.uri,
                fromTag: _this.fromTag,
                callId: _this.callId,
                cseq: _this.cseq
            }, extraHeaders);
            // TODO: Revisit this.
            // The CANCEL needs to use the same branch parameter so that
            // it matches the INVITE transaction, but this is a hacky way to do this.
            // Or at the very least not well documented. If the the branch parameter
            // is set on the outgoing request, the transaction will use it. Otherwise
            // the transaction will make a new one.
            cancel.branch = _this.branch;
            // If the request being cancelled contains a Route header field, the
            // CANCEL request MUST include that Route header field's values.
            // https://tools.ietf.org/html/rfc3261#section-9.1
            if (_this.headers.Route) {
                cancel.headers.Route = _this.headers.Route;
            }
            if (reason) {
                cancel.setHeader("Reason", reason);
            }
            var transport = _this.transaction.transport;
            var user = {
                loggerFactory: _this.ua.getLoggerFactory(),
                onStateChange: function (newState) {
                    if (newState === Transactions_1.TransactionState.Terminated) {
                        _this.ua.destroyTransaction(clientTransaction);
                    }
                },
                receiveResponse: function (response) { return; }
            };
            var clientTransaction = new Transactions_1.NonInviteClientTransaction(cancel, transport, user);
            _this.ua.newTransaction(clientTransaction);
        };
        // A CANCEL request SHOULD NOT be sent to cancel a request other than INVITE.
        // Since requests other than INVITE are responded to immediately, sending a
        // CANCEL for a non-INVITE request would always create a race condition.
        // https://tools.ietf.org/html/rfc3261#section-9.1
        if (!(this.transaction instanceof Transactions_1.InviteClientTransaction)) {
            return;
        }
        // If no provisional response has been received, the CANCEL request MUST
        // NOT be sent; rather, the client MUST wait for the arrival of a
        // provisional response before sending the request. If the original
        // request has generated a final response, the CANCEL SHOULD NOT be
        // sent, as it is an effective no-op, since CANCEL has no effect on
        // requests that have already generated a final response.
        // https://tools.ietf.org/html/rfc3261#section-9.1
        if (this.transaction.state === Transactions_1.TransactionState.Proceeding) {
            sendCancel();
        }
        else {
            this.transaction.once("stateChanged", function () {
                if (_this.transaction && _this.transaction.state === Transactions_1.TransactionState.Proceeding) {
                    sendCancel();
                }
            });
        }
    };
    OutgoingRequest.prototype.toString = function () {
        var msg = "";
        msg += this.method + " " + (this.ruri.type === Enums_1.TypeStrings.URI ?
            this.ruri.toRaw() : this.ruri) + " SIP/2.0\r\n";
        for (var header in this.headers) {
            if (this.headers[header]) {
                for (var _i = 0, _a = this.headers[header]; _i < _a.length; _i++) {
                    var headerPart = _a[_i];
                    msg += header + ": " + headerPart + "\r\n";
                }
            }
        }
        for (var _b = 0, _c = this.extraHeaders; _b < _c.length; _b++) {
            var header = _c[_b];
            msg += header.trim() + "\r\n";
        }
        msg += exports.getSupportedHeader(this);
        msg += "User-Agent: " + this.ua.configuration.userAgentString + "\r\n";
        if (this.body) {
            if (typeof this.body === "string") {
                msg += "Content-Length: " + Utils_1.Utils.str_utf8_length(this.body) + "\r\n\r\n";
                msg += this.body;
            }
            else {
                if (this.body.body && this.body.contentType) {
                    msg += "Content-Type: " + this.body.contentType + "\r\n";
                    msg += "Content-Length: " + Utils_1.Utils.str_utf8_length(this.body.body) + "\r\n\r\n";
                    msg += this.body.body;
                }
                else {
                    msg += "Content-Length: " + 0 + "\r\n\r\n";
                }
            }
        }
        else {
            msg += "Content-Length: " + 0 + "\r\n\r\n";
        }
        return msg;
    };
    return OutgoingRequest;
}());
exports.OutgoingRequest = OutgoingRequest;
/**
 * @class Class for incoming SIP message.
 */
// tslint:disable-next-line:max-classes-per-file
var IncomingMessage = /** @class */ (function () {
    function IncomingMessage() {
        this.type = Enums_1.TypeStrings.IncomingMessage;
        this.headers = {};
    }
    /**
     * Insert a header of the given name and value into the last position of the
     * header array.
     * @param {String} name header name
     * @param {String} value header value
     */
    IncomingMessage.prototype.addHeader = function (name, value) {
        var header = { raw: value };
        name = Utils_1.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.
     * @param {String} name header name
     * @returns {String|undefined} Returns the specified header, undefined if header doesn't exist.
     */
    IncomingMessage.prototype.getHeader = function (name) {
        var header = this.headers[Utils_1.Utils.headerize(name)];
        if (header) {
            if (header[0]) {
                return header[0].raw;
            }
        }
        else {
            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.
     */
    IncomingMessage.prototype.getHeaders = function (name) {
        var header = this.headers[Utils_1.Utils.headerize(name)];
        var result = [];
        if (!header) {
            return [];
        }
        for (var _i = 0, header_1 = header; _i < header_1.length; _i++) {
            var headerPart = header_1[_i];
            result.push(headerPart.raw);
        }
        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
     */
    IncomingMessage.prototype.hasHeader = function (name) {
        return !!this.headers[Utils_1.Utils.headerize(name)];
    };
    /**
     * 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.
     */
    IncomingMessage.prototype.parseHeader = function (name, idx) {
        if (idx === void 0) { idx = 0; }
        name = Utils_1.Utils.headerize(name);
        if (!this.headers[name]) {
            // this.logger.log("header '" + name + "' not present");
            return;
        }
        else if (idx >= this.headers[name].length) {
            // this.logger.log("not so many '" + 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_1.Grammar.parse(value, name.replace(/-/g, "_"));
        if (parsed === -1) {
            this.headers[name].splice(idx, 1); // delete from headers
            // this.logger.warn('error parsing "' + name + '" header field with value "' + 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
     */
    IncomingMessage.prototype.s = function (name, idx) {
        if (idx === void 0) { idx = 0; }
        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
     */
    IncomingMessage.prototype.setHeader = function (name, value) {
        this.headers[Utils_1.Utils.headerize(name)] = [{ raw: value }];
    };
    IncomingMessage.prototype.toString = function () {
        return this.data;
    };
    return IncomingMessage;
}());
exports.IncomingMessage = IncomingMessage;
/**
 * @class Class for incoming SIP request.
 */
// tslint:disable-next-line:max-classes-per-file
var IncomingRequest = /** @class */ (function (_super) {
    __extends(IncomingRequest, _super);
    function IncomingRequest(ua) {
        var _this = _super.call(this) || this;
        _this.ua = ua;
        _this.type = Enums_1.TypeStrings.IncomingRequest;
        _this.logger = ua.getLogger("sip.sipmessage");
        return _this;
    }
    /**
     * Stateful reply.
     * @param {Number} code status code
     * @param {String} reason reason phrase
     * @param {Object} headers extra headers
     * @param {String} body body
     */
    IncomingRequest.prototype.reply = function (code, reason, extraHeaders, body) {
        if (!this.transaction) {
            throw new Error("Transaction undefined.");
        }
        var response = Utils_1.Utils.buildStatusLine(code, reason);
        extraHeaders = (extraHeaders || []).slice();
        if (this.method === Constants_1.C.INVITE && code > 100 && code <= 200) {
            for (var _i = 0, _a = this.getHeaders("record-route"); _i < _a.length; _i++) {
                var route = _a[_i];
                response += "Record-Route: " + route + "\r\n";
            }
        }
        for (var _b = 0, _c = this.getHeaders("via"); _b < _c.length; _b++) {
            var via = _c[_b];
            response += "Via: " + via + "\r\n";
        }
        var to = this.getHeader("to") || "";
        if (!this.toTag && code > 100) {
            to += ";tag=" + Utils_1.Utils.newTag();
        }
        else if (this.toTag && !this.s("to").hasParam("tag")) {
            to += ";tag=" + this.toTag;
        }
        response += "To: " + to + "\r\n";
        response += "From: " + this.getHeader("From") + "\r\n";
        response += "Call-ID: " + this.callId + "\r\n";
        response += "CSeq: " + this.cseq + " " + this.method + "\r\n";
        for (var _d = 0, extraHeaders_1 = extraHeaders; _d < extraHeaders_1.length; _d++) {
            var extraHeader = extraHeaders_1[_d];
            response += extraHeader.trim() + "\r\n";
        }
        response += exports.getSupportedHeader(this);
        response += "User-Agent: " + this.ua.configuration.userAgentString + "\r\n";
        if (body) {
            if (typeof body === "string") {
                response += "Content-Type: application/sdp\r\n";
                response += "Content-Length: " + Utils_1.Utils.str_utf8_length(body) + "\r\n\r\n";
                response += body;
            }
            else {
                if (body.body && body.contentType) {
                    response += "Content-Type: " + body.contentType + "\r\n";
                    response += "Content-Length: " + Utils_1.Utils.str_utf8_length(body.body) + "\r\n\r\n";
                    response += body.body;
                }
                else {
                    response += "Content-Length: " + 0 + "\r\n\r\n";
                }
            }
        }
        else {
            response += "Content-Length: " + 0 + "\r\n\r\n";
        }
        this.transaction.receiveResponse(code, response);
        return response;
    };
    /**
     * Stateless reply.
     * @param {Number} code status code
     * @param {String} reason reason phrase
     */
    IncomingRequest.prototype.reply_sl = function (code, reason) {
        if (!this.transport) {
            throw new Error("Transport undefined.");
        }
        var response = Utils_1.Utils.buildStatusLine(code, reason);
        for (var _i = 0, _a = this.getHeaders("via"); _i < _a.length; _i++) {
            var via = _a[_i];
            response += "Via: " + via + "\r\n";
        }
        var to = this.getHeader("To") || "";
        if (!this.toTag && code > 100) {
            // FIXME: This is a MUST, but we are generating a random tag each response
            // o  To header tags MUST be generated for responses in a stateless
            // manner - in a manner that will generate the same tag for the
            // same request consistently.  For information on tag construction
            // see Section 19.3.
            // https://tools.ietf.org/html/rfc3261#section-8.2.7
            to += ";tag=" + Utils_1.Utils.newTag();
        }
        else if (this.toTag && !this.s("to").hasParam("tag")) {
            to += ";tag=" + this.toTag;
        }
        response += "To: " + to + "\r\n";
        response += "From: " + this.getHeader("From") + "\r\n";
        response += "Call-ID: " + this.callId + "\r\n";
        response += "CSeq: " + this.cseq + " " + this.method + "\r\n";
        response += "User-Agent: " + this.ua.configuration.userAgentString + "\r\n";
        response += "Content-Length: " + 0 + "\r\n\r\n";
        this.transport.send(response);
        return response;
    };
    return IncomingRequest;
}(IncomingMessage));
exports.IncomingRequest = IncomingRequest;
/**
 * @class Class for incoming SIP response.
 */
// tslint:disable-next-line:max-classes-per-file
var IncomingResponse = /** @class */ (function (_super) {
    __extends(IncomingResponse, _super);
    function IncomingResponse(ua) {
        var _this = _super.call(this) || this;
        _this.ua = ua;
        _this.type = Enums_1.TypeStrings.IncomingResponse;
        _this.logger = ua.getLogger("sip.sipmessage");
        _this.headers = {};
        return _this;
    }
    /**
     * Constructs and sends ACK to 2xx final response. Returns the sent ACK.
     * @param response The 2xx final repsonse the ACK is acknowledging.
     * @param options ACK options; extra headers, body.
     */
    IncomingResponse.prototype.ack = function (options) {
        if (!this.statusCode || this.statusCode < 200 || this.statusCode > 299) {
            throw new Error("Response status code must be 2xx to ACK.");
        }
        if (this.method !== Constants_1.C.INVITE) {
            throw new Error("Response must to be for an INVITE to ACK.");
        }
        if (!this.transaction) {
            throw new Error("Transaction undefined.");
        }
        if (!(this.transaction instanceof Transactions_1.InviteClientTransaction)) {
            throw new Error("Transaction not instance of InviteServerTrasaction.");
        }
        // FIXME: This should all be done by the dialog. The current dialog code
        // structure is not currently setup to deal with ACKs to re-INVITEs, so
        // what follows is duplicate code for specifially handling the ACK case.
        // Dialog must exist after receipt of a 2xx response to an INVITE.
        var dialog = this.ua.dialogs[this.callId + this.fromTag + this.toTag];
        if (!dialog) {
            throw new Error("Dialog undefined.");
        }
        // The UAC core MUST generate an ACK request for each 2xx received from
        // the transaction layer.  The header fields of the ACK are constructed
        // in the same way as for any request sent within a dialog (see Section
        // 12) with the exception of the CSeq and the header fields related to
        // authentication.  The sequence number of the CSeq header field MUST be
        // the same as the INVITE being acknowledged, but the CSeq method MUST
        // be ACK.  The ACK MUST contain the same credentials as the INVITE.  If
        // the 2xx contains an offer (based on the rules above), the ACK MUST
        // carry an answer in its body.  If the offer in the 2xx response is not
        // acceptable, the UAC core MUST generate a valid answer in the ACK and
        // then send a BYE immediately.
        // https://tools.ietf.org/html/rfc3261#section-13.2.2.4
        // The URI in the To field of the request MUST be set to the remote URI
        // from the dialog state.  The tag in the To header field of the request
        // MUST be set to the remote tag of the dialog ID.  The From URI of the
        // request MUST be set to the local URI from the dialog state.  The tag
        // in the From header field of the request MUST be set to the local tag
        // of the dialog ID.  If the value of the remote or local tags is null,
        // the tag parameter MUST be omitted from the To or From header fields,
        // respectively.
        //
        // The Call-ID of the request MUST be set to the Call-ID of the dialog.
        // Requests within a dialog MUST contain strictly monotonically
        // increasing and contiguous CSeq sequence numbers (increasing-by-one)
        // in each direction (excepting ACK and CANCEL of course, whose numbers
        // equal the requests being acknowledged or cancelled).
        // https://tools.ietf.org/html/rfc3261#section-12.2.1.1
        var callId = this.callId;
        var cseq = this.cseq;
        var fromUri = dialog.localUri;
        var fromTag = this.fromTag;
        var toUri = dialog.remoteUri;
        var toTag = this.toTag;
        // The UAC uses the remote target and route set to build the Request-URI
        // and Route header field of the request.
        //
        // If the route set is empty, the UAC MUST place the remote target URI
        // into the Request-URI.  The UAC MUST NOT add a Route header field to
        // the request.
        //
        // If the route set is not empty, and the first URI in the route set
        // contains the lr parameter (see Section 19.1.1), the UAC MUST place
        // the remote target URI into the Request-URI and MUST include a Route
        // header field containing the route set values in order, including all
        // parameters.
        //
        // If the route set is not empty, and its first URI does not contain the
        // lr parameter, the UAC MUST place the first URI from the route set
        // into the Request-URI, stripping any parameters that are not allowed
        // in a Request-URI.  The UAC MUST add a Route header field containing
        // the remainder of the route set values in order, including all
        // parameters.  The UAC MUST then place the remote target URI into the
        // Route header field as the last value.
        // https://tools.ietf.org/html/rfc3261#section-12.2.1.1
        // The lr parameter, when present, indicates that the element
        // responsible for this resource implements the routing mechanisms
        // specified in this document.  This parameter will be used in the
        // URIs proxies place into Record-Route header field values, and
        // may appear in the URIs in a pre-existing route set.
        //
        // This parameter is used to achieve backwards compatibility with
        // systems implementing the strict-routing mechanisms of RFC 2543
        // and the rfc2543bis drafts up to bis-05.  An element preparing
        // to send a request based on a URI not containing this parameter
        // can assume the receiving element implements strict-routing and
        // reformat the message to preserve the information in the
        // Request-URI.
        // https://tools.ietf.org/html/rfc3261#section-19.1.1
        // NOTE: Not backwards compatibile with RFC 2543 (no support for strict-routing).
        var ruri = dialog.remoteTarget;
        var routeSet = dialog.routeSet;
        var request = new OutgoingRequest(Constants_1.C.ACK, ruri, this.ua, {
            callId: callId,
            cseq: cseq,
            fromUri: fromUri,
            fromTag: fromTag,
            toUri: toUri,
            toTag: toTag,
            routeSet: routeSet
        }, options ? options.extraHeaders : undefined, options ? options.body : undefined);
        this.transaction.ackResponse(request);
        return request;
    };
    return IncomingResponse;
}(IncomingMessage));
exports.IncomingResponse = IncomingResponse;


/***/ }),
/* 11 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";

Object.defineProperty(exports, "__esModule", { value: true });
var pegGrammar = __webpack_require__(12);
var Grammar;
(function (Grammar) {
    function parse(input, startRule) {
        var options = { startRule: startRule };
        try {
            pegGrammar.parse(input, options);
        }
        catch (e) {
            options.data = -1;
        }
        return options.data;
    }
    Grammar.parse = parse;
    /**
     * Parse the given string and returns a SIP.NameAddrHeader instance or undefined if
     * it is an invalid NameAddrHeader.
     * @public
     * @param {String} name_addr_header
     */
    function nameAddrHeaderParse(nameAddrHeader) {
        var parsedNameAddrHeader = Grammar.parse(nameAddrHeader, "Name_Addr_Header");
        return parsedNameAddrHeader !== -1 ? parsedNameAddrHeader : undefined;
    }
    Grammar.nameAddrHeaderParse = nameAddrHeaderParse;
    /**
     * Parse the given string and returns a SIP.URI instance or undefined if
     * it is an invalid URI.
     * @public
     * @param {String} uri
     */
    function URIParse(uri) {
        var parsedUri = Grammar.parse(uri, "SIP_URI");
        return parsedUri !== -1 ? parsedUri : undefined;
    }
    Grammar.URIParse = URIParse;
})(Grammar = exports.Grammar || (exports.Grammar = {}));


/***/ }),
/* 12 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";

// tslint:disable:interface-name
// tslint:disable: trailing-comma
// tslint:disable: object-literal-sort-keys
// tslint:disable: max-line-length
// tslint:disable: only-arrow-functions
// tslint:disable: one-variable-per-declaration
// tslint:disable: no-consecutive-blank-lines
// tslint:disable: align
// tslint:disable: radix
// tslint:disable: quotemark
// tslint:disable: semicolon
// tslint:disable: object-literal-shorthand
// tslint:disable: variable-name
// tslint:disable: no-var-keyword
// tslint:disable: whitespace
// tslint:disable: curly
// tslint:disable: prefer-const
// tslint:disable: object-literal-key-quotes
// tslint:disable: no-string-literal
// tslint:disable: one-line
// tslint:disable: no-unused-expression
// tslint:disable: space-before-function-paren
// tslint:disable: arrow-return-shorthand
var __extends = (this && this.__extends) || (function () {
    var extendStatics = function (d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
// Generated by PEG.js v. 0.10.0 (ts-pegjs plugin v. 0.2.2 )
//
// https://pegjs.org/   https://github.com/metadevpro/ts-pegjs
var NameAddrHeader_1 = __webpack_require__(13);
var URI_1 = __webpack_require__(14);
var SyntaxError = /** @class */ (function (_super) {
    __extends(SyntaxError, _super);
    function SyntaxError(message, expected, found, location) {
        var _this = _super.call(this) || this;
        _this.message = message;
        _this.expected = expected;
        _this.found = found;
        _this.location = location;
        _this.name = "SyntaxError";
        if (typeof Error.captureStackTrace === "function") {
            Error.captureStackTrace(_this, SyntaxError);
        }
        return _this;
    }
    SyntaxError.buildMessage = function (expected, found) {
        function hex(ch) {
            return ch.charCodeAt(0).toString(16).toUpperCase();
        }
        function literalEscape(s) {
            return s
                .replace(/\\/g, "\\\\")
                .replace(/"/g, "\\\"")
                .replace(/\0/g, "\\0")
                .replace(/\t/g, "\\t")
                .replace(/\n/g, "\\n")
                .replace(/\r/g, "\\r")
                .replace(/[\x00-\x0F]/g, function (ch) { return "\\x0" + hex(ch); })
                .replace(/[\x10-\x1F\x7F-\x9F]/g, function (ch) { return "\\x" + hex(ch); });
        }
        function classEscape(s) {
            return s
                .replace(/\\/g, "\\\\")
                .replace(/\]/g, "\\]")
                .replace(/\^/g, "\\^")
                .replace(/-/g, "\\-")
                .replace(/\0/g, "\\0")
                .replace(/\t/g, "\\t")
                .replace(/\n/g, "\\n")
                .replace(/\r/g, "\\r")
                .replace(/[\x00-\x0F]/g, function (ch) { return "\\x0" + hex(ch); })
                .replace(/[\x10-\x1F\x7F-\x9F]/g, function (ch) { return "\\x" + hex(ch); });
        }
        function describeExpectation(expectation) {
            switch (expectation.type) {
                case "literal":
                    return "\"" + literalEscape(expectation.text) + "\"";
                case "class":
                    var escapedParts = expectation.parts.map(function (part) {
                        return Array.isArray(part)
                            ? classEscape(part[0]) + "-" + classEscape(part[1])
                            : classEscape(part);
                    });
                    return "[" + (expectation.inverted ? "^" : "") + escapedParts + "]";
                case "any":
                    return "any character";
                case "end":
                    return "end of input";
                case "other":
                    return expectation.description;
            }
        }
        function describeExpected(expected1) {
            var descriptions = expected1.map(describeExpectation);
            var i;
            var j;
            descriptions.sort();
            if (descriptions.length > 0) {
                for (i = 1, j = 1; i < descriptions.length; i++) {
                    if (descriptions[i - 1] !== descriptions[i]) {
                        descriptions[j] = descriptions[i];
                        j++;
                    }
                }
                descriptions.length = j;
            }
            switch (descriptions.length) {
                case 1:
                    return descriptions[0];
                case 2:
                    return descriptions[0] + " or " + descriptions[1];
                default:
                    return descriptions.slice(0, -1).join(", ")
                        + ", or "
                        + descriptions[descriptions.length - 1];
            }
        }
        function describeFound(found1) {
            return found1 ? "\"" + literalEscape(found1) + "\"" : "end of input";
        }
        return "Expected " + describeExpected(expected) + " but " + describeFound(found) + " found.";
    };
    return SyntaxError;
}(Error));
exports.SyntaxError = SyntaxError;
function peg$parse(input, options) {
    options = options !== undefined ? options : {};
    var peg$FAILED = {};
    var peg$startRuleFunctions = { Contact: peg$parseContact, Name_Addr_Header: peg$parseName_Addr_Header, Record_Route: peg$parseRecord_Route, Request_Response: peg$parseRequest_Response, SIP_URI: peg$parseSIP_URI, Subscription_State: peg$parseSubscription_State, Supported: peg$parseSupported, Require: peg$parseRequire, Via: peg$parseVia, absoluteURI: peg$parseabsoluteURI, Call_ID: peg$parseCall_ID, Content_Disposition: peg$parseContent_Disposition, Content_Length: peg$parseContent_Length, Content_Type: peg$parseContent_Type, CSeq: peg$parseCSeq, displayName: peg$parsedisplayName, Event: peg$parseEvent, From: peg$parseFrom, host: peg$parsehost, Max_Forwards: peg$parseMax_Forwards, Min_SE: peg$parseMin_SE, Proxy_Authenticate: peg$parseProxy_Authenticate, quoted_string: peg$parsequoted_string, Refer_To: peg$parseRefer_To, Replaces: peg$parseReplaces, Session_Expires: peg$parseSession_Expires, stun_URI: peg$parsestun_URI, To: peg$parseTo, turn_URI: peg$parseturn_URI, uuid: peg$parseuuid, WWW_Authenticate: peg$parseWWW_Authenticate, challenge: peg$parsechallenge, sipfrag: peg$parsesipfrag, Referred_By: peg$parseReferred_By };
    var peg$startRuleFunction = peg$parseContact;
    var peg$c0 = "\r\n";
    var peg$c1 = peg$literalExpectation("\r\n", false);
    var peg$c2 = /^[0-9]/;
    var peg$c3 = peg$classExpectation([["0", "9"]], false, false);
    var peg$c4 = /^[a-zA-Z]/;
    var peg$c5 = peg$classExpectation([["a", "z"], ["A", "Z"]], false, false);
    var peg$c6 = /^[0-9a-fA-F]/;
    var peg$c7 = peg$classExpectation([["0", "9"], ["a", "f"], ["A", "F"]], false, false);
    var peg$c8 = /^[\0-\xFF]/;
    var peg$c9 = peg$classExpectation([["\0", "\xFF"]], false, false);
    var peg$c10 = /^["]/;
    var peg$c11 = peg$classExpectation(["\""], false, false);
    var peg$c12 = " ";
    var peg$c13 = peg$literalExpectation(" ", false);
    var peg$c14 = "\t";
    var peg$c15 = peg$literalExpectation("\t", false);
    var peg$c16 = /^[a-zA-Z0-9]/;
    var peg$c17 = peg$classExpectation([["a", "z"], ["A", "Z"], ["0", "9"]], false, false);
    var peg$c18 = ";";
    var peg$c19 = peg$literalExpectation(";", false);
    var peg$c20 = "/";
    var peg$c21 = peg$literalExpectation("/", false);
    var peg$c22 = "?";
    var peg$c23 = peg$literalExpectation("?", false);
    var peg$c24 = ":";
    var peg$c25 = peg$literalExpectation(":", false);
    var peg$c26 = "@";
    var peg$c27 = peg$literalExpectation("@", false);
    var peg$c28 = "&";
    var peg$c29 = peg$literalExpectation("&", false);
    var peg$c30 = "=";
    var peg$c31 = peg$literalExpectation("=", false);
    var peg$c32 = "+";
    var peg$c33 = peg$literalExpectation("+", false);
    var peg$c34 = "$";
    var peg$c35 = peg$literalExpectation("$", false);
    var peg$c36 = ",";
    var peg$c37 = peg$literalExpectation(",", false);
    var peg$c38 = "-";
    var peg$c39 = peg$literalExpectation("-", false);
    var peg$c40 = "_";
    var peg$c41 = peg$literalExpectation("_", false);
    var peg$c42 = ".";
    var peg$c43 = peg$literalExpectation(".", false);
    var peg$c44 = "!";
    var peg$c45 = peg$literalExpectation("!", false);
    var peg$c46 = "~";
    var peg$c47 = peg$literalExpectation("~", false);
    var peg$c48 = "*";
    var peg$c49 = peg$literalExpectation("*", false);
    var peg$c50 = "'";
    var peg$c51 = peg$literalExpectation("'", false);
    var peg$c52 = "(";
    var peg$c53 = peg$literalExpectation("(", false);
    var peg$c54 = ")";
    var peg$c55 = peg$literalExpectation(")", false);
    var peg$c56 = "%";
    var peg$c57 = peg$literalExpectation("%", false);
    var peg$c58 = function () { return " "; };
    var peg$c59 = function () { return ':'; };
    var peg$c60 = /^[!-~]/;
    var peg$c61 = peg$classExpectation([["!", "~"]], false, false);
    var peg$c62 = /^[\x80-\uFFFF]/;
    var peg$c63 = peg$classExpectation([["\x80", "\uFFFF"]], false, false);
    var peg$c64 = /^[\x80-\xBF]/;
    var peg$c65 = peg$classExpectation([["\x80", "\xBF"]], false, false);
    var peg$c66 = /^[a-f]/;
    var peg$c67 = peg$classExpectation([["a", "f"]], false, false);
    var peg$c68 = "`";
    var peg$c69 = peg$literalExpectation("`", false);
    var peg$c70 = "<";
    var peg$c71 = peg$literalExpectation("<", false);
    var peg$c72 = ">";
    var peg$c73 = peg$literalExpectation(">", false);
    var peg$c74 = "\\";
    var peg$c75 = peg$literalExpectation("\\", false);
    var peg$c76 = "[";
    var peg$c77 = peg$literalExpectation("[", false);
    var peg$c78 = "]";
    var peg$c79 = peg$literalExpectation("]", false);
    var peg$c80 = "{";
    var peg$c81 = peg$literalExpectation("{", false);
    var peg$c82 = "}";
    var peg$c83 = peg$literalExpectation("}", false);
    var peg$c84 = function () { return "*"; };
    var peg$c85 = function () { return "/"; };
    var peg$c86 = function () { return "="; };
    var peg$c87 = function () { return "("; };
    var peg$c88 = function () { return ")"; };
    var peg$c89 = function () { return ">"; };
    var peg$c90 = function () { return "<"; };
    var peg$c91 = function () { return ","; };
    var peg$c92 = function () { return ";"; };
    var peg$c93 = function () { return ":"; };
    var peg$c94 = function () { return "\""; };
    var peg$c95 = /^[!-']/;
    var peg$c96 = peg$classExpectation([["!", "'"]], false, false);
    var peg$c97 = /^[*-[]/;
    var peg$c98 = peg$classExpectation([["*", "["]], false, false);
    var peg$c99 = /^[\]-~]/;
    var peg$c100 = peg$classExpectation([["]", "~"]], false, false);
    var peg$c101 = function (contents) {
        return contents;
    };
    var peg$c102 = /^[#-[]/;
    var peg$c103 = peg$classExpectation([["#", "["]], false, false);
    var peg$c104 = /^[\0-\t]/;
    var peg$c105 = peg$classExpectation([["\0", "\t"]], false, false);
    var peg$c106 = /^[\x0B-\f]/;
    var peg$c107 = peg$classExpectation([["\x0B", "\f"]], false, false);
    var peg$c108 = /^[\x0E-\x7F]/;
    var peg$c109 = peg$classExpectation([["\x0E", "\x7F"]], false, false);
    var peg$c110 = function () {
        options = options || { data: {} };
        options.data.uri = new URI_1.URI(options.data.scheme, options.data.user, options.data.host, options.data.port);
        delete options.data.scheme;
        delete options.data.user;
        delete options.data.host;
        delete options.data.host_type;
        delete options.data.port;
    };
    var peg$c111 = function () {
        options = options || { data: {} };
        options.data.uri = new URI_1.URI(options.data.scheme, options.data.user, options.data.host, options.data.port, options.data.uri_params, options.data.uri_headers);
        delete options.data.scheme;
        delete options.data.user;
        delete options.data.host;
        delete options.data.host_type;
        delete options.data.port;
        delete options.data.uri_params;
        if (options.startRule === 'SIP_URI') {
            options.data = options.data.uri;
        }
    };
    var peg$c112 = "sips";
    var peg$c113 = peg$literalExpectation("sips", true);
    var peg$c114 = "sip";
    var peg$c115 = peg$literalExpectation("sip", true);
    var peg$c116 = function (uri_scheme) {
        options = options || { data: {} };
        options.data.scheme = uri_scheme;
    };
    var peg$c117 = function () {
        options = options || { data: {} };
        options.data.user = decodeURIComponent(text().slice(0, -1));
    };
    var peg$c118 = function () {
        options = options || { data: {} };
        options.data.password = text();
    };
    var peg$c119 = function () {
        options = options || { data: {} };
        options.data.host = text();
        return options.data.host;
    };
    var peg$c120 = function () {
        options = options || { data: {} };
        options.data.host_type = 'domain';
        return text();
    };
    var peg$c121 = /^[a-zA-Z0-9_\-]/;
    var peg$c122 = peg$classExpectation([["a", "z"], ["A", "Z"], ["0", "9"], "_", "-"], false, false);
    var peg$c123 = /^[a-zA-Z0-9\-]/;
    var peg$c124 = peg$classExpectation([["a", "z"], ["A", "Z"], ["0", "9"], "-"], false, false);
    var peg$c125 = function () {
        options = options || { data: {} };
        options.data.host_type = 'IPv6';
        return text();
    };
    var peg$c126 = "::";
    var peg$c127 = peg$literalExpectation("::", false);
    var peg$c128 = function () {
        options = options || { data: {} };
        options.data.host_type = 'IPv6';
        return text();
    };
    var peg$c129 = function () {
        options = options || { data: {} };
        options.data.host_type = 'IPv4';
        return text();
    };
    var peg$c130 = "25";
    var peg$c131 = peg$literalExpectation("25", false);
    var peg$c132 = /^[0-5]/;
    var peg$c133 = peg$classExpectation([["0", "5"]], false, false);
    var peg$c134 = "2";
    var peg$c135 = peg$literalExpectation("2", false);
    var peg$c136 = /^[0-4]/;
    var peg$c137 = peg$classExpectation([["0", "4"]], false, false);
    var peg$c138 = "1";
    var peg$c139 = peg$literalExpectation("1", false);
    var peg$c140 = /^[1-9]/;
    var peg$c141 = peg$classExpectation([["1", "9"]], false, false);
    var peg$c142 = function (port) {
        options = options || { data: {} };
        port = parseInt(port.join(''));
        options.data.port = port;
        return port;
    };
    var peg$c143 = "transport=";
    var peg$c144 = peg$literalExpectation("transport=", true);
    var peg$c145 = "udp";
    var peg$c146 = peg$literalExpectation("udp", true);
    var peg$c147 = "tcp";
    var peg$c148 = peg$literalExpectation("tcp", true);
    var peg$c149 = "sctp";
    var peg$c150 = peg$literalExpectation("sctp", true);
    var peg$c151 = "tls";
    var peg$c152 = peg$literalExpectation("tls", true);
    var peg$c153 = function (transport) {
        options = options || { data: {} };
        if (!options.data.uri_params)
            options.data.uri_params = {};
        options.data.uri_params['transport'] = transport.toLowerCase();
    };
    var peg$c154 = "user=";
    var peg$c155 = peg$literalExpectation("user=", true);
    var peg$c156 = "phone";
    var peg$c157 = peg$literalExpectation("phone", true);
    var peg$c158 = "ip";
    var peg$c159 = peg$literalExpectation("ip", true);
    var peg$c160 = function (user) {
        options = options || { data: {} };
        if (!options.data.uri_params)
            options.data.uri_params = {};
        options.data.uri_params['user'] = user.toLowerCase();
    };
    var peg$c161 = "method=";
    var peg$c162 = peg$literalExpectation("method=", true);
    var peg$c163 = function (method) {
        options = options || { data: {} };
        if (!options.data.uri_params)
            options.data.uri_params = {};
        options.data.uri_params['method'] = method;
    };
    var peg$c164 = "ttl=";
    var peg$c165 = peg$literalExpectation("ttl=", true);
    var peg$c166 = function (ttl) {
        options = options || { data: {} };
        if (!options.data.params)
            options.data.params = {};
        options.data.params['ttl'] = ttl;
    };
    var peg$c167 = "maddr=";
    var peg$c168 = peg$literalExpectation("maddr=", true);
    var peg$c169 = function (maddr) {
        options = options || { data: {} };
        if (!options.data.uri_params)
            options.data.uri_params = {};
        options.data.uri_params['maddr'] = maddr;
    };
    var peg$c170 = "lr";
    var peg$c171 = peg$literalExpectation("lr", true);
    var peg$c172 = function () {
        options = options || { data: {} };
        if (!options.data.uri_params)
            options.data.uri_params = {};
        options.data.uri_params['lr'] = undefined;
    };
    var peg$c173 = function (param, value) {
        options = options || { data: {} };
        if (!options.data.uri_params)
            options.data.uri_params = {};
        if (value === null) {
            value = undefined;
        }
        else {
            value = value[1];
        }
        options.data.uri_params[param.toLowerCase()] = value;
    };
    var peg$c174 = function (hname, hvalue) {
        hname = hname.join('').toLowerCase();
        hvalue = hvalue.join('');
        options = options || { data: {} };
        if (!options.data.uri_headers)
            options.data.uri_headers = {};
        if (!options.data.uri_headers[hname]) {
            options.data.uri_headers[hname] = [hvalue];
        }
        else {
            options.data.uri_headers[hname].push(hvalue);
        }
    };
    var peg$c175 = function () {
        options = options || { data: {} };
        // lots of tests fail if this isn't guarded...
        if (options.startRule === 'Refer_To') {
            options.data.uri = new URI_1.URI(options.data.scheme, options.data.user, options.data.host, options.data.port, options.data.uri_params, options.data.uri_headers);
            delete options.data.scheme;
            delete options.data.user;
            delete options.data.host;
            delete options.data.host_type;
            delete options.data.port;
            delete options.data.uri_params;
        }
    };
    var peg$c176 = "//";
    var peg$c177 = peg$literalExpectation("//", false);
    var peg$c178 = function () {
        options = options || { data: {} };
        options.data.scheme = text();
    };
    var peg$c179 = peg$literalExpectation("SIP", true);
    var peg$c180 = function () {
        options = options || { data: {} };
        options.data.sip_version = text();
    };
    var peg$c181 = "INVITE";
    var peg$c182 = peg$literalExpectation("INVITE", false);
    var peg$c183 = "ACK";
    var peg$c184 = peg$literalExpectation("ACK", false);
    var peg$c185 = "VXACH";
    var peg$c186 = peg$literalExpectation("VXACH", false);
    var peg$c187 = "OPTIONS";
    var peg$c188 = peg$literalExpectation("OPTIONS", false);
    var peg$c189 = "BYE";
    var peg$c190 = peg$literalExpectation("BYE", false);
    var peg$c191 = "CANCEL";
    var peg$c192 = peg$literalExpectation("CANCEL", false);
    var peg$c193 = "REGISTER";
    var peg$c194 = peg$literalExpectation("REGISTER", false);
    var peg$c195 = "SUBSCRIBE";
    var peg$c196 = peg$literalExpectation("SUBSCRIBE", false);
    var peg$c197 = "NOTIFY";
    var peg$c198 = peg$literalExpectation("NOTIFY", false);
    var peg$c199 = "REFER";
    var peg$c200 = peg$literalExpectation("REFER", false);
    var peg$c201 = "PUBLISH";
    var peg$c202 = peg$literalExpectation("PUBLISH", false);
    var peg$c203 = function () {
        options = options || { data: {} };
        options.data.method = text();
        return options.data.method;
    };
    var peg$c204 = function (status_code) {
        options = options || { data: {} };
        options.data.status_code = parseInt(status_code.join(''));
    };
    var peg$c205 = function () {
        options = options || { data: {} };
        options.data.reason_phrase = text();
    };
    var peg$c206 = function () {
        options = options || { data: {} };
        options.data = text();
    };
    var peg$c207 = function () {
        var idx, length;
        options = options || { data: {} };
        length = options.data.multi_header.length;
        for (idx = 0; idx < length; idx++) {
            if (options.data.multi_header[idx].parsed === null) {
                options.data = null;
                break;
            }
        }
        if (options.data !== null) {
            options.data = options.data.multi_header;
        }
        else {
            options.data = -1;
        }
    };
    var peg$c208 = function () {
        var header;
        options = options || { data: {} };
        if (!options.data.multi_header)
            options.data.multi_header = [];
        try {
            header = new NameAddrHeader_1.NameAddrHeader(options.data.uri, options.data.displayName, options.data.params);
            delete options.data.uri;
            delete options.data.displayName;
            delete options.data.params;
        }
        catch (e) {
            header = null;
        }
        options.data.multi_header.push({ 'position': peg$currPos,
            'offset': location().start.offset,
            'parsed': header
        });
    };
    var peg$c209 = function (displayName) {
        displayName = text().trim();
        if (displayName[0] === '\"') {
            displayName = displayName.substring(1, displayName.length - 1);
        }
        options = options || { data: {} };
        options.data.displayName = displayName;
    };
    var peg$c210 = "q";
    var peg$c211 = peg$literalExpectation("q", true);
    var peg$c212 = function (q) {
        options = options || { data: {} };
        if (!options.data.params)
            options.data.params = {};
        options.data.params['q'] = q;
    };
    var peg$c213 = "expires";
    var peg$c214 = peg$literalExpectation("expires", true);
    var peg$c215 = function (expires) {
        options = options || { data: {} };
        if (!options.data.params)
            options.data.params = {};
        options.data.params['expires'] = expires;
    };
    var peg$c216 = function (delta_seconds) {
        return parseInt(delta_seconds.join(''));
    };
    var peg$c217 = "0";
    var peg$c218 = peg$literalExpectation("0", false);
    var peg$c219 = function () {
        return parseFloat(text());
    };
    var peg$c220 = function (param, value) {
        options = options || { data: {} };
        if (!options.data.params)
            options.data.params = {};
        if (value === null) {
            value = undefined;
        }
        else {
            value = value[1];
        }
        options.data.params[param.toLowerCase()] = value;
    };
    var peg$c221 = "render";
    var peg$c222 = peg$literalExpectation("render", true);
    var peg$c223 = "session";
    var peg$c224 = peg$literalExpectation("session", true);
    var peg$c225 = "icon";
    var peg$c226 = peg$literalExpectation("icon", true);
    var peg$c227 = "alert";
    var peg$c228 = peg$literalExpectation("alert", true);
    var peg$c229 = function () {
        options = options || { data: {} };
        if (options.startRule === 'Content_Disposition') {
            options.data.type = text().toLowerCase();
        }
    };
    var peg$c230 = "handling";
    var peg$c231 = peg$literalExpectation("handling", true);
    var peg$c232 = "optional";
    var peg$c233 = peg$literalExpectation("optional", true);
    var peg$c234 = "required";
    var peg$c235 = peg$literalExpectation("required", true);
    var peg$c236 = function (length) {
        options = options || { data: {} };
        options.data = parseInt(length.join(''));
    };
    var peg$c237 = function () {
        options = options || { data: {} };
        options.data = text();
    };
    var peg$c238 = "text";
    var peg$c239 = peg$literalExpectation("text", true);
    var peg$c240 = "image";
    var peg$c241 = peg$literalExpectation("image", true);
    var peg$c242 = "audio";
    var peg$c243 = peg$literalExpectation("audio", true);
    var peg$c244 = "video";
    var peg$c245 = peg$literalExpectation("video", true);
    var peg$c246 = "application";
    var peg$c247 = peg$literalExpectation("application", true);
    var peg$c248 = "message";
    var peg$c249 = peg$literalExpectation("message", true);
    var peg$c250 = "multipart";
    var peg$c251 = peg$literalExpectation("multipart", true);
    var peg$c252 = "x-";
    var peg$c253 = peg$literalExpectation("x-", true);
    var peg$c254 = function (cseq_value) {
        options = options || { data: {} };
        options.data.value = parseInt(cseq_value.join(''));
    };
    var peg$c255 = function (expires) { options = options || { data: {} }; options.data = expires; };
    var peg$c256 = function (event_type) {
        options = options || { data: {} };
        options.data.event = event_type.toLowerCase();
    };
    var peg$c257 = function () {
        options = options || { data: {} };
        var tag = options.data.tag;
        options.data = new NameAddrHeader_1.NameAddrHeader(options.data.uri, options.data.displayName, options.data.params);
        if (tag) {
            options.data.setParam('tag', tag);
        }
    };
    var peg$c258 = "tag";
    var peg$c259 = peg$literalExpectation("tag", true);
    var peg$c260 = function (tag) { options = options || { data: {} }; options.data.tag = tag; };
    var peg$c261 = function (forwards) {
        options = options || { data: {} };
        options.data = parseInt(forwards.join(''));
    };
    var peg$c262 = function (min_expires) { options = options || { data: {} }; options.data = min_expires; };
    var peg$c263 = function () {
        options = options || { data: {} };
        options.data = new NameAddrHeader_1.NameAddrHeader(options.data.uri, options.data.displayName, options.data.params);
    };
    var peg$c264 = "digest";
    var peg$c265 = peg$literalExpectation("Digest", true);
    var peg$c266 = "realm";
    var peg$c267 = peg$literalExpectation("realm", true);
    var peg$c268 = function (realm) { options = options || { data: {} }; options.data.realm = realm; };
    var peg$c269 = "domain";
    var peg$c270 = peg$literalExpectation("domain", true);
    var peg$c271 = "nonce";
    var peg$c272 = peg$literalExpectation("nonce", true);
    var peg$c273 = function (nonce) { options = options || { data: {} }; options.data.nonce = nonce; };
    var peg$c274 = "opaque";
    var peg$c275 = peg$literalExpectation("opaque", true);
    var peg$c276 = function (opaque) { options = options || { data: {} }; options.data.opaque = opaque; };
    var peg$c277 = "stale";
    var peg$c278 = peg$literalExpectation("stale", true);
    var peg$c279 = "true";
    var peg$c280 = peg$literalExpectation("true", true);
    var peg$c281 = function () { options = options || { data: {} }; options.data.stale = true; };
    var peg$c282 = "false";
    var peg$c283 = peg$literalExpectation("false", true);
    var peg$c284 = function () { options = options || { data: {} }; options.data.stale = false; };
    var peg$c285 = "algorithm";
    var peg$c286 = peg$literalExpectation("algorithm", true);
    var peg$c287 = "md5";
    var peg$c288 = peg$literalExpectation("MD5", true);
    var peg$c289 = "md5-sess";
    var peg$c290 = peg$literalExpectation("MD5-sess", true);
    var peg$c291 = function (algorithm) {
        options = options || { data: {} };
        options.data.algorithm = algorithm.toUpperCase();
    };
    var peg$c292 = "qop";
    var peg$c293 = peg$literalExpectation("qop", true);
    var peg$c294 = "auth-int";
    var peg$c295 = peg$literalExpectation("auth-int", true);
    var peg$c296 = "auth";
    var peg$c297 = peg$literalExpectation("auth", true);
    var peg$c298 = function (qop_value) {
        options = options || { data: {} };
        options.data.qop || (options.data.qop = []);
        options.data.qop.push(qop_value.toLowerCase());
    };
    var peg$c299 = function (rack_value) {
        options = options || { data: {} };
        options.data.value = parseInt(rack_value.join(''));
    };
    var peg$c300 = function () {
        var idx, length;
        options = options || { data: {} };
        length = options.data.multi_header.length;
        for (idx = 0; idx < length; idx++) {
            if (options.data.multi_header[idx].parsed === null) {
                options.data = null;
                break;
            }
        }
        if (options.data !== null) {
            options.data = options.data.multi_header;
        }
        else {
            options.data = -1;
        }
    };
    var peg$c301 = function () {
        var header;
        options = options || { data: {} };
        if (!options.data.multi_header)
            options.data.multi_header = [];
        try {
            header = new NameAddrHeader_1.NameAddrHeader(options.data.uri, options.data.displayName, options.data.params);
            delete options.data.uri;
            delete options.data.displayName;
            delete options.data.params;
        }
        catch (e) {
            header = null;
        }
        options.data.multi_header.push({ 'position': peg$currPos,
            'offset': location().start.offset,
            'parsed': header
        });
    };
    var peg$c302 = function () {
        options = options || { data: {} };
        options.data = new NameAddrHeader_1.NameAddrHeader(options.data.uri, options.data.displayName, options.data.params);
    };
    var peg$c303 = function () {
        options = options || { data: {} };
        if (!(options.data.replaces_from_tag && options.data.replaces_to_tag)) {
            options.data = -1;
        }
    };
    var peg$c304 = function () {
        options = options || { data: {} };
        options.data = {
            call_id: options.data
        };
    };
    var peg$c305 = "from-tag";
    var peg$c306 = peg$literalExpectation("from-tag", true);
    var peg$c307 = function (from_tag) {
        options = options || { data: {} };
        options.data.replaces_from_tag = from_tag;
    };
    var peg$c308 = "to-tag";
    var peg$c309 = peg$literalExpectation("to-tag", true);
    var peg$c310 = function (to_tag) {
        options = options || { data: {} };
        options.data.replaces_to_tag = to_tag;
    };
    var peg$c311 = "early-only";
    var peg$c312 = peg$literalExpectation("early-only", true);
    var peg$c313 = function () {
        options = options || { data: {} };
        options.data.early_only = true;
    };
    var peg$c314 = function (head, r) { return r; };
    var peg$c315 = function (head, tail) { return list(head, tail); };
    var peg$c316 = function (value) {
        options = options || { data: {} };
        if (options.startRule === 'Require') {
            options.data = value || [];
        }
    };
    var peg$c317 = function (rseq_value) {
        options = options || { data: {} };
        options.data.value = parseInt(rseq_value.join(''));
    };
    var peg$c318 = "active";
    var peg$c319 = peg$literalExpectation("active", true);
    var peg$c320 = "pending";
    var peg$c321 = peg$literalExpectation("pending", true);
    var peg$c322 = "terminated";
    var peg$c323 = peg$literalExpectation("terminated", true);
    var peg$c324 = function () {
        options = options || { data: {} };
        options.data.state = text();
    };
    var peg$c325 = "reason";
    var peg$c326 = peg$literalExpectation("reason", true);
    var peg$c327 = function (reason) {
        options = options || { data: {} };
        if (typeof reason !== 'undefined')
            options.data.reason = reason;
    };
    var peg$c328 = function (expires) {
        options = options || { data: {} };
        if (typeof expires !== 'undefined')
            options.data.expires = expires;
    };
    var peg$c329 = "retry_after";
    var peg$c330 = peg$literalExpectation("retry_after", true);
    var peg$c331 = function (retry_after) {
        options = options || { data: {} };
        if (typeof retry_after !== 'undefined')
            options.data.retry_after = retry_after;
    };
    var peg$c332 = "deactivated";
    var peg$c333 = peg$literalExpectation("deactivated", true);
    var peg$c334 = "probation";
    var peg$c335 = peg$literalExpectation("probation", true);
    var peg$c336 = "rejected";
    var peg$c337 = peg$literalExpectation("rejected", true);
    var peg$c338 = "timeout";
    var peg$c339 = peg$literalExpectation("timeout", true);
    var peg$c340 = "giveup";
    var peg$c341 = peg$literalExpectation("giveup", true);
    var peg$c342 = "noresource";
    var peg$c343 = peg$literalExpectation("noresource", true);
    var peg$c344 = "invariant";
    var peg$c345 = peg$literalExpectation("invariant", true);
    var peg$c346 = function (value) {
        options = options || { data: {} };
        if (options.startRule === 'Supported') {
            options.data = value || [];
        }
    };
    var peg$c347 = function () {
        options = options || { data: {} };
        var tag = options.data.tag;
        options.data = new NameAddrHeader_1.NameAddrHeader(options.data.uri, options.data.displayName, options.data.params);
        if (tag) {
            options.data.setParam('tag', tag);
        }
    };
    var peg$c348 = "ttl";
    var peg$c349 = peg$literalExpectation("ttl", true);
    var peg$c350 = function (via_ttl_value) {
        options = options || { data: {} };
        options.data.ttl = via_ttl_value;
    };
    var peg$c351 = "maddr";
    var peg$c352 = peg$literalExpectation("maddr", true);
    var peg$c353 = function (via_maddr) {
        options = options || { data: {} };
        options.data.maddr = via_maddr;
    };
    var peg$c354 = "received";
    var peg$c355 = peg$literalExpectation("received", true);
    var peg$c356 = function (via_received) {
        options = options || { data: {} };
        options.data.received = via_received;
    };
    var peg$c357 = "branch";
    var peg$c358 = peg$literalExpectation("branch", true);
    var peg$c359 = function (via_branch) {
        options = options || { data: {} };
        options.data.branch = via_branch;
    };
    var peg$c360 = "rport";
    var peg$c361 = peg$literalExpectation("rport", true);
    var peg$c362 = function (response_port) {
        options = options || { data: {} };
        if (typeof response_port !== 'undefined')
            options.data.rport = response_port.join('');
    };
    var peg$c363 = function (via_protocol) {
        options = options || { data: {} };
        options.data.protocol = via_protocol;
    };
    var peg$c364 = peg$literalExpectation("UDP", true);
    var peg$c365 = peg$literalExpectation("TCP", true);
    var peg$c366 = peg$literalExpectation("TLS", true);
    var peg$c367 = peg$literalExpectation("SCTP", true);
    var peg$c368 = function (via_transport) {
        options = options || { data: {} };
        options.data.transport = via_transport;
    };
    var peg$c369 = function () {
        options = options || { data: {} };
        options.data.host = text();
    };
    var peg$c370 = function (via_sent_by_port) {
        options = options || { data: {} };
        options.data.port = parseInt(via_sent_by_port.join(''));
    };
    var peg$c371 = function (ttl) {
        return parseInt(ttl.join(''));
    };
    var peg$c372 = function (deltaSeconds) {
        options = options || { data: {} };
        if (options.startRule === 'Session_Expires') {
            options.data.deltaSeconds = deltaSeconds;
        }
    };
    var peg$c373 = "refresher";
    var peg$c374 = peg$literalExpectation("refresher", false);
    var peg$c375 = "uas";
    var peg$c376 = peg$literalExpectation("uas", false);
    var peg$c377 = "uac";
    var peg$c378 = peg$literalExpectation("uac", false);
    var peg$c379 = function (endpoint) {
        options = options || { data: {} };
        if (options.startRule === 'Session_Expires') {
            options.data.refresher = endpoint;
        }
    };
    var peg$c380 = function (deltaSeconds) {
        options = options || { data: {} };
        if (options.startRule === 'Min_SE') {
            options.data = deltaSeconds;
        }
    };
    var peg$c381 = "stuns";
    var peg$c382 = peg$literalExpectation("stuns", true);
    var peg$c383 = "stun";
    var peg$c384 = peg$literalExpectation("stun", true);
    var peg$c385 = function (scheme) {
        options = options || { data: {} };
        options.data.scheme = scheme;
    };
    var peg$c386 = function (host) {
        options = options || { data: {} };
        options.data.host = host;
    };
    var peg$c387 = "?transport=";
    var peg$c388 = peg$literalExpectation("?transport=", false);
    var peg$c389 = "turns";
    var peg$c390 = peg$literalExpectation("turns", true);
    var peg$c391 = "turn";
    var peg$c392 = peg$literalExpectation("turn", true);
    var peg$c393 = function (transport) {
        options = options || { data: {} };
        options.data.transport = transport;
    };
    var peg$c394 = function () {
        options = options || { data: {} };
        options.data = text();
    };
    var peg$c395 = "Referred-By";
    var peg$c396 = peg$literalExpectation("Referred-By", false);
    var peg$c397 = "b";
    var peg$c398 = peg$literalExpectation("b", false);
    var peg$c399 = "cid";
    var peg$c400 = peg$literalExpectation("cid", false);
    var peg$currPos = 0;
    var peg$savedPos = 0;
    var peg$posDetailsCache = [{ line: 1, column: 1 }];
    var peg$maxFailPos = 0;
    var peg$maxFailExpected = [];
    var peg$silentFails = 0;
    var peg$result;
    if (options.startRule !== undefined) {
        if (!(options.startRule in peg$startRuleFunctions)) {
            throw new Error("Can't start parsing from rule \"" + options.startRule + "\".");
        }
        peg$startRuleFunction = peg$startRuleFunctions[options.startRule];
    }
    function text() {
        return input.substring(peg$savedPos, peg$currPos);
    }
    function location() {
        return peg$computeLocation(peg$savedPos, peg$currPos);
    }
    function expected(description, location1) {
        location1 = location1 !== undefined
            ? location1
            : peg$computeLocation(peg$savedPos, peg$currPos);
        throw peg$buildStructuredError([peg$otherExpectation(description)], input.substring(peg$savedPos, peg$currPos), location1);
    }
    function error(message, location1) {
        location1 = location1 !== undefined
            ? location1
            : peg$computeLocation(peg$savedPos, peg$currPos);
        throw peg$buildSimpleError(message, location1);
    }
    function peg$literalExpectation(text1, ignoreCase) {
        return { type: "literal", text: text1, ignoreCase: ignoreCase };
    }
    function peg$classExpectation(parts, inverted, ignoreCase) {
        return { type: "class", parts: parts, inverted: inverted, ignoreCase: ignoreCase };
    }
    function peg$anyExpectation() {
        return { type: "any" };
    }
    function peg$endExpectation() {
        return { type: "end" };
    }
    function peg$otherExpectation(description) {
        return { type: "other", description: description };
    }
    function peg$computePosDetails(pos) {
        var details = peg$posDetailsCache[pos];
        var p;
        if (details) {
            return details;
        }
        else {
            p = pos - 1;
            while (!peg$posDetailsCache[p]) {
                p--;
            }
            details = peg$posDetailsCache[p];
            details = {
                line: details.line,
                column: details.column
            };
            while (p < pos) {
                if (input.charCodeAt(p) === 10) {
                    details.line++;
                    details.column = 1;
                }
                else {
                    details.column++;
                }
                p++;
            }
            peg$posDetailsCache[pos] = details;
            return details;
        }
    }
    function peg$computeLocation(startPos, endPos) {
        var startPosDetails = peg$computePosDetails(startPos);
        var endPosDetails = peg$computePosDetails(endPos);
        return {
            start: {
                offset: startPos,
                line: startPosDetails.line,
                column: startPosDetails.column
            },
            end: {
                offset: endPos,
                line: endPosDetails.line,
                column: endPosDetails.column
            }
        };
    }
    function peg$fail(expected1) {
        if (peg$currPos < peg$maxFailPos) {
            return;
        }
        if (peg$currPos > peg$maxFailPos) {
            peg$maxFailPos = peg$currPos;
            peg$maxFailExpected = [];
        }
        peg$maxFailExpected.push(expected1);
    }
    function peg$buildSimpleError(message, location1) {
        return new SyntaxError(message, [], "", location1);
    }
    function peg$buildStructuredError(expected1, found, location1) {
        return new SyntaxError(SyntaxError.buildMessage(expected1, found), expected1, found, location1);
    }
    function peg$parseCRLF() {
        var s0;
        if (input.substr(peg$currPos, 2) === peg$c0) {
            s0 = peg$c0;
            peg$currPos += 2;
        }
        else {
            s0 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c1);
            }
        }
        return s0;
    }
    function peg$parseDIGIT() {
        var s0;
        if (peg$c2.test(input.charAt(peg$currPos))) {
            s0 = input.charAt(peg$currPos);
            peg$currPos++;
        }
        else {
            s0 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c3);
            }
        }
        return s0;
    }
    function peg$parseALPHA() {
        var s0;
        if (peg$c4.test(input.charAt(peg$currPos))) {
            s0 = input.charAt(peg$currPos);
            peg$currPos++;
        }
        else {
            s0 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c5);
            }
        }
        return s0;
    }
    function peg$parseHEXDIG() {
        var s0;
        if (peg$c6.test(input.charAt(peg$currPos))) {
            s0 = input.charAt(peg$currPos);
            peg$currPos++;
        }
        else {
            s0 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c7);
            }
        }
        return s0;
    }
    function peg$parseWSP() {
        var s0;
        s0 = peg$parseSP();
        if (s0 === peg$FAILED) {
            s0 = peg$parseHTAB();
        }
        return s0;
    }
    function peg$parseOCTET() {
        var s0;
        if (peg$c8.test(input.charAt(peg$currPos))) {
            s0 = input.charAt(peg$currPos);
            peg$currPos++;
        }
        else {
            s0 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c9);
            }
        }
        return s0;
    }
    function peg$parseDQUOTE() {
        var s0;
        if (peg$c10.test(input.charAt(peg$currPos))) {
            s0 = input.charAt(peg$currPos);
            peg$currPos++;
        }
        else {
            s0 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c11);
            }
        }
        return s0;
    }
    function peg$parseSP() {
        var s0;
        if (input.charCodeAt(peg$currPos) === 32) {
            s0 = peg$c12;
            peg$currPos++;
        }
        else {
            s0 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c13);
            }
        }
        return s0;
    }
    function peg$parseHTAB() {
        var s0;
        if (input.charCodeAt(peg$currPos) === 9) {
            s0 = peg$c14;
            peg$currPos++;
        }
        else {
            s0 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c15);
            }
        }
        return s0;
    }
    function peg$parsealphanum() {
        var s0;
        if (peg$c16.test(input.charAt(peg$currPos))) {
            s0 = input.charAt(peg$currPos);
            peg$currPos++;
        }
        else {
            s0 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c17);
            }
        }
        return s0;
    }
    function peg$parsereserved() {
        var s0;
        if (input.charCodeAt(peg$currPos) === 59) {
            s0 = peg$c18;
            peg$currPos++;
        }
        else {
            s0 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c19);
            }
        }
        if (s0 === peg$FAILED) {
            if (input.charCodeAt(peg$currPos) === 47) {
                s0 = peg$c20;
                peg$currPos++;
            }
            else {
                s0 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c21);
                }
            }
            if (s0 === peg$FAILED) {
                if (input.charCodeAt(peg$currPos) === 63) {
                    s0 = peg$c22;
                    peg$currPos++;
                }
                else {
                    s0 = peg$FAILED;
                    if (peg$silentFails === 0) {
                        peg$fail(peg$c23);
                    }
                }
                if (s0 === peg$FAILED) {
                    if (input.charCodeAt(peg$currPos) === 58) {
                        s0 = peg$c24;
                        peg$currPos++;
                    }
                    else {
                        s0 = peg$FAILED;
                        if (peg$silentFails === 0) {
                            peg$fail(peg$c25);
                        }
                    }
                    if (s0 === peg$FAILED) {
                        if (input.charCodeAt(peg$currPos) === 64) {
                            s0 = peg$c26;
                            peg$currPos++;
                        }
                        else {
                            s0 = peg$FAILED;
                            if (peg$silentFails === 0) {
                                peg$fail(peg$c27);
                            }
                        }
                        if (s0 === peg$FAILED) {
                            if (input.charCodeAt(peg$currPos) === 38) {
                                s0 = peg$c28;
                                peg$currPos++;
                            }
                            else {
                                s0 = peg$FAILED;
                                if (peg$silentFails === 0) {
                                    peg$fail(peg$c29);
                                }
                            }
                            if (s0 === peg$FAILED) {
                                if (input.charCodeAt(peg$currPos) === 61) {
                                    s0 = peg$c30;
                                    peg$currPos++;
                                }
                                else {
                                    s0 = peg$FAILED;
                                    if (peg$silentFails === 0) {
                                        peg$fail(peg$c31);
                                    }
                                }
                                if (s0 === peg$FAILED) {
                                    if (input.charCodeAt(peg$currPos) === 43) {
                                        s0 = peg$c32;
                                        peg$currPos++;
                                    }
                                    else {
                                        s0 = peg$FAILED;
                                        if (peg$silentFails === 0) {
                                            peg$fail(peg$c33);
                                        }
                                    }
                                    if (s0 === peg$FAILED) {
                                        if (input.charCodeAt(peg$currPos) === 36) {
                                            s0 = peg$c34;
                                            peg$currPos++;
                                        }
                                        else {
                                            s0 = peg$FAILED;
                                            if (peg$silentFails === 0) {
                                                peg$fail(peg$c35);
                                            }
                                        }
                                        if (s0 === peg$FAILED) {
                                            if (input.charCodeAt(peg$currPos) === 44) {
                                                s0 = peg$c36;
                                                peg$currPos++;
                                            }
                                            else {
                                                s0 = peg$FAILED;
                                                if (peg$silentFails === 0) {
                                                    peg$fail(peg$c37);
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        return s0;
    }
    function peg$parseunreserved() {
        var s0;
        s0 = peg$parsealphanum();
        if (s0 === peg$FAILED) {
            s0 = peg$parsemark();
        }
        return s0;
    }
    function peg$parsemark() {
        var s0;
        if (input.charCodeAt(peg$currPos) === 45) {
            s0 = peg$c38;
            peg$currPos++;
        }
        else {
            s0 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c39);
            }
        }
        if (s0 === peg$FAILED) {
            if (input.charCodeAt(peg$currPos) === 95) {
                s0 = peg$c40;
                peg$currPos++;
            }
            else {
                s0 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c41);
                }
            }
            if (s0 === peg$FAILED) {
                if (input.charCodeAt(peg$currPos) === 46) {
                    s0 = peg$c42;
                    peg$currPos++;
                }
                else {
                    s0 = peg$FAILED;
                    if (peg$silentFails === 0) {
                        peg$fail(peg$c43);
                    }
                }
                if (s0 === peg$FAILED) {
                    if (input.charCodeAt(peg$currPos) === 33) {
                        s0 = peg$c44;
                        peg$currPos++;
                    }
                    else {
                        s0 = peg$FAILED;
                        if (peg$silentFails === 0) {
                            peg$fail(peg$c45);
                        }
                    }
                    if (s0 === peg$FAILED) {
                        if (input.charCodeAt(peg$currPos) === 126) {
                            s0 = peg$c46;
                            peg$currPos++;
                        }
                        else {
                            s0 = peg$FAILED;
                            if (peg$silentFails === 0) {
                                peg$fail(peg$c47);
                            }
                        }
                        if (s0 === peg$FAILED) {
                            if (input.charCodeAt(peg$currPos) === 42) {
                                s0 = peg$c48;
                                peg$currPos++;
                            }
                            else {
                                s0 = peg$FAILED;
                                if (peg$silentFails === 0) {
                                    peg$fail(peg$c49);
                                }
                            }
                            if (s0 === peg$FAILED) {
                                if (input.charCodeAt(peg$currPos) === 39) {
                                    s0 = peg$c50;
                                    peg$currPos++;
                                }
                                else {
                                    s0 = peg$FAILED;
                                    if (peg$silentFails === 0) {
                                        peg$fail(peg$c51);
                                    }
                                }
                                if (s0 === peg$FAILED) {
                                    if (input.charCodeAt(peg$currPos) === 40) {
                                        s0 = peg$c52;
                                        peg$currPos++;
                                    }
                                    else {
                                        s0 = peg$FAILED;
                                        if (peg$silentFails === 0) {
                                            peg$fail(peg$c53);
                                        }
                                    }
                                    if (s0 === peg$FAILED) {
                                        if (input.charCodeAt(peg$currPos) === 41) {
                                            s0 = peg$c54;
                                            peg$currPos++;
                                        }
                                        else {
                                            s0 = peg$FAILED;
                                            if (peg$silentFails === 0) {
                                                peg$fail(peg$c55);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        return s0;
    }
    function peg$parseescaped() {
        var s0, s1, s2, s3, s4;
        s0 = peg$currPos;
        s1 = peg$currPos;
        if (input.charCodeAt(peg$currPos) === 37) {
            s2 = peg$c56;
            peg$currPos++;
        }
        else {
            s2 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c57);
            }
        }
        if (s2 !== peg$FAILED) {
            s3 = peg$parseHEXDIG();
            if (s3 !== peg$FAILED) {
                s4 = peg$parseHEXDIG();
                if (s4 !== peg$FAILED) {
                    s2 = [s2, s3, s4];
                    s1 = s2;
                }
                else {
                    peg$currPos = s1;
                    s1 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s1;
                s1 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s1;
            s1 = peg$FAILED;
        }
        if (s1 !== peg$FAILED) {
            s0 = input.substring(s0, peg$currPos);
        }
        else {
            s0 = s1;
        }
        return s0;
    }
    function peg$parseLWS() {
        var s0, s1, s2, s3;
        s0 = peg$currPos;
        s1 = peg$currPos;
        s2 = [];
        s3 = peg$parseWSP();
        while (s3 !== peg$FAILED) {
            s2.push(s3);
            s3 = peg$parseWSP();
        }
        if (s2 !== peg$FAILED) {
            s3 = peg$parseCRLF();
            if (s3 !== peg$FAILED) {
                s2 = [s2, s3];
                s1 = s2;
            }
            else {
                peg$currPos = s1;
                s1 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s1;
            s1 = peg$FAILED;
        }
        if (s1 === peg$FAILED) {
            s1 = null;
        }
        if (s1 !== peg$FAILED) {
            s2 = [];
            s3 = peg$parseWSP();
            if (s3 !== peg$FAILED) {
                while (s3 !== peg$FAILED) {
                    s2.push(s3);
                    s3 = peg$parseWSP();
                }
            }
            else {
                s2 = peg$FAILED;
            }
            if (s2 !== peg$FAILED) {
                peg$savedPos = s0;
                s1 = peg$c58();
                s0 = s1;
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parseSWS() {
        var s0;
        s0 = peg$parseLWS();
        if (s0 === peg$FAILED) {
            s0 = null;
        }
        return s0;
    }
    function peg$parseHCOLON() {
        var s0, s1, s2, s3;
        s0 = peg$currPos;
        s1 = [];
        s2 = peg$parseSP();
        if (s2 === peg$FAILED) {
            s2 = peg$parseHTAB();
        }
        while (s2 !== peg$FAILED) {
            s1.push(s2);
            s2 = peg$parseSP();
            if (s2 === peg$FAILED) {
                s2 = peg$parseHTAB();
            }
        }
        if (s1 !== peg$FAILED) {
            if (input.charCodeAt(peg$currPos) === 58) {
                s2 = peg$c24;
                peg$currPos++;
            }
            else {
                s2 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c25);
                }
            }
            if (s2 !== peg$FAILED) {
                s3 = peg$parseSWS();
                if (s3 !== peg$FAILED) {
                    peg$savedPos = s0;
                    s1 = peg$c59();
                    s0 = s1;
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parseTEXT_UTF8_TRIM() {
        var s0, s1, s2, s3, s4, s5, s6;
        s0 = peg$currPos;
        s1 = peg$currPos;
        s2 = [];
        s3 = peg$parseTEXT_UTF8char();
        if (s3 !== peg$FAILED) {
            while (s3 !== peg$FAILED) {
                s2.push(s3);
                s3 = peg$parseTEXT_UTF8char();
            }
        }
        else {
            s2 = peg$FAILED;
        }
        if (s2 !== peg$FAILED) {
            s3 = [];
            s4 = peg$currPos;
            s5 = [];
            s6 = peg$parseLWS();
            while (s6 !== peg$FAILED) {
                s5.push(s6);
                s6 = peg$parseLWS();
            }
            if (s5 !== peg$FAILED) {
                s6 = peg$parseTEXT_UTF8char();
                if (s6 !== peg$FAILED) {
                    s5 = [s5, s6];
                    s4 = s5;
                }
                else {
                    peg$currPos = s4;
                    s4 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s4;
                s4 = peg$FAILED;
            }
            while (s4 !== peg$FAILED) {
                s3.push(s4);
                s4 = peg$currPos;
                s5 = [];
                s6 = peg$parseLWS();
                while (s6 !== peg$FAILED) {
                    s5.push(s6);
                    s6 = peg$parseLWS();
                }
                if (s5 !== peg$FAILED) {
                    s6 = peg$parseTEXT_UTF8char();
                    if (s6 !== peg$FAILED) {
                        s5 = [s5, s6];
                        s4 = s5;
                    }
                    else {
                        peg$currPos = s4;
                        s4 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s4;
                    s4 = peg$FAILED;
                }
            }
            if (s3 !== peg$FAILED) {
                s2 = [s2, s3];
                s1 = s2;
            }
            else {
                peg$currPos = s1;
                s1 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s1;
            s1 = peg$FAILED;
        }
        if (s1 !== peg$FAILED) {
            s0 = input.substring(s0, peg$currPos);
        }
        else {
            s0 = s1;
        }
        return s0;
    }
    function peg$parseTEXT_UTF8char() {
        var s0;
        if (peg$c60.test(input.charAt(peg$currPos))) {
            s0 = input.charAt(peg$currPos);
            peg$currPos++;
        }
        else {
            s0 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c61);
            }
        }
        if (s0 === peg$FAILED) {
            s0 = peg$parseUTF8_NONASCII();
        }
        return s0;
    }
    function peg$parseUTF8_NONASCII() {
        var s0;
        if (peg$c62.test(input.charAt(peg$currPos))) {
            s0 = input.charAt(peg$currPos);
            peg$currPos++;
        }
        else {
            s0 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c63);
            }
        }
        return s0;
    }
    function peg$parseUTF8_CONT() {
        var s0;
        if (peg$c64.test(input.charAt(peg$currPos))) {
            s0 = input.charAt(peg$currPos);
            peg$currPos++;
        }
        else {
            s0 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c65);
            }
        }
        return s0;
    }
    function peg$parseLHEX() {
        var s0;
        s0 = peg$parseDIGIT();
        if (s0 === peg$FAILED) {
            if (peg$c66.test(input.charAt(peg$currPos))) {
                s0 = input.charAt(peg$currPos);
                peg$currPos++;
            }
            else {
                s0 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c67);
                }
            }
        }
        return s0;
    }
    function peg$parsetoken() {
        var s0, s1, s2;
        s0 = peg$currPos;
        s1 = [];
        s2 = peg$parsealphanum();
        if (s2 === peg$FAILED) {
            if (input.charCodeAt(peg$currPos) === 45) {
                s2 = peg$c38;
                peg$currPos++;
            }
            else {
                s2 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c39);
                }
            }
            if (s2 === peg$FAILED) {
                if (input.charCodeAt(peg$currPos) === 46) {
                    s2 = peg$c42;
                    peg$currPos++;
                }
                else {
                    s2 = peg$FAILED;
                    if (peg$silentFails === 0) {
                        peg$fail(peg$c43);
                    }
                }
                if (s2 === peg$FAILED) {
                    if (input.charCodeAt(peg$currPos) === 33) {
                        s2 = peg$c44;
                        peg$currPos++;
                    }
                    else {
                        s2 = peg$FAILED;
                        if (peg$silentFails === 0) {
                            peg$fail(peg$c45);
                        }
                    }
                    if (s2 === peg$FAILED) {
                        if (input.charCodeAt(peg$currPos) === 37) {
                            s2 = peg$c56;
                            peg$currPos++;
                        }
                        else {
                            s2 = peg$FAILED;
                            if (peg$silentFails === 0) {
                                peg$fail(peg$c57);
                            }
                        }
                        if (s2 === peg$FAILED) {
                            if (input.charCodeAt(peg$currPos) === 42) {
                                s2 = peg$c48;
                                peg$currPos++;
                            }
                            else {
                                s2 = peg$FAILED;
                                if (peg$silentFails === 0) {
                                    peg$fail(peg$c49);
                                }
                            }
                            if (s2 === peg$FAILED) {
                                if (input.charCodeAt(peg$currPos) === 95) {
                                    s2 = peg$c40;
                                    peg$currPos++;
                                }
                                else {
                                    s2 = peg$FAILED;
                                    if (peg$silentFails === 0) {
                                        peg$fail(peg$c41);
                                    }
                                }
                                if (s2 === peg$FAILED) {
                                    if (input.charCodeAt(peg$currPos) === 43) {
                                        s2 = peg$c32;
                                        peg$currPos++;
                                    }
                                    else {
                                        s2 = peg$FAILED;
                                        if (peg$silentFails === 0) {
                                            peg$fail(peg$c33);
                                        }
                                    }
                                    if (s2 === peg$FAILED) {
                                        if (input.charCodeAt(peg$currPos) === 96) {
                                            s2 = peg$c68;
                                            peg$currPos++;
                                        }
                                        else {
                                            s2 = peg$FAILED;
                                            if (peg$silentFails === 0) {
                                                peg$fail(peg$c69);
                                            }
                                        }
                                        if (s2 === peg$FAILED) {
                                            if (input.charCodeAt(peg$currPos) === 39) {
                                                s2 = peg$c50;
                                                peg$currPos++;
                                            }
                                            else {
                                                s2 = peg$FAILED;
                                                if (peg$silentFails === 0) {
                                                    peg$fail(peg$c51);
                                                }
                                            }
                                            if (s2 === peg$FAILED) {
                                                if (input.charCodeAt(peg$currPos) === 126) {
                                                    s2 = peg$c46;
                                                    peg$currPos++;
                                                }
                                                else {
                                                    s2 = peg$FAILED;
                                                    if (peg$silentFails === 0) {
                                                        peg$fail(peg$c47);
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        if (s2 !== peg$FAILED) {
            while (s2 !== peg$FAILED) {
                s1.push(s2);
                s2 = peg$parsealphanum();
                if (s2 === peg$FAILED) {
                    if (input.charCodeAt(peg$currPos) === 45) {
                        s2 = peg$c38;
                        peg$currPos++;
                    }
                    else {
                        s2 = peg$FAILED;
                        if (peg$silentFails === 0) {
                            peg$fail(peg$c39);
                        }
                    }
                    if (s2 === peg$FAILED) {
                        if (input.charCodeAt(peg$currPos) === 46) {
                            s2 = peg$c42;
                            peg$currPos++;
                        }
                        else {
                            s2 = peg$FAILED;
                            if (peg$silentFails === 0) {
                                peg$fail(peg$c43);
                            }
                        }
                        if (s2 === peg$FAILED) {
                            if (input.charCodeAt(peg$currPos) === 33) {
                                s2 = peg$c44;
                                peg$currPos++;
                            }
                            else {
                                s2 = peg$FAILED;
                                if (peg$silentFails === 0) {
                                    peg$fail(peg$c45);
                                }
                            }
                            if (s2 === peg$FAILED) {
                                if (input.charCodeAt(peg$currPos) === 37) {
                                    s2 = peg$c56;
                                    peg$currPos++;
                                }
                                else {
                                    s2 = peg$FAILED;
                                    if (peg$silentFails === 0) {
                                        peg$fail(peg$c57);
                                    }
                                }
                                if (s2 === peg$FAILED) {
                                    if (input.charCodeAt(peg$currPos) === 42) {
                                        s2 = peg$c48;
                                        peg$currPos++;
                                    }
                                    else {
                                        s2 = peg$FAILED;
                                        if (peg$silentFails === 0) {
                                            peg$fail(peg$c49);
                                        }
                                    }
                                    if (s2 === peg$FAILED) {
                                        if (input.charCodeAt(peg$currPos) === 95) {
                                            s2 = peg$c40;
                                            peg$currPos++;
                                        }
                                        else {
                                            s2 = peg$FAILED;
                                            if (peg$silentFails === 0) {
                                                peg$fail(peg$c41);
                                            }
                                        }
                                        if (s2 === peg$FAILED) {
                                            if (input.charCodeAt(peg$currPos) === 43) {
                                                s2 = peg$c32;
                                                peg$currPos++;
                                            }
                                            else {
                                                s2 = peg$FAILED;
                                                if (peg$silentFails === 0) {
                                                    peg$fail(peg$c33);
                                                }
                                            }
                                            if (s2 === peg$FAILED) {
                                                if (input.charCodeAt(peg$currPos) === 96) {
                                                    s2 = peg$c68;
                                                    peg$currPos++;
                                                }
                                                else {
                                                    s2 = peg$FAILED;
                                                    if (peg$silentFails === 0) {
                                                        peg$fail(peg$c69);
                                                    }
                                                }
                                                if (s2 === peg$FAILED) {
                                                    if (input.charCodeAt(peg$currPos) === 39) {
                                                        s2 = peg$c50;
                                                        peg$currPos++;
                                                    }
                                                    else {
                                                        s2 = peg$FAILED;
                                                        if (peg$silentFails === 0) {
                                                            peg$fail(peg$c51);
                                                        }
                                                    }
                                                    if (s2 === peg$FAILED) {
                                                        if (input.charCodeAt(peg$currPos) === 126) {
                                                            s2 = peg$c46;
                                                            peg$currPos++;
                                                        }
                                                        else {
                                                            s2 = peg$FAILED;
                                                            if (peg$silentFails === 0) {
                                                                peg$fail(peg$c47);
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        else {
            s1 = peg$FAILED;
        }
        if (s1 !== peg$FAILED) {
            s0 = input.substring(s0, peg$currPos);
        }
        else {
            s0 = s1;
        }
        return s0;
    }
    function peg$parsetoken_nodot() {
        var s0, s1, s2;
        s0 = peg$currPos;
        s1 = [];
        s2 = peg$parsealphanum();
        if (s2 === peg$FAILED) {
            if (input.charCodeAt(peg$currPos) === 45) {
                s2 = peg$c38;
                peg$currPos++;
            }
            else {
                s2 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c39);
                }
            }
            if (s2 === peg$FAILED) {
                if (input.charCodeAt(peg$currPos) === 33) {
                    s2 = peg$c44;
                    peg$currPos++;
                }
                else {
                    s2 = peg$FAILED;
                    if (peg$silentFails === 0) {
                        peg$fail(peg$c45);
                    }
                }
                if (s2 === peg$FAILED) {
                    if (input.charCodeAt(peg$currPos) === 37) {
                        s2 = peg$c56;
                        peg$currPos++;
                    }
                    else {
                        s2 = peg$FAILED;
                        if (peg$silentFails === 0) {
                            peg$fail(peg$c57);
                        }
                    }
                    if (s2 === peg$FAILED) {
                        if (input.charCodeAt(peg$currPos) === 42) {
                            s2 = peg$c48;
                            peg$currPos++;
                        }
                        else {
                            s2 = peg$FAILED;
                            if (peg$silentFails === 0) {
                                peg$fail(peg$c49);
                            }
                        }
                        if (s2 === peg$FAILED) {
                            if (input.charCodeAt(peg$currPos) === 95) {
                                s2 = peg$c40;
                                peg$currPos++;
                            }
                            else {
                                s2 = peg$FAILED;
                                if (peg$silentFails === 0) {
                                    peg$fail(peg$c41);
                                }
                            }
                            if (s2 === peg$FAILED) {
                                if (input.charCodeAt(peg$currPos) === 43) {
                                    s2 = peg$c32;
                                    peg$currPos++;
                                }
                                else {
                                    s2 = peg$FAILED;
                                    if (peg$silentFails === 0) {
                                        peg$fail(peg$c33);
                                    }
                                }
                                if (s2 === peg$FAILED) {
                                    if (input.charCodeAt(peg$currPos) === 96) {
                                        s2 = peg$c68;
                                        peg$currPos++;
                                    }
                                    else {
                                        s2 = peg$FAILED;
                                        if (peg$silentFails === 0) {
                                            peg$fail(peg$c69);
                                        }
                                    }
                                    if (s2 === peg$FAILED) {
                                        if (input.charCodeAt(peg$currPos) === 39) {
                                            s2 = peg$c50;
                                            peg$currPos++;
                                        }
                                        else {
                                            s2 = peg$FAILED;
                                            if (peg$silentFails === 0) {
                                                peg$fail(peg$c51);
                                            }
                                        }
                                        if (s2 === peg$FAILED) {
                                            if (input.charCodeAt(peg$currPos) === 126) {
                                                s2 = peg$c46;
                                                peg$currPos++;
                                            }
                                            else {
                                                s2 = peg$FAILED;
                                                if (peg$silentFails === 0) {
                                                    peg$fail(peg$c47);
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        if (s2 !== peg$FAILED) {
            while (s2 !== peg$FAILED) {
                s1.push(s2);
                s2 = peg$parsealphanum();
                if (s2 === peg$FAILED) {
                    if (input.charCodeAt(peg$currPos) === 45) {
                        s2 = peg$c38;
                        peg$currPos++;
                    }
                    else {
                        s2 = peg$FAILED;
                        if (peg$silentFails === 0) {
                            peg$fail(peg$c39);
                        }
                    }
                    if (s2 === peg$FAILED) {
                        if (input.charCodeAt(peg$currPos) === 33) {
                            s2 = peg$c44;
                            peg$currPos++;
                        }
                        else {
                            s2 = peg$FAILED;
                            if (peg$silentFails === 0) {
                                peg$fail(peg$c45);
                            }
                        }
                        if (s2 === peg$FAILED) {
                            if (input.charCodeAt(peg$currPos) === 37) {
                                s2 = peg$c56;
                                peg$currPos++;
                            }
                            else {
                                s2 = peg$FAILED;
                                if (peg$silentFails === 0) {
                                    peg$fail(peg$c57);
                                }
                            }
                            if (s2 === peg$FAILED) {
                                if (input.charCodeAt(peg$currPos) === 42) {
                                    s2 = peg$c48;
                                    peg$currPos++;
                                }
                                else {
                                    s2 = peg$FAILED;
                                    if (peg$silentFails === 0) {
                                        peg$fail(peg$c49);
                                    }
                                }
                                if (s2 === peg$FAILED) {
                                    if (input.charCodeAt(peg$currPos) === 95) {
                                        s2 = peg$c40;
                                        peg$currPos++;
                                    }
                                    else {
                                        s2 = peg$FAILED;
                                        if (peg$silentFails === 0) {
                                            peg$fail(peg$c41);
                                        }
                                    }
                                    if (s2 === peg$FAILED) {
                                        if (input.charCodeAt(peg$currPos) === 43) {
                                            s2 = peg$c32;
                                            peg$currPos++;
                                        }
                                        else {
                                            s2 = peg$FAILED;
                                            if (peg$silentFails === 0) {
                                                peg$fail(peg$c33);
                                            }
                                        }
                                        if (s2 === peg$FAILED) {
                                            if (input.charCodeAt(peg$currPos) === 96) {
                                                s2 = peg$c68;
                                                peg$currPos++;
                                            }
                                            else {
                                                s2 = peg$FAILED;
                                                if (peg$silentFails === 0) {
                                                    peg$fail(peg$c69);
                                                }
                                            }
                                            if (s2 === peg$FAILED) {
                                                if (input.charCodeAt(peg$currPos) === 39) {
                                                    s2 = peg$c50;
                                                    peg$currPos++;
                                                }
                                                else {
                                                    s2 = peg$FAILED;
                                                    if (peg$silentFails === 0) {
                                                        peg$fail(peg$c51);
                                                    }
                                                }
                                                if (s2 === peg$FAILED) {
                                                    if (input.charCodeAt(peg$currPos) === 126) {
                                                        s2 = peg$c46;
                                                        peg$currPos++;
                                                    }
                                                    else {
                                                        s2 = peg$FAILED;
                                                        if (peg$silentFails === 0) {
                                                            peg$fail(peg$c47);
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        else {
            s1 = peg$FAILED;
        }
        if (s1 !== peg$FAILED) {
            s0 = input.substring(s0, peg$currPos);
        }
        else {
            s0 = s1;
        }
        return s0;
    }
    function peg$parseseparators() {
        var s0;
        if (input.charCodeAt(peg$currPos) === 40) {
            s0 = peg$c52;
            peg$currPos++;
        }
        else {
            s0 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c53);
            }
        }
        if (s0 === peg$FAILED) {
            if (input.charCodeAt(peg$currPos) === 41) {
                s0 = peg$c54;
                peg$currPos++;
            }
            else {
                s0 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c55);
                }
            }
            if (s0 === peg$FAILED) {
                if (input.charCodeAt(peg$currPos) === 60) {
                    s0 = peg$c70;
                    peg$currPos++;
                }
                else {
                    s0 = peg$FAILED;
                    if (peg$silentFails === 0) {
                        peg$fail(peg$c71);
                    }
                }
                if (s0 === peg$FAILED) {
                    if (input.charCodeAt(peg$currPos) === 62) {
                        s0 = peg$c72;
                        peg$currPos++;
                    }
                    else {
                        s0 = peg$FAILED;
                        if (peg$silentFails === 0) {
                            peg$fail(peg$c73);
                        }
                    }
                    if (s0 === peg$FAILED) {
                        if (input.charCodeAt(peg$currPos) === 64) {
                            s0 = peg$c26;
                            peg$currPos++;
                        }
                        else {
                            s0 = peg$FAILED;
                            if (peg$silentFails === 0) {
                                peg$fail(peg$c27);
                            }
                        }
                        if (s0 === peg$FAILED) {
                            if (input.charCodeAt(peg$currPos) === 44) {
                                s0 = peg$c36;
                                peg$currPos++;
                            }
                            else {
                                s0 = peg$FAILED;
                                if (peg$silentFails === 0) {
                                    peg$fail(peg$c37);
                                }
                            }
                            if (s0 === peg$FAILED) {
                                if (input.charCodeAt(peg$currPos) === 59) {
                                    s0 = peg$c18;
                                    peg$currPos++;
                                }
                                else {
                                    s0 = peg$FAILED;
                                    if (peg$silentFails === 0) {
                                        peg$fail(peg$c19);
                                    }
                                }
                                if (s0 === peg$FAILED) {
                                    if (input.charCodeAt(peg$currPos) === 58) {
                                        s0 = peg$c24;
                                        peg$currPos++;
                                    }
                                    else {
                                        s0 = peg$FAILED;
                                        if (peg$silentFails === 0) {
                                            peg$fail(peg$c25);
                                        }
                                    }
                                    if (s0 === peg$FAILED) {
                                        if (input.charCodeAt(peg$currPos) === 92) {
                                            s0 = peg$c74;
                                            peg$currPos++;
                                        }
                                        else {
                                            s0 = peg$FAILED;
                                            if (peg$silentFails === 0) {
                                                peg$fail(peg$c75);
                                            }
                                        }
                                        if (s0 === peg$FAILED) {
                                            s0 = peg$parseDQUOTE();
                                            if (s0 === peg$FAILED) {
                                                if (input.charCodeAt(peg$currPos) === 47) {
                                                    s0 = peg$c20;
                                                    peg$currPos++;
                                                }
                                                else {
                                                    s0 = peg$FAILED;
                                                    if (peg$silentFails === 0) {
                                                        peg$fail(peg$c21);
                                                    }
                                                }
                                                if (s0 === peg$FAILED) {
                                                    if (input.charCodeAt(peg$currPos) === 91) {
                                                        s0 = peg$c76;
                                                        peg$currPos++;
                                                    }
                                                    else {
                                                        s0 = peg$FAILED;
                                                        if (peg$silentFails === 0) {
                                                            peg$fail(peg$c77);
                                                        }
                                                    }
                                                    if (s0 === peg$FAILED) {
                                                        if (input.charCodeAt(peg$currPos) === 93) {
                                                            s0 = peg$c78;
                                                            peg$currPos++;
                                                        }
                                                        else {
                                                            s0 = peg$FAILED;
                                                            if (peg$silentFails === 0) {
                                                                peg$fail(peg$c79);
                                                            }
                                                        }
                                                        if (s0 === peg$FAILED) {
                                                            if (input.charCodeAt(peg$currPos) === 63) {
                                                                s0 = peg$c22;
                                                                peg$currPos++;
                                                            }
                                                            else {
                                                                s0 = peg$FAILED;
                                                                if (peg$silentFails === 0) {
                                                                    peg$fail(peg$c23);
                                                                }
                                                            }
                                                            if (s0 === peg$FAILED) {
                                                                if (input.charCodeAt(peg$currPos) === 61) {
                                                                    s0 = peg$c30;
                                                                    peg$currPos++;
                                                                }
                                                                else {
                                                                    s0 = peg$FAILED;
                                                                    if (peg$silentFails === 0) {
                                                                        peg$fail(peg$c31);
                                                                    }
                                                                }
                                                                if (s0 === peg$FAILED) {
                                                                    if (input.charCodeAt(peg$currPos) === 123) {
                                                                        s0 = peg$c80;
                                                                        peg$currPos++;
                                                                    }
                                                                    else {
                                                                        s0 = peg$FAILED;
                                                                        if (peg$silentFails === 0) {
                                                                            peg$fail(peg$c81);
                                                                        }
                                                                    }
                                                                    if (s0 === peg$FAILED) {
                                                                        if (input.charCodeAt(peg$currPos) === 125) {
                                                                            s0 = peg$c82;
                                                                            peg$currPos++;
                                                                        }
                                                                        else {
                                                                            s0 = peg$FAILED;
                                                                            if (peg$silentFails === 0) {
                                                                                peg$fail(peg$c83);
                                                                            }
                                                                        }
                                                                        if (s0 === peg$FAILED) {
                                                                            s0 = peg$parseSP();
                                                                            if (s0 === peg$FAILED) {
                                                                                s0 = peg$parseHTAB();
                                                                            }
                                                                        }
                                                                    }
                                                                }
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        return s0;
    }
    function peg$parseword() {
        var s0, s1, s2;
        s0 = peg$currPos;
        s1 = [];
        s2 = peg$parsealphanum();
        if (s2 === peg$FAILED) {
            if (input.charCodeAt(peg$currPos) === 45) {
                s2 = peg$c38;
                peg$currPos++;
            }
            else {
                s2 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c39);
                }
            }
            if (s2 === peg$FAILED) {
                if (input.charCodeAt(peg$currPos) === 46) {
                    s2 = peg$c42;
                    peg$currPos++;
                }
                else {
                    s2 = peg$FAILED;
                    if (peg$silentFails === 0) {
                        peg$fail(peg$c43);
                    }
                }
                if (s2 === peg$FAILED) {
                    if (input.charCodeAt(peg$currPos) === 33) {
                        s2 = peg$c44;
                        peg$currPos++;
                    }
                    else {
                        s2 = peg$FAILED;
                        if (peg$silentFails === 0) {
                            peg$fail(peg$c45);
                        }
                    }
                    if (s2 === peg$FAILED) {
                        if (input.charCodeAt(peg$currPos) === 37) {
                            s2 = peg$c56;
                            peg$currPos++;
                        }
                        else {
                            s2 = peg$FAILED;
                            if (peg$silentFails === 0) {
                                peg$fail(peg$c57);
                            }
                        }
                        if (s2 === peg$FAILED) {
                            if (input.charCodeAt(peg$currPos) === 42) {
                                s2 = peg$c48;
                                peg$currPos++;
                            }
                            else {
                                s2 = peg$FAILED;
                                if (peg$silentFails === 0) {
                                    peg$fail(peg$c49);
                                }
                            }
                            if (s2 === peg$FAILED) {
                                if (input.charCodeAt(peg$currPos) === 95) {
                                    s2 = peg$c40;
                                    peg$currPos++;
                                }
                                else {
                                    s2 = peg$FAILED;
                                    if (peg$silentFails === 0) {
                                        peg$fail(peg$c41);
                                    }
                                }
                                if (s2 === peg$FAILED) {
                                    if (input.charCodeAt(peg$currPos) === 43) {
                                        s2 = peg$c32;
                                        peg$currPos++;
                                    }
                                    else {
                                        s2 = peg$FAILED;
                                        if (peg$silentFails === 0) {
                                            peg$fail(peg$c33);
                                        }
                                    }
                                    if (s2 === peg$FAILED) {
                                        if (input.charCodeAt(peg$currPos) === 96) {
                                            s2 = peg$c68;
                                            peg$currPos++;
                                        }
                                        else {
                                            s2 = peg$FAILED;
                                            if (peg$silentFails === 0) {
                                                peg$fail(peg$c69);
                                            }
                                        }
                                        if (s2 === peg$FAILED) {
                                            if (input.charCodeAt(peg$currPos) === 39) {
                                                s2 = peg$c50;
                                                peg$currPos++;
                                            }
                                            else {
                                                s2 = peg$FAILED;
                                                if (peg$silentFails === 0) {
                                                    peg$fail(peg$c51);
                                                }
                                            }
                                            if (s2 === peg$FAILED) {
                                                if (input.charCodeAt(peg$currPos) === 126) {
                                                    s2 = peg$c46;
                                                    peg$currPos++;
                                                }
                                                else {
                                                    s2 = peg$FAILED;
                                                    if (peg$silentFails === 0) {
                                                        peg$fail(peg$c47);
                                                    }
                                                }
                                                if (s2 === peg$FAILED) {
                                                    if (input.charCodeAt(peg$currPos) === 40) {
                                                        s2 = peg$c52;
                                                        peg$currPos++;
                                                    }
                                                    else {
                                                        s2 = peg$FAILED;
                                                        if (peg$silentFails === 0) {
                                                            peg$fail(peg$c53);
                                                        }
                                                    }
                                                    if (s2 === peg$FAILED) {
                                                        if (input.charCodeAt(peg$currPos) === 41) {
                                                            s2 = peg$c54;
                                                            peg$currPos++;
                                                        }
                                                        else {
                                                            s2 = peg$FAILED;
                                                            if (peg$silentFails === 0) {
                                                                peg$fail(peg$c55);
                                                            }
                                                        }
                                                        if (s2 === peg$FAILED) {
                                                            if (input.charCodeAt(peg$currPos) === 60) {
                                                                s2 = peg$c70;
                                                                peg$currPos++;
                                                            }
                                                            else {
                                                                s2 = peg$FAILED;
                                                                if (peg$silentFails === 0) {
                                                                    peg$fail(peg$c71);
                                                                }
                                                            }
                                                            if (s2 === peg$FAILED) {
                                                                if (input.charCodeAt(peg$currPos) === 62) {
                                                                    s2 = peg$c72;
                                                                    peg$currPos++;
                                                                }
                                                                else {
                                                                    s2 = peg$FAILED;
                                                                    if (peg$silentFails === 0) {
                                                                        peg$fail(peg$c73);
                                                                    }
                                                                }
                                                                if (s2 === peg$FAILED) {
                                                                    if (input.charCodeAt(peg$currPos) === 58) {
                                                                        s2 = peg$c24;
                                                                        peg$currPos++;
                                                                    }
                                                                    else {
                                                                        s2 = peg$FAILED;
                                                                        if (peg$silentFails === 0) {
                                                                            peg$fail(peg$c25);
                                                                        }
                                                                    }
                                                                    if (s2 === peg$FAILED) {
                                                                        if (input.charCodeAt(peg$currPos) === 92) {
                                                                            s2 = peg$c74;
                                                                            peg$currPos++;
                                                                        }
                                                                        else {
                                                                            s2 = peg$FAILED;
                                                                            if (peg$silentFails === 0) {
                                                                                peg$fail(peg$c75);
                                                                            }
                                                                        }
                                                                        if (s2 === peg$FAILED) {
                                                                            s2 = peg$parseDQUOTE();
                                                                            if (s2 === peg$FAILED) {
                                                                                if (input.charCodeAt(peg$currPos) === 47) {
                                                                                    s2 = peg$c20;
                                                                                    peg$currPos++;
                                                                                }
                                                                                else {
                                                                                    s2 = peg$FAILED;
                                                                                    if (peg$silentFails === 0) {
                                                                                        peg$fail(peg$c21);
                                                                                    }
                                                                                }
                                                                                if (s2 === peg$FAILED) {
                                                                                    if (input.charCodeAt(peg$currPos) === 91) {
                                                                                        s2 = peg$c76;
                                                                                        peg$currPos++;
                                                                                    }
                                                                                    else {
                                                                                        s2 = peg$FAILED;
                                                                                        if (peg$silentFails === 0) {
                                                                                            peg$fail(peg$c77);
                                                                                        }
                                                                                    }
                                                                                    if (s2 === peg$FAILED) {
                                                                                        if (input.charCodeAt(peg$currPos) === 93) {
                                                                                            s2 = peg$c78;
                                                                                            peg$currPos++;
                                                                                        }
                                                                                        else {
                                                                                            s2 = peg$FAILED;
                                                                                            if (peg$silentFails === 0) {
                                                                                                peg$fail(peg$c79);
                                                                                            }
                                                                                        }
                                                                                        if (s2 === peg$FAILED) {
                                                                                            if (input.charCodeAt(peg$currPos) === 63) {
                                                                                                s2 = peg$c22;
                                                                                                peg$currPos++;
                                                                                            }
                                                                                            else {
                                                                                                s2 = peg$FAILED;
                                                                                                if (peg$silentFails === 0) {
                                                                                                    peg$fail(peg$c23);
                                                                                                }
                                                                                            }
                                                                                            if (s2 === peg$FAILED) {
                                                                                                if (input.charCodeAt(peg$currPos) === 123) {
                                                                                                    s2 = peg$c80;
                                                                                                    peg$currPos++;
                                                                                                }
                                                                                                else {
                                                                                                    s2 = peg$FAILED;
                                                                                                    if (peg$silentFails === 0) {
                                                                                                        peg$fail(peg$c81);
                                                                                                    }
                                                                                                }
                                                                                                if (s2 === peg$FAILED) {
                                                                                                    if (input.charCodeAt(peg$currPos) === 125) {
                                                                                                        s2 = peg$c82;
                                                                                                        peg$currPos++;
                                                                                                    }
                                                                                                    else {
                                                                                                        s2 = peg$FAILED;
                                                                                                        if (peg$silentFails === 0) {
                                                                                                            peg$fail(peg$c83);
                                                                                                        }
                                                                                                    }
                                                                                                }
                                                                                            }
                                                                                        }
                                                                                    }
                                                                                }
                                                                            }
                                                                        }
                                                                    }
                                                                }
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        if (s2 !== peg$FAILED) {
            while (s2 !== peg$FAILED) {
                s1.push(s2);
                s2 = peg$parsealphanum();
                if (s2 === peg$FAILED) {
                    if (input.charCodeAt(peg$currPos) === 45) {
                        s2 = peg$c38;
                        peg$currPos++;
                    }
                    else {
                        s2 = peg$FAILED;
                        if (peg$silentFails === 0) {
                            peg$fail(peg$c39);
                        }
                    }
                    if (s2 === peg$FAILED) {
                        if (input.charCodeAt(peg$currPos) === 46) {
                            s2 = peg$c42;
                            peg$currPos++;
                        }
                        else {
                            s2 = peg$FAILED;
                            if (peg$silentFails === 0) {
                                peg$fail(peg$c43);
                            }
                        }
                        if (s2 === peg$FAILED) {
                            if (input.charCodeAt(peg$currPos) === 33) {
                                s2 = peg$c44;
                                peg$currPos++;
                            }
                            else {
                                s2 = peg$FAILED;
                                if (peg$silentFails === 0) {
                                    peg$fail(peg$c45);
                                }
                            }
                            if (s2 === peg$FAILED) {
                                if (input.charCodeAt(peg$currPos) === 37) {
                                    s2 = peg$c56;
                                    peg$currPos++;
                                }
                                else {
                                    s2 = peg$FAILED;
                                    if (peg$silentFails === 0) {
                                        peg$fail(peg$c57);
                                    }
                                }
                                if (s2 === peg$FAILED) {
                                    if (input.charCodeAt(peg$currPos) === 42) {
                                        s2 = peg$c48;
                                        peg$currPos++;
                                    }
                                    else {
                                        s2 = peg$FAILED;
                                        if (peg$silentFails === 0) {
                                            peg$fail(peg$c49);
                                        }
                                    }
                                    if (s2 === peg$FAILED) {
                                        if (input.charCodeAt(peg$currPos) === 95) {
                                            s2 = peg$c40;
                                            peg$currPos++;
                                        }
                                        else {
                                            s2 = peg$FAILED;
                                            if (peg$silentFails === 0) {
                                                peg$fail(peg$c41);
                                            }
                                        }
                                        if (s2 === peg$FAILED) {
                                            if (input.charCodeAt(peg$currPos) === 43) {
                                                s2 = peg$c32;
                                                peg$currPos++;
                                            }
                                            else {
                                                s2 = peg$FAILED;
                                                if (peg$silentFails === 0) {
                                                    peg$fail(peg$c33);
                                                }
                                            }
                                            if (s2 === peg$FAILED) {
                                                if (input.charCodeAt(peg$currPos) === 96) {
                                                    s2 = peg$c68;
                                                    peg$currPos++;
                                                }
                                                else {
                                                    s2 = peg$FAILED;
                                                    if (peg$silentFails === 0) {
                                                        peg$fail(peg$c69);
                                                    }
                                                }
                                                if (s2 === peg$FAILED) {
                                                    if (input.charCodeAt(peg$currPos) === 39) {
                                                        s2 = peg$c50;
                                                        peg$currPos++;
                                                    }
                                                    else {
                                                        s2 = peg$FAILED;
                                                        if (peg$silentFails === 0) {
                                                            peg$fail(peg$c51);
                                                        }
                                                    }
                                                    if (s2 === peg$FAILED) {
                                                        if (input.charCodeAt(peg$currPos) === 126) {
                                                            s2 = peg$c46;
                                                            peg$currPos++;
                                                        }
                                                        else {
                                                            s2 = peg$FAILED;
                                                            if (peg$silentFails === 0) {
                                                                peg$fail(peg$c47);
                                                            }
                                                        }
                                                        if (s2 === peg$FAILED) {
                                                            if (input.charCodeAt(peg$currPos) === 40) {
                                                                s2 = peg$c52;
                                                                peg$currPos++;
                                                            }
                                                            else {
                                                                s2 = peg$FAILED;
                                                                if (peg$silentFails === 0) {
                                                                    peg$fail(peg$c53);
                                                                }
                                                            }
                                                            if (s2 === peg$FAILED) {
                                                                if (input.charCodeAt(peg$currPos) === 41) {
                                                                    s2 = peg$c54;
                                                                    peg$currPos++;
                                                                }
                                                                else {
                                                                    s2 = peg$FAILED;
                                                                    if (peg$silentFails === 0) {
                                                                        peg$fail(peg$c55);
                                                                    }
                                                                }
                                                                if (s2 === peg$FAILED) {
                                                                    if (input.charCodeAt(peg$currPos) === 60) {
                                                                        s2 = peg$c70;
                                                                        peg$currPos++;
                                                                    }
                                                                    else {
                                                                        s2 = peg$FAILED;
                                                                        if (peg$silentFails === 0) {
                                                                            peg$fail(peg$c71);
                                                                        }
                                                                    }
                                                                    if (s2 === peg$FAILED) {
                                                                        if (input.charCodeAt(peg$currPos) === 62) {
                                                                            s2 = peg$c72;
                                                                            peg$currPos++;
                                                                        }
                                                                        else {
                                                                            s2 = peg$FAILED;
                                                                            if (peg$silentFails === 0) {
                                                                                peg$fail(peg$c73);
                                                                            }
                                                                        }
                                                                        if (s2 === peg$FAILED) {
                                                                            if (input.charCodeAt(peg$currPos) === 58) {
                                                                                s2 = peg$c24;
                                                                                peg$currPos++;
                                                                            }
                                                                            else {
                                                                                s2 = peg$FAILED;
                                                                                if (peg$silentFails === 0) {
                                                                                    peg$fail(peg$c25);
                                                                                }
                                                                            }
                                                                            if (s2 === peg$FAILED) {
                                                                                if (input.charCodeAt(peg$currPos) === 92) {
                                                                                    s2 = peg$c74;
                                                                                    peg$currPos++;
                                                                                }
                                                                                else {
                                                                                    s2 = peg$FAILED;
                                                                                    if (peg$silentFails === 0) {
                                                                                        peg$fail(peg$c75);
                                                                                    }
                                                                                }
                                                                                if (s2 === peg$FAILED) {
                                                                                    s2 = peg$parseDQUOTE();
                                                                                    if (s2 === peg$FAILED) {
                                                                                        if (input.charCodeAt(peg$currPos) === 47) {
                                                                                            s2 = peg$c20;
                                                                                            peg$currPos++;
                                                                                        }
                                                                                        else {
                                                                                            s2 = peg$FAILED;
                                                                                            if (peg$silentFails === 0) {
                                                                                                peg$fail(peg$c21);
                                                                                            }
                                                                                        }
                                                                                        if (s2 === peg$FAILED) {
                                                                                            if (input.charCodeAt(peg$currPos) === 91) {
                                                                                                s2 = peg$c76;
                                                                                                peg$currPos++;
                                                                                            }
                                                                                            else {
                                                                                                s2 = peg$FAILED;
                                                                                                if (peg$silentFails === 0) {
                                                                                                    peg$fail(peg$c77);
                                                                                                }
                                                                                            }
                                                                                            if (s2 === peg$FAILED) {
                                                                                                if (input.charCodeAt(peg$currPos) === 93) {
                                                                                                    s2 = peg$c78;
                                                                                                    peg$currPos++;
                                                                                                }
                                                                                                else {
                                                                                                    s2 = peg$FAILED;
                                                                                                    if (peg$silentFails === 0) {
                                                                                                        peg$fail(peg$c79);
                                                                                                    }
                                                                                                }
                                                                                                if (s2 === peg$FAILED) {
                                                                                                    if (input.charCodeAt(peg$currPos) === 63) {
                                                                                                        s2 = peg$c22;
                                                                                                        peg$currPos++;
                                                                                                    }
                                                                                                    else {
                                                                                                        s2 = peg$FAILED;
                                                                                                        if (peg$silentFails === 0) {
                                                                                                            peg$fail(peg$c23);
                                                                                                        }
                                                                                                    }
                                                                                                    if (s2 === peg$FAILED) {
                                                                                                        if (input.charCodeAt(peg$currPos) === 123) {
                                                                                                            s2 = peg$c80;
                                                                                                            peg$currPos++;
                                                                                                        }
                                                                                                        else {
                                                                                                            s2 = peg$FAILED;
                                                                                                            if (peg$silentFails === 0) {
                                                                                                                peg$fail(peg$c81);
                                                                                                            }
                                                                                                        }
                                                                                                        if (s2 === peg$FAILED) {
                                                                                                            if (input.charCodeAt(peg$currPos) === 125) {
                                                                                                                s2 = peg$c82;
                                                                                                                peg$currPos++;
                                                                                                            }
                                                                                                            else {
                                                                                                                s2 = peg$FAILED;
                                                                                                                if (peg$silentFails === 0) {
                                                                                                                    peg$fail(peg$c83);
                                                                                                                }
                                                                                                            }
                                                                                                        }
                                                                                                    }
                                                                                                }
                                                                                            }
                                                                                        }
                                                                                    }
                                                                                }
                                                                            }
                                                                        }
                                                                    }
                                                                }
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        else {
            s1 = peg$FAILED;
        }
        if (s1 !== peg$FAILED) {
            s0 = input.substring(s0, peg$currPos);
        }
        else {
            s0 = s1;
        }
        return s0;
    }
    function peg$parseSTAR() {
        var s0, s1, s2, s3;
        s0 = peg$currPos;
        s1 = peg$parseSWS();
        if (s1 !== peg$FAILED) {
            if (input.charCodeAt(peg$currPos) === 42) {
                s2 = peg$c48;
                peg$currPos++;
            }
            else {
                s2 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c49);
                }
            }
            if (s2 !== peg$FAILED) {
                s3 = peg$parseSWS();
                if (s3 !== peg$FAILED) {
                    peg$savedPos = s0;
                    s1 = peg$c84();
                    s0 = s1;
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parseSLASH() {
        var s0, s1, s2, s3;
        s0 = peg$currPos;
        s1 = peg$parseSWS();
        if (s1 !== peg$FAILED) {
            if (input.charCodeAt(peg$currPos) === 47) {
                s2 = peg$c20;
                peg$currPos++;
            }
            else {
                s2 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c21);
                }
            }
            if (s2 !== peg$FAILED) {
                s3 = peg$parseSWS();
                if (s3 !== peg$FAILED) {
                    peg$savedPos = s0;
                    s1 = peg$c85();
                    s0 = s1;
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parseEQUAL() {
        var s0, s1, s2, s3;
        s0 = peg$currPos;
        s1 = peg$parseSWS();
        if (s1 !== peg$FAILED) {
            if (input.charCodeAt(peg$currPos) === 61) {
                s2 = peg$c30;
                peg$currPos++;
            }
            else {
                s2 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c31);
                }
            }
            if (s2 !== peg$FAILED) {
                s3 = peg$parseSWS();
                if (s3 !== peg$FAILED) {
                    peg$savedPos = s0;
                    s1 = peg$c86();
                    s0 = s1;
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parseLPAREN() {
        var s0, s1, s2, s3;
        s0 = peg$currPos;
        s1 = peg$parseSWS();
        if (s1 !== peg$FAILED) {
            if (input.charCodeAt(peg$currPos) === 40) {
                s2 = peg$c52;
                peg$currPos++;
            }
            else {
                s2 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c53);
                }
            }
            if (s2 !== peg$FAILED) {
                s3 = peg$parseSWS();
                if (s3 !== peg$FAILED) {
                    peg$savedPos = s0;
                    s1 = peg$c87();
                    s0 = s1;
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parseRPAREN() {
        var s0, s1, s2, s3;
        s0 = peg$currPos;
        s1 = peg$parseSWS();
        if (s1 !== peg$FAILED) {
            if (input.charCodeAt(peg$currPos) === 41) {
                s2 = peg$c54;
                peg$currPos++;
            }
            else {
                s2 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c55);
                }
            }
            if (s2 !== peg$FAILED) {
                s3 = peg$parseSWS();
                if (s3 !== peg$FAILED) {
                    peg$savedPos = s0;
                    s1 = peg$c88();
                    s0 = s1;
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parseRAQUOT() {
        var s0, s1, s2;
        s0 = peg$currPos;
        if (input.charCodeAt(peg$currPos) === 62) {
            s1 = peg$c72;
            peg$currPos++;
        }
        else {
            s1 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c73);
            }
        }
        if (s1 !== peg$FAILED) {
            s2 = peg$parseSWS();
            if (s2 !== peg$FAILED) {
                peg$savedPos = s0;
                s1 = peg$c89();
                s0 = s1;
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parseLAQUOT() {
        var s0, s1, s2;
        s0 = peg$currPos;
        s1 = peg$parseSWS();
        if (s1 !== peg$FAILED) {
            if (input.charCodeAt(peg$currPos) === 60) {
                s2 = peg$c70;
                peg$currPos++;
            }
            else {
                s2 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c71);
                }
            }
            if (s2 !== peg$FAILED) {
                peg$savedPos = s0;
                s1 = peg$c90();
                s0 = s1;
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parseCOMMA() {
        var s0, s1, s2, s3;
        s0 = peg$currPos;
        s1 = peg$parseSWS();
        if (s1 !== peg$FAILED) {
            if (input.charCodeAt(peg$currPos) === 44) {
                s2 = peg$c36;
                peg$currPos++;
            }
            else {
                s2 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c37);
                }
            }
            if (s2 !== peg$FAILED) {
                s3 = peg$parseSWS();
                if (s3 !== peg$FAILED) {
                    peg$savedPos = s0;
                    s1 = peg$c91();
                    s0 = s1;
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parseSEMI() {
        var s0, s1, s2, s3;
        s0 = peg$currPos;
        s1 = peg$parseSWS();
        if (s1 !== peg$FAILED) {
            if (input.charCodeAt(peg$currPos) === 59) {
                s2 = peg$c18;
                peg$currPos++;
            }
            else {
                s2 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c19);
                }
            }
            if (s2 !== peg$FAILED) {
                s3 = peg$parseSWS();
                if (s3 !== peg$FAILED) {
                    peg$savedPos = s0;
                    s1 = peg$c92();
                    s0 = s1;
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parseCOLON() {
        var s0, s1, s2, s3;
        s0 = peg$currPos;
        s1 = peg$parseSWS();
        if (s1 !== peg$FAILED) {
            if (input.charCodeAt(peg$currPos) === 58) {
                s2 = peg$c24;
                peg$currPos++;
            }
            else {
                s2 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c25);
                }
            }
            if (s2 !== peg$FAILED) {
                s3 = peg$parseSWS();
                if (s3 !== peg$FAILED) {
                    peg$savedPos = s0;
                    s1 = peg$c93();
                    s0 = s1;
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parseLDQUOT() {
        var s0, s1, s2;
        s0 = peg$currPos;
        s1 = peg$parseSWS();
        if (s1 !== peg$FAILED) {
            s2 = peg$parseDQUOTE();
            if (s2 !== peg$FAILED) {
                peg$savedPos = s0;
                s1 = peg$c94();
                s0 = s1;
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parseRDQUOT() {
        var s0, s1, s2;
        s0 = peg$currPos;
        s1 = peg$parseDQUOTE();
        if (s1 !== peg$FAILED) {
            s2 = peg$parseSWS();
            if (s2 !== peg$FAILED) {
                peg$savedPos = s0;
                s1 = peg$c94();
                s0 = s1;
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parsecomment() {
        var s0, s1, s2, s3;
        s0 = peg$currPos;
        s1 = peg$parseLPAREN();
        if (s1 !== peg$FAILED) {
            s2 = [];
            s3 = peg$parsectext();
            if (s3 === peg$FAILED) {
                s3 = peg$parsequoted_pair();
                if (s3 === peg$FAILED) {
                    s3 = peg$parsecomment();
                }
            }
            while (s3 !== peg$FAILED) {
                s2.push(s3);
                s3 = peg$parsectext();
                if (s3 === peg$FAILED) {
                    s3 = peg$parsequoted_pair();
                    if (s3 === peg$FAILED) {
                        s3 = peg$parsecomment();
                    }
                }
            }
            if (s2 !== peg$FAILED) {
                s3 = peg$parseRPAREN();
                if (s3 !== peg$FAILED) {
                    s1 = [s1, s2, s3];
                    s0 = s1;
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parsectext() {
        var s0;
        if (peg$c95.test(input.charAt(peg$currPos))) {
            s0 = input.charAt(peg$currPos);
            peg$currPos++;
        }
        else {
            s0 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c96);
            }
        }
        if (s0 === peg$FAILED) {
            if (peg$c97.test(input.charAt(peg$currPos))) {
                s0 = input.charAt(peg$currPos);
                peg$currPos++;
            }
            else {
                s0 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c98);
                }
            }
            if (s0 === peg$FAILED) {
                if (peg$c99.test(input.charAt(peg$currPos))) {
                    s0 = input.charAt(peg$currPos);
                    peg$currPos++;
                }
                else {
                    s0 = peg$FAILED;
                    if (peg$silentFails === 0) {
                        peg$fail(peg$c100);
                    }
                }
                if (s0 === peg$FAILED) {
                    s0 = peg$parseUTF8_NONASCII();
                    if (s0 === peg$FAILED) {
                        s0 = peg$parseLWS();
                    }
                }
            }
        }
        return s0;
    }
    function peg$parsequoted_string() {
        var s0, s1, s2, s3, s4, s5;
        s0 = peg$currPos;
        s1 = peg$currPos;
        s2 = peg$parseSWS();
        if (s2 !== peg$FAILED) {
            s3 = peg$parseDQUOTE();
            if (s3 !== peg$FAILED) {
                s4 = [];
                s5 = peg$parseqdtext();
                if (s5 === peg$FAILED) {
                    s5 = peg$parsequoted_pair();
                }
                while (s5 !== peg$FAILED) {
                    s4.push(s5);
                    s5 = peg$parseqdtext();
                    if (s5 === peg$FAILED) {
                        s5 = peg$parsequoted_pair();
                    }
                }
                if (s4 !== peg$FAILED) {
                    s5 = peg$parseDQUOTE();
                    if (s5 !== peg$FAILED) {
                        s2 = [s2, s3, s4, s5];
                        s1 = s2;
                    }
                    else {
                        peg$currPos = s1;
                        s1 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s1;
                    s1 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s1;
                s1 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s1;
            s1 = peg$FAILED;
        }
        if (s1 !== peg$FAILED) {
            s0 = input.substring(s0, peg$currPos);
        }
        else {
            s0 = s1;
        }
        return s0;
    }
    function peg$parsequoted_string_clean() {
        var s0, s1, s2, s3, s4, s5;
        s0 = peg$currPos;
        s1 = peg$parseSWS();
        if (s1 !== peg$FAILED) {
            s2 = peg$parseDQUOTE();
            if (s2 !== peg$FAILED) {
                s3 = peg$currPos;
                s4 = [];
                s5 = peg$parseqdtext();
                if (s5 === peg$FAILED) {
                    s5 = peg$parsequoted_pair();
                }
                while (s5 !== peg$FAILED) {
                    s4.push(s5);
                    s5 = peg$parseqdtext();
                    if (s5 === peg$FAILED) {
                        s5 = peg$parsequoted_pair();
                    }
                }
                if (s4 !== peg$FAILED) {
                    s3 = input.substring(s3, peg$currPos);
                }
                else {
                    s3 = s4;
                }
                if (s3 !== peg$FAILED) {
                    s4 = peg$parseDQUOTE();
                    if (s4 !== peg$FAILED) {
                        peg$savedPos = s0;
                        s1 = peg$c101(s3);
                        s0 = s1;
                    }
                    else {
                        peg$currPos = s0;
                        s0 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parseqdtext() {
        var s0;
        s0 = peg$parseLWS();
        if (s0 === peg$FAILED) {
            if (input.charCodeAt(peg$currPos) === 33) {
                s0 = peg$c44;
                peg$currPos++;
            }
            else {
                s0 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c45);
                }
            }
            if (s0 === peg$FAILED) {
                if (peg$c102.test(input.charAt(peg$currPos))) {
                    s0 = input.charAt(peg$currPos);
                    peg$currPos++;
                }
                else {
                    s0 = peg$FAILED;
                    if (peg$silentFails === 0) {
                        peg$fail(peg$c103);
                    }
                }
                if (s0 === peg$FAILED) {
                    if (peg$c99.test(input.charAt(peg$currPos))) {
                        s0 = input.charAt(peg$currPos);
                        peg$currPos++;
                    }
                    else {
                        s0 = peg$FAILED;
                        if (peg$silentFails === 0) {
                            peg$fail(peg$c100);
                        }
                    }
                    if (s0 === peg$FAILED) {
                        s0 = peg$parseUTF8_NONASCII();
                    }
                }
            }
        }
        return s0;
    }
    function peg$parsequoted_pair() {
        var s0, s1, s2;
        s0 = peg$currPos;
        if (input.charCodeAt(peg$currPos) === 92) {
            s1 = peg$c74;
            peg$currPos++;
        }
        else {
            s1 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c75);
            }
        }
        if (s1 !== peg$FAILED) {
            if (peg$c104.test(input.charAt(peg$currPos))) {
                s2 = input.charAt(peg$currPos);
                peg$currPos++;
            }
            else {
                s2 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c105);
                }
            }
            if (s2 === peg$FAILED) {
                if (peg$c106.test(input.charAt(peg$currPos))) {
                    s2 = input.charAt(peg$currPos);
                    peg$currPos++;
                }
                else {
                    s2 = peg$FAILED;
                    if (peg$silentFails === 0) {
                        peg$fail(peg$c107);
                    }
                }
                if (s2 === peg$FAILED) {
                    if (peg$c108.test(input.charAt(peg$currPos))) {
                        s2 = input.charAt(peg$currPos);
                        peg$currPos++;
                    }
                    else {
                        s2 = peg$FAILED;
                        if (peg$silentFails === 0) {
                            peg$fail(peg$c109);
                        }
                    }
                }
            }
            if (s2 !== peg$FAILED) {
                s1 = [s1, s2];
                s0 = s1;
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parseSIP_URI_noparams() {
        var s0, s1, s2, s3, s4;
        s0 = peg$currPos;
        s1 = peg$parseuri_scheme();
        if (s1 !== peg$FAILED) {
            if (input.charCodeAt(peg$currPos) === 58) {
                s2 = peg$c24;
                peg$currPos++;
            }
            else {
                s2 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c25);
                }
            }
            if (s2 !== peg$FAILED) {
                s3 = peg$parseuserinfo();
                if (s3 === peg$FAILED) {
                    s3 = null;
                }
                if (s3 !== peg$FAILED) {
                    s4 = peg$parsehostport();
                    if (s4 !== peg$FAILED) {
                        peg$savedPos = s0;
                        s1 = peg$c110();
                        s0 = s1;
                    }
                    else {
                        peg$currPos = s0;
                        s0 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parseSIP_URI() {
        var s0, s1, s2, s3, s4, s5, s6;
        s0 = peg$currPos;
        s1 = peg$parseuri_scheme();
        if (s1 !== peg$FAILED) {
            if (input.charCodeAt(peg$currPos) === 58) {
                s2 = peg$c24;
                peg$currPos++;
            }
            else {
                s2 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c25);
                }
            }
            if (s2 !== peg$FAILED) {
                s3 = peg$parseuserinfo();
                if (s3 === peg$FAILED) {
                    s3 = null;
                }
                if (s3 !== peg$FAILED) {
                    s4 = peg$parsehostport();
                    if (s4 !== peg$FAILED) {
                        s5 = peg$parseuri_parameters();
                        if (s5 !== peg$FAILED) {
                            s6 = peg$parseheaders();
                            if (s6 === peg$FAILED) {
                                s6 = null;
                            }
                            if (s6 !== peg$FAILED) {
                                peg$savedPos = s0;
                                s1 = peg$c111();
                                s0 = s1;
                            }
                            else {
                                peg$currPos = s0;
                                s0 = peg$FAILED;
                            }
                        }
                        else {
                            peg$currPos = s0;
                            s0 = peg$FAILED;
                        }
                    }
                    else {
                        peg$currPos = s0;
                        s0 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parseuri_scheme() {
        var s0, s1;
        s0 = peg$currPos;
        if (input.substr(peg$currPos, 4).toLowerCase() === peg$c112) {
            s1 = input.substr(peg$currPos, 4);
            peg$currPos += 4;
        }
        else {
            s1 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c113);
            }
        }
        if (s1 === peg$FAILED) {
            if (input.substr(peg$currPos, 3).toLowerCase() === peg$c114) {
                s1 = input.substr(peg$currPos, 3);
                peg$currPos += 3;
            }
            else {
                s1 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c115);
                }
            }
        }
        if (s1 !== peg$FAILED) {
            peg$savedPos = s0;
            s1 = peg$c116(s1);
        }
        s0 = s1;
        return s0;
    }
    function peg$parseuserinfo() {
        var s0, s1, s2, s3, s4;
        s0 = peg$currPos;
        s1 = peg$parseuser();
        if (s1 !== peg$FAILED) {
            s2 = peg$currPos;
            if (input.charCodeAt(peg$currPos) === 58) {
                s3 = peg$c24;
                peg$currPos++;
            }
            else {
                s3 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c25);
                }
            }
            if (s3 !== peg$FAILED) {
                s4 = peg$parsepassword();
                if (s4 !== peg$FAILED) {
                    s3 = [s3, s4];
                    s2 = s3;
                }
                else {
                    peg$currPos = s2;
                    s2 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s2;
                s2 = peg$FAILED;
            }
            if (s2 === peg$FAILED) {
                s2 = null;
            }
            if (s2 !== peg$FAILED) {
                if (input.charCodeAt(peg$currPos) === 64) {
                    s3 = peg$c26;
                    peg$currPos++;
                }
                else {
                    s3 = peg$FAILED;
                    if (peg$silentFails === 0) {
                        peg$fail(peg$c27);
                    }
                }
                if (s3 !== peg$FAILED) {
                    peg$savedPos = s0;
                    s1 = peg$c117();
                    s0 = s1;
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parseuser() {
        var s0, s1;
        s0 = [];
        s1 = peg$parseunreserved();
        if (s1 === peg$FAILED) {
            s1 = peg$parseescaped();
            if (s1 === peg$FAILED) {
                s1 = peg$parseuser_unreserved();
            }
        }
        if (s1 !== peg$FAILED) {
            while (s1 !== peg$FAILED) {
                s0.push(s1);
                s1 = peg$parseunreserved();
                if (s1 === peg$FAILED) {
                    s1 = peg$parseescaped();
                    if (s1 === peg$FAILED) {
                        s1 = peg$parseuser_unreserved();
                    }
                }
            }
        }
        else {
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parseuser_unreserved() {
        var s0;
        if (input.charCodeAt(peg$currPos) === 38) {
            s0 = peg$c28;
            peg$currPos++;
        }
        else {
            s0 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c29);
            }
        }
        if (s0 === peg$FAILED) {
            if (input.charCodeAt(peg$currPos) === 61) {
                s0 = peg$c30;
                peg$currPos++;
            }
            else {
                s0 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c31);
                }
            }
            if (s0 === peg$FAILED) {
                if (input.charCodeAt(peg$currPos) === 43) {
                    s0 = peg$c32;
                    peg$currPos++;
                }
                else {
                    s0 = peg$FAILED;
                    if (peg$silentFails === 0) {
                        peg$fail(peg$c33);
                    }
                }
                if (s0 === peg$FAILED) {
                    if (input.charCodeAt(peg$currPos) === 36) {
                        s0 = peg$c34;
                        peg$currPos++;
                    }
                    else {
                        s0 = peg$FAILED;
                        if (peg$silentFails === 0) {
                            peg$fail(peg$c35);
                        }
                    }
                    if (s0 === peg$FAILED) {
                        if (input.charCodeAt(peg$currPos) === 44) {
                            s0 = peg$c36;
                            peg$currPos++;
                        }
                        else {
                            s0 = peg$FAILED;
                            if (peg$silentFails === 0) {
                                peg$fail(peg$c37);
                            }
                        }
                        if (s0 === peg$FAILED) {
                            if (input.charCodeAt(peg$currPos) === 59) {
                                s0 = peg$c18;
                                peg$currPos++;
                            }
                            else {
                                s0 = peg$FAILED;
                                if (peg$silentFails === 0) {
                                    peg$fail(peg$c19);
                                }
                            }
                            if (s0 === peg$FAILED) {
                                if (input.charCodeAt(peg$currPos) === 63) {
                                    s0 = peg$c22;
                                    peg$currPos++;
                                }
                                else {
                                    s0 = peg$FAILED;
                                    if (peg$silentFails === 0) {
                                        peg$fail(peg$c23);
                                    }
                                }
                                if (s0 === peg$FAILED) {
                                    if (input.charCodeAt(peg$currPos) === 47) {
                                        s0 = peg$c20;
                                        peg$currPos++;
                                    }
                                    else {
                                        s0 = peg$FAILED;
                                        if (peg$silentFails === 0) {
                                            peg$fail(peg$c21);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        return s0;
    }
    function peg$parsepassword() {
        var s0, s1, s2;
        s0 = peg$currPos;
        s1 = [];
        s2 = peg$parseunreserved();
        if (s2 === peg$FAILED) {
            s2 = peg$parseescaped();
            if (s2 === peg$FAILED) {
                if (input.charCodeAt(peg$currPos) === 38) {
                    s2 = peg$c28;
                    peg$currPos++;
                }
                else {
                    s2 = peg$FAILED;
                    if (peg$silentFails === 0) {
                        peg$fail(peg$c29);
                    }
                }
                if (s2 === peg$FAILED) {
                    if (input.charCodeAt(peg$currPos) === 61) {
                        s2 = peg$c30;
                        peg$currPos++;
                    }
                    else {
                        s2 = peg$FAILED;
                        if (peg$silentFails === 0) {
                            peg$fail(peg$c31);
                        }
                    }
                    if (s2 === peg$FAILED) {
                        if (input.charCodeAt(peg$currPos) === 43) {
                            s2 = peg$c32;
                            peg$currPos++;
                        }
                        else {
                            s2 = peg$FAILED;
                            if (peg$silentFails === 0) {
                                peg$fail(peg$c33);
                            }
                        }
                        if (s2 === peg$FAILED) {
                            if (input.charCodeAt(peg$currPos) === 36) {
                                s2 = peg$c34;
                                peg$currPos++;
                            }
                            else {
                                s2 = peg$FAILED;
                                if (peg$silentFails === 0) {
                                    peg$fail(peg$c35);
                                }
                            }
                            if (s2 === peg$FAILED) {
                                if (input.charCodeAt(peg$currPos) === 44) {
                                    s2 = peg$c36;
                                    peg$currPos++;
                                }
                                else {
                                    s2 = peg$FAILED;
                                    if (peg$silentFails === 0) {
                                        peg$fail(peg$c37);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        while (s2 !== peg$FAILED) {
            s1.push(s2);
            s2 = peg$parseunreserved();
            if (s2 === peg$FAILED) {
                s2 = peg$parseescaped();
                if (s2 === peg$FAILED) {
                    if (input.charCodeAt(peg$currPos) === 38) {
                        s2 = peg$c28;
                        peg$currPos++;
                    }
                    else {
                        s2 = peg$FAILED;
                        if (peg$silentFails === 0) {
                            peg$fail(peg$c29);
                        }
                    }
                    if (s2 === peg$FAILED) {
                        if (input.charCodeAt(peg$currPos) === 61) {
                            s2 = peg$c30;
                            peg$currPos++;
                        }
                        else {
                            s2 = peg$FAILED;
                            if (peg$silentFails === 0) {
                                peg$fail(peg$c31);
                            }
                        }
                        if (s2 === peg$FAILED) {
                            if (input.charCodeAt(peg$currPos) === 43) {
                                s2 = peg$c32;
                                peg$currPos++;
                            }
                            else {
                                s2 = peg$FAILED;
                                if (peg$silentFails === 0) {
                                    peg$fail(peg$c33);
                                }
                            }
                            if (s2 === peg$FAILED) {
                                if (input.charCodeAt(peg$currPos) === 36) {
                                    s2 = peg$c34;
                                    peg$currPos++;
                                }
                                else {
                                    s2 = peg$FAILED;
                                    if (peg$silentFails === 0) {
                                        peg$fail(peg$c35);
                                    }
                                }
                                if (s2 === peg$FAILED) {
                                    if (input.charCodeAt(peg$currPos) === 44) {
                                        s2 = peg$c36;
                                        peg$currPos++;
                                    }
                                    else {
                                        s2 = peg$FAILED;
                                        if (peg$silentFails === 0) {
                                            peg$fail(peg$c37);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        if (s1 !== peg$FAILED) {
            peg$savedPos = s0;
            s1 = peg$c118();
        }
        s0 = s1;
        return s0;
    }
    function peg$parsehostport() {
        var s0, s1, s2, s3, s4;
        s0 = peg$currPos;
        s1 = peg$parsehost();
        if (s1 !== peg$FAILED) {
            s2 = peg$currPos;
            if (input.charCodeAt(peg$currPos) === 58) {
                s3 = peg$c24;
                peg$currPos++;
            }
            else {
                s3 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c25);
                }
            }
            if (s3 !== peg$FAILED) {
                s4 = peg$parseport();
                if (s4 !== peg$FAILED) {
                    s3 = [s3, s4];
                    s2 = s3;
                }
                else {
                    peg$currPos = s2;
                    s2 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s2;
                s2 = peg$FAILED;
            }
            if (s2 === peg$FAILED) {
                s2 = null;
            }
            if (s2 !== peg$FAILED) {
                s1 = [s1, s2];
                s0 = s1;
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parsehost() {
        var s0, s1;
        s0 = peg$currPos;
        s1 = peg$parsehostname();
        if (s1 === peg$FAILED) {
            s1 = peg$parseIPv4address();
            if (s1 === peg$FAILED) {
                s1 = peg$parseIPv6reference();
            }
        }
        if (s1 !== peg$FAILED) {
            peg$savedPos = s0;
            s1 = peg$c119();
        }
        s0 = s1;
        return s0;
    }
    function peg$parsehostname() {
        var s0, s1, s2, s3, s4;
        s0 = peg$currPos;
        s1 = [];
        s2 = peg$currPos;
        s3 = peg$parsedomainlabel();
        if (s3 !== peg$FAILED) {
            if (input.charCodeAt(peg$currPos) === 46) {
                s4 = peg$c42;
                peg$currPos++;
            }
            else {
                s4 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c43);
                }
            }
            if (s4 !== peg$FAILED) {
                s3 = [s3, s4];
                s2 = s3;
            }
            else {
                peg$currPos = s2;
                s2 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s2;
            s2 = peg$FAILED;
        }
        while (s2 !== peg$FAILED) {
            s1.push(s2);
            s2 = peg$currPos;
            s3 = peg$parsedomainlabel();
            if (s3 !== peg$FAILED) {
                if (input.charCodeAt(peg$currPos) === 46) {
                    s4 = peg$c42;
                    peg$currPos++;
                }
                else {
                    s4 = peg$FAILED;
                    if (peg$silentFails === 0) {
                        peg$fail(peg$c43);
                    }
                }
                if (s4 !== peg$FAILED) {
                    s3 = [s3, s4];
                    s2 = s3;
                }
                else {
                    peg$currPos = s2;
                    s2 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s2;
                s2 = peg$FAILED;
            }
        }
        if (s1 !== peg$FAILED) {
            s2 = peg$parsetoplabel();
            if (s2 !== peg$FAILED) {
                if (input.charCodeAt(peg$currPos) === 46) {
                    s3 = peg$c42;
                    peg$currPos++;
                }
                else {
                    s3 = peg$FAILED;
                    if (peg$silentFails === 0) {
                        peg$fail(peg$c43);
                    }
                }
                if (s3 === peg$FAILED) {
                    s3 = null;
                }
                if (s3 !== peg$FAILED) {
                    peg$savedPos = s0;
                    s1 = peg$c120();
                    s0 = s1;
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parsedomainlabel() {
        var s0, s1;
        s0 = [];
        if (peg$c121.test(input.charAt(peg$currPos))) {
            s1 = input.charAt(peg$currPos);
            peg$currPos++;
        }
        else {
            s1 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c122);
            }
        }
        if (s1 !== peg$FAILED) {
            while (s1 !== peg$FAILED) {
                s0.push(s1);
                if (peg$c121.test(input.charAt(peg$currPos))) {
                    s1 = input.charAt(peg$currPos);
                    peg$currPos++;
                }
                else {
                    s1 = peg$FAILED;
                    if (peg$silentFails === 0) {
                        peg$fail(peg$c122);
                    }
                }
            }
        }
        else {
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parsetoplabel() {
        var s0, s1, s2, s3;
        s0 = peg$currPos;
        if (peg$c4.test(input.charAt(peg$currPos))) {
            s1 = input.charAt(peg$currPos);
            peg$currPos++;
        }
        else {
            s1 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c5);
            }
        }
        if (s1 !== peg$FAILED) {
            s2 = [];
            if (peg$c123.test(input.charAt(peg$currPos))) {
                s3 = input.charAt(peg$currPos);
                peg$currPos++;
            }
            else {
                s3 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c124);
                }
            }
            while (s3 !== peg$FAILED) {
                s2.push(s3);
                if (peg$c123.test(input.charAt(peg$currPos))) {
                    s3 = input.charAt(peg$currPos);
                    peg$currPos++;
                }
                else {
                    s3 = peg$FAILED;
                    if (peg$silentFails === 0) {
                        peg$fail(peg$c124);
                    }
                }
            }
            if (s2 !== peg$FAILED) {
                s1 = [s1, s2];
                s0 = s1;
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parseIPv6reference() {
        var s0, s1, s2, s3;
        s0 = peg$currPos;
        if (input.charCodeAt(peg$currPos) === 91) {
            s1 = peg$c76;
            peg$currPos++;
        }
        else {
            s1 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c77);
            }
        }
        if (s1 !== peg$FAILED) {
            s2 = peg$parseIPv6address();
            if (s2 !== peg$FAILED) {
                if (input.charCodeAt(peg$currPos) === 93) {
                    s3 = peg$c78;
                    peg$currPos++;
                }
                else {
                    s3 = peg$FAILED;
                    if (peg$silentFails === 0) {
                        peg$fail(peg$c79);
                    }
                }
                if (s3 !== peg$FAILED) {
                    peg$savedPos = s0;
                    s1 = peg$c125();
                    s0 = s1;
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parseIPv6address() {
        var s0, s1, s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14;
        s0 = peg$currPos;
        s1 = peg$currPos;
        s2 = peg$parseh16();
        if (s2 !== peg$FAILED) {
            if (input.charCodeAt(peg$currPos) === 58) {
                s3 = peg$c24;
                peg$currPos++;
            }
            else {
                s3 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c25);
                }
            }
            if (s3 !== peg$FAILED) {
                s4 = peg$parseh16();
                if (s4 !== peg$FAILED) {
                    if (input.charCodeAt(peg$currPos) === 58) {
                        s5 = peg$c24;
                        peg$currPos++;
                    }
                    else {
                        s5 = peg$FAILED;
                        if (peg$silentFails === 0) {
                            peg$fail(peg$c25);
                        }
                    }
                    if (s5 !== peg$FAILED) {
                        s6 = peg$parseh16();
                        if (s6 !== peg$FAILED) {
                            if (input.charCodeAt(peg$currPos) === 58) {
                                s7 = peg$c24;
                                peg$currPos++;
                            }
                            else {
                                s7 = peg$FAILED;
                                if (peg$silentFails === 0) {
                                    peg$fail(peg$c25);
                                }
                            }
                            if (s7 !== peg$FAILED) {
                                s8 = peg$parseh16();
                                if (s8 !== peg$FAILED) {
                                    if (input.charCodeAt(peg$currPos) === 58) {
                                        s9 = peg$c24;
                                        peg$currPos++;
                                    }
                                    else {
                                        s9 = peg$FAILED;
                                        if (peg$silentFails === 0) {
                                            peg$fail(peg$c25);
                                        }
                                    }
                                    if (s9 !== peg$FAILED) {
                                        s10 = peg$parseh16();
                                        if (s10 !== peg$FAILED) {
                                            if (input.charCodeAt(peg$currPos) === 58) {
                                                s11 = peg$c24;
                                                peg$currPos++;
                                            }
                                            else {
                                                s11 = peg$FAILED;
                                                if (peg$silentFails === 0) {
                                                    peg$fail(peg$c25);
                                                }
                                            }
                                            if (s11 !== peg$FAILED) {
                                                s12 = peg$parseh16();
                                                if (s12 !== peg$FAILED) {
                                                    if (input.charCodeAt(peg$currPos) === 58) {
                                                        s13 = peg$c24;
                                                        peg$currPos++;
                                                    }
                                                    else {
                                                        s13 = peg$FAILED;
                                                        if (peg$silentFails === 0) {
                                                            peg$fail(peg$c25);
                                                        }
                                                    }
                                                    if (s13 !== peg$FAILED) {
                                                        s14 = peg$parsels32();
                                                        if (s14 !== peg$FAILED) {
                                                            s2 = [s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13, s14];
                                                            s1 = s2;
                                                        }
                                                        else {
                                                            peg$currPos = s1;
                                                            s1 = peg$FAILED;
                                                        }
                                                    }
                                                    else {
                                                        peg$currPos = s1;
                                                        s1 = peg$FAILED;
                                                    }
                                                }
                                                else {
                                                    peg$currPos = s1;
                                                    s1 = peg$FAILED;
                                                }
                                            }
                                            else {
                                                peg$currPos = s1;
                                                s1 = peg$FAILED;
                                            }
                                        }
                                        else {
                                            peg$currPos = s1;
                                            s1 = peg$FAILED;
                                        }
                                    }
                                    else {
                                        peg$currPos = s1;
                                        s1 = peg$FAILED;
                                    }
                                }
                                else {
                                    peg$currPos = s1;
                                    s1 = peg$FAILED;
                                }
                            }
                            else {
                                peg$currPos = s1;
                                s1 = peg$FAILED;
                            }
                        }
                        else {
                            peg$currPos = s1;
                            s1 = peg$FAILED;
                        }
                    }
                    else {
                        peg$currPos = s1;
                        s1 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s1;
                    s1 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s1;
                s1 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s1;
            s1 = peg$FAILED;
        }
        if (s1 === peg$FAILED) {
            s1 = peg$currPos;
            if (input.substr(peg$currPos, 2) === peg$c126) {
                s2 = peg$c126;
                peg$currPos += 2;
            }
            else {
                s2 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c127);
                }
            }
            if (s2 !== peg$FAILED) {
                s3 = peg$parseh16();
                if (s3 !== peg$FAILED) {
                    if (input.charCodeAt(peg$currPos) === 58) {
                        s4 = peg$c24;
                        peg$currPos++;
                    }
                    else {
                        s4 = peg$FAILED;
                        if (peg$silentFails === 0) {
                            peg$fail(peg$c25);
                        }
                    }
                    if (s4 !== peg$FAILED) {
                        s5 = peg$parseh16();
                        if (s5 !== peg$FAILED) {
                            if (input.charCodeAt(peg$currPos) === 58) {
                                s6 = peg$c24;
                                peg$currPos++;
                            }
                            else {
                                s6 = peg$FAILED;
                                if (peg$silentFails === 0) {
                                    peg$fail(peg$c25);
                                }
                            }
                            if (s6 !== peg$FAILED) {
                                s7 = peg$parseh16();
                                if (s7 !== peg$FAILED) {
                                    if (input.charCodeAt(peg$currPos) === 58) {
                                        s8 = peg$c24;
                                        peg$currPos++;
                                    }
                                    else {
                                        s8 = peg$FAILED;
                                        if (peg$silentFails === 0) {
                                            peg$fail(peg$c25);
                                        }
                                    }
                                    if (s8 !== peg$FAILED) {
                                        s9 = peg$parseh16();
                                        if (s9 !== peg$FAILED) {
                                            if (input.charCodeAt(peg$currPos) === 58) {
                                                s10 = peg$c24;
                                                peg$currPos++;
                                            }
                                            else {
                                                s10 = peg$FAILED;
                                                if (peg$silentFails === 0) {
                                                    peg$fail(peg$c25);
                                                }
                                            }
                                            if (s10 !== peg$FAILED) {
                                                s11 = peg$parseh16();
                                                if (s11 !== peg$FAILED) {
                                                    if (input.charCodeAt(peg$currPos) === 58) {
                                                        s12 = peg$c24;
                                                        peg$currPos++;
                                                    }
                                                    else {
                                                        s12 = peg$FAILED;
                                                        if (peg$silentFails === 0) {
                                                            peg$fail(peg$c25);
                                                        }
                                                    }
                                                    if (s12 !== peg$FAILED) {
                                                        s13 = peg$parsels32();
                                                        if (s13 !== peg$FAILED) {
                                                            s2 = [s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12, s13];
                                                            s1 = s2;
                                                        }
                                                        else {
                                                            peg$currPos = s1;
                                                            s1 = peg$FAILED;
                                                        }
                                                    }
                                                    else {
                                                        peg$currPos = s1;
                                                        s1 = peg$FAILED;
                                                    }
                                                }
                                                else {
                                                    peg$currPos = s1;
                                                    s1 = peg$FAILED;
                                                }
                                            }
                                            else {
                                                peg$currPos = s1;
                                                s1 = peg$FAILED;
                                            }
                                        }
                                        else {
                                            peg$currPos = s1;
                                            s1 = peg$FAILED;
                                        }
                                    }
                                    else {
                                        peg$currPos = s1;
                                        s1 = peg$FAILED;
                                    }
                                }
                                else {
                                    peg$currPos = s1;
                                    s1 = peg$FAILED;
                                }
                            }
                            else {
                                peg$currPos = s1;
                                s1 = peg$FAILED;
                            }
                        }
                        else {
                            peg$currPos = s1;
                            s1 = peg$FAILED;
                        }
                    }
                    else {
                        peg$currPos = s1;
                        s1 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s1;
                    s1 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s1;
                s1 = peg$FAILED;
            }
            if (s1 === peg$FAILED) {
                s1 = peg$currPos;
                if (input.substr(peg$currPos, 2) === peg$c126) {
                    s2 = peg$c126;
                    peg$currPos += 2;
                }
                else {
                    s2 = peg$FAILED;
                    if (peg$silentFails === 0) {
                        peg$fail(peg$c127);
                    }
                }
                if (s2 !== peg$FAILED) {
                    s3 = peg$parseh16();
                    if (s3 !== peg$FAILED) {
                        if (input.charCodeAt(peg$currPos) === 58) {
                            s4 = peg$c24;
                            peg$currPos++;
                        }
                        else {
                            s4 = peg$FAILED;
                            if (peg$silentFails === 0) {
                                peg$fail(peg$c25);
                            }
                        }
                        if (s4 !== peg$FAILED) {
                            s5 = peg$parseh16();
                            if (s5 !== peg$FAILED) {
                                if (input.charCodeAt(peg$currPos) === 58) {
                                    s6 = peg$c24;
                                    peg$currPos++;
                                }
                                else {
                                    s6 = peg$FAILED;
                                    if (peg$silentFails === 0) {
                                        peg$fail(peg$c25);
                                    }
                                }
                                if (s6 !== peg$FAILED) {
                                    s7 = peg$parseh16();
                                    if (s7 !== peg$FAILED) {
                                        if (input.charCodeAt(peg$currPos) === 58) {
                                            s8 = peg$c24;
                                            peg$currPos++;
                                        }
                                        else {
                                            s8 = peg$FAILED;
                                            if (peg$silentFails === 0) {
                                                peg$fail(peg$c25);
                                            }
                                        }
                                        if (s8 !== peg$FAILED) {
                                            s9 = peg$parseh16();
                                            if (s9 !== peg$FAILED) {
                                                if (input.charCodeAt(peg$currPos) === 58) {
                                                    s10 = peg$c24;
                                                    peg$currPos++;
                                                }
                                                else {
                                                    s10 = peg$FAILED;
                                                    if (peg$silentFails === 0) {
                                                        peg$fail(peg$c25);
                                                    }
                                                }
                                                if (s10 !== peg$FAILED) {
                                                    s11 = peg$parsels32();
                                                    if (s11 !== peg$FAILED) {
                                                        s2 = [s2, s3, s4, s5, s6, s7, s8, s9, s10, s11];
                                                        s1 = s2;
                                                    }
                                                    else {
                                                        peg$currPos = s1;
                                                        s1 = peg$FAILED;
                                                    }
                                                }
                                                else {
                                                    peg$currPos = s1;
                                                    s1 = peg$FAILED;
                                                }
                                            }
                                            else {
                                                peg$currPos = s1;
                                                s1 = peg$FAILED;
                                            }
                                        }
                                        else {
                                            peg$currPos = s1;
                                            s1 = peg$FAILED;
                                        }
                                    }
                                    else {
                                        peg$currPos = s1;
                                        s1 = peg$FAILED;
                                    }
                                }
                                else {
                                    peg$currPos = s1;
                                    s1 = peg$FAILED;
                                }
                            }
                            else {
                                peg$currPos = s1;
                                s1 = peg$FAILED;
                            }
                        }
                        else {
                            peg$currPos = s1;
                            s1 = peg$FAILED;
                        }
                    }
                    else {
                        peg$currPos = s1;
                        s1 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s1;
                    s1 = peg$FAILED;
                }
                if (s1 === peg$FAILED) {
                    s1 = peg$currPos;
                    if (input.substr(peg$currPos, 2) === peg$c126) {
                        s2 = peg$c126;
                        peg$currPos += 2;
                    }
                    else {
                        s2 = peg$FAILED;
                        if (peg$silentFails === 0) {
                            peg$fail(peg$c127);
                        }
                    }
                    if (s2 !== peg$FAILED) {
                        s3 = peg$parseh16();
                        if (s3 !== peg$FAILED) {
                            if (input.charCodeAt(peg$currPos) === 58) {
                                s4 = peg$c24;
                                peg$currPos++;
                            }
                            else {
                                s4 = peg$FAILED;
                                if (peg$silentFails === 0) {
                                    peg$fail(peg$c25);
                                }
                            }
                            if (s4 !== peg$FAILED) {
                                s5 = peg$parseh16();
                                if (s5 !== peg$FAILED) {
                                    if (input.charCodeAt(peg$currPos) === 58) {
                                        s6 = peg$c24;
                                        peg$currPos++;
                                    }
                                    else {
                                        s6 = peg$FAILED;
                                        if (peg$silentFails === 0) {
                                            peg$fail(peg$c25);
                                        }
                                    }
                                    if (s6 !== peg$FAILED) {
                                        s7 = peg$parseh16();
                                        if (s7 !== peg$FAILED) {
                                            if (input.charCodeAt(peg$currPos) === 58) {
                                                s8 = peg$c24;
                                                peg$currPos++;
                                            }
                                            else {
                                                s8 = peg$FAILED;
                                                if (peg$silentFails === 0) {
                                                    peg$fail(peg$c25);
                                                }
                                            }
                                            if (s8 !== peg$FAILED) {
                                                s9 = peg$parsels32();
                                                if (s9 !== peg$FAILED) {
                                                    s2 = [s2, s3, s4, s5, s6, s7, s8, s9];
                                                    s1 = s2;
                                                }
                                                else {
                                                    peg$currPos = s1;
                                                    s1 = peg$FAILED;
                                                }
                                            }
                                            else {
                                                peg$currPos = s1;
                                                s1 = peg$FAILED;
                                            }
                                        }
                                        else {
                                            peg$currPos = s1;
                                            s1 = peg$FAILED;
                                        }
                                    }
                                    else {
                                        peg$currPos = s1;
                                        s1 = peg$FAILED;
                                    }
                                }
                                else {
                                    peg$currPos = s1;
                                    s1 = peg$FAILED;
                                }
                            }
                            else {
                                peg$currPos = s1;
                                s1 = peg$FAILED;
                            }
                        }
                        else {
                            peg$currPos = s1;
                            s1 = peg$FAILED;
                        }
                    }
                    else {
                        peg$currPos = s1;
                        s1 = peg$FAILED;
                    }
                    if (s1 === peg$FAILED) {
                        s1 = peg$currPos;
                        if (input.substr(peg$currPos, 2) === peg$c126) {
                            s2 = peg$c126;
                            peg$currPos += 2;
                        }
                        else {
                            s2 = peg$FAILED;
                            if (peg$silentFails === 0) {
                                peg$fail(peg$c127);
                            }
                        }
                        if (s2 !== peg$FAILED) {
                            s3 = peg$parseh16();
                            if (s3 !== peg$FAILED) {
                                if (input.charCodeAt(peg$currPos) === 58) {
                                    s4 = peg$c24;
                                    peg$currPos++;
                                }
                                else {
                                    s4 = peg$FAILED;
                                    if (peg$silentFails === 0) {
                                        peg$fail(peg$c25);
                                    }
                                }
                                if (s4 !== peg$FAILED) {
                                    s5 = peg$parseh16();
                                    if (s5 !== peg$FAILED) {
                                        if (input.charCodeAt(peg$currPos) === 58) {
                                            s6 = peg$c24;
                                            peg$currPos++;
                                        }
                                        else {
                                            s6 = peg$FAILED;
                                            if (peg$silentFails === 0) {
                                                peg$fail(peg$c25);
                                            }
                                        }
                                        if (s6 !== peg$FAILED) {
                                            s7 = peg$parsels32();
                                            if (s7 !== peg$FAILED) {
                                                s2 = [s2, s3, s4, s5, s6, s7];
                                                s1 = s2;
                                            }
                                            else {
                                                peg$currPos = s1;
                                                s1 = peg$FAILED;
                                            }
                                        }
                                        else {
                                            peg$currPos = s1;
                                            s1 = peg$FAILED;
                                        }
                                    }
                                    else {
                                        peg$currPos = s1;
                                        s1 = peg$FAILED;
                                    }
                                }
                                else {
                                    peg$currPos = s1;
                                    s1 = peg$FAILED;
                                }
                            }
                            else {
                                peg$currPos = s1;
                                s1 = peg$FAILED;
                            }
                        }
                        else {
                            peg$currPos = s1;
                            s1 = peg$FAILED;
                        }
                        if (s1 === peg$FAILED) {
                            s1 = peg$currPos;
                            if (input.substr(peg$currPos, 2) === peg$c126) {
                                s2 = peg$c126;
                                peg$currPos += 2;
                            }
                            else {
                                s2 = peg$FAILED;
                                if (peg$silentFails === 0) {
                                    peg$fail(peg$c127);
                                }
                            }
                            if (s2 !== peg$FAILED) {
                                s3 = peg$parseh16();
                                if (s3 !== peg$FAILED) {
                                    if (input.charCodeAt(peg$currPos) === 58) {
                                        s4 = peg$c24;
                                        peg$currPos++;
                                    }
                                    else {
                                        s4 = peg$FAILED;
                                        if (peg$silentFails === 0) {
                                            peg$fail(peg$c25);
                                        }
                                    }
                                    if (s4 !== peg$FAILED) {
                                        s5 = peg$parsels32();
                                        if (s5 !== peg$FAILED) {
                                            s2 = [s2, s3, s4, s5];
                                            s1 = s2;
                                        }
                                        else {
                                            peg$currPos = s1;
                                            s1 = peg$FAILED;
                                        }
                                    }
                                    else {
                                        peg$currPos = s1;
                                        s1 = peg$FAILED;
                                    }
                                }
                                else {
                                    peg$currPos = s1;
                                    s1 = peg$FAILED;
                                }
                            }
                            else {
                                peg$currPos = s1;
                                s1 = peg$FAILED;
                            }
                            if (s1 === peg$FAILED) {
                                s1 = peg$currPos;
                                if (input.substr(peg$currPos, 2) === peg$c126) {
                                    s2 = peg$c126;
                                    peg$currPos += 2;
                                }
                                else {
                                    s2 = peg$FAILED;
                                    if (peg$silentFails === 0) {
                                        peg$fail(peg$c127);
                                    }
                                }
                                if (s2 !== peg$FAILED) {
                                    s3 = peg$parsels32();
                                    if (s3 !== peg$FAILED) {
                                        s2 = [s2, s3];
                                        s1 = s2;
                                    }
                                    else {
                                        peg$currPos = s1;
                                        s1 = peg$FAILED;
                                    }
                                }
                                else {
                                    peg$currPos = s1;
                                    s1 = peg$FAILED;
                                }
                                if (s1 === peg$FAILED) {
                                    s1 = peg$currPos;
                                    if (input.substr(peg$currPos, 2) === peg$c126) {
                                        s2 = peg$c126;
                                        peg$currPos += 2;
                                    }
                                    else {
                                        s2 = peg$FAILED;
                                        if (peg$silentFails === 0) {
                                            peg$fail(peg$c127);
                                        }
                                    }
                                    if (s2 !== peg$FAILED) {
                                        s3 = peg$parseh16();
                                        if (s3 !== peg$FAILED) {
                                            s2 = [s2, s3];
                                            s1 = s2;
                                        }
                                        else {
                                            peg$currPos = s1;
                                            s1 = peg$FAILED;
                                        }
                                    }
                                    else {
                                        peg$currPos = s1;
                                        s1 = peg$FAILED;
                                    }
                                    if (s1 === peg$FAILED) {
                                        s1 = peg$currPos;
                                        s2 = peg$parseh16();
                                        if (s2 !== peg$FAILED) {
                                            if (input.substr(peg$currPos, 2) === peg$c126) {
                                                s3 = peg$c126;
                                                peg$currPos += 2;
                                            }
                                            else {
                                                s3 = peg$FAILED;
                                                if (peg$silentFails === 0) {
                                                    peg$fail(peg$c127);
                                                }
                                            }
                                            if (s3 !== peg$FAILED) {
                                                s4 = peg$parseh16();
                                                if (s4 !== peg$FAILED) {
                                                    if (input.charCodeAt(peg$currPos) === 58) {
                                                        s5 = peg$c24;
                                                        peg$currPos++;
                                                    }
                                                    else {
                                                        s5 = peg$FAILED;
                                                        if (peg$silentFails === 0) {
                                                            peg$fail(peg$c25);
                                                        }
                                                    }
                                                    if (s5 !== peg$FAILED) {
                                                        s6 = peg$parseh16();
                                                        if (s6 !== peg$FAILED) {
                                                            if (input.charCodeAt(peg$currPos) === 58) {
                                                                s7 = peg$c24;
                                                                peg$currPos++;
                                                            }
                                                            else {
                                                                s7 = peg$FAILED;
                                                                if (peg$silentFails === 0) {
                                                                    peg$fail(peg$c25);
                                                                }
                                                            }
                                                            if (s7 !== peg$FAILED) {
                                                                s8 = peg$parseh16();
                                                                if (s8 !== peg$FAILED) {
                                                                    if (input.charCodeAt(peg$currPos) === 58) {
                                                                        s9 = peg$c24;
                                                                        peg$currPos++;
                                                                    }
                                                                    else {
                                                                        s9 = peg$FAILED;
                                                                        if (peg$silentFails === 0) {
                                                                            peg$fail(peg$c25);
                                                                        }
                                                                    }
                                                                    if (s9 !== peg$FAILED) {
                                                                        s10 = peg$parseh16();
                                                                        if (s10 !== peg$FAILED) {
                                                                            if (input.charCodeAt(peg$currPos) === 58) {
                                                                                s11 = peg$c24;
                                                                                peg$currPos++;
                                                                            }
                                                                            else {
                                                                                s11 = peg$FAILED;
                                                                                if (peg$silentFails === 0) {
                                                                                    peg$fail(peg$c25);
                                                                                }
                                                                            }
                                                                            if (s11 !== peg$FAILED) {
                                                                                s12 = peg$parsels32();
                                                                                if (s12 !== peg$FAILED) {
                                                                                    s2 = [s2, s3, s4, s5, s6, s7, s8, s9, s10, s11, s12];
                                                                                    s1 = s2;
                                                                                }
                                                                                else {
                                                                                    peg$currPos = s1;
                                                                                    s1 = peg$FAILED;
                                                                                }
                                                                            }
                                                                            else {
                                                                                peg$currPos = s1;
                                                                                s1 = peg$FAILED;
                                                                            }
                                                                        }
                                                                        else {
                                                                            peg$currPos = s1;
                                                                            s1 = peg$FAILED;
                                                                        }
                                                                    }
                                                                    else {
                                                                        peg$currPos = s1;
                                                                        s1 = peg$FAILED;
                                                                    }
                                                                }
                                                                else {
                                                                    peg$currPos = s1;
                                                                    s1 = peg$FAILED;
                                                                }
                                                            }
                                                            else {
                                                                peg$currPos = s1;
                                                                s1 = peg$FAILED;
                                                            }
                                                        }
                                                        else {
                                                            peg$currPos = s1;
                                                            s1 = peg$FAILED;
                                                        }
                                                    }
                                                    else {
                                                        peg$currPos = s1;
                                                        s1 = peg$FAILED;
                                                    }
                                                }
                                                else {
                                                    peg$currPos = s1;
                                                    s1 = peg$FAILED;
                                                }
                                            }
                                            else {
                                                peg$currPos = s1;
                                                s1 = peg$FAILED;
                                            }
                                        }
                                        else {
                                            peg$currPos = s1;
                                            s1 = peg$FAILED;
                                        }
                                        if (s1 === peg$FAILED) {
                                            s1 = peg$currPos;
                                            s2 = peg$parseh16();
                                            if (s2 !== peg$FAILED) {
                                                s3 = peg$currPos;
                                                if (input.charCodeAt(peg$currPos) === 58) {
                                                    s4 = peg$c24;
                                                    peg$currPos++;
                                                }
                                                else {
                                                    s4 = peg$FAILED;
                                                    if (peg$silentFails === 0) {
                                                        peg$fail(peg$c25);
                                                    }
                                                }
                                                if (s4 !== peg$FAILED) {
                                                    s5 = peg$parseh16();
                                                    if (s5 !== peg$FAILED) {
                                                        s4 = [s4, s5];
                                                        s3 = s4;
                                                    }
                                                    else {
                                                        peg$currPos = s3;
                                                        s3 = peg$FAILED;
                                                    }
                                                }
                                                else {
                                                    peg$currPos = s3;
                                                    s3 = peg$FAILED;
                                                }
                                                if (s3 === peg$FAILED) {
                                                    s3 = null;
                                                }
                                                if (s3 !== peg$FAILED) {
                                                    if (input.substr(peg$currPos, 2) === peg$c126) {
                                                        s4 = peg$c126;
                                                        peg$currPos += 2;
                                                    }
                                                    else {
                                                        s4 = peg$FAILED;
                                                        if (peg$silentFails === 0) {
                                                            peg$fail(peg$c127);
                                                        }
                                                    }
                                                    if (s4 !== peg$FAILED) {
                                                        s5 = peg$parseh16();
                                                        if (s5 !== peg$FAILED) {
                                                            if (input.charCodeAt(peg$currPos) === 58) {
                                                                s6 = peg$c24;
                                                                peg$currPos++;
                                                            }
                                                            else {
                                                                s6 = peg$FAILED;
                                                                if (peg$silentFails === 0) {
                                                                    peg$fail(peg$c25);
                                                                }
                                                            }
                                                            if (s6 !== peg$FAILED) {
                                                                s7 = peg$parseh16();
                                                                if (s7 !== peg$FAILED) {
                                                                    if (input.charCodeAt(peg$currPos) === 58) {
                                                                        s8 = peg$c24;
                                                                        peg$currPos++;
                                                                    }
                                                                    else {
                                                                        s8 = peg$FAILED;
                                                                        if (peg$silentFails === 0) {
                                                                            peg$fail(peg$c25);
                                                                        }
                                                                    }
                                                                    if (s8 !== peg$FAILED) {
                                                                        s9 = peg$parseh16();
                                                                        if (s9 !== peg$FAILED) {
                                                                            if (input.charCodeAt(peg$currPos) === 58) {
                                                                                s10 = peg$c24;
                                                                                peg$currPos++;
                                                                            }
                                                                            else {
                                                                                s10 = peg$FAILED;
                                                                                if (peg$silentFails === 0) {
                                                                                    peg$fail(peg$c25);
                                                                                }
                                                                            }
                                                                            if (s10 !== peg$FAILED) {
                                                                                s11 = peg$parsels32();
                                                                                if (s11 !== peg$FAILED) {
                                                                                    s2 = [s2, s3, s4, s5, s6, s7, s8, s9, s10, s11];
                                                                                    s1 = s2;
                                                                                }
                                                                                else {
                                                                                    peg$currPos = s1;
                                                                                    s1 = peg$FAILED;
                                                                                }
                                                                            }
                                                                            else {
                                                                                peg$currPos = s1;
                                                                                s1 = peg$FAILED;
                                                                            }
                                                                        }
                                                                        else {
                                                                            peg$currPos = s1;
                                                                            s1 = peg$FAILED;
                                                                        }
                                                                    }
                                                                    else {
                                                                        peg$currPos = s1;
                                                                        s1 = peg$FAILED;
                                                                    }
                                                                }
                                                                else {
                                                                    peg$currPos = s1;
                                                                    s1 = peg$FAILED;
                                                                }
                                                            }
                                                            else {
                                                                peg$currPos = s1;
                                                                s1 = peg$FAILED;
                                                            }
                                                        }
                                                        else {
                                                            peg$currPos = s1;
                                                            s1 = peg$FAILED;
                                                        }
                                                    }
                                                    else {
                                                        peg$currPos = s1;
                                                        s1 = peg$FAILED;
                                                    }
                                                }
                                                else {
                                                    peg$currPos = s1;
                                                    s1 = peg$FAILED;
                                                }
                                            }
                                            else {
                                                peg$currPos = s1;
                                                s1 = peg$FAILED;
                                            }
                                            if (s1 === peg$FAILED) {
                                                s1 = peg$currPos;
                                                s2 = peg$parseh16();
                                                if (s2 !== peg$FAILED) {
                                                    s3 = peg$currPos;
                                                    if (input.charCodeAt(peg$currPos) === 58) {
                                                        s4 = peg$c24;
                                                        peg$currPos++;
                                                    }
                                                    else {
                                                        s4 = peg$FAILED;
                                                        if (peg$silentFails === 0) {
                                                            peg$fail(peg$c25);
                                                        }
                                                    }
                                                    if (s4 !== peg$FAILED) {
                                                        s5 = peg$parseh16();
                                                        if (s5 !== peg$FAILED) {
                                                            s4 = [s4, s5];
                                                            s3 = s4;
                                                        }
                                                        else {
                                                            peg$currPos = s3;
                                                            s3 = peg$FAILED;
                                                        }
                                                    }
                                                    else {
                                                        peg$currPos = s3;
                                                        s3 = peg$FAILED;
                                                    }
                                                    if (s3 === peg$FAILED) {
                                                        s3 = null;
                                                    }
                                                    if (s3 !== peg$FAILED) {
                                                        s4 = peg$currPos;
                                                        if (input.charCodeAt(peg$currPos) === 58) {
                                                            s5 = peg$c24;
                                                            peg$currPos++;
                                                        }
                                                        else {
                                                            s5 = peg$FAILED;
                                                            if (peg$silentFails === 0) {
                                                                peg$fail(peg$c25);
                                                            }
                                                        }
                                                        if (s5 !== peg$FAILED) {
                                                            s6 = peg$parseh16();
                                                            if (s6 !== peg$FAILED) {
                                                                s5 = [s5, s6];
                                                                s4 = s5;
                                                            }
                                                            else {
                                                                peg$currPos = s4;
                                                                s4 = peg$FAILED;
                                                            }
                                                        }
                                                        else {
                                                            peg$currPos = s4;
                                                            s4 = peg$FAILED;
                                                        }
                                                        if (s4 === peg$FAILED) {
                                                            s4 = null;
                                                        }
                                                        if (s4 !== peg$FAILED) {
                                                            if (input.substr(peg$currPos, 2) === peg$c126) {
                                                                s5 = peg$c126;
                                                                peg$currPos += 2;
                                                            }
                                                            else {
                                                                s5 = peg$FAILED;
                                                                if (peg$silentFails === 0) {
                                                                    peg$fail(peg$c127);
                                                                }
                                                            }
                                                            if (s5 !== peg$FAILED) {
                                                                s6 = peg$parseh16();
                                                                if (s6 !== peg$FAILED) {
                                                                    if (input.charCodeAt(peg$currPos) === 58) {
                                                                        s7 = peg$c24;
                                                                        peg$currPos++;
                                                                    }
                                                                    else {
                                                                        s7 = peg$FAILED;
                                                                        if (peg$silentFails === 0) {
                                                                            peg$fail(peg$c25);
                                                                        }
                                                                    }
                                                                    if (s7 !== peg$FAILED) {
                                                                        s8 = peg$parseh16();
                                                                        if (s8 !== peg$FAILED) {
                                                                            if (input.charCodeAt(peg$currPos) === 58) {
                                                                                s9 = peg$c24;
                                                                                peg$currPos++;
                                                                            }
                                                                            else {
                                                                                s9 = peg$FAILED;
                                                                                if (peg$silentFails === 0) {
                                                                                    peg$fail(peg$c25);
                                                                                }
                                                                            }
                                                                            if (s9 !== peg$FAILED) {
                                                                                s10 = peg$parsels32();
                                                                                if (s10 !== peg$FAILED) {
                                                                                    s2 = [s2, s3, s4, s5, s6, s7, s8, s9, s10];
                                                                                    s1 = s2;
                                                                                }
                                                                                else {
                                                                                    peg$currPos = s1;
                                                                                    s1 = peg$FAILED;
                                                                                }
                                                                            }
                                                                            else {
                                                                                peg$currPos = s1;
                                                                                s1 = peg$FAILED;
                                                                            }
                                                                        }
                                                                        else {
                                                                            peg$currPos = s1;
                                                                            s1 = peg$FAILED;
                                                                        }
                                                                    }
                                                                    else {
                                                                        peg$currPos = s1;
                                                                        s1 = peg$FAILED;
                                                                    }
                                                                }
                                                                else {
                                                                    peg$currPos = s1;
                                                                    s1 = peg$FAILED;
                                                                }
                                                            }
                                                            else {
                                                                peg$currPos = s1;
                                                                s1 = peg$FAILED;
                                                            }
                                                        }
                                                        else {
                                                            peg$currPos = s1;
                                                            s1 = peg$FAILED;
                                                        }
                                                    }
                                                    else {
                                                        peg$currPos = s1;
                                                        s1 = peg$FAILED;
                                                    }
                                                }
                                                else {
                                                    peg$currPos = s1;
                                                    s1 = peg$FAILED;
                                                }
                                                if (s1 === peg$FAILED) {
                                                    s1 = peg$currPos;
                                                    s2 = peg$parseh16();
                                                    if (s2 !== peg$FAILED) {
                                                        s3 = peg$currPos;
                                                        if (input.charCodeAt(peg$currPos) === 58) {
                                                            s4 = peg$c24;
                                                            peg$currPos++;
                                                        }
                                                        else {
                                                            s4 = peg$FAILED;
                                                            if (peg$silentFails === 0) {
                                                                peg$fail(peg$c25);
                                                            }
                                                        }
                                                        if (s4 !== peg$FAILED) {
                                                            s5 = peg$parseh16();
                                                            if (s5 !== peg$FAILED) {
                                                                s4 = [s4, s5];
                                                                s3 = s4;
                                                            }
                                                            else {
                                                                peg$currPos = s3;
                                                                s3 = peg$FAILED;
                                                            }
                                                        }
                                                        else {
                                                            peg$currPos = s3;
                                                            s3 = peg$FAILED;
                                                        }
                                                        if (s3 === peg$FAILED) {
                                                            s3 = null;
                                                        }
                                                        if (s3 !== peg$FAILED) {
                                                            s4 = peg$currPos;
                                                            if (input.charCodeAt(peg$currPos) === 58) {
                                                                s5 = peg$c24;
                                                                peg$currPos++;
                                                            }
                                                            else {
                                                                s5 = peg$FAILED;
                                                                if (peg$silentFails === 0) {
                                                                    peg$fail(peg$c25);
                                                                }
                                                            }
                                                            if (s5 !== peg$FAILED) {
                                                                s6 = peg$parseh16();
                                                                if (s6 !== peg$FAILED) {
                                                                    s5 = [s5, s6];
                                                                    s4 = s5;
                                                                }
                                                                else {
                                                                    peg$currPos = s4;
                                                                    s4 = peg$FAILED;
                                                                }
                                                            }
                                                            else {
                                                                peg$currPos = s4;
                                                                s4 = peg$FAILED;
                                                            }
                                                            if (s4 === peg$FAILED) {
                                                                s4 = null;
                                                            }
                                                            if (s4 !== peg$FAILED) {
                                                                s5 = peg$currPos;
                                                                if (input.charCodeAt(peg$currPos) === 58) {
                                                                    s6 = peg$c24;
                                                                    peg$currPos++;
                                                                }
                                                                else {
                                                                    s6 = peg$FAILED;
                                                                    if (peg$silentFails === 0) {
                                                                        peg$fail(peg$c25);
                                                                    }
                                                                }
                                                                if (s6 !== peg$FAILED) {
                                                                    s7 = peg$parseh16();
                                                                    if (s7 !== peg$FAILED) {
                                                                        s6 = [s6, s7];
                                                                        s5 = s6;
                                                                    }
                                                                    else {
                                                                        peg$currPos = s5;
                                                                        s5 = peg$FAILED;
                                                                    }
                                                                }
                                                                else {
                                                                    peg$currPos = s5;
                                                                    s5 = peg$FAILED;
                                                                }
                                                                if (s5 === peg$FAILED) {
                                                                    s5 = null;
                                                                }
                                                                if (s5 !== peg$FAILED) {
                                                                    if (input.substr(peg$currPos, 2) === peg$c126) {
                                                                        s6 = peg$c126;
                                                                        peg$currPos += 2;
                                                                    }
                                                                    else {
                                                                        s6 = peg$FAILED;
                                                                        if (peg$silentFails === 0) {
                                                                            peg$fail(peg$c127);
                                                                        }
                                                                    }
                                                                    if (s6 !== peg$FAILED) {
                                                                        s7 = peg$parseh16();
                                                                        if (s7 !== peg$FAILED) {
                                                                            if (input.charCodeAt(peg$currPos) === 58) {
                                                                                s8 = peg$c24;
                                                                                peg$currPos++;
                                                                            }
                                                                            else {
                                                                                s8 = peg$FAILED;
                                                                                if (peg$silentFails === 0) {
                                                                                    peg$fail(peg$c25);
                                                                                }
                                                                            }
                                                                            if (s8 !== peg$FAILED) {
                                                                                s9 = peg$parsels32();
                                                                                if (s9 !== peg$FAILED) {
                                                                                    s2 = [s2, s3, s4, s5, s6, s7, s8, s9];
                                                                                    s1 = s2;
                                                                                }
                                                                                else {
                                                                                    peg$currPos = s1;
                                                                                    s1 = peg$FAILED;
                                                                                }
                                                                            }
                                                                            else {
                                                                                peg$currPos = s1;
                                                                                s1 = peg$FAILED;
                                                                            }
                                                                        }
                                                                        else {
                                                                            peg$currPos = s1;
                                                                            s1 = peg$FAILED;
                                                                        }
                                                                    }
                                                                    else {
                                                                        peg$currPos = s1;
                                                                        s1 = peg$FAILED;
                                                                    }
                                                                }
                                                                else {
                                                                    peg$currPos = s1;
                                                                    s1 = peg$FAILED;
                                                                }
                                                            }
                                                            else {
                                                                peg$currPos = s1;
                                                                s1 = peg$FAILED;
                                                            }
                                                        }
                                                        else {
                                                            peg$currPos = s1;
                                                            s1 = peg$FAILED;
                                                        }
                                                    }
                                                    else {
                                                        peg$currPos = s1;
                                                        s1 = peg$FAILED;
                                                    }
                                                    if (s1 === peg$FAILED) {
                                                        s1 = peg$currPos;
                                                        s2 = peg$parseh16();
                                                        if (s2 !== peg$FAILED) {
                                                            s3 = peg$currPos;
                                                            if (input.charCodeAt(peg$currPos) === 58) {
                                                                s4 = peg$c24;
                                                                peg$currPos++;
                                                            }
                                                            else {
                                                                s4 = peg$FAILED;
                                                                if (peg$silentFails === 0) {
                                                                    peg$fail(peg$c25);
                                                                }
                                                            }
                                                            if (s4 !== peg$FAILED) {
                                                                s5 = peg$parseh16();
                                                                if (s5 !== peg$FAILED) {
                                                                    s4 = [s4, s5];
                                                                    s3 = s4;
                                                                }
                                                                else {
                                                                    peg$currPos = s3;
                                                                    s3 = peg$FAILED;
                                                                }
                                                            }
                                                            else {
                                                                peg$currPos = s3;
                                                                s3 = peg$FAILED;
                                                            }
                                                            if (s3 === peg$FAILED) {
                                                                s3 = null;
                                                            }
                                                            if (s3 !== peg$FAILED) {
                                                                s4 = peg$currPos;
                                                                if (input.charCodeAt(peg$currPos) === 58) {
                                                                    s5 = peg$c24;
                                                                    peg$currPos++;
                                                                }
                                                                else {
                                                                    s5 = peg$FAILED;
                                                                    if (peg$silentFails === 0) {
                                                                        peg$fail(peg$c25);
                                                                    }
                                                                }
                                                                if (s5 !== peg$FAILED) {
                                                                    s6 = peg$parseh16();
                                                                    if (s6 !== peg$FAILED) {
                                                                        s5 = [s5, s6];
                                                                        s4 = s5;
                                                                    }
                                                                    else {
                                                                        peg$currPos = s4;
                                                                        s4 = peg$FAILED;
                                                                    }
                                                                }
                                                                else {
                                                                    peg$currPos = s4;
                                                                    s4 = peg$FAILED;
                                                                }
                                                                if (s4 === peg$FAILED) {
                                                                    s4 = null;
                                                                }
                                                                if (s4 !== peg$FAILED) {
                                                                    s5 = peg$currPos;
                                                                    if (input.charCodeAt(peg$currPos) === 58) {
                                                                        s6 = peg$c24;
                                                                        peg$currPos++;
                                                                    }
                                                                    else {
                                                                        s6 = peg$FAILED;
                                                                        if (peg$silentFails === 0) {
                                                                            peg$fail(peg$c25);
                                                                        }
                                                                    }
                                                                    if (s6 !== peg$FAILED) {
                                                                        s7 = peg$parseh16();
                                                                        if (s7 !== peg$FAILED) {
                                                                            s6 = [s6, s7];
                                                                            s5 = s6;
                                                                        }
                                                                        else {
                                                                            peg$currPos = s5;
                                                                            s5 = peg$FAILED;
                                                                        }
                                                                    }
                                                                    else {
                                                                        peg$currPos = s5;
                                                                        s5 = peg$FAILED;
                                                                    }
                                                                    if (s5 === peg$FAILED) {
                                                                        s5 = null;
                                                                    }
                                                                    if (s5 !== peg$FAILED) {
                                                                        s6 = peg$currPos;
                                                                        if (input.charCodeAt(peg$currPos) === 58) {
                                                                            s7 = peg$c24;
                                                                            peg$currPos++;
                                                                        }
                                                                        else {
                                                                            s7 = peg$FAILED;
                                                                            if (peg$silentFails === 0) {
                                                                                peg$fail(peg$c25);
                                                                            }
                                                                        }
                                                                        if (s7 !== peg$FAILED) {
                                                                            s8 = peg$parseh16();
                                                                            if (s8 !== peg$FAILED) {
                                                                                s7 = [s7, s8];
                                                                                s6 = s7;
                                                                            }
                                                                            else {
                                                                                peg$currPos = s6;
                                                                                s6 = peg$FAILED;
                                                                            }
                                                                        }
                                                                        else {
                                                                            peg$currPos = s6;
                                                                            s6 = peg$FAILED;
                                                                        }
                                                                        if (s6 === peg$FAILED) {
                                                                            s6 = null;
                                                                        }
                                                                        if (s6 !== peg$FAILED) {
                                                                            if (input.substr(peg$currPos, 2) === peg$c126) {
                                                                                s7 = peg$c126;
                                                                                peg$currPos += 2;
                                                                            }
                                                                            else {
                                                                                s7 = peg$FAILED;
                                                                                if (peg$silentFails === 0) {
                                                                                    peg$fail(peg$c127);
                                                                                }
                                                                            }
                                                                            if (s7 !== peg$FAILED) {
                                                                                s8 = peg$parsels32();
                                                                                if (s8 !== peg$FAILED) {
                                                                                    s2 = [s2, s3, s4, s5, s6, s7, s8];
                                                                                    s1 = s2;
                                                                                }
                                                                                else {
                                                                                    peg$currPos = s1;
                                                                                    s1 = peg$FAILED;
                                                                                }
                                                                            }
                                                                            else {
                                                                                peg$currPos = s1;
                                                                                s1 = peg$FAILED;
                                                                            }
                                                                        }
                                                                        else {
                                                                            peg$currPos = s1;
                                                                            s1 = peg$FAILED;
                                                                        }
                                                                    }
                                                                    else {
                                                                        peg$currPos = s1;
                                                                        s1 = peg$FAILED;
                                                                    }
                                                                }
                                                                else {
                                                                    peg$currPos = s1;
                                                                    s1 = peg$FAILED;
                                                                }
                                                            }
                                                            else {
                                                                peg$currPos = s1;
                                                                s1 = peg$FAILED;
                                                            }
                                                        }
                                                        else {
                                                            peg$currPos = s1;
                                                            s1 = peg$FAILED;
                                                        }
                                                        if (s1 === peg$FAILED) {
                                                            s1 = peg$currPos;
                                                            s2 = peg$parseh16();
                                                            if (s2 !== peg$FAILED) {
                                                                s3 = peg$currPos;
                                                                if (input.charCodeAt(peg$currPos) === 58) {
                                                                    s4 = peg$c24;
                                                                    peg$currPos++;
                                                                }
                                                                else {
                                                                    s4 = peg$FAILED;
                                                                    if (peg$silentFails === 0) {
                                                                        peg$fail(peg$c25);
                                                                    }
                                                                }
                                                                if (s4 !== peg$FAILED) {
                                                                    s5 = peg$parseh16();
                                                                    if (s5 !== peg$FAILED) {
                                                                        s4 = [s4, s5];
                                                                        s3 = s4;
                                                                    }
                                                                    else {
                                                                        peg$currPos = s3;
                                                                        s3 = peg$FAILED;
                                                                    }
                                                                }
                                                                else {
                                                                    peg$currPos = s3;
                                                                    s3 = peg$FAILED;
                                                                }
                                                                if (s3 === peg$FAILED) {
                                                                    s3 = null;
                                                                }
                                                                if (s3 !== peg$FAILED) {
                                                                    s4 = peg$currPos;
                                                                    if (input.charCodeAt(peg$currPos) === 58) {
                                                                        s5 = peg$c24;
                                                                        peg$currPos++;
                                                                    }
                                                                    else {
                                                                        s5 = peg$FAILED;
                                                                        if (peg$silentFails === 0) {
                                                                            peg$fail(peg$c25);
                                                                        }
                                                                    }
                                                                    if (s5 !== peg$FAILED) {
                                                                        s6 = peg$parseh16();
                                                                        if (s6 !== peg$FAILED) {
                                                                            s5 = [s5, s6];
                                                                            s4 = s5;
                                                                        }
                                                                        else {
                                                                            peg$currPos = s4;
                                                                            s4 = peg$FAILED;
                                                                        }
                                                                    }
                                                                    else {
                                                                        peg$currPos = s4;
                                                                        s4 = peg$FAILED;
                                                                    }
                                                                    if (s4 === peg$FAILED) {
                                                                        s4 = null;
                                                                    }
                                                                    if (s4 !== peg$FAILED) {
                                                                        s5 = peg$currPos;
                                                                        if (input.charCodeAt(peg$currPos) === 58) {
                                                                            s6 = peg$c24;
                                                                            peg$currPos++;
                                                                        }
                                                                        else {
                                                                            s6 = peg$FAILED;
                                                                            if (peg$silentFails === 0) {
                                                                                peg$fail(peg$c25);
                                                                            }
                                                                        }
                                                                        if (s6 !== peg$FAILED) {
                                                                            s7 = peg$parseh16();
                                                                            if (s7 !== peg$FAILED) {
                                                                                s6 = [s6, s7];
                                                                                s5 = s6;
                                                                            }
                                                                            else {
                                                                                peg$currPos = s5;
                                                                                s5 = peg$FAILED;
                                                                            }
                                                                        }
                                                                        else {
                                                                            peg$currPos = s5;
                                                                            s5 = peg$FAILED;
                                                                        }
                                                                        if (s5 === peg$FAILED) {
                                                                            s5 = null;
                                                                        }
                                                                        if (s5 !== peg$FAILED) {
                                                                            s6 = peg$currPos;
                                                                            if (input.charCodeAt(peg$currPos) === 58) {
                                                                                s7 = peg$c24;
                                                                                peg$currPos++;
                                                                            }
                                                                            else {
                                                                                s7 = peg$FAILED;
                                                                                if (peg$silentFails === 0) {
                                                                                    peg$fail(peg$c25);
                                                                                }
                                                                            }
                                                                            if (s7 !== peg$FAILED) {
                                                                                s8 = peg$parseh16();
                                                                                if (s8 !== peg$FAILED) {
                                                                                    s7 = [s7, s8];
                                                                                    s6 = s7;
                                                                                }
                                                                                else {
                                                                                    peg$currPos = s6;
                                                                                    s6 = peg$FAILED;
                                                                                }
                                                                            }
                                                                            else {
                                                                                peg$currPos = s6;
                                                                                s6 = peg$FAILED;
                                                                            }
                                                                            if (s6 === peg$FAILED) {
                                                                                s6 = null;
                                                                            }
                                                                            if (s6 !== peg$FAILED) {
                                                                                s7 = peg$currPos;
                                                                                if (input.charCodeAt(peg$currPos) === 58) {
                                                                                    s8 = peg$c24;
                                                                                    peg$currPos++;
                                                                                }
                                                                                else {
                                                                                    s8 = peg$FAILED;
                                                                                    if (peg$silentFails === 0) {
                                                                                        peg$fail(peg$c25);
                                                                                    }
                                                                                }
                                                                                if (s8 !== peg$FAILED) {
                                                                                    s9 = peg$parseh16();
                                                                                    if (s9 !== peg$FAILED) {
                                                                                        s8 = [s8, s9];
                                                                                        s7 = s8;
                                                                                    }
                                                                                    else {
                                                                                        peg$currPos = s7;
                                                                                        s7 = peg$FAILED;
                                                                                    }
                                                                                }
                                                                                else {
                                                                                    peg$currPos = s7;
                                                                                    s7 = peg$FAILED;
                                                                                }
                                                                                if (s7 === peg$FAILED) {
                                                                                    s7 = null;
                                                                                }
                                                                                if (s7 !== peg$FAILED) {
                                                                                    if (input.substr(peg$currPos, 2) === peg$c126) {
                                                                                        s8 = peg$c126;
                                                                                        peg$currPos += 2;
                                                                                    }
                                                                                    else {
                                                                                        s8 = peg$FAILED;
                                                                                        if (peg$silentFails === 0) {
                                                                                            peg$fail(peg$c127);
                                                                                        }
                                                                                    }
                                                                                    if (s8 !== peg$FAILED) {
                                                                                        s9 = peg$parseh16();
                                                                                        if (s9 !== peg$FAILED) {
                                                                                            s2 = [s2, s3, s4, s5, s6, s7, s8, s9];
                                                                                            s1 = s2;
                                                                                        }
                                                                                        else {
                                                                                            peg$currPos = s1;
                                                                                            s1 = peg$FAILED;
                                                                                        }
                                                                                    }
                                                                                    else {
                                                                                        peg$currPos = s1;
                                                                                        s1 = peg$FAILED;
                                                                                    }
                                                                                }
                                                                                else {
                                                                                    peg$currPos = s1;
                                                                                    s1 = peg$FAILED;
                                                                                }
                                                                            }
                                                                            else {
                                                                                peg$currPos = s1;
                                                                                s1 = peg$FAILED;
                                                                            }
                                                                        }
                                                                        else {
                                                                            peg$currPos = s1;
                                                                            s1 = peg$FAILED;
                                                                        }
                                                                    }
                                                                    else {
                                                                        peg$currPos = s1;
                                                                        s1 = peg$FAILED;
                                                                    }
                                                                }
                                                                else {
                                                                    peg$currPos = s1;
                                                                    s1 = peg$FAILED;
                                                                }
                                                            }
                                                            else {
                                                                peg$currPos = s1;
                                                                s1 = peg$FAILED;
                                                            }
                                                            if (s1 === peg$FAILED) {
                                                                s1 = peg$currPos;
                                                                s2 = peg$parseh16();
                                                                if (s2 !== peg$FAILED) {
                                                                    s3 = peg$currPos;
                                                                    if (input.charCodeAt(peg$currPos) === 58) {
                                                                        s4 = peg$c24;
                                                                        peg$currPos++;
                                                                    }
                                                                    else {
                                                                        s4 = peg$FAILED;
                                                                        if (peg$silentFails === 0) {
                                                                            peg$fail(peg$c25);
                                                                        }
                                                                    }
                                                                    if (s4 !== peg$FAILED) {
                                                                        s5 = peg$parseh16();
                                                                        if (s5 !== peg$FAILED) {
                                                                            s4 = [s4, s5];
                                                                            s3 = s4;
                                                                        }
                                                                        else {
                                                                            peg$currPos = s3;
                                                                            s3 = peg$FAILED;
                                                                        }
                                                                    }
                                                                    else {
                                                                        peg$currPos = s3;
                                                                        s3 = peg$FAILED;
                                                                    }
                                                                    if (s3 === peg$FAILED) {
                                                                        s3 = null;
                                                                    }
                                                                    if (s3 !== peg$FAILED) {
                                                                        s4 = peg$currPos;
                                                                        if (input.charCodeAt(peg$currPos) === 58) {
                                                                            s5 = peg$c24;
                                                                            peg$currPos++;
                                                                        }
                                                                        else {
                                                                            s5 = peg$FAILED;
                                                                            if (peg$silentFails === 0) {
                                                                                peg$fail(peg$c25);
                                                                            }
                                                                        }
                                                                        if (s5 !== peg$FAILED) {
                                                                            s6 = peg$parseh16();
                                                                            if (s6 !== peg$FAILED) {
                                                                                s5 = [s5, s6];
                                                                                s4 = s5;
                                                                            }
                                                                            else {
                                                                                peg$currPos = s4;
                                                                                s4 = peg$FAILED;
                                                                            }
                                                                        }
                                                                        else {
                                                                            peg$currPos = s4;
                                                                            s4 = peg$FAILED;
                                                                        }
                                                                        if (s4 === peg$FAILED) {
                                                                            s4 = null;
                                                                        }
                                                                        if (s4 !== peg$FAILED) {
                                                                            s5 = peg$currPos;
                                                                            if (input.charCodeAt(peg$currPos) === 58) {
                                                                                s6 = peg$c24;
                                                                                peg$currPos++;
                                                                            }
                                                                            else {
                                                                                s6 = peg$FAILED;
                                                                                if (peg$silentFails === 0) {
                                                                                    peg$fail(peg$c25);
                                                                                }
                                                                            }
                                                                            if (s6 !== peg$FAILED) {
                                                                                s7 = peg$parseh16();
                                                                                if (s7 !== peg$FAILED) {
                                                                                    s6 = [s6, s7];
                                                                                    s5 = s6;
                                                                                }
                                                                                else {
                                                                                    peg$currPos = s5;
                                                                                    s5 = peg$FAILED;
                                                                                }
                                                                            }
                                                                            else {
                                                                                peg$currPos = s5;
                                                                                s5 = peg$FAILED;
                                                                            }
                                                                            if (s5 === peg$FAILED) {
                                                                                s5 = null;
                                                                            }
                                                                            if (s5 !== peg$FAILED) {
                                                                                s6 = peg$currPos;
                                                                                if (input.charCodeAt(peg$currPos) === 58) {
                                                                                    s7 = peg$c24;
                                                                                    peg$currPos++;
                                                                                }
                                                                                else {
                                                                                    s7 = peg$FAILED;
                                                                                    if (peg$silentFails === 0) {
                                                                                        peg$fail(peg$c25);
                                                                                    }
                                                                                }
                                                                                if (s7 !== peg$FAILED) {
                                                                                    s8 = peg$parseh16();
                                                                                    if (s8 !== peg$FAILED) {
                                                                                        s7 = [s7, s8];
                                                                                        s6 = s7;
                                                                                    }
                                                                                    else {
                                                                                        peg$currPos = s6;
                                                                                        s6 = peg$FAILED;
                                                                                    }
                                                                                }
                                                                                else {
                                                                                    peg$currPos = s6;
                                                                                    s6 = peg$FAILED;
                                                                                }
                                                                                if (s6 === peg$FAILED) {
                                                                                    s6 = null;
                                                                                }
                                                                                if (s6 !== peg$FAILED) {
                                                                                    s7 = peg$currPos;
                                                                                    if (input.charCodeAt(peg$currPos) === 58) {
                                                                                        s8 = peg$c24;
                                                                                        peg$currPos++;
                                                                                    }
                                                                                    else {
                                                                                        s8 = peg$FAILED;
                                                                                        if (peg$silentFails === 0) {
                                                                                            peg$fail(peg$c25);
                                                                                        }
                                                                                    }
                                                                                    if (s8 !== peg$FAILED) {
                                                                                        s9 = peg$parseh16();
                                                                                        if (s9 !== peg$FAILED) {
                                                                                            s8 = [s8, s9];
                                                                                            s7 = s8;
                                                                                        }
                                                                                        else {
                                                                                            peg$currPos = s7;
                                                                                            s7 = peg$FAILED;
                                                                                        }
                                                                                    }
                                                                                    else {
                                                                                        peg$currPos = s7;
                                                                                        s7 = peg$FAILED;
                                                                                    }
                                                                                    if (s7 === peg$FAILED) {
                                                                                        s7 = null;
                                                                                    }
                                                                                    if (s7 !== peg$FAILED) {
                                                                                        s8 = peg$currPos;
                                                                                        if (input.charCodeAt(peg$currPos) === 58) {
                                                                                            s9 = peg$c24;
                                                                                            peg$currPos++;
                                                                                        }
                                                                                        else {
                                                                                            s9 = peg$FAILED;
                                                                                            if (peg$silentFails === 0) {
                                                                                                peg$fail(peg$c25);
                                                                                            }
                                                                                        }
                                                                                        if (s9 !== peg$FAILED) {
                                                                                            s10 = peg$parseh16();
                                                                                            if (s10 !== peg$FAILED) {
                                                                                                s9 = [s9, s10];
                                                                                                s8 = s9;
                                                                                            }
                                                                                            else {
                                                                                                peg$currPos = s8;
                                                                                                s8 = peg$FAILED;
                                                                                            }
                                                                                        }
                                                                                        else {
                                                                                            peg$currPos = s8;
                                                                                            s8 = peg$FAILED;
                                                                                        }
                                                                                        if (s8 === peg$FAILED) {
                                                                                            s8 = null;
                                                                                        }
                                                                                        if (s8 !== peg$FAILED) {
                                                                                            if (input.substr(peg$currPos, 2) === peg$c126) {
                                                                                                s9 = peg$c126;
                                                                                                peg$currPos += 2;
                                                                                            }
                                                                                            else {
                                                                                                s9 = peg$FAILED;
                                                                                                if (peg$silentFails === 0) {
                                                                                                    peg$fail(peg$c127);
                                                                                                }
                                                                                            }
                                                                                            if (s9 !== peg$FAILED) {
                                                                                                s2 = [s2, s3, s4, s5, s6, s7, s8, s9];
                                                                                                s1 = s2;
                                                                                            }
                                                                                            else {
                                                                                                peg$currPos = s1;
                                                                                                s1 = peg$FAILED;
                                                                                            }
                                                                                        }
                                                                                        else {
                                                                                            peg$currPos = s1;
                                                                                            s1 = peg$FAILED;
                                                                                        }
                                                                                    }
                                                                                    else {
                                                                                        peg$currPos = s1;
                                                                                        s1 = peg$FAILED;
                                                                                    }
                                                                                }
                                                                                else {
                                                                                    peg$currPos = s1;
                                                                                    s1 = peg$FAILED;
                                                                                }
                                                                            }
                                                                            else {
                                                                                peg$currPos = s1;
                                                                                s1 = peg$FAILED;
                                                                            }
                                                                        }
                                                                        else {
                                                                            peg$currPos = s1;
                                                                            s1 = peg$FAILED;
                                                                        }
                                                                    }
                                                                    else {
                                                                        peg$currPos = s1;
                                                                        s1 = peg$FAILED;
                                                                    }
                                                                }
                                                                else {
                                                                    peg$currPos = s1;
                                                                    s1 = peg$FAILED;
                                                                }
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        if (s1 !== peg$FAILED) {
            peg$savedPos = s0;
            s1 = peg$c128();
        }
        s0 = s1;
        return s0;
    }
    function peg$parseh16() {
        var s0, s1, s2, s3, s4;
        s0 = peg$currPos;
        s1 = peg$parseHEXDIG();
        if (s1 !== peg$FAILED) {
            s2 = peg$parseHEXDIG();
            if (s2 === peg$FAILED) {
                s2 = null;
            }
            if (s2 !== peg$FAILED) {
                s3 = peg$parseHEXDIG();
                if (s3 === peg$FAILED) {
                    s3 = null;
                }
                if (s3 !== peg$FAILED) {
                    s4 = peg$parseHEXDIG();
                    if (s4 === peg$FAILED) {
                        s4 = null;
                    }
                    if (s4 !== peg$FAILED) {
                        s1 = [s1, s2, s3, s4];
                        s0 = s1;
                    }
                    else {
                        peg$currPos = s0;
                        s0 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parsels32() {
        var s0, s1, s2, s3;
        s0 = peg$currPos;
        s1 = peg$parseh16();
        if (s1 !== peg$FAILED) {
            if (input.charCodeAt(peg$currPos) === 58) {
                s2 = peg$c24;
                peg$currPos++;
            }
            else {
                s2 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c25);
                }
            }
            if (s2 !== peg$FAILED) {
                s3 = peg$parseh16();
                if (s3 !== peg$FAILED) {
                    s1 = [s1, s2, s3];
                    s0 = s1;
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        if (s0 === peg$FAILED) {
            s0 = peg$parseIPv4address();
        }
        return s0;
    }
    function peg$parseIPv4address() {
        var s0, s1, s2, s3, s4, s5, s6, s7;
        s0 = peg$currPos;
        s1 = peg$parsedec_octet();
        if (s1 !== peg$FAILED) {
            if (input.charCodeAt(peg$currPos) === 46) {
                s2 = peg$c42;
                peg$currPos++;
            }
            else {
                s2 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c43);
                }
            }
            if (s2 !== peg$FAILED) {
                s3 = peg$parsedec_octet();
                if (s3 !== peg$FAILED) {
                    if (input.charCodeAt(peg$currPos) === 46) {
                        s4 = peg$c42;
                        peg$currPos++;
                    }
                    else {
                        s4 = peg$FAILED;
                        if (peg$silentFails === 0) {
                            peg$fail(peg$c43);
                        }
                    }
                    if (s4 !== peg$FAILED) {
                        s5 = peg$parsedec_octet();
                        if (s5 !== peg$FAILED) {
                            if (input.charCodeAt(peg$currPos) === 46) {
                                s6 = peg$c42;
                                peg$currPos++;
                            }
                            else {
                                s6 = peg$FAILED;
                                if (peg$silentFails === 0) {
                                    peg$fail(peg$c43);
                                }
                            }
                            if (s6 !== peg$FAILED) {
                                s7 = peg$parsedec_octet();
                                if (s7 !== peg$FAILED) {
                                    peg$savedPos = s0;
                                    s1 = peg$c129();
                                    s0 = s1;
                                }
                                else {
                                    peg$currPos = s0;
                                    s0 = peg$FAILED;
                                }
                            }
                            else {
                                peg$currPos = s0;
                                s0 = peg$FAILED;
                            }
                        }
                        else {
                            peg$currPos = s0;
                            s0 = peg$FAILED;
                        }
                    }
                    else {
                        peg$currPos = s0;
                        s0 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parsedec_octet() {
        var s0, s1, s2, s3;
        s0 = peg$currPos;
        if (input.substr(peg$currPos, 2) === peg$c130) {
            s1 = peg$c130;
            peg$currPos += 2;
        }
        else {
            s1 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c131);
            }
        }
        if (s1 !== peg$FAILED) {
            if (peg$c132.test(input.charAt(peg$currPos))) {
                s2 = input.charAt(peg$currPos);
                peg$currPos++;
            }
            else {
                s2 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c133);
                }
            }
            if (s2 !== peg$FAILED) {
                s1 = [s1, s2];
                s0 = s1;
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        if (s0 === peg$FAILED) {
            s0 = peg$currPos;
            if (input.charCodeAt(peg$currPos) === 50) {
                s1 = peg$c134;
                peg$currPos++;
            }
            else {
                s1 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c135);
                }
            }
            if (s1 !== peg$FAILED) {
                if (peg$c136.test(input.charAt(peg$currPos))) {
                    s2 = input.charAt(peg$currPos);
                    peg$currPos++;
                }
                else {
                    s2 = peg$FAILED;
                    if (peg$silentFails === 0) {
                        peg$fail(peg$c137);
                    }
                }
                if (s2 !== peg$FAILED) {
                    s3 = peg$parseDIGIT();
                    if (s3 !== peg$FAILED) {
                        s1 = [s1, s2, s3];
                        s0 = s1;
                    }
                    else {
                        peg$currPos = s0;
                        s0 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
            if (s0 === peg$FAILED) {
                s0 = peg$currPos;
                if (input.charCodeAt(peg$currPos) === 49) {
                    s1 = peg$c138;
                    peg$currPos++;
                }
                else {
                    s1 = peg$FAILED;
                    if (peg$silentFails === 0) {
                        peg$fail(peg$c139);
                    }
                }
                if (s1 !== peg$FAILED) {
                    s2 = peg$parseDIGIT();
                    if (s2 !== peg$FAILED) {
                        s3 = peg$parseDIGIT();
                        if (s3 !== peg$FAILED) {
                            s1 = [s1, s2, s3];
                            s0 = s1;
                        }
                        else {
                            peg$currPos = s0;
                            s0 = peg$FAILED;
                        }
                    }
                    else {
                        peg$currPos = s0;
                        s0 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
                if (s0 === peg$FAILED) {
                    s0 = peg$currPos;
                    if (peg$c140.test(input.charAt(peg$currPos))) {
                        s1 = input.charAt(peg$currPos);
                        peg$currPos++;
                    }
                    else {
                        s1 = peg$FAILED;
                        if (peg$silentFails === 0) {
                            peg$fail(peg$c141);
                        }
                    }
                    if (s1 !== peg$FAILED) {
                        s2 = peg$parseDIGIT();
                        if (s2 !== peg$FAILED) {
                            s1 = [s1, s2];
                            s0 = s1;
                        }
                        else {
                            peg$currPos = s0;
                            s0 = peg$FAILED;
                        }
                    }
                    else {
                        peg$currPos = s0;
                        s0 = peg$FAILED;
                    }
                    if (s0 === peg$FAILED) {
                        s0 = peg$parseDIGIT();
                    }
                }
            }
        }
        return s0;
    }
    function peg$parseport() {
        var s0, s1, s2, s3, s4, s5, s6;
        s0 = peg$currPos;
        s1 = peg$currPos;
        s2 = peg$parseDIGIT();
        if (s2 === peg$FAILED) {
            s2 = null;
        }
        if (s2 !== peg$FAILED) {
            s3 = peg$parseDIGIT();
            if (s3 === peg$FAILED) {
                s3 = null;
            }
            if (s3 !== peg$FAILED) {
                s4 = peg$parseDIGIT();
                if (s4 === peg$FAILED) {
                    s4 = null;
                }
                if (s4 !== peg$FAILED) {
                    s5 = peg$parseDIGIT();
                    if (s5 === peg$FAILED) {
                        s5 = null;
                    }
                    if (s5 !== peg$FAILED) {
                        s6 = peg$parseDIGIT();
                        if (s6 === peg$FAILED) {
                            s6 = null;
                        }
                        if (s6 !== peg$FAILED) {
                            s2 = [s2, s3, s4, s5, s6];
                            s1 = s2;
                        }
                        else {
                            peg$currPos = s1;
                            s1 = peg$FAILED;
                        }
                    }
                    else {
                        peg$currPos = s1;
                        s1 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s1;
                    s1 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s1;
                s1 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s1;
            s1 = peg$FAILED;
        }
        if (s1 !== peg$FAILED) {
            peg$savedPos = s0;
            s1 = peg$c142(s1);
        }
        s0 = s1;
        return s0;
    }
    function peg$parseuri_parameters() {
        var s0, s1, s2, s3;
        s0 = [];
        s1 = peg$currPos;
        if (input.charCodeAt(peg$currPos) === 59) {
            s2 = peg$c18;
            peg$currPos++;
        }
        else {
            s2 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c19);
            }
        }
        if (s2 !== peg$FAILED) {
            s3 = peg$parseuri_parameter();
            if (s3 !== peg$FAILED) {
                s2 = [s2, s3];
                s1 = s2;
            }
            else {
                peg$currPos = s1;
                s1 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s1;
            s1 = peg$FAILED;
        }
        while (s1 !== peg$FAILED) {
            s0.push(s1);
            s1 = peg$currPos;
            if (input.charCodeAt(peg$currPos) === 59) {
                s2 = peg$c18;
                peg$currPos++;
            }
            else {
                s2 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c19);
                }
            }
            if (s2 !== peg$FAILED) {
                s3 = peg$parseuri_parameter();
                if (s3 !== peg$FAILED) {
                    s2 = [s2, s3];
                    s1 = s2;
                }
                else {
                    peg$currPos = s1;
                    s1 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s1;
                s1 = peg$FAILED;
            }
        }
        return s0;
    }
    function peg$parseuri_parameter() {
        var s0;
        s0 = peg$parsetransport_param();
        if (s0 === peg$FAILED) {
            s0 = peg$parseuser_param();
            if (s0 === peg$FAILED) {
                s0 = peg$parsemethod_param();
                if (s0 === peg$FAILED) {
                    s0 = peg$parsettl_param();
                    if (s0 === peg$FAILED) {
                        s0 = peg$parsemaddr_param();
                        if (s0 === peg$FAILED) {
                            s0 = peg$parselr_param();
                            if (s0 === peg$FAILED) {
                                s0 = peg$parseother_param();
                            }
                        }
                    }
                }
            }
        }
        return s0;
    }
    function peg$parsetransport_param() {
        var s0, s1, s2;
        s0 = peg$currPos;
        if (input.substr(peg$currPos, 10).toLowerCase() === peg$c143) {
            s1 = input.substr(peg$currPos, 10);
            peg$currPos += 10;
        }
        else {
            s1 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c144);
            }
        }
        if (s1 !== peg$FAILED) {
            if (input.substr(peg$currPos, 3).toLowerCase() === peg$c145) {
                s2 = input.substr(peg$currPos, 3);
                peg$currPos += 3;
            }
            else {
                s2 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c146);
                }
            }
            if (s2 === peg$FAILED) {
                if (input.substr(peg$currPos, 3).toLowerCase() === peg$c147) {
                    s2 = input.substr(peg$currPos, 3);
                    peg$currPos += 3;
                }
                else {
                    s2 = peg$FAILED;
                    if (peg$silentFails === 0) {
                        peg$fail(peg$c148);
                    }
                }
                if (s2 === peg$FAILED) {
                    if (input.substr(peg$currPos, 4).toLowerCase() === peg$c149) {
                        s2 = input.substr(peg$currPos, 4);
                        peg$currPos += 4;
                    }
                    else {
                        s2 = peg$FAILED;
                        if (peg$silentFails === 0) {
                            peg$fail(peg$c150);
                        }
                    }
                    if (s2 === peg$FAILED) {
                        if (input.substr(peg$currPos, 3).toLowerCase() === peg$c151) {
                            s2 = input.substr(peg$currPos, 3);
                            peg$currPos += 3;
                        }
                        else {
                            s2 = peg$FAILED;
                            if (peg$silentFails === 0) {
                                peg$fail(peg$c152);
                            }
                        }
                        if (s2 === peg$FAILED) {
                            s2 = peg$parsetoken();
                        }
                    }
                }
            }
            if (s2 !== peg$FAILED) {
                peg$savedPos = s0;
                s1 = peg$c153(s2);
                s0 = s1;
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parseuser_param() {
        var s0, s1, s2;
        s0 = peg$currPos;
        if (input.substr(peg$currPos, 5).toLowerCase() === peg$c154) {
            s1 = input.substr(peg$currPos, 5);
            peg$currPos += 5;
        }
        else {
            s1 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c155);
            }
        }
        if (s1 !== peg$FAILED) {
            if (input.substr(peg$currPos, 5).toLowerCase() === peg$c156) {
                s2 = input.substr(peg$currPos, 5);
                peg$currPos += 5;
            }
            else {
                s2 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c157);
                }
            }
            if (s2 === peg$FAILED) {
                if (input.substr(peg$currPos, 2).toLowerCase() === peg$c158) {
                    s2 = input.substr(peg$currPos, 2);
                    peg$currPos += 2;
                }
                else {
                    s2 = peg$FAILED;
                    if (peg$silentFails === 0) {
                        peg$fail(peg$c159);
                    }
                }
                if (s2 === peg$FAILED) {
                    s2 = peg$parsetoken();
                }
            }
            if (s2 !== peg$FAILED) {
                peg$savedPos = s0;
                s1 = peg$c160(s2);
                s0 = s1;
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parsemethod_param() {
        var s0, s1, s2;
        s0 = peg$currPos;
        if (input.substr(peg$currPos, 7).toLowerCase() === peg$c161) {
            s1 = input.substr(peg$currPos, 7);
            peg$currPos += 7;
        }
        else {
            s1 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c162);
            }
        }
        if (s1 !== peg$FAILED) {
            s2 = peg$parseMethod();
            if (s2 !== peg$FAILED) {
                peg$savedPos = s0;
                s1 = peg$c163(s2);
                s0 = s1;
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parsettl_param() {
        var s0, s1, s2;
        s0 = peg$currPos;
        if (input.substr(peg$currPos, 4).toLowerCase() === peg$c164) {
            s1 = input.substr(peg$currPos, 4);
            peg$currPos += 4;
        }
        else {
            s1 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c165);
            }
        }
        if (s1 !== peg$FAILED) {
            s2 = peg$parsettl();
            if (s2 !== peg$FAILED) {
                peg$savedPos = s0;
                s1 = peg$c166(s2);
                s0 = s1;
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parsemaddr_param() {
        var s0, s1, s2;
        s0 = peg$currPos;
        if (input.substr(peg$currPos, 6).toLowerCase() === peg$c167) {
            s1 = input.substr(peg$currPos, 6);
            peg$currPos += 6;
        }
        else {
            s1 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c168);
            }
        }
        if (s1 !== peg$FAILED) {
            s2 = peg$parsehost();
            if (s2 !== peg$FAILED) {
                peg$savedPos = s0;
                s1 = peg$c169(s2);
                s0 = s1;
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parselr_param() {
        var s0, s1, s2, s3, s4;
        s0 = peg$currPos;
        if (input.substr(peg$currPos, 2).toLowerCase() === peg$c170) {
            s1 = input.substr(peg$currPos, 2);
            peg$currPos += 2;
        }
        else {
            s1 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c171);
            }
        }
        if (s1 !== peg$FAILED) {
            s2 = peg$currPos;
            if (input.charCodeAt(peg$currPos) === 61) {
                s3 = peg$c30;
                peg$currPos++;
            }
            else {
                s3 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c31);
                }
            }
            if (s3 !== peg$FAILED) {
                s4 = peg$parsetoken();
                if (s4 !== peg$FAILED) {
                    s3 = [s3, s4];
                    s2 = s3;
                }
                else {
                    peg$currPos = s2;
                    s2 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s2;
                s2 = peg$FAILED;
            }
            if (s2 === peg$FAILED) {
                s2 = null;
            }
            if (s2 !== peg$FAILED) {
                peg$savedPos = s0;
                s1 = peg$c172();
                s0 = s1;
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parseother_param() {
        var s0, s1, s2, s3, s4;
        s0 = peg$currPos;
        s1 = peg$parsepname();
        if (s1 !== peg$FAILED) {
            s2 = peg$currPos;
            if (input.charCodeAt(peg$currPos) === 61) {
                s3 = peg$c30;
                peg$currPos++;
            }
            else {
                s3 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c31);
                }
            }
            if (s3 !== peg$FAILED) {
                s4 = peg$parsepvalue();
                if (s4 !== peg$FAILED) {
                    s3 = [s3, s4];
                    s2 = s3;
                }
                else {
                    peg$currPos = s2;
                    s2 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s2;
                s2 = peg$FAILED;
            }
            if (s2 === peg$FAILED) {
                s2 = null;
            }
            if (s2 !== peg$FAILED) {
                peg$savedPos = s0;
                s1 = peg$c173(s1, s2);
                s0 = s1;
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parsepname() {
        var s0, s1, s2;
        s0 = peg$currPos;
        s1 = [];
        s2 = peg$parseparamchar();
        if (s2 !== peg$FAILED) {
            while (s2 !== peg$FAILED) {
                s1.push(s2);
                s2 = peg$parseparamchar();
            }
        }
        else {
            s1 = peg$FAILED;
        }
        if (s1 !== peg$FAILED) {
            s0 = input.substring(s0, peg$currPos);
        }
        else {
            s0 = s1;
        }
        return s0;
    }
    function peg$parsepvalue() {
        var s0, s1, s2;
        s0 = peg$currPos;
        s1 = [];
        s2 = peg$parseparamchar();
        if (s2 !== peg$FAILED) {
            while (s2 !== peg$FAILED) {
                s1.push(s2);
                s2 = peg$parseparamchar();
            }
        }
        else {
            s1 = peg$FAILED;
        }
        if (s1 !== peg$FAILED) {
            s0 = input.substring(s0, peg$currPos);
        }
        else {
            s0 = s1;
        }
        return s0;
    }
    function peg$parseparamchar() {
        var s0;
        s0 = peg$parseparam_unreserved();
        if (s0 === peg$FAILED) {
            s0 = peg$parseunreserved();
            if (s0 === peg$FAILED) {
                s0 = peg$parseescaped();
            }
        }
        return s0;
    }
    function peg$parseparam_unreserved() {
        var s0;
        if (input.charCodeAt(peg$currPos) === 91) {
            s0 = peg$c76;
            peg$currPos++;
        }
        else {
            s0 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c77);
            }
        }
        if (s0 === peg$FAILED) {
            if (input.charCodeAt(peg$currPos) === 93) {
                s0 = peg$c78;
                peg$currPos++;
            }
            else {
                s0 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c79);
                }
            }
            if (s0 === peg$FAILED) {
                if (input.charCodeAt(peg$currPos) === 47) {
                    s0 = peg$c20;
                    peg$currPos++;
                }
                else {
                    s0 = peg$FAILED;
                    if (peg$silentFails === 0) {
                        peg$fail(peg$c21);
                    }
                }
                if (s0 === peg$FAILED) {
                    if (input.charCodeAt(peg$currPos) === 58) {
                        s0 = peg$c24;
                        peg$currPos++;
                    }
                    else {
                        s0 = peg$FAILED;
                        if (peg$silentFails === 0) {
                            peg$fail(peg$c25);
                        }
                    }
                    if (s0 === peg$FAILED) {
                        if (input.charCodeAt(peg$currPos) === 38) {
                            s0 = peg$c28;
                            peg$currPos++;
                        }
                        else {
                            s0 = peg$FAILED;
                            if (peg$silentFails === 0) {
                                peg$fail(peg$c29);
                            }
                        }
                        if (s0 === peg$FAILED) {
                            if (input.charCodeAt(peg$currPos) === 43) {
                                s0 = peg$c32;
                                peg$currPos++;
                            }
                            else {
                                s0 = peg$FAILED;
                                if (peg$silentFails === 0) {
                                    peg$fail(peg$c33);
                                }
                            }
                            if (s0 === peg$FAILED) {
                                if (input.charCodeAt(peg$currPos) === 36) {
                                    s0 = peg$c34;
                                    peg$currPos++;
                                }
                                else {
                                    s0 = peg$FAILED;
                                    if (peg$silentFails === 0) {
                                        peg$fail(peg$c35);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        return s0;
    }
    function peg$parseheaders() {
        var s0, s1, s2, s3, s4, s5, s6;
        s0 = peg$currPos;
        if (input.charCodeAt(peg$currPos) === 63) {
            s1 = peg$c22;
            peg$currPos++;
        }
        else {
            s1 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c23);
            }
        }
        if (s1 !== peg$FAILED) {
            s2 = peg$parseheader();
            if (s2 !== peg$FAILED) {
                s3 = [];
                s4 = peg$currPos;
                if (input.charCodeAt(peg$currPos) === 38) {
                    s5 = peg$c28;
                    peg$currPos++;
                }
                else {
                    s5 = peg$FAILED;
                    if (peg$silentFails === 0) {
                        peg$fail(peg$c29);
                    }
                }
                if (s5 !== peg$FAILED) {
                    s6 = peg$parseheader();
                    if (s6 !== peg$FAILED) {
                        s5 = [s5, s6];
                        s4 = s5;
                    }
                    else {
                        peg$currPos = s4;
                        s4 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s4;
                    s4 = peg$FAILED;
                }
                while (s4 !== peg$FAILED) {
                    s3.push(s4);
                    s4 = peg$currPos;
                    if (input.charCodeAt(peg$currPos) === 38) {
                        s5 = peg$c28;
                        peg$currPos++;
                    }
                    else {
                        s5 = peg$FAILED;
                        if (peg$silentFails === 0) {
                            peg$fail(peg$c29);
                        }
                    }
                    if (s5 !== peg$FAILED) {
                        s6 = peg$parseheader();
                        if (s6 !== peg$FAILED) {
                            s5 = [s5, s6];
                            s4 = s5;
                        }
                        else {
                            peg$currPos = s4;
                            s4 = peg$FAILED;
                        }
                    }
                    else {
                        peg$currPos = s4;
                        s4 = peg$FAILED;
                    }
                }
                if (s3 !== peg$FAILED) {
                    s1 = [s1, s2, s3];
                    s0 = s1;
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parseheader() {
        var s0, s1, s2, s3;
        s0 = peg$currPos;
        s1 = peg$parsehname();
        if (s1 !== peg$FAILED) {
            if (input.charCodeAt(peg$currPos) === 61) {
                s2 = peg$c30;
                peg$currPos++;
            }
            else {
                s2 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c31);
                }
            }
            if (s2 !== peg$FAILED) {
                s3 = peg$parsehvalue();
                if (s3 !== peg$FAILED) {
                    peg$savedPos = s0;
                    s1 = peg$c174(s1, s3);
                    s0 = s1;
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parsehname() {
        var s0, s1;
        s0 = [];
        s1 = peg$parsehnv_unreserved();
        if (s1 === peg$FAILED) {
            s1 = peg$parseunreserved();
            if (s1 === peg$FAILED) {
                s1 = peg$parseescaped();
            }
        }
        if (s1 !== peg$FAILED) {
            while (s1 !== peg$FAILED) {
                s0.push(s1);
                s1 = peg$parsehnv_unreserved();
                if (s1 === peg$FAILED) {
                    s1 = peg$parseunreserved();
                    if (s1 === peg$FAILED) {
                        s1 = peg$parseescaped();
                    }
                }
            }
        }
        else {
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parsehvalue() {
        var s0, s1;
        s0 = [];
        s1 = peg$parsehnv_unreserved();
        if (s1 === peg$FAILED) {
            s1 = peg$parseunreserved();
            if (s1 === peg$FAILED) {
                s1 = peg$parseescaped();
            }
        }
        while (s1 !== peg$FAILED) {
            s0.push(s1);
            s1 = peg$parsehnv_unreserved();
            if (s1 === peg$FAILED) {
                s1 = peg$parseunreserved();
                if (s1 === peg$FAILED) {
                    s1 = peg$parseescaped();
                }
            }
        }
        return s0;
    }
    function peg$parsehnv_unreserved() {
        var s0;
        if (input.charCodeAt(peg$currPos) === 91) {
            s0 = peg$c76;
            peg$currPos++;
        }
        else {
            s0 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c77);
            }
        }
        if (s0 === peg$FAILED) {
            if (input.charCodeAt(peg$currPos) === 93) {
                s0 = peg$c78;
                peg$currPos++;
            }
            else {
                s0 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c79);
                }
            }
            if (s0 === peg$FAILED) {
                if (input.charCodeAt(peg$currPos) === 47) {
                    s0 = peg$c20;
                    peg$currPos++;
                }
                else {
                    s0 = peg$FAILED;
                    if (peg$silentFails === 0) {
                        peg$fail(peg$c21);
                    }
                }
                if (s0 === peg$FAILED) {
                    if (input.charCodeAt(peg$currPos) === 63) {
                        s0 = peg$c22;
                        peg$currPos++;
                    }
                    else {
                        s0 = peg$FAILED;
                        if (peg$silentFails === 0) {
                            peg$fail(peg$c23);
                        }
                    }
                    if (s0 === peg$FAILED) {
                        if (input.charCodeAt(peg$currPos) === 58) {
                            s0 = peg$c24;
                            peg$currPos++;
                        }
                        else {
                            s0 = peg$FAILED;
                            if (peg$silentFails === 0) {
                                peg$fail(peg$c25);
                            }
                        }
                        if (s0 === peg$FAILED) {
                            if (input.charCodeAt(peg$currPos) === 43) {
                                s0 = peg$c32;
                                peg$currPos++;
                            }
                            else {
                                s0 = peg$FAILED;
                                if (peg$silentFails === 0) {
                                    peg$fail(peg$c33);
                                }
                            }
                            if (s0 === peg$FAILED) {
                                if (input.charCodeAt(peg$currPos) === 36) {
                                    s0 = peg$c34;
                                    peg$currPos++;
                                }
                                else {
                                    s0 = peg$FAILED;
                                    if (peg$silentFails === 0) {
                                        peg$fail(peg$c35);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        return s0;
    }
    function peg$parseRequest_Response() {
        var s0;
        s0 = peg$parseStatus_Line();
        if (s0 === peg$FAILED) {
            s0 = peg$parseRequest_Line();
        }
        return s0;
    }
    function peg$parseRequest_Line() {
        var s0, s1, s2, s3, s4, s5;
        s0 = peg$currPos;
        s1 = peg$parseMethod();
        if (s1 !== peg$FAILED) {
            s2 = peg$parseSP();
            if (s2 !== peg$FAILED) {
                s3 = peg$parseRequest_URI();
                if (s3 !== peg$FAILED) {
                    s4 = peg$parseSP();
                    if (s4 !== peg$FAILED) {
                        s5 = peg$parseSIP_Version();
                        if (s5 !== peg$FAILED) {
                            s1 = [s1, s2, s3, s4, s5];
                            s0 = s1;
                        }
                        else {
                            peg$currPos = s0;
                            s0 = peg$FAILED;
                        }
                    }
                    else {
                        peg$currPos = s0;
                        s0 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parseRequest_URI() {
        var s0;
        s0 = peg$parseSIP_URI();
        if (s0 === peg$FAILED) {
            s0 = peg$parseabsoluteURI();
        }
        return s0;
    }
    function peg$parseabsoluteURI() {
        var s0, s1, s2, s3;
        s0 = peg$currPos;
        s1 = peg$parsescheme();
        if (s1 !== peg$FAILED) {
            if (input.charCodeAt(peg$currPos) === 58) {
                s2 = peg$c24;
                peg$currPos++;
            }
            else {
                s2 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c25);
                }
            }
            if (s2 !== peg$FAILED) {
                s3 = peg$parsehier_part();
                if (s3 === peg$FAILED) {
                    s3 = peg$parseopaque_part();
                }
                if (s3 !== peg$FAILED) {
                    peg$savedPos = s0;
                    s1 = peg$c175();
                    s0 = s1;
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parsehier_part() {
        var s0, s1, s2, s3, s4;
        s0 = peg$currPos;
        s1 = peg$parsenet_path();
        if (s1 === peg$FAILED) {
            s1 = peg$parseabs_path();
        }
        if (s1 !== peg$FAILED) {
            s2 = peg$currPos;
            if (input.charCodeAt(peg$currPos) === 63) {
                s3 = peg$c22;
                peg$currPos++;
            }
            else {
                s3 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c23);
                }
            }
            if (s3 !== peg$FAILED) {
                s4 = peg$parsequery();
                if (s4 !== peg$FAILED) {
                    s3 = [s3, s4];
                    s2 = s3;
                }
                else {
                    peg$currPos = s2;
                    s2 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s2;
                s2 = peg$FAILED;
            }
            if (s2 === peg$FAILED) {
                s2 = null;
            }
            if (s2 !== peg$FAILED) {
                s1 = [s1, s2];
                s0 = s1;
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parsenet_path() {
        var s0, s1, s2, s3;
        s0 = peg$currPos;
        if (input.substr(peg$currPos, 2) === peg$c176) {
            s1 = peg$c176;
            peg$currPos += 2;
        }
        else {
            s1 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c177);
            }
        }
        if (s1 !== peg$FAILED) {
            s2 = peg$parseauthority();
            if (s2 !== peg$FAILED) {
                s3 = peg$parseabs_path();
                if (s3 === peg$FAILED) {
                    s3 = null;
                }
                if (s3 !== peg$FAILED) {
                    s1 = [s1, s2, s3];
                    s0 = s1;
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parseabs_path() {
        var s0, s1, s2;
        s0 = peg$currPos;
        if (input.charCodeAt(peg$currPos) === 47) {
            s1 = peg$c20;
            peg$currPos++;
        }
        else {
            s1 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c21);
            }
        }
        if (s1 !== peg$FAILED) {
            s2 = peg$parsepath_segments();
            if (s2 !== peg$FAILED) {
                s1 = [s1, s2];
                s0 = s1;
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parseopaque_part() {
        var s0, s1, s2, s3;
        s0 = peg$currPos;
        s1 = peg$parseuric_no_slash();
        if (s1 !== peg$FAILED) {
            s2 = [];
            s3 = peg$parseuric();
            while (s3 !== peg$FAILED) {
                s2.push(s3);
                s3 = peg$parseuric();
            }
            if (s2 !== peg$FAILED) {
                s1 = [s1, s2];
                s0 = s1;
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parseuric() {
        var s0;
        s0 = peg$parsereserved();
        if (s0 === peg$FAILED) {
            s0 = peg$parseunreserved();
            if (s0 === peg$FAILED) {
                s0 = peg$parseescaped();
            }
        }
        return s0;
    }
    function peg$parseuric_no_slash() {
        var s0;
        s0 = peg$parseunreserved();
        if (s0 === peg$FAILED) {
            s0 = peg$parseescaped();
            if (s0 === peg$FAILED) {
                if (input.charCodeAt(peg$currPos) === 59) {
                    s0 = peg$c18;
                    peg$currPos++;
                }
                else {
                    s0 = peg$FAILED;
                    if (peg$silentFails === 0) {
                        peg$fail(peg$c19);
                    }
                }
                if (s0 === peg$FAILED) {
                    if (input.charCodeAt(peg$currPos) === 63) {
                        s0 = peg$c22;
                        peg$currPos++;
                    }
                    else {
                        s0 = peg$FAILED;
                        if (peg$silentFails === 0) {
                            peg$fail(peg$c23);
                        }
                    }
                    if (s0 === peg$FAILED) {
                        if (input.charCodeAt(peg$currPos) === 58) {
                            s0 = peg$c24;
                            peg$currPos++;
                        }
                        else {
                            s0 = peg$FAILED;
                            if (peg$silentFails === 0) {
                                peg$fail(peg$c25);
                            }
                        }
                        if (s0 === peg$FAILED) {
                            if (input.charCodeAt(peg$currPos) === 64) {
                                s0 = peg$c26;
                                peg$currPos++;
                            }
                            else {
                                s0 = peg$FAILED;
                                if (peg$silentFails === 0) {
                                    peg$fail(peg$c27);
                                }
                            }
                            if (s0 === peg$FAILED) {
                                if (input.charCodeAt(peg$currPos) === 38) {
                                    s0 = peg$c28;
                                    peg$currPos++;
                                }
                                else {
                                    s0 = peg$FAILED;
                                    if (peg$silentFails === 0) {
                                        peg$fail(peg$c29);
                                    }
                                }
                                if (s0 === peg$FAILED) {
                                    if (input.charCodeAt(peg$currPos) === 61) {
                                        s0 = peg$c30;
                                        peg$currPos++;
                                    }
                                    else {
                                        s0 = peg$FAILED;
                                        if (peg$silentFails === 0) {
                                            peg$fail(peg$c31);
                                        }
                                    }
                                    if (s0 === peg$FAILED) {
                                        if (input.charCodeAt(peg$currPos) === 43) {
                                            s0 = peg$c32;
                                            peg$currPos++;
                                        }
                                        else {
                                            s0 = peg$FAILED;
                                            if (peg$silentFails === 0) {
                                                peg$fail(peg$c33);
                                            }
                                        }
                                        if (s0 === peg$FAILED) {
                                            if (input.charCodeAt(peg$currPos) === 36) {
                                                s0 = peg$c34;
                                                peg$currPos++;
                                            }
                                            else {
                                                s0 = peg$FAILED;
                                                if (peg$silentFails === 0) {
                                                    peg$fail(peg$c35);
                                                }
                                            }
                                            if (s0 === peg$FAILED) {
                                                if (input.charCodeAt(peg$currPos) === 44) {
                                                    s0 = peg$c36;
                                                    peg$currPos++;
                                                }
                                                else {
                                                    s0 = peg$FAILED;
                                                    if (peg$silentFails === 0) {
                                                        peg$fail(peg$c37);
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        return s0;
    }
    function peg$parsepath_segments() {
        var s0, s1, s2, s3, s4, s5;
        s0 = peg$currPos;
        s1 = peg$parsesegment();
        if (s1 !== peg$FAILED) {
            s2 = [];
            s3 = peg$currPos;
            if (input.charCodeAt(peg$currPos) === 47) {
                s4 = peg$c20;
                peg$currPos++;
            }
            else {
                s4 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c21);
                }
            }
            if (s4 !== peg$FAILED) {
                s5 = peg$parsesegment();
                if (s5 !== peg$FAILED) {
                    s4 = [s4, s5];
                    s3 = s4;
                }
                else {
                    peg$currPos = s3;
                    s3 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s3;
                s3 = peg$FAILED;
            }
            while (s3 !== peg$FAILED) {
                s2.push(s3);
                s3 = peg$currPos;
                if (input.charCodeAt(peg$currPos) === 47) {
                    s4 = peg$c20;
                    peg$currPos++;
                }
                else {
                    s4 = peg$FAILED;
                    if (peg$silentFails === 0) {
                        peg$fail(peg$c21);
                    }
                }
                if (s4 !== peg$FAILED) {
                    s5 = peg$parsesegment();
                    if (s5 !== peg$FAILED) {
                        s4 = [s4, s5];
                        s3 = s4;
                    }
                    else {
                        peg$currPos = s3;
                        s3 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s3;
                    s3 = peg$FAILED;
                }
            }
            if (s2 !== peg$FAILED) {
                s1 = [s1, s2];
                s0 = s1;
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parsesegment() {
        var s0, s1, s2, s3, s4, s5;
        s0 = peg$currPos;
        s1 = [];
        s2 = peg$parsepchar();
        while (s2 !== peg$FAILED) {
            s1.push(s2);
            s2 = peg$parsepchar();
        }
        if (s1 !== peg$FAILED) {
            s2 = [];
            s3 = peg$currPos;
            if (input.charCodeAt(peg$currPos) === 59) {
                s4 = peg$c18;
                peg$currPos++;
            }
            else {
                s4 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c19);
                }
            }
            if (s4 !== peg$FAILED) {
                s5 = peg$parseparam();
                if (s5 !== peg$FAILED) {
                    s4 = [s4, s5];
                    s3 = s4;
                }
                else {
                    peg$currPos = s3;
                    s3 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s3;
                s3 = peg$FAILED;
            }
            while (s3 !== peg$FAILED) {
                s2.push(s3);
                s3 = peg$currPos;
                if (input.charCodeAt(peg$currPos) === 59) {
                    s4 = peg$c18;
                    peg$currPos++;
                }
                else {
                    s4 = peg$FAILED;
                    if (peg$silentFails === 0) {
                        peg$fail(peg$c19);
                    }
                }
                if (s4 !== peg$FAILED) {
                    s5 = peg$parseparam();
                    if (s5 !== peg$FAILED) {
                        s4 = [s4, s5];
                        s3 = s4;
                    }
                    else {
                        peg$currPos = s3;
                        s3 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s3;
                    s3 = peg$FAILED;
                }
            }
            if (s2 !== peg$FAILED) {
                s1 = [s1, s2];
                s0 = s1;
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parseparam() {
        var s0, s1;
        s0 = [];
        s1 = peg$parsepchar();
        while (s1 !== peg$FAILED) {
            s0.push(s1);
            s1 = peg$parsepchar();
        }
        return s0;
    }
    function peg$parsepchar() {
        var s0;
        s0 = peg$parseunreserved();
        if (s0 === peg$FAILED) {
            s0 = peg$parseescaped();
            if (s0 === peg$FAILED) {
                if (input.charCodeAt(peg$currPos) === 58) {
                    s0 = peg$c24;
                    peg$currPos++;
                }
                else {
                    s0 = peg$FAILED;
                    if (peg$silentFails === 0) {
                        peg$fail(peg$c25);
                    }
                }
                if (s0 === peg$FAILED) {
                    if (input.charCodeAt(peg$currPos) === 64) {
                        s0 = peg$c26;
                        peg$currPos++;
                    }
                    else {
                        s0 = peg$FAILED;
                        if (peg$silentFails === 0) {
                            peg$fail(peg$c27);
                        }
                    }
                    if (s0 === peg$FAILED) {
                        if (input.charCodeAt(peg$currPos) === 38) {
                            s0 = peg$c28;
                            peg$currPos++;
                        }
                        else {
                            s0 = peg$FAILED;
                            if (peg$silentFails === 0) {
                                peg$fail(peg$c29);
                            }
                        }
                        if (s0 === peg$FAILED) {
                            if (input.charCodeAt(peg$currPos) === 61) {
                                s0 = peg$c30;
                                peg$currPos++;
                            }
                            else {
                                s0 = peg$FAILED;
                                if (peg$silentFails === 0) {
                                    peg$fail(peg$c31);
                                }
                            }
                            if (s0 === peg$FAILED) {
                                if (input.charCodeAt(peg$currPos) === 43) {
                                    s0 = peg$c32;
                                    peg$currPos++;
                                }
                                else {
                                    s0 = peg$FAILED;
                                    if (peg$silentFails === 0) {
                                        peg$fail(peg$c33);
                                    }
                                }
                                if (s0 === peg$FAILED) {
                                    if (input.charCodeAt(peg$currPos) === 36) {
                                        s0 = peg$c34;
                                        peg$currPos++;
                                    }
                                    else {
                                        s0 = peg$FAILED;
                                        if (peg$silentFails === 0) {
                                            peg$fail(peg$c35);
                                        }
                                    }
                                    if (s0 === peg$FAILED) {
                                        if (input.charCodeAt(peg$currPos) === 44) {
                                            s0 = peg$c36;
                                            peg$currPos++;
                                        }
                                        else {
                                            s0 = peg$FAILED;
                                            if (peg$silentFails === 0) {
                                                peg$fail(peg$c37);
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        return s0;
    }
    function peg$parsescheme() {
        var s0, s1, s2, s3, s4;
        s0 = peg$currPos;
        s1 = peg$currPos;
        s2 = peg$parseALPHA();
        if (s2 !== peg$FAILED) {
            s3 = [];
            s4 = peg$parseALPHA();
            if (s4 === peg$FAILED) {
                s4 = peg$parseDIGIT();
                if (s4 === peg$FAILED) {
                    if (input.charCodeAt(peg$currPos) === 43) {
                        s4 = peg$c32;
                        peg$currPos++;
                    }
                    else {
                        s4 = peg$FAILED;
                        if (peg$silentFails === 0) {
                            peg$fail(peg$c33);
                        }
                    }
                    if (s4 === peg$FAILED) {
                        if (input.charCodeAt(peg$currPos) === 45) {
                            s4 = peg$c38;
                            peg$currPos++;
                        }
                        else {
                            s4 = peg$FAILED;
                            if (peg$silentFails === 0) {
                                peg$fail(peg$c39);
                            }
                        }
                        if (s4 === peg$FAILED) {
                            if (input.charCodeAt(peg$currPos) === 46) {
                                s4 = peg$c42;
                                peg$currPos++;
                            }
                            else {
                                s4 = peg$FAILED;
                                if (peg$silentFails === 0) {
                                    peg$fail(peg$c43);
                                }
                            }
                        }
                    }
                }
            }
            while (s4 !== peg$FAILED) {
                s3.push(s4);
                s4 = peg$parseALPHA();
                if (s4 === peg$FAILED) {
                    s4 = peg$parseDIGIT();
                    if (s4 === peg$FAILED) {
                        if (input.charCodeAt(peg$currPos) === 43) {
                            s4 = peg$c32;
                            peg$currPos++;
                        }
                        else {
                            s4 = peg$FAILED;
                            if (peg$silentFails === 0) {
                                peg$fail(peg$c33);
                            }
                        }
                        if (s4 === peg$FAILED) {
                            if (input.charCodeAt(peg$currPos) === 45) {
                                s4 = peg$c38;
                                peg$currPos++;
                            }
                            else {
                                s4 = peg$FAILED;
                                if (peg$silentFails === 0) {
                                    peg$fail(peg$c39);
                                }
                            }
                            if (s4 === peg$FAILED) {
                                if (input.charCodeAt(peg$currPos) === 46) {
                                    s4 = peg$c42;
                                    peg$currPos++;
                                }
                                else {
                                    s4 = peg$FAILED;
                                    if (peg$silentFails === 0) {
                                        peg$fail(peg$c43);
                                    }
                                }
                            }
                        }
                    }
                }
            }
            if (s3 !== peg$FAILED) {
                s2 = [s2, s3];
                s1 = s2;
            }
            else {
                peg$currPos = s1;
                s1 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s1;
            s1 = peg$FAILED;
        }
        if (s1 !== peg$FAILED) {
            peg$savedPos = s0;
            s1 = peg$c178();
        }
        s0 = s1;
        return s0;
    }
    function peg$parseauthority() {
        var s0;
        s0 = peg$parsesrvr();
        if (s0 === peg$FAILED) {
            s0 = peg$parsereg_name();
        }
        return s0;
    }
    function peg$parsesrvr() {
        var s0, s1, s2, s3;
        s0 = peg$currPos;
        s1 = peg$currPos;
        s2 = peg$parseuserinfo();
        if (s2 !== peg$FAILED) {
            if (input.charCodeAt(peg$currPos) === 64) {
                s3 = peg$c26;
                peg$currPos++;
            }
            else {
                s3 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c27);
                }
            }
            if (s3 !== peg$FAILED) {
                s2 = [s2, s3];
                s1 = s2;
            }
            else {
                peg$currPos = s1;
                s1 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s1;
            s1 = peg$FAILED;
        }
        if (s1 === peg$FAILED) {
            s1 = null;
        }
        if (s1 !== peg$FAILED) {
            s2 = peg$parsehostport();
            if (s2 !== peg$FAILED) {
                s1 = [s1, s2];
                s0 = s1;
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        if (s0 === peg$FAILED) {
            s0 = null;
        }
        return s0;
    }
    function peg$parsereg_name() {
        var s0, s1;
        s0 = [];
        s1 = peg$parseunreserved();
        if (s1 === peg$FAILED) {
            s1 = peg$parseescaped();
            if (s1 === peg$FAILED) {
                if (input.charCodeAt(peg$currPos) === 36) {
                    s1 = peg$c34;
                    peg$currPos++;
                }
                else {
                    s1 = peg$FAILED;
                    if (peg$silentFails === 0) {
                        peg$fail(peg$c35);
                    }
                }
                if (s1 === peg$FAILED) {
                    if (input.charCodeAt(peg$currPos) === 44) {
                        s1 = peg$c36;
                        peg$currPos++;
                    }
                    else {
                        s1 = peg$FAILED;
                        if (peg$silentFails === 0) {
                            peg$fail(peg$c37);
                        }
                    }
                    if (s1 === peg$FAILED) {
                        if (input.charCodeAt(peg$currPos) === 59) {
                            s1 = peg$c18;
                            peg$currPos++;
                        }
                        else {
                            s1 = peg$FAILED;
                            if (peg$silentFails === 0) {
                                peg$fail(peg$c19);
                            }
                        }
                        if (s1 === peg$FAILED) {
                            if (input.charCodeAt(peg$currPos) === 58) {
                                s1 = peg$c24;
                                peg$currPos++;
                            }
                            else {
                                s1 = peg$FAILED;
                                if (peg$silentFails === 0) {
                                    peg$fail(peg$c25);
                                }
                            }
                            if (s1 === peg$FAILED) {
                                if (input.charCodeAt(peg$currPos) === 64) {
                                    s1 = peg$c26;
                                    peg$currPos++;
                                }
                                else {
                                    s1 = peg$FAILED;
                                    if (peg$silentFails === 0) {
                                        peg$fail(peg$c27);
                                    }
                                }
                                if (s1 === peg$FAILED) {
                                    if (input.charCodeAt(peg$currPos) === 38) {
                                        s1 = peg$c28;
                                        peg$currPos++;
                                    }
                                    else {
                                        s1 = peg$FAILED;
                                        if (peg$silentFails === 0) {
                                            peg$fail(peg$c29);
                                        }
                                    }
                                    if (s1 === peg$FAILED) {
                                        if (input.charCodeAt(peg$currPos) === 61) {
                                            s1 = peg$c30;
                                            peg$currPos++;
                                        }
                                        else {
                                            s1 = peg$FAILED;
                                            if (peg$silentFails === 0) {
                                                peg$fail(peg$c31);
                                            }
                                        }
                                        if (s1 === peg$FAILED) {
                                            if (input.charCodeAt(peg$currPos) === 43) {
                                                s1 = peg$c32;
                                                peg$currPos++;
                                            }
                                            else {
                                                s1 = peg$FAILED;
                                                if (peg$silentFails === 0) {
                                                    peg$fail(peg$c33);
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        if (s1 !== peg$FAILED) {
            while (s1 !== peg$FAILED) {
                s0.push(s1);
                s1 = peg$parseunreserved();
                if (s1 === peg$FAILED) {
                    s1 = peg$parseescaped();
                    if (s1 === peg$FAILED) {
                        if (input.charCodeAt(peg$currPos) === 36) {
                            s1 = peg$c34;
                            peg$currPos++;
                        }
                        else {
                            s1 = peg$FAILED;
                            if (peg$silentFails === 0) {
                                peg$fail(peg$c35);
                            }
                        }
                        if (s1 === peg$FAILED) {
                            if (input.charCodeAt(peg$currPos) === 44) {
                                s1 = peg$c36;
                                peg$currPos++;
                            }
                            else {
                                s1 = peg$FAILED;
                                if (peg$silentFails === 0) {
                                    peg$fail(peg$c37);
                                }
                            }
                            if (s1 === peg$FAILED) {
                                if (input.charCodeAt(peg$currPos) === 59) {
                                    s1 = peg$c18;
                                    peg$currPos++;
                                }
                                else {
                                    s1 = peg$FAILED;
                                    if (peg$silentFails === 0) {
                                        peg$fail(peg$c19);
                                    }
                                }
                                if (s1 === peg$FAILED) {
                                    if (input.charCodeAt(peg$currPos) === 58) {
                                        s1 = peg$c24;
                                        peg$currPos++;
                                    }
                                    else {
                                        s1 = peg$FAILED;
                                        if (peg$silentFails === 0) {
                                            peg$fail(peg$c25);
                                        }
                                    }
                                    if (s1 === peg$FAILED) {
                                        if (input.charCodeAt(peg$currPos) === 64) {
                                            s1 = peg$c26;
                                            peg$currPos++;
                                        }
                                        else {
                                            s1 = peg$FAILED;
                                            if (peg$silentFails === 0) {
                                                peg$fail(peg$c27);
                                            }
                                        }
                                        if (s1 === peg$FAILED) {
                                            if (input.charCodeAt(peg$currPos) === 38) {
                                                s1 = peg$c28;
                                                peg$currPos++;
                                            }
                                            else {
                                                s1 = peg$FAILED;
                                                if (peg$silentFails === 0) {
                                                    peg$fail(peg$c29);
                                                }
                                            }
                                            if (s1 === peg$FAILED) {
                                                if (input.charCodeAt(peg$currPos) === 61) {
                                                    s1 = peg$c30;
                                                    peg$currPos++;
                                                }
                                                else {
                                                    s1 = peg$FAILED;
                                                    if (peg$silentFails === 0) {
                                                        peg$fail(peg$c31);
                                                    }
                                                }
                                                if (s1 === peg$FAILED) {
                                                    if (input.charCodeAt(peg$currPos) === 43) {
                                                        s1 = peg$c32;
                                                        peg$currPos++;
                                                    }
                                                    else {
                                                        s1 = peg$FAILED;
                                                        if (peg$silentFails === 0) {
                                                            peg$fail(peg$c33);
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        else {
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parsequery() {
        var s0, s1;
        s0 = [];
        s1 = peg$parseuric();
        while (s1 !== peg$FAILED) {
            s0.push(s1);
            s1 = peg$parseuric();
        }
        return s0;
    }
    function peg$parseSIP_Version() {
        var s0, s1, s2, s3, s4, s5, s6;
        s0 = peg$currPos;
        if (input.substr(peg$currPos, 3).toLowerCase() === peg$c114) {
            s1 = input.substr(peg$currPos, 3);
            peg$currPos += 3;
        }
        else {
            s1 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c179);
            }
        }
        if (s1 !== peg$FAILED) {
            if (input.charCodeAt(peg$currPos) === 47) {
                s2 = peg$c20;
                peg$currPos++;
            }
            else {
                s2 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c21);
                }
            }
            if (s2 !== peg$FAILED) {
                s3 = [];
                s4 = peg$parseDIGIT();
                if (s4 !== peg$FAILED) {
                    while (s4 !== peg$FAILED) {
                        s3.push(s4);
                        s4 = peg$parseDIGIT();
                    }
                }
                else {
                    s3 = peg$FAILED;
                }
                if (s3 !== peg$FAILED) {
                    if (input.charCodeAt(peg$currPos) === 46) {
                        s4 = peg$c42;
                        peg$currPos++;
                    }
                    else {
                        s4 = peg$FAILED;
                        if (peg$silentFails === 0) {
                            peg$fail(peg$c43);
                        }
                    }
                    if (s4 !== peg$FAILED) {
                        s5 = [];
                        s6 = peg$parseDIGIT();
                        if (s6 !== peg$FAILED) {
                            while (s6 !== peg$FAILED) {
                                s5.push(s6);
                                s6 = peg$parseDIGIT();
                            }
                        }
                        else {
                            s5 = peg$FAILED;
                        }
                        if (s5 !== peg$FAILED) {
                            peg$savedPos = s0;
                            s1 = peg$c180();
                            s0 = s1;
                        }
                        else {
                            peg$currPos = s0;
                            s0 = peg$FAILED;
                        }
                    }
                    else {
                        peg$currPos = s0;
                        s0 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parseINVITEm() {
        var s0;
        if (input.substr(peg$currPos, 6) === peg$c181) {
            s0 = peg$c181;
            peg$currPos += 6;
        }
        else {
            s0 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c182);
            }
        }
        return s0;
    }
    function peg$parseACKm() {
        var s0;
        if (input.substr(peg$currPos, 3) === peg$c183) {
            s0 = peg$c183;
            peg$currPos += 3;
        }
        else {
            s0 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c184);
            }
        }
        return s0;
    }
    function peg$parsePRACKm() {
        var s0;
        if (input.substr(peg$currPos, 5) === peg$c185) {
            s0 = peg$c185;
            peg$currPos += 5;
        }
        else {
            s0 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c186);
            }
        }
        return s0;
    }
    function peg$parseOPTIONSm() {
        var s0;
        if (input.substr(peg$currPos, 7) === peg$c187) {
            s0 = peg$c187;
            peg$currPos += 7;
        }
        else {
            s0 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c188);
            }
        }
        return s0;
    }
    function peg$parseBYEm() {
        var s0;
        if (input.substr(peg$currPos, 3) === peg$c189) {
            s0 = peg$c189;
            peg$currPos += 3;
        }
        else {
            s0 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c190);
            }
        }
        return s0;
    }
    function peg$parseCANCELm() {
        var s0;
        if (input.substr(peg$currPos, 6) === peg$c191) {
            s0 = peg$c191;
            peg$currPos += 6;
        }
        else {
            s0 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c192);
            }
        }
        return s0;
    }
    function peg$parseREGISTERm() {
        var s0;
        if (input.substr(peg$currPos, 8) === peg$c193) {
            s0 = peg$c193;
            peg$currPos += 8;
        }
        else {
            s0 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c194);
            }
        }
        return s0;
    }
    function peg$parseSUBSCRIBEm() {
        var s0;
        if (input.substr(peg$currPos, 9) === peg$c195) {
            s0 = peg$c195;
            peg$currPos += 9;
        }
        else {
            s0 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c196);
            }
        }
        return s0;
    }
    function peg$parseNOTIFYm() {
        var s0;
        if (input.substr(peg$currPos, 6) === peg$c197) {
            s0 = peg$c197;
            peg$currPos += 6;
        }
        else {
            s0 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c198);
            }
        }
        return s0;
    }
    function peg$parseREFERm() {
        var s0;
        if (input.substr(peg$currPos, 5) === peg$c199) {
            s0 = peg$c199;
            peg$currPos += 5;
        }
        else {
            s0 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c200);
            }
        }
        return s0;
    }
    function peg$parsePUBLISHm() {
        var s0;
        if (input.substr(peg$currPos, 7) === peg$c201) {
            s0 = peg$c201;
            peg$currPos += 7;
        }
        else {
            s0 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c202);
            }
        }
        return s0;
    }
    function peg$parseMethod() {
        var s0, s1;
        s0 = peg$currPos;
        s1 = peg$parseINVITEm();
        if (s1 === peg$FAILED) {
            s1 = peg$parseACKm();
            if (s1 === peg$FAILED) {
                s1 = peg$parseOPTIONSm();
                if (s1 === peg$FAILED) {
                    s1 = peg$parseBYEm();
                    if (s1 === peg$FAILED) {
                        s1 = peg$parseCANCELm();
                        if (s1 === peg$FAILED) {
                            s1 = peg$parseREGISTERm();
                            if (s1 === peg$FAILED) {
                                s1 = peg$parseSUBSCRIBEm();
                                if (s1 === peg$FAILED) {
                                    s1 = peg$parsePUBLISHm();
                                    if (s1 === peg$FAILED) {
                                        s1 = peg$parseNOTIFYm();
                                        if (s1 === peg$FAILED) {
                                            s1 = peg$parseREFERm();
                                            if (s1 === peg$FAILED) {
                                                s1 = peg$parsetoken();
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        if (s1 !== peg$FAILED) {
            peg$savedPos = s0;
            s1 = peg$c203();
        }
        s0 = s1;
        return s0;
    }
    function peg$parseStatus_Line() {
        var s0, s1, s2, s3, s4, s5;
        s0 = peg$currPos;
        s1 = peg$parseSIP_Version();
        if (s1 !== peg$FAILED) {
            s2 = peg$parseSP();
            if (s2 !== peg$FAILED) {
                s3 = peg$parseStatus_Code();
                if (s3 !== peg$FAILED) {
                    s4 = peg$parseSP();
                    if (s4 !== peg$FAILED) {
                        s5 = peg$parseReason_Phrase();
                        if (s5 !== peg$FAILED) {
                            s1 = [s1, s2, s3, s4, s5];
                            s0 = s1;
                        }
                        else {
                            peg$currPos = s0;
                            s0 = peg$FAILED;
                        }
                    }
                    else {
                        peg$currPos = s0;
                        s0 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parseStatus_Code() {
        var s0, s1;
        s0 = peg$currPos;
        s1 = peg$parseextension_code();
        if (s1 !== peg$FAILED) {
            peg$savedPos = s0;
            s1 = peg$c204(s1);
        }
        s0 = s1;
        return s0;
    }
    function peg$parseextension_code() {
        var s0, s1, s2, s3;
        s0 = peg$currPos;
        s1 = peg$parseDIGIT();
        if (s1 !== peg$FAILED) {
            s2 = peg$parseDIGIT();
            if (s2 !== peg$FAILED) {
                s3 = peg$parseDIGIT();
                if (s3 !== peg$FAILED) {
                    s1 = [s1, s2, s3];
                    s0 = s1;
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parseReason_Phrase() {
        var s0, s1, s2;
        s0 = peg$currPos;
        s1 = [];
        s2 = peg$parsereserved();
        if (s2 === peg$FAILED) {
            s2 = peg$parseunreserved();
            if (s2 === peg$FAILED) {
                s2 = peg$parseescaped();
                if (s2 === peg$FAILED) {
                    s2 = peg$parseUTF8_NONASCII();
                    if (s2 === peg$FAILED) {
                        s2 = peg$parseUTF8_CONT();
                        if (s2 === peg$FAILED) {
                            s2 = peg$parseSP();
                            if (s2 === peg$FAILED) {
                                s2 = peg$parseHTAB();
                            }
                        }
                    }
                }
            }
        }
        while (s2 !== peg$FAILED) {
            s1.push(s2);
            s2 = peg$parsereserved();
            if (s2 === peg$FAILED) {
                s2 = peg$parseunreserved();
                if (s2 === peg$FAILED) {
                    s2 = peg$parseescaped();
                    if (s2 === peg$FAILED) {
                        s2 = peg$parseUTF8_NONASCII();
                        if (s2 === peg$FAILED) {
                            s2 = peg$parseUTF8_CONT();
                            if (s2 === peg$FAILED) {
                                s2 = peg$parseSP();
                                if (s2 === peg$FAILED) {
                                    s2 = peg$parseHTAB();
                                }
                            }
                        }
                    }
                }
            }
        }
        if (s1 !== peg$FAILED) {
            peg$savedPos = s0;
            s1 = peg$c205();
        }
        s0 = s1;
        return s0;
    }
    function peg$parseAllow_Events() {
        var s0, s1, s2, s3, s4, s5;
        s0 = peg$currPos;
        s1 = peg$parseevent_type();
        if (s1 !== peg$FAILED) {
            s2 = [];
            s3 = peg$currPos;
            s4 = peg$parseCOMMA();
            if (s4 !== peg$FAILED) {
                s5 = peg$parseevent_type();
                if (s5 !== peg$FAILED) {
                    s4 = [s4, s5];
                    s3 = s4;
                }
                else {
                    peg$currPos = s3;
                    s3 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s3;
                s3 = peg$FAILED;
            }
            while (s3 !== peg$FAILED) {
                s2.push(s3);
                s3 = peg$currPos;
                s4 = peg$parseCOMMA();
                if (s4 !== peg$FAILED) {
                    s5 = peg$parseevent_type();
                    if (s5 !== peg$FAILED) {
                        s4 = [s4, s5];
                        s3 = s4;
                    }
                    else {
                        peg$currPos = s3;
                        s3 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s3;
                    s3 = peg$FAILED;
                }
            }
            if (s2 !== peg$FAILED) {
                s1 = [s1, s2];
                s0 = s1;
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parseCall_ID() {
        var s0, s1, s2, s3, s4;
        s0 = peg$currPos;
        s1 = peg$parseword();
        if (s1 !== peg$FAILED) {
            s2 = peg$currPos;
            if (input.charCodeAt(peg$currPos) === 64) {
                s3 = peg$c26;
                peg$currPos++;
            }
            else {
                s3 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c27);
                }
            }
            if (s3 !== peg$FAILED) {
                s4 = peg$parseword();
                if (s4 !== peg$FAILED) {
                    s3 = [s3, s4];
                    s2 = s3;
                }
                else {
                    peg$currPos = s2;
                    s2 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s2;
                s2 = peg$FAILED;
            }
            if (s2 === peg$FAILED) {
                s2 = null;
            }
            if (s2 !== peg$FAILED) {
                peg$savedPos = s0;
                s1 = peg$c206();
                s0 = s1;
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parseContact() {
        var s0, s1, s2, s3, s4, s5, s6;
        s0 = peg$currPos;
        s1 = peg$parseSTAR();
        if (s1 === peg$FAILED) {
            s1 = peg$currPos;
            s2 = peg$parsecontact_param();
            if (s2 !== peg$FAILED) {
                s3 = [];
                s4 = peg$currPos;
                s5 = peg$parseCOMMA();
                if (s5 !== peg$FAILED) {
                    s6 = peg$parsecontact_param();
                    if (s6 !== peg$FAILED) {
                        s5 = [s5, s6];
                        s4 = s5;
                    }
                    else {
                        peg$currPos = s4;
                        s4 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s4;
                    s4 = peg$FAILED;
                }
                while (s4 !== peg$FAILED) {
                    s3.push(s4);
                    s4 = peg$currPos;
                    s5 = peg$parseCOMMA();
                    if (s5 !== peg$FAILED) {
                        s6 = peg$parsecontact_param();
                        if (s6 !== peg$FAILED) {
                            s5 = [s5, s6];
                            s4 = s5;
                        }
                        else {
                            peg$currPos = s4;
                            s4 = peg$FAILED;
                        }
                    }
                    else {
                        peg$currPos = s4;
                        s4 = peg$FAILED;
                    }
                }
                if (s3 !== peg$FAILED) {
                    s2 = [s2, s3];
                    s1 = s2;
                }
                else {
                    peg$currPos = s1;
                    s1 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s1;
                s1 = peg$FAILED;
            }
        }
        if (s1 !== peg$FAILED) {
            peg$savedPos = s0;
            s1 = peg$c207();
        }
        s0 = s1;
        return s0;
    }
    function peg$parsecontact_param() {
        var s0, s1, s2, s3, s4, s5;
        s0 = peg$currPos;
        s1 = peg$parseSIP_URI_noparams();
        if (s1 === peg$FAILED) {
            s1 = peg$parsename_addr();
        }
        if (s1 !== peg$FAILED) {
            s2 = [];
            s3 = peg$currPos;
            s4 = peg$parseSEMI();
            if (s4 !== peg$FAILED) {
                s5 = peg$parsecontact_params();
                if (s5 !== peg$FAILED) {
                    s4 = [s4, s5];
                    s3 = s4;
                }
                else {
                    peg$currPos = s3;
                    s3 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s3;
                s3 = peg$FAILED;
            }
            while (s3 !== peg$FAILED) {
                s2.push(s3);
                s3 = peg$currPos;
                s4 = peg$parseSEMI();
                if (s4 !== peg$FAILED) {
                    s5 = peg$parsecontact_params();
                    if (s5 !== peg$FAILED) {
                        s4 = [s4, s5];
                        s3 = s4;
                    }
                    else {
                        peg$currPos = s3;
                        s3 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s3;
                    s3 = peg$FAILED;
                }
            }
            if (s2 !== peg$FAILED) {
                peg$savedPos = s0;
                s1 = peg$c208();
                s0 = s1;
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parsename_addr() {
        var s0, s1, s2, s3, s4;
        s0 = peg$currPos;
        s1 = peg$parsedisplayName();
        if (s1 === peg$FAILED) {
            s1 = null;
        }
        if (s1 !== peg$FAILED) {
            s2 = peg$parseLAQUOT();
            if (s2 !== peg$FAILED) {
                s3 = peg$parseSIP_URI();
                if (s3 !== peg$FAILED) {
                    s4 = peg$parseRAQUOT();
                    if (s4 !== peg$FAILED) {
                        s1 = [s1, s2, s3, s4];
                        s0 = s1;
                    }
                    else {
                        peg$currPos = s0;
                        s0 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parsedisplayName() {
        var s0, s1, s2, s3, s4, s5, s6;
        s0 = peg$currPos;
        s1 = peg$currPos;
        s2 = peg$parsetoken();
        if (s2 !== peg$FAILED) {
            s3 = [];
            s4 = peg$currPos;
            s5 = peg$parseLWS();
            if (s5 !== peg$FAILED) {
                s6 = peg$parsetoken();
                if (s6 !== peg$FAILED) {
                    s5 = [s5, s6];
                    s4 = s5;
                }
                else {
                    peg$currPos = s4;
                    s4 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s4;
                s4 = peg$FAILED;
            }
            while (s4 !== peg$FAILED) {
                s3.push(s4);
                s4 = peg$currPos;
                s5 = peg$parseLWS();
                if (s5 !== peg$FAILED) {
                    s6 = peg$parsetoken();
                    if (s6 !== peg$FAILED) {
                        s5 = [s5, s6];
                        s4 = s5;
                    }
                    else {
                        peg$currPos = s4;
                        s4 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s4;
                    s4 = peg$FAILED;
                }
            }
            if (s3 !== peg$FAILED) {
                s2 = [s2, s3];
                s1 = s2;
            }
            else {
                peg$currPos = s1;
                s1 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s1;
            s1 = peg$FAILED;
        }
        if (s1 === peg$FAILED) {
            s1 = peg$parsequoted_string();
        }
        if (s1 !== peg$FAILED) {
            peg$savedPos = s0;
            s1 = peg$c209(s1);
        }
        s0 = s1;
        return s0;
    }
    function peg$parsecontact_params() {
        var s0;
        s0 = peg$parsec_p_q();
        if (s0 === peg$FAILED) {
            s0 = peg$parsec_p_expires();
            if (s0 === peg$FAILED) {
                s0 = peg$parsegeneric_param();
            }
        }
        return s0;
    }
    function peg$parsec_p_q() {
        var s0, s1, s2, s3;
        s0 = peg$currPos;
        if (input.substr(peg$currPos, 1).toLowerCase() === peg$c210) {
            s1 = input.charAt(peg$currPos);
            peg$currPos++;
        }
        else {
            s1 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c211);
            }
        }
        if (s1 !== peg$FAILED) {
            s2 = peg$parseEQUAL();
            if (s2 !== peg$FAILED) {
                s3 = peg$parseqvalue();
                if (s3 !== peg$FAILED) {
                    peg$savedPos = s0;
                    s1 = peg$c212(s3);
                    s0 = s1;
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parsec_p_expires() {
        var s0, s1, s2, s3;
        s0 = peg$currPos;
        if (input.substr(peg$currPos, 7).toLowerCase() === peg$c213) {
            s1 = input.substr(peg$currPos, 7);
            peg$currPos += 7;
        }
        else {
            s1 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c214);
            }
        }
        if (s1 !== peg$FAILED) {
            s2 = peg$parseEQUAL();
            if (s2 !== peg$FAILED) {
                s3 = peg$parsedelta_seconds();
                if (s3 !== peg$FAILED) {
                    peg$savedPos = s0;
                    s1 = peg$c215(s3);
                    s0 = s1;
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parsedelta_seconds() {
        var s0, s1, s2;
        s0 = peg$currPos;
        s1 = [];
        s2 = peg$parseDIGIT();
        if (s2 !== peg$FAILED) {
            while (s2 !== peg$FAILED) {
                s1.push(s2);
                s2 = peg$parseDIGIT();
            }
        }
        else {
            s1 = peg$FAILED;
        }
        if (s1 !== peg$FAILED) {
            peg$savedPos = s0;
            s1 = peg$c216(s1);
        }
        s0 = s1;
        return s0;
    }
    function peg$parseqvalue() {
        var s0, s1, s2, s3, s4, s5, s6;
        s0 = peg$currPos;
        if (input.charCodeAt(peg$currPos) === 48) {
            s1 = peg$c217;
            peg$currPos++;
        }
        else {
            s1 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c218);
            }
        }
        if (s1 !== peg$FAILED) {
            s2 = peg$currPos;
            if (input.charCodeAt(peg$currPos) === 46) {
                s3 = peg$c42;
                peg$currPos++;
            }
            else {
                s3 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c43);
                }
            }
            if (s3 !== peg$FAILED) {
                s4 = peg$parseDIGIT();
                if (s4 === peg$FAILED) {
                    s4 = null;
                }
                if (s4 !== peg$FAILED) {
                    s5 = peg$parseDIGIT();
                    if (s5 === peg$FAILED) {
                        s5 = null;
                    }
                    if (s5 !== peg$FAILED) {
                        s6 = peg$parseDIGIT();
                        if (s6 === peg$FAILED) {
                            s6 = null;
                        }
                        if (s6 !== peg$FAILED) {
                            s3 = [s3, s4, s5, s6];
                            s2 = s3;
                        }
                        else {
                            peg$currPos = s2;
                            s2 = peg$FAILED;
                        }
                    }
                    else {
                        peg$currPos = s2;
                        s2 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s2;
                    s2 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s2;
                s2 = peg$FAILED;
            }
            if (s2 === peg$FAILED) {
                s2 = null;
            }
            if (s2 !== peg$FAILED) {
                peg$savedPos = s0;
                s1 = peg$c219();
                s0 = s1;
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parsegeneric_param() {
        var s0, s1, s2, s3, s4;
        s0 = peg$currPos;
        s1 = peg$parsetoken();
        if (s1 !== peg$FAILED) {
            s2 = peg$currPos;
            s3 = peg$parseEQUAL();
            if (s3 !== peg$FAILED) {
                s4 = peg$parsegen_value();
                if (s4 !== peg$FAILED) {
                    s3 = [s3, s4];
                    s2 = s3;
                }
                else {
                    peg$currPos = s2;
                    s2 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s2;
                s2 = peg$FAILED;
            }
            if (s2 === peg$FAILED) {
                s2 = null;
            }
            if (s2 !== peg$FAILED) {
                peg$savedPos = s0;
                s1 = peg$c220(s1, s2);
                s0 = s1;
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parsegen_value() {
        var s0;
        s0 = peg$parsetoken();
        if (s0 === peg$FAILED) {
            s0 = peg$parsehost();
            if (s0 === peg$FAILED) {
                s0 = peg$parsequoted_string();
            }
        }
        return s0;
    }
    function peg$parseContent_Disposition() {
        var s0, s1, s2, s3, s4, s5;
        s0 = peg$currPos;
        s1 = peg$parsedisp_type();
        if (s1 !== peg$FAILED) {
            s2 = [];
            s3 = peg$currPos;
            s4 = peg$parseSEMI();
            if (s4 !== peg$FAILED) {
                s5 = peg$parsedisp_param();
                if (s5 !== peg$FAILED) {
                    s4 = [s4, s5];
                    s3 = s4;
                }
                else {
                    peg$currPos = s3;
                    s3 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s3;
                s3 = peg$FAILED;
            }
            while (s3 !== peg$FAILED) {
                s2.push(s3);
                s3 = peg$currPos;
                s4 = peg$parseSEMI();
                if (s4 !== peg$FAILED) {
                    s5 = peg$parsedisp_param();
                    if (s5 !== peg$FAILED) {
                        s4 = [s4, s5];
                        s3 = s4;
                    }
                    else {
                        peg$currPos = s3;
                        s3 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s3;
                    s3 = peg$FAILED;
                }
            }
            if (s2 !== peg$FAILED) {
                s1 = [s1, s2];
                s0 = s1;
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parsedisp_type() {
        var s0, s1;
        s0 = peg$currPos;
        if (input.substr(peg$currPos, 6).toLowerCase() === peg$c221) {
            s1 = input.substr(peg$currPos, 6);
            peg$currPos += 6;
        }
        else {
            s1 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c222);
            }
        }
        if (s1 === peg$FAILED) {
            if (input.substr(peg$currPos, 7).toLowerCase() === peg$c223) {
                s1 = input.substr(peg$currPos, 7);
                peg$currPos += 7;
            }
            else {
                s1 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c224);
                }
            }
            if (s1 === peg$FAILED) {
                if (input.substr(peg$currPos, 4).toLowerCase() === peg$c225) {
                    s1 = input.substr(peg$currPos, 4);
                    peg$currPos += 4;
                }
                else {
                    s1 = peg$FAILED;
                    if (peg$silentFails === 0) {
                        peg$fail(peg$c226);
                    }
                }
                if (s1 === peg$FAILED) {
                    if (input.substr(peg$currPos, 5).toLowerCase() === peg$c227) {
                        s1 = input.substr(peg$currPos, 5);
                        peg$currPos += 5;
                    }
                    else {
                        s1 = peg$FAILED;
                        if (peg$silentFails === 0) {
                            peg$fail(peg$c228);
                        }
                    }
                    if (s1 === peg$FAILED) {
                        s1 = peg$parsetoken();
                    }
                }
            }
        }
        if (s1 !== peg$FAILED) {
            peg$savedPos = s0;
            s1 = peg$c229();
        }
        s0 = s1;
        return s0;
    }
    function peg$parsedisp_param() {
        var s0;
        s0 = peg$parsehandling_param();
        if (s0 === peg$FAILED) {
            s0 = peg$parsegeneric_param();
        }
        return s0;
    }
    function peg$parsehandling_param() {
        var s0, s1, s2, s3;
        s0 = peg$currPos;
        if (input.substr(peg$currPos, 8).toLowerCase() === peg$c230) {
            s1 = input.substr(peg$currPos, 8);
            peg$currPos += 8;
        }
        else {
            s1 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c231);
            }
        }
        if (s1 !== peg$FAILED) {
            s2 = peg$parseEQUAL();
            if (s2 !== peg$FAILED) {
                if (input.substr(peg$currPos, 8).toLowerCase() === peg$c232) {
                    s3 = input.substr(peg$currPos, 8);
                    peg$currPos += 8;
                }
                else {
                    s3 = peg$FAILED;
                    if (peg$silentFails === 0) {
                        peg$fail(peg$c233);
                    }
                }
                if (s3 === peg$FAILED) {
                    if (input.substr(peg$currPos, 8).toLowerCase() === peg$c234) {
                        s3 = input.substr(peg$currPos, 8);
                        peg$currPos += 8;
                    }
                    else {
                        s3 = peg$FAILED;
                        if (peg$silentFails === 0) {
                            peg$fail(peg$c235);
                        }
                    }
                    if (s3 === peg$FAILED) {
                        s3 = peg$parsetoken();
                    }
                }
                if (s3 !== peg$FAILED) {
                    s1 = [s1, s2, s3];
                    s0 = s1;
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parseContent_Encoding() {
        var s0, s1, s2, s3, s4, s5;
        s0 = peg$currPos;
        s1 = peg$parsetoken();
        if (s1 !== peg$FAILED) {
            s2 = [];
            s3 = peg$currPos;
            s4 = peg$parseCOMMA();
            if (s4 !== peg$FAILED) {
                s5 = peg$parsetoken();
                if (s5 !== peg$FAILED) {
                    s4 = [s4, s5];
                    s3 = s4;
                }
                else {
                    peg$currPos = s3;
                    s3 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s3;
                s3 = peg$FAILED;
            }
            while (s3 !== peg$FAILED) {
                s2.push(s3);
                s3 = peg$currPos;
                s4 = peg$parseCOMMA();
                if (s4 !== peg$FAILED) {
                    s5 = peg$parsetoken();
                    if (s5 !== peg$FAILED) {
                        s4 = [s4, s5];
                        s3 = s4;
                    }
                    else {
                        peg$currPos = s3;
                        s3 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s3;
                    s3 = peg$FAILED;
                }
            }
            if (s2 !== peg$FAILED) {
                s1 = [s1, s2];
                s0 = s1;
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parseContent_Length() {
        var s0, s1, s2;
        s0 = peg$currPos;
        s1 = [];
        s2 = peg$parseDIGIT();
        if (s2 !== peg$FAILED) {
            while (s2 !== peg$FAILED) {
                s1.push(s2);
                s2 = peg$parseDIGIT();
            }
        }
        else {
            s1 = peg$FAILED;
        }
        if (s1 !== peg$FAILED) {
            peg$savedPos = s0;
            s1 = peg$c236(s1);
        }
        s0 = s1;
        return s0;
    }
    function peg$parseContent_Type() {
        var s0, s1;
        s0 = peg$currPos;
        s1 = peg$parsemedia_type();
        if (s1 !== peg$FAILED) {
            peg$savedPos = s0;
            s1 = peg$c237();
        }
        s0 = s1;
        return s0;
    }
    function peg$parsemedia_type() {
        var s0, s1, s2, s3, s4, s5, s6, s7;
        s0 = peg$currPos;
        s1 = peg$parsem_type();
        if (s1 !== peg$FAILED) {
            s2 = peg$parseSLASH();
            if (s2 !== peg$FAILED) {
                s3 = peg$parsem_subtype();
                if (s3 !== peg$FAILED) {
                    s4 = [];
                    s5 = peg$currPos;
                    s6 = peg$parseSEMI();
                    if (s6 !== peg$FAILED) {
                        s7 = peg$parsem_parameter();
                        if (s7 !== peg$FAILED) {
                            s6 = [s6, s7];
                            s5 = s6;
                        }
                        else {
                            peg$currPos = s5;
                            s5 = peg$FAILED;
                        }
                    }
                    else {
                        peg$currPos = s5;
                        s5 = peg$FAILED;
                    }
                    while (s5 !== peg$FAILED) {
                        s4.push(s5);
                        s5 = peg$currPos;
                        s6 = peg$parseSEMI();
                        if (s6 !== peg$FAILED) {
                            s7 = peg$parsem_parameter();
                            if (s7 !== peg$FAILED) {
                                s6 = [s6, s7];
                                s5 = s6;
                            }
                            else {
                                peg$currPos = s5;
                                s5 = peg$FAILED;
                            }
                        }
                        else {
                            peg$currPos = s5;
                            s5 = peg$FAILED;
                        }
                    }
                    if (s4 !== peg$FAILED) {
                        s1 = [s1, s2, s3, s4];
                        s0 = s1;
                    }
                    else {
                        peg$currPos = s0;
                        s0 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parsem_type() {
        var s0;
        s0 = peg$parsediscrete_type();
        if (s0 === peg$FAILED) {
            s0 = peg$parsecomposite_type();
        }
        return s0;
    }
    function peg$parsediscrete_type() {
        var s0;
        if (input.substr(peg$currPos, 4).toLowerCase() === peg$c238) {
            s0 = input.substr(peg$currPos, 4);
            peg$currPos += 4;
        }
        else {
            s0 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c239);
            }
        }
        if (s0 === peg$FAILED) {
            if (input.substr(peg$currPos, 5).toLowerCase() === peg$c240) {
                s0 = input.substr(peg$currPos, 5);
                peg$currPos += 5;
            }
            else {
                s0 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c241);
                }
            }
            if (s0 === peg$FAILED) {
                if (input.substr(peg$currPos, 5).toLowerCase() === peg$c242) {
                    s0 = input.substr(peg$currPos, 5);
                    peg$currPos += 5;
                }
                else {
                    s0 = peg$FAILED;
                    if (peg$silentFails === 0) {
                        peg$fail(peg$c243);
                    }
                }
                if (s0 === peg$FAILED) {
                    if (input.substr(peg$currPos, 5).toLowerCase() === peg$c244) {
                        s0 = input.substr(peg$currPos, 5);
                        peg$currPos += 5;
                    }
                    else {
                        s0 = peg$FAILED;
                        if (peg$silentFails === 0) {
                            peg$fail(peg$c245);
                        }
                    }
                    if (s0 === peg$FAILED) {
                        if (input.substr(peg$currPos, 11).toLowerCase() === peg$c246) {
                            s0 = input.substr(peg$currPos, 11);
                            peg$currPos += 11;
                        }
                        else {
                            s0 = peg$FAILED;
                            if (peg$silentFails === 0) {
                                peg$fail(peg$c247);
                            }
                        }
                        if (s0 === peg$FAILED) {
                            s0 = peg$parseextension_token();
                        }
                    }
                }
            }
        }
        return s0;
    }
    function peg$parsecomposite_type() {
        var s0;
        if (input.substr(peg$currPos, 7).toLowerCase() === peg$c248) {
            s0 = input.substr(peg$currPos, 7);
            peg$currPos += 7;
        }
        else {
            s0 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c249);
            }
        }
        if (s0 === peg$FAILED) {
            if (input.substr(peg$currPos, 9).toLowerCase() === peg$c250) {
                s0 = input.substr(peg$currPos, 9);
                peg$currPos += 9;
            }
            else {
                s0 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c251);
                }
            }
            if (s0 === peg$FAILED) {
                s0 = peg$parseextension_token();
            }
        }
        return s0;
    }
    function peg$parseextension_token() {
        var s0;
        s0 = peg$parsetoken();
        if (s0 === peg$FAILED) {
            s0 = peg$parsex_token();
        }
        return s0;
    }
    function peg$parsex_token() {
        var s0, s1, s2;
        s0 = peg$currPos;
        if (input.substr(peg$currPos, 2).toLowerCase() === peg$c252) {
            s1 = input.substr(peg$currPos, 2);
            peg$currPos += 2;
        }
        else {
            s1 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c253);
            }
        }
        if (s1 !== peg$FAILED) {
            s2 = peg$parsetoken();
            if (s2 !== peg$FAILED) {
                s1 = [s1, s2];
                s0 = s1;
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parsem_subtype() {
        var s0;
        s0 = peg$parseextension_token();
        if (s0 === peg$FAILED) {
            s0 = peg$parsetoken();
        }
        return s0;
    }
    function peg$parsem_parameter() {
        var s0, s1, s2, s3;
        s0 = peg$currPos;
        s1 = peg$parsetoken();
        if (s1 !== peg$FAILED) {
            s2 = peg$parseEQUAL();
            if (s2 !== peg$FAILED) {
                s3 = peg$parsem_value();
                if (s3 !== peg$FAILED) {
                    s1 = [s1, s2, s3];
                    s0 = s1;
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parsem_value() {
        var s0;
        s0 = peg$parsetoken();
        if (s0 === peg$FAILED) {
            s0 = peg$parsequoted_string();
        }
        return s0;
    }
    function peg$parseCSeq() {
        var s0, s1, s2, s3;
        s0 = peg$currPos;
        s1 = peg$parseCSeq_value();
        if (s1 !== peg$FAILED) {
            s2 = peg$parseLWS();
            if (s2 !== peg$FAILED) {
                s3 = peg$parseMethod();
                if (s3 !== peg$FAILED) {
                    s1 = [s1, s2, s3];
                    s0 = s1;
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parseCSeq_value() {
        var s0, s1, s2;
        s0 = peg$currPos;
        s1 = [];
        s2 = peg$parseDIGIT();
        if (s2 !== peg$FAILED) {
            while (s2 !== peg$FAILED) {
                s1.push(s2);
                s2 = peg$parseDIGIT();
            }
        }
        else {
            s1 = peg$FAILED;
        }
        if (s1 !== peg$FAILED) {
            peg$savedPos = s0;
            s1 = peg$c254(s1);
        }
        s0 = s1;
        return s0;
    }
    function peg$parseExpires() {
        var s0, s1;
        s0 = peg$currPos;
        s1 = peg$parsedelta_seconds();
        if (s1 !== peg$FAILED) {
            peg$savedPos = s0;
            s1 = peg$c255(s1);
        }
        s0 = s1;
        return s0;
    }
    function peg$parseEvent() {
        var s0, s1, s2, s3, s4, s5;
        s0 = peg$currPos;
        s1 = peg$parseevent_type();
        if (s1 !== peg$FAILED) {
            s2 = [];
            s3 = peg$currPos;
            s4 = peg$parseSEMI();
            if (s4 !== peg$FAILED) {
                s5 = peg$parsegeneric_param();
                if (s5 !== peg$FAILED) {
                    s4 = [s4, s5];
                    s3 = s4;
                }
                else {
                    peg$currPos = s3;
                    s3 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s3;
                s3 = peg$FAILED;
            }
            while (s3 !== peg$FAILED) {
                s2.push(s3);
                s3 = peg$currPos;
                s4 = peg$parseSEMI();
                if (s4 !== peg$FAILED) {
                    s5 = peg$parsegeneric_param();
                    if (s5 !== peg$FAILED) {
                        s4 = [s4, s5];
                        s3 = s4;
                    }
                    else {
                        peg$currPos = s3;
                        s3 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s3;
                    s3 = peg$FAILED;
                }
            }
            if (s2 !== peg$FAILED) {
                peg$savedPos = s0;
                s1 = peg$c256(s1);
                s0 = s1;
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parseevent_type() {
        var s0, s1, s2, s3, s4, s5, s6;
        s0 = peg$currPos;
        s1 = peg$currPos;
        s2 = peg$parsetoken_nodot();
        if (s2 !== peg$FAILED) {
            s3 = [];
            s4 = peg$currPos;
            if (input.charCodeAt(peg$currPos) === 46) {
                s5 = peg$c42;
                peg$currPos++;
            }
            else {
                s5 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c43);
                }
            }
            if (s5 !== peg$FAILED) {
                s6 = peg$parsetoken_nodot();
                if (s6 !== peg$FAILED) {
                    s5 = [s5, s6];
                    s4 = s5;
                }
                else {
                    peg$currPos = s4;
                    s4 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s4;
                s4 = peg$FAILED;
            }
            while (s4 !== peg$FAILED) {
                s3.push(s4);
                s4 = peg$currPos;
                if (input.charCodeAt(peg$currPos) === 46) {
                    s5 = peg$c42;
                    peg$currPos++;
                }
                else {
                    s5 = peg$FAILED;
                    if (peg$silentFails === 0) {
                        peg$fail(peg$c43);
                    }
                }
                if (s5 !== peg$FAILED) {
                    s6 = peg$parsetoken_nodot();
                    if (s6 !== peg$FAILED) {
                        s5 = [s5, s6];
                        s4 = s5;
                    }
                    else {
                        peg$currPos = s4;
                        s4 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s4;
                    s4 = peg$FAILED;
                }
            }
            if (s3 !== peg$FAILED) {
                s2 = [s2, s3];
                s1 = s2;
            }
            else {
                peg$currPos = s1;
                s1 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s1;
            s1 = peg$FAILED;
        }
        if (s1 !== peg$FAILED) {
            s0 = input.substring(s0, peg$currPos);
        }
        else {
            s0 = s1;
        }
        return s0;
    }
    function peg$parseFrom() {
        var s0, s1, s2, s3, s4, s5;
        s0 = peg$currPos;
        s1 = peg$parseSIP_URI_noparams();
        if (s1 === peg$FAILED) {
            s1 = peg$parsename_addr();
        }
        if (s1 !== peg$FAILED) {
            s2 = [];
            s3 = peg$currPos;
            s4 = peg$parseSEMI();
            if (s4 !== peg$FAILED) {
                s5 = peg$parsefrom_param();
                if (s5 !== peg$FAILED) {
                    s4 = [s4, s5];
                    s3 = s4;
                }
                else {
                    peg$currPos = s3;
                    s3 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s3;
                s3 = peg$FAILED;
            }
            while (s3 !== peg$FAILED) {
                s2.push(s3);
                s3 = peg$currPos;
                s4 = peg$parseSEMI();
                if (s4 !== peg$FAILED) {
                    s5 = peg$parsefrom_param();
                    if (s5 !== peg$FAILED) {
                        s4 = [s4, s5];
                        s3 = s4;
                    }
                    else {
                        peg$currPos = s3;
                        s3 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s3;
                    s3 = peg$FAILED;
                }
            }
            if (s2 !== peg$FAILED) {
                peg$savedPos = s0;
                s1 = peg$c257();
                s0 = s1;
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parsefrom_param() {
        var s0;
        s0 = peg$parsetag_param();
        if (s0 === peg$FAILED) {
            s0 = peg$parsegeneric_param();
        }
        return s0;
    }
    function peg$parsetag_param() {
        var s0, s1, s2, s3;
        s0 = peg$currPos;
        if (input.substr(peg$currPos, 3).toLowerCase() === peg$c258) {
            s1 = input.substr(peg$currPos, 3);
            peg$currPos += 3;
        }
        else {
            s1 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c259);
            }
        }
        if (s1 !== peg$FAILED) {
            s2 = peg$parseEQUAL();
            if (s2 !== peg$FAILED) {
                s3 = peg$parsetoken();
                if (s3 !== peg$FAILED) {
                    peg$savedPos = s0;
                    s1 = peg$c260(s3);
                    s0 = s1;
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parseMax_Forwards() {
        var s0, s1, s2;
        s0 = peg$currPos;
        s1 = [];
        s2 = peg$parseDIGIT();
        if (s2 !== peg$FAILED) {
            while (s2 !== peg$FAILED) {
                s1.push(s2);
                s2 = peg$parseDIGIT();
            }
        }
        else {
            s1 = peg$FAILED;
        }
        if (s1 !== peg$FAILED) {
            peg$savedPos = s0;
            s1 = peg$c261(s1);
        }
        s0 = s1;
        return s0;
    }
    function peg$parseMin_Expires() {
        var s0, s1;
        s0 = peg$currPos;
        s1 = peg$parsedelta_seconds();
        if (s1 !== peg$FAILED) {
            peg$savedPos = s0;
            s1 = peg$c262(s1);
        }
        s0 = s1;
        return s0;
    }
    function peg$parseName_Addr_Header() {
        var s0, s1, s2, s3, s4, s5, s6, s7, s8;
        s0 = peg$currPos;
        s1 = [];
        s2 = peg$parsedisplayName();
        while (s2 !== peg$FAILED) {
            s1.push(s2);
            s2 = peg$parsedisplayName();
        }
        if (s1 !== peg$FAILED) {
            s2 = peg$parseLAQUOT();
            if (s2 !== peg$FAILED) {
                s3 = peg$parseSIP_URI();
                if (s3 !== peg$FAILED) {
                    s4 = peg$parseRAQUOT();
                    if (s4 !== peg$FAILED) {
                        s5 = [];
                        s6 = peg$currPos;
                        s7 = peg$parseSEMI();
                        if (s7 !== peg$FAILED) {
                            s8 = peg$parsegeneric_param();
                            if (s8 !== peg$FAILED) {
                                s7 = [s7, s8];
                                s6 = s7;
                            }
                            else {
                                peg$currPos = s6;
                                s6 = peg$FAILED;
                            }
                        }
                        else {
                            peg$currPos = s6;
                            s6 = peg$FAILED;
                        }
                        while (s6 !== peg$FAILED) {
                            s5.push(s6);
                            s6 = peg$currPos;
                            s7 = peg$parseSEMI();
                            if (s7 !== peg$FAILED) {
                                s8 = peg$parsegeneric_param();
                                if (s8 !== peg$FAILED) {
                                    s7 = [s7, s8];
                                    s6 = s7;
                                }
                                else {
                                    peg$currPos = s6;
                                    s6 = peg$FAILED;
                                }
                            }
                            else {
                                peg$currPos = s6;
                                s6 = peg$FAILED;
                            }
                        }
                        if (s5 !== peg$FAILED) {
                            peg$savedPos = s0;
                            s1 = peg$c263();
                            s0 = s1;
                        }
                        else {
                            peg$currPos = s0;
                            s0 = peg$FAILED;
                        }
                    }
                    else {
                        peg$currPos = s0;
                        s0 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parseProxy_Authenticate() {
        var s0;
        s0 = peg$parsechallenge();
        return s0;
    }
    function peg$parsechallenge() {
        var s0, s1, s2, s3, s4, s5, s6, s7;
        s0 = peg$currPos;
        if (input.substr(peg$currPos, 6).toLowerCase() === peg$c264) {
            s1 = input.substr(peg$currPos, 6);
            peg$currPos += 6;
        }
        else {
            s1 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c265);
            }
        }
        if (s1 !== peg$FAILED) {
            s2 = peg$parseLWS();
            if (s2 !== peg$FAILED) {
                s3 = peg$parsedigest_cln();
                if (s3 !== peg$FAILED) {
                    s4 = [];
                    s5 = peg$currPos;
                    s6 = peg$parseCOMMA();
                    if (s6 !== peg$FAILED) {
                        s7 = peg$parsedigest_cln();
                        if (s7 !== peg$FAILED) {
                            s6 = [s6, s7];
                            s5 = s6;
                        }
                        else {
                            peg$currPos = s5;
                            s5 = peg$FAILED;
                        }
                    }
                    else {
                        peg$currPos = s5;
                        s5 = peg$FAILED;
                    }
                    while (s5 !== peg$FAILED) {
                        s4.push(s5);
                        s5 = peg$currPos;
                        s6 = peg$parseCOMMA();
                        if (s6 !== peg$FAILED) {
                            s7 = peg$parsedigest_cln();
                            if (s7 !== peg$FAILED) {
                                s6 = [s6, s7];
                                s5 = s6;
                            }
                            else {
                                peg$currPos = s5;
                                s5 = peg$FAILED;
                            }
                        }
                        else {
                            peg$currPos = s5;
                            s5 = peg$FAILED;
                        }
                    }
                    if (s4 !== peg$FAILED) {
                        s1 = [s1, s2, s3, s4];
                        s0 = s1;
                    }
                    else {
                        peg$currPos = s0;
                        s0 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        if (s0 === peg$FAILED) {
            s0 = peg$parseother_challenge();
        }
        return s0;
    }
    function peg$parseother_challenge() {
        var s0, s1, s2, s3, s4, s5, s6, s7;
        s0 = peg$currPos;
        s1 = peg$parsetoken();
        if (s1 !== peg$FAILED) {
            s2 = peg$parseLWS();
            if (s2 !== peg$FAILED) {
                s3 = peg$parseauth_param();
                if (s3 !== peg$FAILED) {
                    s4 = [];
                    s5 = peg$currPos;
                    s6 = peg$parseCOMMA();
                    if (s6 !== peg$FAILED) {
                        s7 = peg$parseauth_param();
                        if (s7 !== peg$FAILED) {
                            s6 = [s6, s7];
                            s5 = s6;
                        }
                        else {
                            peg$currPos = s5;
                            s5 = peg$FAILED;
                        }
                    }
                    else {
                        peg$currPos = s5;
                        s5 = peg$FAILED;
                    }
                    while (s5 !== peg$FAILED) {
                        s4.push(s5);
                        s5 = peg$currPos;
                        s6 = peg$parseCOMMA();
                        if (s6 !== peg$FAILED) {
                            s7 = peg$parseauth_param();
                            if (s7 !== peg$FAILED) {
                                s6 = [s6, s7];
                                s5 = s6;
                            }
                            else {
                                peg$currPos = s5;
                                s5 = peg$FAILED;
                            }
                        }
                        else {
                            peg$currPos = s5;
                            s5 = peg$FAILED;
                        }
                    }
                    if (s4 !== peg$FAILED) {
                        s1 = [s1, s2, s3, s4];
                        s0 = s1;
                    }
                    else {
                        peg$currPos = s0;
                        s0 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parseauth_param() {
        var s0, s1, s2, s3;
        s0 = peg$currPos;
        s1 = peg$parsetoken();
        if (s1 !== peg$FAILED) {
            s2 = peg$parseEQUAL();
            if (s2 !== peg$FAILED) {
                s3 = peg$parsetoken();
                if (s3 === peg$FAILED) {
                    s3 = peg$parsequoted_string();
                }
                if (s3 !== peg$FAILED) {
                    s1 = [s1, s2, s3];
                    s0 = s1;
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parsedigest_cln() {
        var s0;
        s0 = peg$parserealm();
        if (s0 === peg$FAILED) {
            s0 = peg$parsedomain();
            if (s0 === peg$FAILED) {
                s0 = peg$parsenonce();
                if (s0 === peg$FAILED) {
                    s0 = peg$parseopaque();
                    if (s0 === peg$FAILED) {
                        s0 = peg$parsestale();
                        if (s0 === peg$FAILED) {
                            s0 = peg$parsealgorithm();
                            if (s0 === peg$FAILED) {
                                s0 = peg$parseqop_options();
                                if (s0 === peg$FAILED) {
                                    s0 = peg$parseauth_param();
                                }
                            }
                        }
                    }
                }
            }
        }
        return s0;
    }
    function peg$parserealm() {
        var s0, s1, s2, s3;
        s0 = peg$currPos;
        if (input.substr(peg$currPos, 5).toLowerCase() === peg$c266) {
            s1 = input.substr(peg$currPos, 5);
            peg$currPos += 5;
        }
        else {
            s1 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c267);
            }
        }
        if (s1 !== peg$FAILED) {
            s2 = peg$parseEQUAL();
            if (s2 !== peg$FAILED) {
                s3 = peg$parserealm_value();
                if (s3 !== peg$FAILED) {
                    s1 = [s1, s2, s3];
                    s0 = s1;
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parserealm_value() {
        var s0, s1;
        s0 = peg$currPos;
        s1 = peg$parsequoted_string_clean();
        if (s1 !== peg$FAILED) {
            peg$savedPos = s0;
            s1 = peg$c268(s1);
        }
        s0 = s1;
        return s0;
    }
    function peg$parsedomain() {
        var s0, s1, s2, s3, s4, s5, s6, s7, s8;
        s0 = peg$currPos;
        if (input.substr(peg$currPos, 6).toLowerCase() === peg$c269) {
            s1 = input.substr(peg$currPos, 6);
            peg$currPos += 6;
        }
        else {
            s1 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c270);
            }
        }
        if (s1 !== peg$FAILED) {
            s2 = peg$parseEQUAL();
            if (s2 !== peg$FAILED) {
                s3 = peg$parseLDQUOT();
                if (s3 !== peg$FAILED) {
                    s4 = peg$parseURI();
                    if (s4 !== peg$FAILED) {
                        s5 = [];
                        s6 = peg$currPos;
                        s7 = [];
                        s8 = peg$parseSP();
                        if (s8 !== peg$FAILED) {
                            while (s8 !== peg$FAILED) {
                                s7.push(s8);
                                s8 = peg$parseSP();
                            }
                        }
                        else {
                            s7 = peg$FAILED;
                        }
                        if (s7 !== peg$FAILED) {
                            s8 = peg$parseURI();
                            if (s8 !== peg$FAILED) {
                                s7 = [s7, s8];
                                s6 = s7;
                            }
                            else {
                                peg$currPos = s6;
                                s6 = peg$FAILED;
                            }
                        }
                        else {
                            peg$currPos = s6;
                            s6 = peg$FAILED;
                        }
                        while (s6 !== peg$FAILED) {
                            s5.push(s6);
                            s6 = peg$currPos;
                            s7 = [];
                            s8 = peg$parseSP();
                            if (s8 !== peg$FAILED) {
                                while (s8 !== peg$FAILED) {
                                    s7.push(s8);
                                    s8 = peg$parseSP();
                                }
                            }
                            else {
                                s7 = peg$FAILED;
                            }
                            if (s7 !== peg$FAILED) {
                                s8 = peg$parseURI();
                                if (s8 !== peg$FAILED) {
                                    s7 = [s7, s8];
                                    s6 = s7;
                                }
                                else {
                                    peg$currPos = s6;
                                    s6 = peg$FAILED;
                                }
                            }
                            else {
                                peg$currPos = s6;
                                s6 = peg$FAILED;
                            }
                        }
                        if (s5 !== peg$FAILED) {
                            s6 = peg$parseRDQUOT();
                            if (s6 !== peg$FAILED) {
                                s1 = [s1, s2, s3, s4, s5, s6];
                                s0 = s1;
                            }
                            else {
                                peg$currPos = s0;
                                s0 = peg$FAILED;
                            }
                        }
                        else {
                            peg$currPos = s0;
                            s0 = peg$FAILED;
                        }
                    }
                    else {
                        peg$currPos = s0;
                        s0 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parseURI() {
        var s0;
        s0 = peg$parseabsoluteURI();
        if (s0 === peg$FAILED) {
            s0 = peg$parseabs_path();
        }
        return s0;
    }
    function peg$parsenonce() {
        var s0, s1, s2, s3;
        s0 = peg$currPos;
        if (input.substr(peg$currPos, 5).toLowerCase() === peg$c271) {
            s1 = input.substr(peg$currPos, 5);
            peg$currPos += 5;
        }
        else {
            s1 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c272);
            }
        }
        if (s1 !== peg$FAILED) {
            s2 = peg$parseEQUAL();
            if (s2 !== peg$FAILED) {
                s3 = peg$parsenonce_value();
                if (s3 !== peg$FAILED) {
                    s1 = [s1, s2, s3];
                    s0 = s1;
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parsenonce_value() {
        var s0, s1;
        s0 = peg$currPos;
        s1 = peg$parsequoted_string_clean();
        if (s1 !== peg$FAILED) {
            peg$savedPos = s0;
            s1 = peg$c273(s1);
        }
        s0 = s1;
        return s0;
    }
    function peg$parseopaque() {
        var s0, s1, s2, s3;
        s0 = peg$currPos;
        if (input.substr(peg$currPos, 6).toLowerCase() === peg$c274) {
            s1 = input.substr(peg$currPos, 6);
            peg$currPos += 6;
        }
        else {
            s1 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c275);
            }
        }
        if (s1 !== peg$FAILED) {
            s2 = peg$parseEQUAL();
            if (s2 !== peg$FAILED) {
                s3 = peg$parsequoted_string_clean();
                if (s3 !== peg$FAILED) {
                    peg$savedPos = s0;
                    s1 = peg$c276(s3);
                    s0 = s1;
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parsestale() {
        var s0, s1, s2, s3, s4;
        s0 = peg$currPos;
        if (input.substr(peg$currPos, 5).toLowerCase() === peg$c277) {
            s1 = input.substr(peg$currPos, 5);
            peg$currPos += 5;
        }
        else {
            s1 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c278);
            }
        }
        if (s1 !== peg$FAILED) {
            s2 = peg$parseEQUAL();
            if (s2 !== peg$FAILED) {
                s3 = peg$currPos;
                if (input.substr(peg$currPos, 4).toLowerCase() === peg$c279) {
                    s4 = input.substr(peg$currPos, 4);
                    peg$currPos += 4;
                }
                else {
                    s4 = peg$FAILED;
                    if (peg$silentFails === 0) {
                        peg$fail(peg$c280);
                    }
                }
                if (s4 !== peg$FAILED) {
                    peg$savedPos = s3;
                    s4 = peg$c281();
                }
                s3 = s4;
                if (s3 === peg$FAILED) {
                    s3 = peg$currPos;
                    if (input.substr(peg$currPos, 5).toLowerCase() === peg$c282) {
                        s4 = input.substr(peg$currPos, 5);
                        peg$currPos += 5;
                    }
                    else {
                        s4 = peg$FAILED;
                        if (peg$silentFails === 0) {
                            peg$fail(peg$c283);
                        }
                    }
                    if (s4 !== peg$FAILED) {
                        peg$savedPos = s3;
                        s4 = peg$c284();
                    }
                    s3 = s4;
                }
                if (s3 !== peg$FAILED) {
                    s1 = [s1, s2, s3];
                    s0 = s1;
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parsealgorithm() {
        var s0, s1, s2, s3;
        s0 = peg$currPos;
        if (input.substr(peg$currPos, 9).toLowerCase() === peg$c285) {
            s1 = input.substr(peg$currPos, 9);
            peg$currPos += 9;
        }
        else {
            s1 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c286);
            }
        }
        if (s1 !== peg$FAILED) {
            s2 = peg$parseEQUAL();
            if (s2 !== peg$FAILED) {
                if (input.substr(peg$currPos, 3).toLowerCase() === peg$c287) {
                    s3 = input.substr(peg$currPos, 3);
                    peg$currPos += 3;
                }
                else {
                    s3 = peg$FAILED;
                    if (peg$silentFails === 0) {
                        peg$fail(peg$c288);
                    }
                }
                if (s3 === peg$FAILED) {
                    if (input.substr(peg$currPos, 8).toLowerCase() === peg$c289) {
                        s3 = input.substr(peg$currPos, 8);
                        peg$currPos += 8;
                    }
                    else {
                        s3 = peg$FAILED;
                        if (peg$silentFails === 0) {
                            peg$fail(peg$c290);
                        }
                    }
                    if (s3 === peg$FAILED) {
                        s3 = peg$parsetoken();
                    }
                }
                if (s3 !== peg$FAILED) {
                    peg$savedPos = s0;
                    s1 = peg$c291(s3);
                    s0 = s1;
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parseqop_options() {
        var s0, s1, s2, s3, s4, s5, s6, s7, s8, s9;
        s0 = peg$currPos;
        if (input.substr(peg$currPos, 3).toLowerCase() === peg$c292) {
            s1 = input.substr(peg$currPos, 3);
            peg$currPos += 3;
        }
        else {
            s1 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c293);
            }
        }
        if (s1 !== peg$FAILED) {
            s2 = peg$parseEQUAL();
            if (s2 !== peg$FAILED) {
                s3 = peg$parseLDQUOT();
                if (s3 !== peg$FAILED) {
                    s4 = peg$currPos;
                    s5 = peg$parseqop_value();
                    if (s5 !== peg$FAILED) {
                        s6 = [];
                        s7 = peg$currPos;
                        if (input.charCodeAt(peg$currPos) === 44) {
                            s8 = peg$c36;
                            peg$currPos++;
                        }
                        else {
                            s8 = peg$FAILED;
                            if (peg$silentFails === 0) {
                                peg$fail(peg$c37);
                            }
                        }
                        if (s8 !== peg$FAILED) {
                            s9 = peg$parseqop_value();
                            if (s9 !== peg$FAILED) {
                                s8 = [s8, s9];
                                s7 = s8;
                            }
                            else {
                                peg$currPos = s7;
                                s7 = peg$FAILED;
                            }
                        }
                        else {
                            peg$currPos = s7;
                            s7 = peg$FAILED;
                        }
                        while (s7 !== peg$FAILED) {
                            s6.push(s7);
                            s7 = peg$currPos;
                            if (input.charCodeAt(peg$currPos) === 44) {
                                s8 = peg$c36;
                                peg$currPos++;
                            }
                            else {
                                s8 = peg$FAILED;
                                if (peg$silentFails === 0) {
                                    peg$fail(peg$c37);
                                }
                            }
                            if (s8 !== peg$FAILED) {
                                s9 = peg$parseqop_value();
                                if (s9 !== peg$FAILED) {
                                    s8 = [s8, s9];
                                    s7 = s8;
                                }
                                else {
                                    peg$currPos = s7;
                                    s7 = peg$FAILED;
                                }
                            }
                            else {
                                peg$currPos = s7;
                                s7 = peg$FAILED;
                            }
                        }
                        if (s6 !== peg$FAILED) {
                            s5 = [s5, s6];
                            s4 = s5;
                        }
                        else {
                            peg$currPos = s4;
                            s4 = peg$FAILED;
                        }
                    }
                    else {
                        peg$currPos = s4;
                        s4 = peg$FAILED;
                    }
                    if (s4 !== peg$FAILED) {
                        s5 = peg$parseRDQUOT();
                        if (s5 !== peg$FAILED) {
                            s1 = [s1, s2, s3, s4, s5];
                            s0 = s1;
                        }
                        else {
                            peg$currPos = s0;
                            s0 = peg$FAILED;
                        }
                    }
                    else {
                        peg$currPos = s0;
                        s0 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parseqop_value() {
        var s0, s1;
        s0 = peg$currPos;
        if (input.substr(peg$currPos, 8).toLowerCase() === peg$c294) {
            s1 = input.substr(peg$currPos, 8);
            peg$currPos += 8;
        }
        else {
            s1 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c295);
            }
        }
        if (s1 === peg$FAILED) {
            if (input.substr(peg$currPos, 4).toLowerCase() === peg$c296) {
                s1 = input.substr(peg$currPos, 4);
                peg$currPos += 4;
            }
            else {
                s1 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c297);
                }
            }
            if (s1 === peg$FAILED) {
                s1 = peg$parsetoken();
            }
        }
        if (s1 !== peg$FAILED) {
            peg$savedPos = s0;
            s1 = peg$c298(s1);
        }
        s0 = s1;
        return s0;
    }
    function peg$parseProxy_Require() {
        var s0, s1, s2, s3, s4, s5;
        s0 = peg$currPos;
        s1 = peg$parsetoken();
        if (s1 !== peg$FAILED) {
            s2 = [];
            s3 = peg$currPos;
            s4 = peg$parseCOMMA();
            if (s4 !== peg$FAILED) {
                s5 = peg$parsetoken();
                if (s5 !== peg$FAILED) {
                    s4 = [s4, s5];
                    s3 = s4;
                }
                else {
                    peg$currPos = s3;
                    s3 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s3;
                s3 = peg$FAILED;
            }
            while (s3 !== peg$FAILED) {
                s2.push(s3);
                s3 = peg$currPos;
                s4 = peg$parseCOMMA();
                if (s4 !== peg$FAILED) {
                    s5 = peg$parsetoken();
                    if (s5 !== peg$FAILED) {
                        s4 = [s4, s5];
                        s3 = s4;
                    }
                    else {
                        peg$currPos = s3;
                        s3 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s3;
                    s3 = peg$FAILED;
                }
            }
            if (s2 !== peg$FAILED) {
                s1 = [s1, s2];
                s0 = s1;
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parseRAck() {
        var s0, s1, s2, s3, s4, s5;
        s0 = peg$currPos;
        s1 = peg$parseRAck_value();
        if (s1 !== peg$FAILED) {
            s2 = peg$parseLWS();
            if (s2 !== peg$FAILED) {
                s3 = peg$parseRAck_value();
                if (s3 !== peg$FAILED) {
                    s4 = peg$parseLWS();
                    if (s4 !== peg$FAILED) {
                        s5 = peg$parseMethod();
                        if (s5 !== peg$FAILED) {
                            s1 = [s1, s2, s3, s4, s5];
                            s0 = s1;
                        }
                        else {
                            peg$currPos = s0;
                            s0 = peg$FAILED;
                        }
                    }
                    else {
                        peg$currPos = s0;
                        s0 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parseRAck_value() {
        var s0, s1, s2;
        s0 = peg$currPos;
        s1 = [];
        s2 = peg$parseDIGIT();
        if (s2 !== peg$FAILED) {
            while (s2 !== peg$FAILED) {
                s1.push(s2);
                s2 = peg$parseDIGIT();
            }
        }
        else {
            s1 = peg$FAILED;
        }
        if (s1 !== peg$FAILED) {
            peg$savedPos = s0;
            s1 = peg$c299(s1);
        }
        s0 = s1;
        return s0;
    }
    function peg$parseRecord_Route() {
        var s0, s1, s2, s3, s4, s5;
        s0 = peg$currPos;
        s1 = peg$parserec_route();
        if (s1 !== peg$FAILED) {
            s2 = [];
            s3 = peg$currPos;
            s4 = peg$parseCOMMA();
            if (s4 !== peg$FAILED) {
                s5 = peg$parserec_route();
                if (s5 !== peg$FAILED) {
                    s4 = [s4, s5];
                    s3 = s4;
                }
                else {
                    peg$currPos = s3;
                    s3 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s3;
                s3 = peg$FAILED;
            }
            while (s3 !== peg$FAILED) {
                s2.push(s3);
                s3 = peg$currPos;
                s4 = peg$parseCOMMA();
                if (s4 !== peg$FAILED) {
                    s5 = peg$parserec_route();
                    if (s5 !== peg$FAILED) {
                        s4 = [s4, s5];
                        s3 = s4;
                    }
                    else {
                        peg$currPos = s3;
                        s3 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s3;
                    s3 = peg$FAILED;
                }
            }
            if (s2 !== peg$FAILED) {
                peg$savedPos = s0;
                s1 = peg$c300();
                s0 = s1;
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parserec_route() {
        var s0, s1, s2, s3, s4, s5;
        s0 = peg$currPos;
        s1 = peg$parsename_addr();
        if (s1 !== peg$FAILED) {
            s2 = [];
            s3 = peg$currPos;
            s4 = peg$parseSEMI();
            if (s4 !== peg$FAILED) {
                s5 = peg$parsegeneric_param();
                if (s5 !== peg$FAILED) {
                    s4 = [s4, s5];
                    s3 = s4;
                }
                else {
                    peg$currPos = s3;
                    s3 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s3;
                s3 = peg$FAILED;
            }
            while (s3 !== peg$FAILED) {
                s2.push(s3);
                s3 = peg$currPos;
                s4 = peg$parseSEMI();
                if (s4 !== peg$FAILED) {
                    s5 = peg$parsegeneric_param();
                    if (s5 !== peg$FAILED) {
                        s4 = [s4, s5];
                        s3 = s4;
                    }
                    else {
                        peg$currPos = s3;
                        s3 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s3;
                    s3 = peg$FAILED;
                }
            }
            if (s2 !== peg$FAILED) {
                peg$savedPos = s0;
                s1 = peg$c301();
                s0 = s1;
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parseRefer_To() {
        var s0, s1, s2, s3, s4, s5;
        s0 = peg$currPos;
        s1 = peg$parseSIP_URI_noparams();
        if (s1 === peg$FAILED) {
            s1 = peg$parsename_addr();
            if (s1 === peg$FAILED) {
                s1 = peg$currPos;
                s2 = peg$parseLAQUOT();
                if (s2 === peg$FAILED) {
                    s2 = null;
                }
                if (s2 !== peg$FAILED) {
                    s3 = peg$parseabsoluteURI();
                    if (s3 !== peg$FAILED) {
                        s4 = peg$parseRAQUOT();
                        if (s4 === peg$FAILED) {
                            s4 = null;
                        }
                        if (s4 !== peg$FAILED) {
                            s2 = [s2, s3, s4];
                            s1 = s2;
                        }
                        else {
                            peg$currPos = s1;
                            s1 = peg$FAILED;
                        }
                    }
                    else {
                        peg$currPos = s1;
                        s1 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s1;
                    s1 = peg$FAILED;
                }
            }
        }
        if (s1 !== peg$FAILED) {
            s2 = [];
            s3 = peg$currPos;
            s4 = peg$parseSEMI();
            if (s4 !== peg$FAILED) {
                s5 = peg$parsegeneric_param();
                if (s5 !== peg$FAILED) {
                    s4 = [s4, s5];
                    s3 = s4;
                }
                else {
                    peg$currPos = s3;
                    s3 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s3;
                s3 = peg$FAILED;
            }
            while (s3 !== peg$FAILED) {
                s2.push(s3);
                s3 = peg$currPos;
                s4 = peg$parseSEMI();
                if (s4 !== peg$FAILED) {
                    s5 = peg$parsegeneric_param();
                    if (s5 !== peg$FAILED) {
                        s4 = [s4, s5];
                        s3 = s4;
                    }
                    else {
                        peg$currPos = s3;
                        s3 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s3;
                    s3 = peg$FAILED;
                }
            }
            if (s2 !== peg$FAILED) {
                peg$savedPos = s0;
                s1 = peg$c302();
                s0 = s1;
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parseReplaces() {
        var s0, s1, s2, s3, s4, s5;
        s0 = peg$currPos;
        s1 = peg$parsereplaces_call_id();
        if (s1 !== peg$FAILED) {
            s2 = [];
            s3 = peg$currPos;
            s4 = peg$parseSEMI();
            if (s4 !== peg$FAILED) {
                s5 = peg$parsereplaces_params();
                if (s5 !== peg$FAILED) {
                    s4 = [s4, s5];
                    s3 = s4;
                }
                else {
                    peg$currPos = s3;
                    s3 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s3;
                s3 = peg$FAILED;
            }
            while (s3 !== peg$FAILED) {
                s2.push(s3);
                s3 = peg$currPos;
                s4 = peg$parseSEMI();
                if (s4 !== peg$FAILED) {
                    s5 = peg$parsereplaces_params();
                    if (s5 !== peg$FAILED) {
                        s4 = [s4, s5];
                        s3 = s4;
                    }
                    else {
                        peg$currPos = s3;
                        s3 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s3;
                    s3 = peg$FAILED;
                }
            }
            if (s2 !== peg$FAILED) {
                peg$savedPos = s0;
                s1 = peg$c303();
                s0 = s1;
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parsereplaces_call_id() {
        var s0, s1;
        s0 = peg$currPos;
        s1 = peg$parseCall_ID();
        if (s1 !== peg$FAILED) {
            peg$savedPos = s0;
            s1 = peg$c304();
        }
        s0 = s1;
        return s0;
    }
    function peg$parsereplaces_params() {
        var s0, s1, s2, s3;
        s0 = peg$currPos;
        if (input.substr(peg$currPos, 8).toLowerCase() === peg$c305) {
            s1 = input.substr(peg$currPos, 8);
            peg$currPos += 8;
        }
        else {
            s1 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c306);
            }
        }
        if (s1 !== peg$FAILED) {
            s2 = peg$parseEQUAL();
            if (s2 !== peg$FAILED) {
                s3 = peg$parsetoken();
                if (s3 !== peg$FAILED) {
                    peg$savedPos = s0;
                    s1 = peg$c307(s3);
                    s0 = s1;
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        if (s0 === peg$FAILED) {
            s0 = peg$currPos;
            if (input.substr(peg$currPos, 6).toLowerCase() === peg$c308) {
                s1 = input.substr(peg$currPos, 6);
                peg$currPos += 6;
            }
            else {
                s1 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c309);
                }
            }
            if (s1 !== peg$FAILED) {
                s2 = peg$parseEQUAL();
                if (s2 !== peg$FAILED) {
                    s3 = peg$parsetoken();
                    if (s3 !== peg$FAILED) {
                        peg$savedPos = s0;
                        s1 = peg$c310(s3);
                        s0 = s1;
                    }
                    else {
                        peg$currPos = s0;
                        s0 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
            if (s0 === peg$FAILED) {
                s0 = peg$currPos;
                if (input.substr(peg$currPos, 10).toLowerCase() === peg$c311) {
                    s1 = input.substr(peg$currPos, 10);
                    peg$currPos += 10;
                }
                else {
                    s1 = peg$FAILED;
                    if (peg$silentFails === 0) {
                        peg$fail(peg$c312);
                    }
                }
                if (s1 !== peg$FAILED) {
                    peg$savedPos = s0;
                    s1 = peg$c313();
                }
                s0 = s1;
                if (s0 === peg$FAILED) {
                    s0 = peg$parsegeneric_param();
                }
            }
        }
        return s0;
    }
    function peg$parseRequire() {
        var s0, s1, s2, s3, s4, s5, s6;
        s0 = peg$currPos;
        s1 = peg$currPos;
        s2 = peg$parsetoken();
        if (s2 !== peg$FAILED) {
            s3 = [];
            s4 = peg$currPos;
            s5 = peg$parseCOMMA();
            if (s5 !== peg$FAILED) {
                s6 = peg$parsetoken();
                if (s6 !== peg$FAILED) {
                    peg$savedPos = s4;
                    s5 = peg$c314(s2, s6);
                    s4 = s5;
                }
                else {
                    peg$currPos = s4;
                    s4 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s4;
                s4 = peg$FAILED;
            }
            while (s4 !== peg$FAILED) {
                s3.push(s4);
                s4 = peg$currPos;
                s5 = peg$parseCOMMA();
                if (s5 !== peg$FAILED) {
                    s6 = peg$parsetoken();
                    if (s6 !== peg$FAILED) {
                        peg$savedPos = s4;
                        s5 = peg$c314(s2, s6);
                        s4 = s5;
                    }
                    else {
                        peg$currPos = s4;
                        s4 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s4;
                    s4 = peg$FAILED;
                }
            }
            if (s3 !== peg$FAILED) {
                peg$savedPos = s1;
                s2 = peg$c315(s2, s3);
                s1 = s2;
            }
            else {
                peg$currPos = s1;
                s1 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s1;
            s1 = peg$FAILED;
        }
        if (s1 === peg$FAILED) {
            s1 = null;
        }
        if (s1 !== peg$FAILED) {
            peg$savedPos = s0;
            s1 = peg$c316(s1);
        }
        s0 = s1;
        return s0;
    }
    function peg$parseRoute() {
        var s0, s1, s2, s3, s4, s5;
        s0 = peg$currPos;
        s1 = peg$parseroute_param();
        if (s1 !== peg$FAILED) {
            s2 = [];
            s3 = peg$currPos;
            s4 = peg$parseCOMMA();
            if (s4 !== peg$FAILED) {
                s5 = peg$parseroute_param();
                if (s5 !== peg$FAILED) {
                    s4 = [s4, s5];
                    s3 = s4;
                }
                else {
                    peg$currPos = s3;
                    s3 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s3;
                s3 = peg$FAILED;
            }
            while (s3 !== peg$FAILED) {
                s2.push(s3);
                s3 = peg$currPos;
                s4 = peg$parseCOMMA();
                if (s4 !== peg$FAILED) {
                    s5 = peg$parseroute_param();
                    if (s5 !== peg$FAILED) {
                        s4 = [s4, s5];
                        s3 = s4;
                    }
                    else {
                        peg$currPos = s3;
                        s3 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s3;
                    s3 = peg$FAILED;
                }
            }
            if (s2 !== peg$FAILED) {
                s1 = [s1, s2];
                s0 = s1;
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parseroute_param() {
        var s0, s1, s2, s3, s4, s5;
        s0 = peg$currPos;
        s1 = peg$parsename_addr();
        if (s1 !== peg$FAILED) {
            s2 = [];
            s3 = peg$currPos;
            s4 = peg$parseSEMI();
            if (s4 !== peg$FAILED) {
                s5 = peg$parsegeneric_param();
                if (s5 !== peg$FAILED) {
                    s4 = [s4, s5];
                    s3 = s4;
                }
                else {
                    peg$currPos = s3;
                    s3 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s3;
                s3 = peg$FAILED;
            }
            while (s3 !== peg$FAILED) {
                s2.push(s3);
                s3 = peg$currPos;
                s4 = peg$parseSEMI();
                if (s4 !== peg$FAILED) {
                    s5 = peg$parsegeneric_param();
                    if (s5 !== peg$FAILED) {
                        s4 = [s4, s5];
                        s3 = s4;
                    }
                    else {
                        peg$currPos = s3;
                        s3 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s3;
                    s3 = peg$FAILED;
                }
            }
            if (s2 !== peg$FAILED) {
                s1 = [s1, s2];
                s0 = s1;
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parseRSeq() {
        var s0, s1, s2;
        s0 = peg$currPos;
        s1 = [];
        s2 = peg$parseDIGIT();
        if (s2 !== peg$FAILED) {
            while (s2 !== peg$FAILED) {
                s1.push(s2);
                s2 = peg$parseDIGIT();
            }
        }
        else {
            s1 = peg$FAILED;
        }
        if (s1 !== peg$FAILED) {
            peg$savedPos = s0;
            s1 = peg$c317(s1);
        }
        s0 = s1;
        return s0;
    }
    function peg$parseSubscription_State() {
        var s0, s1, s2, s3, s4, s5;
        s0 = peg$currPos;
        s1 = peg$parsesubstate_value();
        if (s1 !== peg$FAILED) {
            s2 = [];
            s3 = peg$currPos;
            s4 = peg$parseSEMI();
            if (s4 !== peg$FAILED) {
                s5 = peg$parsesubexp_params();
                if (s5 !== peg$FAILED) {
                    s4 = [s4, s5];
                    s3 = s4;
                }
                else {
                    peg$currPos = s3;
                    s3 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s3;
                s3 = peg$FAILED;
            }
            while (s3 !== peg$FAILED) {
                s2.push(s3);
                s3 = peg$currPos;
                s4 = peg$parseSEMI();
                if (s4 !== peg$FAILED) {
                    s5 = peg$parsesubexp_params();
                    if (s5 !== peg$FAILED) {
                        s4 = [s4, s5];
                        s3 = s4;
                    }
                    else {
                        peg$currPos = s3;
                        s3 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s3;
                    s3 = peg$FAILED;
                }
            }
            if (s2 !== peg$FAILED) {
                s1 = [s1, s2];
                s0 = s1;
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parsesubstate_value() {
        var s0, s1;
        s0 = peg$currPos;
        if (input.substr(peg$currPos, 6).toLowerCase() === peg$c318) {
            s1 = input.substr(peg$currPos, 6);
            peg$currPos += 6;
        }
        else {
            s1 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c319);
            }
        }
        if (s1 === peg$FAILED) {
            if (input.substr(peg$currPos, 7).toLowerCase() === peg$c320) {
                s1 = input.substr(peg$currPos, 7);
                peg$currPos += 7;
            }
            else {
                s1 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c321);
                }
            }
            if (s1 === peg$FAILED) {
                if (input.substr(peg$currPos, 10).toLowerCase() === peg$c322) {
                    s1 = input.substr(peg$currPos, 10);
                    peg$currPos += 10;
                }
                else {
                    s1 = peg$FAILED;
                    if (peg$silentFails === 0) {
                        peg$fail(peg$c323);
                    }
                }
                if (s1 === peg$FAILED) {
                    s1 = peg$parsetoken();
                }
            }
        }
        if (s1 !== peg$FAILED) {
            peg$savedPos = s0;
            s1 = peg$c324();
        }
        s0 = s1;
        return s0;
    }
    function peg$parsesubexp_params() {
        var s0, s1, s2, s3;
        s0 = peg$currPos;
        if (input.substr(peg$currPos, 6).toLowerCase() === peg$c325) {
            s1 = input.substr(peg$currPos, 6);
            peg$currPos += 6;
        }
        else {
            s1 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c326);
            }
        }
        if (s1 !== peg$FAILED) {
            s2 = peg$parseEQUAL();
            if (s2 !== peg$FAILED) {
                s3 = peg$parseevent_reason_value();
                if (s3 !== peg$FAILED) {
                    peg$savedPos = s0;
                    s1 = peg$c327(s3);
                    s0 = s1;
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        if (s0 === peg$FAILED) {
            s0 = peg$currPos;
            if (input.substr(peg$currPos, 7).toLowerCase() === peg$c213) {
                s1 = input.substr(peg$currPos, 7);
                peg$currPos += 7;
            }
            else {
                s1 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c214);
                }
            }
            if (s1 !== peg$FAILED) {
                s2 = peg$parseEQUAL();
                if (s2 !== peg$FAILED) {
                    s3 = peg$parsedelta_seconds();
                    if (s3 !== peg$FAILED) {
                        peg$savedPos = s0;
                        s1 = peg$c328(s3);
                        s0 = s1;
                    }
                    else {
                        peg$currPos = s0;
                        s0 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
            if (s0 === peg$FAILED) {
                s0 = peg$currPos;
                if (input.substr(peg$currPos, 11).toLowerCase() === peg$c329) {
                    s1 = input.substr(peg$currPos, 11);
                    peg$currPos += 11;
                }
                else {
                    s1 = peg$FAILED;
                    if (peg$silentFails === 0) {
                        peg$fail(peg$c330);
                    }
                }
                if (s1 !== peg$FAILED) {
                    s2 = peg$parseEQUAL();
                    if (s2 !== peg$FAILED) {
                        s3 = peg$parsedelta_seconds();
                        if (s3 !== peg$FAILED) {
                            peg$savedPos = s0;
                            s1 = peg$c331(s3);
                            s0 = s1;
                        }
                        else {
                            peg$currPos = s0;
                            s0 = peg$FAILED;
                        }
                    }
                    else {
                        peg$currPos = s0;
                        s0 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
                if (s0 === peg$FAILED) {
                    s0 = peg$parsegeneric_param();
                }
            }
        }
        return s0;
    }
    function peg$parseevent_reason_value() {
        var s0;
        if (input.substr(peg$currPos, 11).toLowerCase() === peg$c332) {
            s0 = input.substr(peg$currPos, 11);
            peg$currPos += 11;
        }
        else {
            s0 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c333);
            }
        }
        if (s0 === peg$FAILED) {
            if (input.substr(peg$currPos, 9).toLowerCase() === peg$c334) {
                s0 = input.substr(peg$currPos, 9);
                peg$currPos += 9;
            }
            else {
                s0 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c335);
                }
            }
            if (s0 === peg$FAILED) {
                if (input.substr(peg$currPos, 8).toLowerCase() === peg$c336) {
                    s0 = input.substr(peg$currPos, 8);
                    peg$currPos += 8;
                }
                else {
                    s0 = peg$FAILED;
                    if (peg$silentFails === 0) {
                        peg$fail(peg$c337);
                    }
                }
                if (s0 === peg$FAILED) {
                    if (input.substr(peg$currPos, 7).toLowerCase() === peg$c338) {
                        s0 = input.substr(peg$currPos, 7);
                        peg$currPos += 7;
                    }
                    else {
                        s0 = peg$FAILED;
                        if (peg$silentFails === 0) {
                            peg$fail(peg$c339);
                        }
                    }
                    if (s0 === peg$FAILED) {
                        if (input.substr(peg$currPos, 6).toLowerCase() === peg$c340) {
                            s0 = input.substr(peg$currPos, 6);
                            peg$currPos += 6;
                        }
                        else {
                            s0 = peg$FAILED;
                            if (peg$silentFails === 0) {
                                peg$fail(peg$c341);
                            }
                        }
                        if (s0 === peg$FAILED) {
                            if (input.substr(peg$currPos, 10).toLowerCase() === peg$c342) {
                                s0 = input.substr(peg$currPos, 10);
                                peg$currPos += 10;
                            }
                            else {
                                s0 = peg$FAILED;
                                if (peg$silentFails === 0) {
                                    peg$fail(peg$c343);
                                }
                            }
                            if (s0 === peg$FAILED) {
                                if (input.substr(peg$currPos, 9).toLowerCase() === peg$c344) {
                                    s0 = input.substr(peg$currPos, 9);
                                    peg$currPos += 9;
                                }
                                else {
                                    s0 = peg$FAILED;
                                    if (peg$silentFails === 0) {
                                        peg$fail(peg$c345);
                                    }
                                }
                                if (s0 === peg$FAILED) {
                                    s0 = peg$parsetoken();
                                }
                            }
                        }
                    }
                }
            }
        }
        return s0;
    }
    function peg$parseSubject() {
        var s0;
        s0 = peg$parseTEXT_UTF8_TRIM();
        if (s0 === peg$FAILED) {
            s0 = null;
        }
        return s0;
    }
    function peg$parseSupported() {
        var s0, s1, s2, s3, s4, s5, s6;
        s0 = peg$currPos;
        s1 = peg$currPos;
        s2 = peg$parsetoken();
        if (s2 !== peg$FAILED) {
            s3 = [];
            s4 = peg$currPos;
            s5 = peg$parseCOMMA();
            if (s5 !== peg$FAILED) {
                s6 = peg$parsetoken();
                if (s6 !== peg$FAILED) {
                    peg$savedPos = s4;
                    s5 = peg$c314(s2, s6);
                    s4 = s5;
                }
                else {
                    peg$currPos = s4;
                    s4 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s4;
                s4 = peg$FAILED;
            }
            while (s4 !== peg$FAILED) {
                s3.push(s4);
                s4 = peg$currPos;
                s5 = peg$parseCOMMA();
                if (s5 !== peg$FAILED) {
                    s6 = peg$parsetoken();
                    if (s6 !== peg$FAILED) {
                        peg$savedPos = s4;
                        s5 = peg$c314(s2, s6);
                        s4 = s5;
                    }
                    else {
                        peg$currPos = s4;
                        s4 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s4;
                    s4 = peg$FAILED;
                }
            }
            if (s3 !== peg$FAILED) {
                peg$savedPos = s1;
                s2 = peg$c315(s2, s3);
                s1 = s2;
            }
            else {
                peg$currPos = s1;
                s1 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s1;
            s1 = peg$FAILED;
        }
        if (s1 === peg$FAILED) {
            s1 = null;
        }
        if (s1 !== peg$FAILED) {
            peg$savedPos = s0;
            s1 = peg$c346(s1);
        }
        s0 = s1;
        return s0;
    }
    function peg$parseTo() {
        var s0, s1, s2, s3, s4, s5;
        s0 = peg$currPos;
        s1 = peg$parseSIP_URI_noparams();
        if (s1 === peg$FAILED) {
            s1 = peg$parsename_addr();
        }
        if (s1 !== peg$FAILED) {
            s2 = [];
            s3 = peg$currPos;
            s4 = peg$parseSEMI();
            if (s4 !== peg$FAILED) {
                s5 = peg$parseto_param();
                if (s5 !== peg$FAILED) {
                    s4 = [s4, s5];
                    s3 = s4;
                }
                else {
                    peg$currPos = s3;
                    s3 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s3;
                s3 = peg$FAILED;
            }
            while (s3 !== peg$FAILED) {
                s2.push(s3);
                s3 = peg$currPos;
                s4 = peg$parseSEMI();
                if (s4 !== peg$FAILED) {
                    s5 = peg$parseto_param();
                    if (s5 !== peg$FAILED) {
                        s4 = [s4, s5];
                        s3 = s4;
                    }
                    else {
                        peg$currPos = s3;
                        s3 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s3;
                    s3 = peg$FAILED;
                }
            }
            if (s2 !== peg$FAILED) {
                peg$savedPos = s0;
                s1 = peg$c347();
                s0 = s1;
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parseto_param() {
        var s0;
        s0 = peg$parsetag_param();
        if (s0 === peg$FAILED) {
            s0 = peg$parsegeneric_param();
        }
        return s0;
    }
    function peg$parseVia() {
        var s0, s1, s2, s3, s4, s5;
        s0 = peg$currPos;
        s1 = peg$parsevia_parm();
        if (s1 !== peg$FAILED) {
            s2 = [];
            s3 = peg$currPos;
            s4 = peg$parseCOMMA();
            if (s4 !== peg$FAILED) {
                s5 = peg$parsevia_parm();
                if (s5 !== peg$FAILED) {
                    s4 = [s4, s5];
                    s3 = s4;
                }
                else {
                    peg$currPos = s3;
                    s3 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s3;
                s3 = peg$FAILED;
            }
            while (s3 !== peg$FAILED) {
                s2.push(s3);
                s3 = peg$currPos;
                s4 = peg$parseCOMMA();
                if (s4 !== peg$FAILED) {
                    s5 = peg$parsevia_parm();
                    if (s5 !== peg$FAILED) {
                        s4 = [s4, s5];
                        s3 = s4;
                    }
                    else {
                        peg$currPos = s3;
                        s3 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s3;
                    s3 = peg$FAILED;
                }
            }
            if (s2 !== peg$FAILED) {
                s1 = [s1, s2];
                s0 = s1;
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parsevia_parm() {
        var s0, s1, s2, s3, s4, s5, s6, s7;
        s0 = peg$currPos;
        s1 = peg$parsesent_protocol();
        if (s1 !== peg$FAILED) {
            s2 = peg$parseLWS();
            if (s2 !== peg$FAILED) {
                s3 = peg$parsesent_by();
                if (s3 !== peg$FAILED) {
                    s4 = [];
                    s5 = peg$currPos;
                    s6 = peg$parseSEMI();
                    if (s6 !== peg$FAILED) {
                        s7 = peg$parsevia_params();
                        if (s7 !== peg$FAILED) {
                            s6 = [s6, s7];
                            s5 = s6;
                        }
                        else {
                            peg$currPos = s5;
                            s5 = peg$FAILED;
                        }
                    }
                    else {
                        peg$currPos = s5;
                        s5 = peg$FAILED;
                    }
                    while (s5 !== peg$FAILED) {
                        s4.push(s5);
                        s5 = peg$currPos;
                        s6 = peg$parseSEMI();
                        if (s6 !== peg$FAILED) {
                            s7 = peg$parsevia_params();
                            if (s7 !== peg$FAILED) {
                                s6 = [s6, s7];
                                s5 = s6;
                            }
                            else {
                                peg$currPos = s5;
                                s5 = peg$FAILED;
                            }
                        }
                        else {
                            peg$currPos = s5;
                            s5 = peg$FAILED;
                        }
                    }
                    if (s4 !== peg$FAILED) {
                        s1 = [s1, s2, s3, s4];
                        s0 = s1;
                    }
                    else {
                        peg$currPos = s0;
                        s0 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parsevia_params() {
        var s0;
        s0 = peg$parsevia_ttl();
        if (s0 === peg$FAILED) {
            s0 = peg$parsevia_maddr();
            if (s0 === peg$FAILED) {
                s0 = peg$parsevia_received();
                if (s0 === peg$FAILED) {
                    s0 = peg$parsevia_branch();
                    if (s0 === peg$FAILED) {
                        s0 = peg$parseresponse_port();
                        if (s0 === peg$FAILED) {
                            s0 = peg$parsegeneric_param();
                        }
                    }
                }
            }
        }
        return s0;
    }
    function peg$parsevia_ttl() {
        var s0, s1, s2, s3;
        s0 = peg$currPos;
        if (input.substr(peg$currPos, 3).toLowerCase() === peg$c348) {
            s1 = input.substr(peg$currPos, 3);
            peg$currPos += 3;
        }
        else {
            s1 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c349);
            }
        }
        if (s1 !== peg$FAILED) {
            s2 = peg$parseEQUAL();
            if (s2 !== peg$FAILED) {
                s3 = peg$parsettl();
                if (s3 !== peg$FAILED) {
                    peg$savedPos = s0;
                    s1 = peg$c350(s3);
                    s0 = s1;
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parsevia_maddr() {
        var s0, s1, s2, s3;
        s0 = peg$currPos;
        if (input.substr(peg$currPos, 5).toLowerCase() === peg$c351) {
            s1 = input.substr(peg$currPos, 5);
            peg$currPos += 5;
        }
        else {
            s1 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c352);
            }
        }
        if (s1 !== peg$FAILED) {
            s2 = peg$parseEQUAL();
            if (s2 !== peg$FAILED) {
                s3 = peg$parsehost();
                if (s3 !== peg$FAILED) {
                    peg$savedPos = s0;
                    s1 = peg$c353(s3);
                    s0 = s1;
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parsevia_received() {
        var s0, s1, s2, s3;
        s0 = peg$currPos;
        if (input.substr(peg$currPos, 8).toLowerCase() === peg$c354) {
            s1 = input.substr(peg$currPos, 8);
            peg$currPos += 8;
        }
        else {
            s1 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c355);
            }
        }
        if (s1 !== peg$FAILED) {
            s2 = peg$parseEQUAL();
            if (s2 !== peg$FAILED) {
                s3 = peg$parseIPv4address();
                if (s3 === peg$FAILED) {
                    s3 = peg$parseIPv6address();
                    if (s3 === peg$FAILED) {
                        s3 = peg$parseIPv6reference();
                    }
                }
                if (s3 !== peg$FAILED) {
                    peg$savedPos = s0;
                    s1 = peg$c356(s3);
                    s0 = s1;
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parsevia_branch() {
        var s0, s1, s2, s3;
        s0 = peg$currPos;
        if (input.substr(peg$currPos, 6).toLowerCase() === peg$c357) {
            s1 = input.substr(peg$currPos, 6);
            peg$currPos += 6;
        }
        else {
            s1 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c358);
            }
        }
        if (s1 !== peg$FAILED) {
            s2 = peg$parseEQUAL();
            if (s2 !== peg$FAILED) {
                s3 = peg$parsetoken();
                if (s3 !== peg$FAILED) {
                    peg$savedPos = s0;
                    s1 = peg$c359(s3);
                    s0 = s1;
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parseresponse_port() {
        var s0, s1, s2, s3, s4;
        s0 = peg$currPos;
        if (input.substr(peg$currPos, 5).toLowerCase() === peg$c360) {
            s1 = input.substr(peg$currPos, 5);
            peg$currPos += 5;
        }
        else {
            s1 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c361);
            }
        }
        if (s1 !== peg$FAILED) {
            s2 = peg$parseEQUAL();
            if (s2 !== peg$FAILED) {
                s3 = [];
                s4 = peg$parseDIGIT();
                while (s4 !== peg$FAILED) {
                    s3.push(s4);
                    s4 = peg$parseDIGIT();
                }
                if (s3 !== peg$FAILED) {
                    peg$savedPos = s0;
                    s1 = peg$c362(s3);
                    s0 = s1;
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parsesent_protocol() {
        var s0, s1, s2, s3, s4, s5;
        s0 = peg$currPos;
        s1 = peg$parseprotocol_name();
        if (s1 !== peg$FAILED) {
            s2 = peg$parseSLASH();
            if (s2 !== peg$FAILED) {
                s3 = peg$parsetoken();
                if (s3 !== peg$FAILED) {
                    s4 = peg$parseSLASH();
                    if (s4 !== peg$FAILED) {
                        s5 = peg$parsetransport();
                        if (s5 !== peg$FAILED) {
                            s1 = [s1, s2, s3, s4, s5];
                            s0 = s1;
                        }
                        else {
                            peg$currPos = s0;
                            s0 = peg$FAILED;
                        }
                    }
                    else {
                        peg$currPos = s0;
                        s0 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parseprotocol_name() {
        var s0, s1;
        s0 = peg$currPos;
        if (input.substr(peg$currPos, 3).toLowerCase() === peg$c114) {
            s1 = input.substr(peg$currPos, 3);
            peg$currPos += 3;
        }
        else {
            s1 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c179);
            }
        }
        if (s1 === peg$FAILED) {
            s1 = peg$parsetoken();
        }
        if (s1 !== peg$FAILED) {
            peg$savedPos = s0;
            s1 = peg$c363(s1);
        }
        s0 = s1;
        return s0;
    }
    function peg$parsetransport() {
        var s0, s1;
        s0 = peg$currPos;
        if (input.substr(peg$currPos, 3).toLowerCase() === peg$c145) {
            s1 = input.substr(peg$currPos, 3);
            peg$currPos += 3;
        }
        else {
            s1 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c364);
            }
        }
        if (s1 === peg$FAILED) {
            if (input.substr(peg$currPos, 3).toLowerCase() === peg$c147) {
                s1 = input.substr(peg$currPos, 3);
                peg$currPos += 3;
            }
            else {
                s1 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c365);
                }
            }
            if (s1 === peg$FAILED) {
                if (input.substr(peg$currPos, 3).toLowerCase() === peg$c151) {
                    s1 = input.substr(peg$currPos, 3);
                    peg$currPos += 3;
                }
                else {
                    s1 = peg$FAILED;
                    if (peg$silentFails === 0) {
                        peg$fail(peg$c366);
                    }
                }
                if (s1 === peg$FAILED) {
                    if (input.substr(peg$currPos, 4).toLowerCase() === peg$c149) {
                        s1 = input.substr(peg$currPos, 4);
                        peg$currPos += 4;
                    }
                    else {
                        s1 = peg$FAILED;
                        if (peg$silentFails === 0) {
                            peg$fail(peg$c367);
                        }
                    }
                    if (s1 === peg$FAILED) {
                        s1 = peg$parsetoken();
                    }
                }
            }
        }
        if (s1 !== peg$FAILED) {
            peg$savedPos = s0;
            s1 = peg$c368(s1);
        }
        s0 = s1;
        return s0;
    }
    function peg$parsesent_by() {
        var s0, s1, s2, s3, s4;
        s0 = peg$currPos;
        s1 = peg$parseviaHost();
        if (s1 !== peg$FAILED) {
            s2 = peg$currPos;
            s3 = peg$parseCOLON();
            if (s3 !== peg$FAILED) {
                s4 = peg$parsevia_port();
                if (s4 !== peg$FAILED) {
                    s3 = [s3, s4];
                    s2 = s3;
                }
                else {
                    peg$currPos = s2;
                    s2 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s2;
                s2 = peg$FAILED;
            }
            if (s2 === peg$FAILED) {
                s2 = null;
            }
            if (s2 !== peg$FAILED) {
                s1 = [s1, s2];
                s0 = s1;
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parseviaHost() {
        var s0, s1;
        s0 = peg$currPos;
        s1 = peg$parsehostname();
        if (s1 === peg$FAILED) {
            s1 = peg$parseIPv4address();
            if (s1 === peg$FAILED) {
                s1 = peg$parseIPv6reference();
            }
        }
        if (s1 !== peg$FAILED) {
            peg$savedPos = s0;
            s1 = peg$c369();
        }
        s0 = s1;
        return s0;
    }
    function peg$parsevia_port() {
        var s0, s1, s2, s3, s4, s5, s6;
        s0 = peg$currPos;
        s1 = peg$currPos;
        s2 = peg$parseDIGIT();
        if (s2 === peg$FAILED) {
            s2 = null;
        }
        if (s2 !== peg$FAILED) {
            s3 = peg$parseDIGIT();
            if (s3 === peg$FAILED) {
                s3 = null;
            }
            if (s3 !== peg$FAILED) {
                s4 = peg$parseDIGIT();
                if (s4 === peg$FAILED) {
                    s4 = null;
                }
                if (s4 !== peg$FAILED) {
                    s5 = peg$parseDIGIT();
                    if (s5 === peg$FAILED) {
                        s5 = null;
                    }
                    if (s5 !== peg$FAILED) {
                        s6 = peg$parseDIGIT();
                        if (s6 === peg$FAILED) {
                            s6 = null;
                        }
                        if (s6 !== peg$FAILED) {
                            s2 = [s2, s3, s4, s5, s6];
                            s1 = s2;
                        }
                        else {
                            peg$currPos = s1;
                            s1 = peg$FAILED;
                        }
                    }
                    else {
                        peg$currPos = s1;
                        s1 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s1;
                    s1 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s1;
                s1 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s1;
            s1 = peg$FAILED;
        }
        if (s1 !== peg$FAILED) {
            peg$savedPos = s0;
            s1 = peg$c370(s1);
        }
        s0 = s1;
        return s0;
    }
    function peg$parsettl() {
        var s0, s1, s2, s3, s4;
        s0 = peg$currPos;
        s1 = peg$currPos;
        s2 = peg$parseDIGIT();
        if (s2 !== peg$FAILED) {
            s3 = peg$parseDIGIT();
            if (s3 === peg$FAILED) {
                s3 = null;
            }
            if (s3 !== peg$FAILED) {
                s4 = peg$parseDIGIT();
                if (s4 === peg$FAILED) {
                    s4 = null;
                }
                if (s4 !== peg$FAILED) {
                    s2 = [s2, s3, s4];
                    s1 = s2;
                }
                else {
                    peg$currPos = s1;
                    s1 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s1;
                s1 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s1;
            s1 = peg$FAILED;
        }
        if (s1 !== peg$FAILED) {
            peg$savedPos = s0;
            s1 = peg$c371(s1);
        }
        s0 = s1;
        return s0;
    }
    function peg$parseWWW_Authenticate() {
        var s0;
        s0 = peg$parsechallenge();
        return s0;
    }
    function peg$parseSession_Expires() {
        var s0, s1, s2, s3, s4, s5;
        s0 = peg$currPos;
        s1 = peg$parsedelta_seconds();
        if (s1 !== peg$FAILED) {
            s2 = [];
            s3 = peg$currPos;
            s4 = peg$parseSEMI();
            if (s4 !== peg$FAILED) {
                s5 = peg$parsese_params();
                if (s5 !== peg$FAILED) {
                    s4 = [s4, s5];
                    s3 = s4;
                }
                else {
                    peg$currPos = s3;
                    s3 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s3;
                s3 = peg$FAILED;
            }
            while (s3 !== peg$FAILED) {
                s2.push(s3);
                s3 = peg$currPos;
                s4 = peg$parseSEMI();
                if (s4 !== peg$FAILED) {
                    s5 = peg$parsese_params();
                    if (s5 !== peg$FAILED) {
                        s4 = [s4, s5];
                        s3 = s4;
                    }
                    else {
                        peg$currPos = s3;
                        s3 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s3;
                    s3 = peg$FAILED;
                }
            }
            if (s2 !== peg$FAILED) {
                peg$savedPos = s0;
                s1 = peg$c372(s1);
                s0 = s1;
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parsese_params() {
        var s0;
        s0 = peg$parserefresher_param();
        if (s0 === peg$FAILED) {
            s0 = peg$parsegeneric_param();
        }
        return s0;
    }
    function peg$parserefresher_param() {
        var s0, s1, s2, s3;
        s0 = peg$currPos;
        if (input.substr(peg$currPos, 9) === peg$c373) {
            s1 = peg$c373;
            peg$currPos += 9;
        }
        else {
            s1 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c374);
            }
        }
        if (s1 !== peg$FAILED) {
            s2 = peg$parseEQUAL();
            if (s2 !== peg$FAILED) {
                if (input.substr(peg$currPos, 3) === peg$c375) {
                    s3 = peg$c375;
                    peg$currPos += 3;
                }
                else {
                    s3 = peg$FAILED;
                    if (peg$silentFails === 0) {
                        peg$fail(peg$c376);
                    }
                }
                if (s3 === peg$FAILED) {
                    if (input.substr(peg$currPos, 3) === peg$c377) {
                        s3 = peg$c377;
                        peg$currPos += 3;
                    }
                    else {
                        s3 = peg$FAILED;
                        if (peg$silentFails === 0) {
                            peg$fail(peg$c378);
                        }
                    }
                }
                if (s3 !== peg$FAILED) {
                    peg$savedPos = s0;
                    s1 = peg$c379(s3);
                    s0 = s1;
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parseMin_SE() {
        var s0, s1, s2, s3, s4, s5;
        s0 = peg$currPos;
        s1 = peg$parsedelta_seconds();
        if (s1 !== peg$FAILED) {
            s2 = [];
            s3 = peg$currPos;
            s4 = peg$parseSEMI();
            if (s4 !== peg$FAILED) {
                s5 = peg$parsegeneric_param();
                if (s5 !== peg$FAILED) {
                    s4 = [s4, s5];
                    s3 = s4;
                }
                else {
                    peg$currPos = s3;
                    s3 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s3;
                s3 = peg$FAILED;
            }
            while (s3 !== peg$FAILED) {
                s2.push(s3);
                s3 = peg$currPos;
                s4 = peg$parseSEMI();
                if (s4 !== peg$FAILED) {
                    s5 = peg$parsegeneric_param();
                    if (s5 !== peg$FAILED) {
                        s4 = [s4, s5];
                        s3 = s4;
                    }
                    else {
                        peg$currPos = s3;
                        s3 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s3;
                    s3 = peg$FAILED;
                }
            }
            if (s2 !== peg$FAILED) {
                peg$savedPos = s0;
                s1 = peg$c380(s1);
                s0 = s1;
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parseextension_header() {
        var s0, s1, s2, s3;
        s0 = peg$currPos;
        s1 = peg$parsetoken();
        if (s1 !== peg$FAILED) {
            s2 = peg$parseHCOLON();
            if (s2 !== peg$FAILED) {
                s3 = peg$parseheader_value();
                if (s3 !== peg$FAILED) {
                    s1 = [s1, s2, s3];
                    s0 = s1;
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parseheader_value() {
        var s0, s1;
        s0 = [];
        s1 = peg$parseTEXT_UTF8char();
        if (s1 === peg$FAILED) {
            s1 = peg$parseUTF8_CONT();
            if (s1 === peg$FAILED) {
                s1 = peg$parseLWS();
            }
        }
        while (s1 !== peg$FAILED) {
            s0.push(s1);
            s1 = peg$parseTEXT_UTF8char();
            if (s1 === peg$FAILED) {
                s1 = peg$parseUTF8_CONT();
                if (s1 === peg$FAILED) {
                    s1 = peg$parseLWS();
                }
            }
        }
        return s0;
    }
    function peg$parsemessage_body() {
        var s0, s1;
        s0 = [];
        s1 = peg$parseOCTET();
        while (s1 !== peg$FAILED) {
            s0.push(s1);
            s1 = peg$parseOCTET();
        }
        return s0;
    }
    function peg$parsestun_URI() {
        var s0, s1, s2, s3;
        s0 = peg$currPos;
        s1 = peg$parsestun_scheme();
        if (s1 !== peg$FAILED) {
            if (input.charCodeAt(peg$currPos) === 58) {
                s2 = peg$c24;
                peg$currPos++;
            }
            else {
                s2 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c25);
                }
            }
            if (s2 !== peg$FAILED) {
                s3 = peg$parsestun_host_port();
                if (s3 !== peg$FAILED) {
                    s1 = [s1, s2, s3];
                    s0 = s1;
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parsestun_scheme() {
        var s0, s1;
        s0 = peg$currPos;
        if (input.substr(peg$currPos, 5).toLowerCase() === peg$c381) {
            s1 = input.substr(peg$currPos, 5);
            peg$currPos += 5;
        }
        else {
            s1 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c382);
            }
        }
        if (s1 === peg$FAILED) {
            if (input.substr(peg$currPos, 4).toLowerCase() === peg$c383) {
                s1 = input.substr(peg$currPos, 4);
                peg$currPos += 4;
            }
            else {
                s1 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c384);
                }
            }
        }
        if (s1 !== peg$FAILED) {
            peg$savedPos = s0;
            s1 = peg$c385(s1);
        }
        s0 = s1;
        return s0;
    }
    function peg$parsestun_host_port() {
        var s0, s1, s2, s3, s4;
        s0 = peg$currPos;
        s1 = peg$parsestun_host();
        if (s1 !== peg$FAILED) {
            s2 = peg$currPos;
            if (input.charCodeAt(peg$currPos) === 58) {
                s3 = peg$c24;
                peg$currPos++;
            }
            else {
                s3 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c25);
                }
            }
            if (s3 !== peg$FAILED) {
                s4 = peg$parseport();
                if (s4 !== peg$FAILED) {
                    s3 = [s3, s4];
                    s2 = s3;
                }
                else {
                    peg$currPos = s2;
                    s2 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s2;
                s2 = peg$FAILED;
            }
            if (s2 === peg$FAILED) {
                s2 = null;
            }
            if (s2 !== peg$FAILED) {
                s1 = [s1, s2];
                s0 = s1;
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parsestun_host() {
        var s0, s1;
        s0 = peg$currPos;
        s1 = peg$parseIPv4address();
        if (s1 === peg$FAILED) {
            s1 = peg$parseIPv6reference();
            if (s1 === peg$FAILED) {
                s1 = peg$parsereg_name();
            }
        }
        if (s1 !== peg$FAILED) {
            peg$savedPos = s0;
            s1 = peg$c386(s1);
        }
        s0 = s1;
        return s0;
    }
    function peg$parsestun_unreserved() {
        var s0;
        s0 = peg$parseALPHA();
        if (s0 === peg$FAILED) {
            s0 = peg$parseDIGIT();
            if (s0 === peg$FAILED) {
                if (input.charCodeAt(peg$currPos) === 45) {
                    s0 = peg$c38;
                    peg$currPos++;
                }
                else {
                    s0 = peg$FAILED;
                    if (peg$silentFails === 0) {
                        peg$fail(peg$c39);
                    }
                }
                if (s0 === peg$FAILED) {
                    if (input.charCodeAt(peg$currPos) === 46) {
                        s0 = peg$c42;
                        peg$currPos++;
                    }
                    else {
                        s0 = peg$FAILED;
                        if (peg$silentFails === 0) {
                            peg$fail(peg$c43);
                        }
                    }
                    if (s0 === peg$FAILED) {
                        if (input.charCodeAt(peg$currPos) === 95) {
                            s0 = peg$c40;
                            peg$currPos++;
                        }
                        else {
                            s0 = peg$FAILED;
                            if (peg$silentFails === 0) {
                                peg$fail(peg$c41);
                            }
                        }
                        if (s0 === peg$FAILED) {
                            if (input.charCodeAt(peg$currPos) === 126) {
                                s0 = peg$c46;
                                peg$currPos++;
                            }
                            else {
                                s0 = peg$FAILED;
                                if (peg$silentFails === 0) {
                                    peg$fail(peg$c47);
                                }
                            }
                        }
                    }
                }
            }
        }
        return s0;
    }
    function peg$parsesub_delims() {
        var s0;
        if (input.charCodeAt(peg$currPos) === 33) {
            s0 = peg$c44;
            peg$currPos++;
        }
        else {
            s0 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c45);
            }
        }
        if (s0 === peg$FAILED) {
            if (input.charCodeAt(peg$currPos) === 36) {
                s0 = peg$c34;
                peg$currPos++;
            }
            else {
                s0 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c35);
                }
            }
            if (s0 === peg$FAILED) {
                if (input.charCodeAt(peg$currPos) === 38) {
                    s0 = peg$c28;
                    peg$currPos++;
                }
                else {
                    s0 = peg$FAILED;
                    if (peg$silentFails === 0) {
                        peg$fail(peg$c29);
                    }
                }
                if (s0 === peg$FAILED) {
                    if (input.charCodeAt(peg$currPos) === 39) {
                        s0 = peg$c50;
                        peg$currPos++;
                    }
                    else {
                        s0 = peg$FAILED;
                        if (peg$silentFails === 0) {
                            peg$fail(peg$c51);
                        }
                    }
                    if (s0 === peg$FAILED) {
                        if (input.charCodeAt(peg$currPos) === 40) {
                            s0 = peg$c52;
                            peg$currPos++;
                        }
                        else {
                            s0 = peg$FAILED;
                            if (peg$silentFails === 0) {
                                peg$fail(peg$c53);
                            }
                        }
                        if (s0 === peg$FAILED) {
                            if (input.charCodeAt(peg$currPos) === 41) {
                                s0 = peg$c54;
                                peg$currPos++;
                            }
                            else {
                                s0 = peg$FAILED;
                                if (peg$silentFails === 0) {
                                    peg$fail(peg$c55);
                                }
                            }
                            if (s0 === peg$FAILED) {
                                if (input.charCodeAt(peg$currPos) === 42) {
                                    s0 = peg$c48;
                                    peg$currPos++;
                                }
                                else {
                                    s0 = peg$FAILED;
                                    if (peg$silentFails === 0) {
                                        peg$fail(peg$c49);
                                    }
                                }
                                if (s0 === peg$FAILED) {
                                    if (input.charCodeAt(peg$currPos) === 43) {
                                        s0 = peg$c32;
                                        peg$currPos++;
                                    }
                                    else {
                                        s0 = peg$FAILED;
                                        if (peg$silentFails === 0) {
                                            peg$fail(peg$c33);
                                        }
                                    }
                                    if (s0 === peg$FAILED) {
                                        if (input.charCodeAt(peg$currPos) === 44) {
                                            s0 = peg$c36;
                                            peg$currPos++;
                                        }
                                        else {
                                            s0 = peg$FAILED;
                                            if (peg$silentFails === 0) {
                                                peg$fail(peg$c37);
                                            }
                                        }
                                        if (s0 === peg$FAILED) {
                                            if (input.charCodeAt(peg$currPos) === 59) {
                                                s0 = peg$c18;
                                                peg$currPos++;
                                            }
                                            else {
                                                s0 = peg$FAILED;
                                                if (peg$silentFails === 0) {
                                                    peg$fail(peg$c19);
                                                }
                                            }
                                            if (s0 === peg$FAILED) {
                                                if (input.charCodeAt(peg$currPos) === 61) {
                                                    s0 = peg$c30;
                                                    peg$currPos++;
                                                }
                                                else {
                                                    s0 = peg$FAILED;
                                                    if (peg$silentFails === 0) {
                                                        peg$fail(peg$c31);
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        return s0;
    }
    function peg$parseturn_URI() {
        var s0, s1, s2, s3, s4, s5, s6;
        s0 = peg$currPos;
        s1 = peg$parseturn_scheme();
        if (s1 !== peg$FAILED) {
            if (input.charCodeAt(peg$currPos) === 58) {
                s2 = peg$c24;
                peg$currPos++;
            }
            else {
                s2 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c25);
                }
            }
            if (s2 !== peg$FAILED) {
                s3 = peg$parsestun_host_port();
                if (s3 !== peg$FAILED) {
                    s4 = peg$currPos;
                    if (input.substr(peg$currPos, 11) === peg$c387) {
                        s5 = peg$c387;
                        peg$currPos += 11;
                    }
                    else {
                        s5 = peg$FAILED;
                        if (peg$silentFails === 0) {
                            peg$fail(peg$c388);
                        }
                    }
                    if (s5 !== peg$FAILED) {
                        s6 = peg$parsetransport();
                        if (s6 !== peg$FAILED) {
                            s5 = [s5, s6];
                            s4 = s5;
                        }
                        else {
                            peg$currPos = s4;
                            s4 = peg$FAILED;
                        }
                    }
                    else {
                        peg$currPos = s4;
                        s4 = peg$FAILED;
                    }
                    if (s4 === peg$FAILED) {
                        s4 = null;
                    }
                    if (s4 !== peg$FAILED) {
                        s1 = [s1, s2, s3, s4];
                        s0 = s1;
                    }
                    else {
                        peg$currPos = s0;
                        s0 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parseturn_scheme() {
        var s0, s1;
        s0 = peg$currPos;
        if (input.substr(peg$currPos, 5).toLowerCase() === peg$c389) {
            s1 = input.substr(peg$currPos, 5);
            peg$currPos += 5;
        }
        else {
            s1 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c390);
            }
        }
        if (s1 === peg$FAILED) {
            if (input.substr(peg$currPos, 4).toLowerCase() === peg$c391) {
                s1 = input.substr(peg$currPos, 4);
                peg$currPos += 4;
            }
            else {
                s1 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c392);
                }
            }
        }
        if (s1 !== peg$FAILED) {
            peg$savedPos = s0;
            s1 = peg$c385(s1);
        }
        s0 = s1;
        return s0;
    }
    function peg$parseturn_transport() {
        var s0, s1, s2;
        s0 = peg$currPos;
        if (input.substr(peg$currPos, 3).toLowerCase() === peg$c145) {
            s1 = input.substr(peg$currPos, 3);
            peg$currPos += 3;
        }
        else {
            s1 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c146);
            }
        }
        if (s1 === peg$FAILED) {
            if (input.substr(peg$currPos, 3).toLowerCase() === peg$c147) {
                s1 = input.substr(peg$currPos, 3);
                peg$currPos += 3;
            }
            else {
                s1 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c148);
                }
            }
            if (s1 === peg$FAILED) {
                s1 = [];
                s2 = peg$parseunreserved();
                while (s2 !== peg$FAILED) {
                    s1.push(s2);
                    s2 = peg$parseunreserved();
                }
            }
        }
        if (s1 !== peg$FAILED) {
            peg$savedPos = s0;
            s1 = peg$c393(s1);
        }
        s0 = s1;
        return s0;
    }
    function peg$parseuuid() {
        var s0, s1, s2, s3, s4, s5, s6, s7, s8, s9;
        s0 = peg$currPos;
        s1 = peg$parsehex8();
        if (s1 !== peg$FAILED) {
            if (input.charCodeAt(peg$currPos) === 45) {
                s2 = peg$c38;
                peg$currPos++;
            }
            else {
                s2 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c39);
                }
            }
            if (s2 !== peg$FAILED) {
                s3 = peg$parsehex4();
                if (s3 !== peg$FAILED) {
                    if (input.charCodeAt(peg$currPos) === 45) {
                        s4 = peg$c38;
                        peg$currPos++;
                    }
                    else {
                        s4 = peg$FAILED;
                        if (peg$silentFails === 0) {
                            peg$fail(peg$c39);
                        }
                    }
                    if (s4 !== peg$FAILED) {
                        s5 = peg$parsehex4();
                        if (s5 !== peg$FAILED) {
                            if (input.charCodeAt(peg$currPos) === 45) {
                                s6 = peg$c38;
                                peg$currPos++;
                            }
                            else {
                                s6 = peg$FAILED;
                                if (peg$silentFails === 0) {
                                    peg$fail(peg$c39);
                                }
                            }
                            if (s6 !== peg$FAILED) {
                                s7 = peg$parsehex4();
                                if (s7 !== peg$FAILED) {
                                    if (input.charCodeAt(peg$currPos) === 45) {
                                        s8 = peg$c38;
                                        peg$currPos++;
                                    }
                                    else {
                                        s8 = peg$FAILED;
                                        if (peg$silentFails === 0) {
                                            peg$fail(peg$c39);
                                        }
                                    }
                                    if (s8 !== peg$FAILED) {
                                        s9 = peg$parsehex12();
                                        if (s9 !== peg$FAILED) {
                                            peg$savedPos = s0;
                                            s1 = peg$c394();
                                            s0 = s1;
                                        }
                                        else {
                                            peg$currPos = s0;
                                            s0 = peg$FAILED;
                                        }
                                    }
                                    else {
                                        peg$currPos = s0;
                                        s0 = peg$FAILED;
                                    }
                                }
                                else {
                                    peg$currPos = s0;
                                    s0 = peg$FAILED;
                                }
                            }
                            else {
                                peg$currPos = s0;
                                s0 = peg$FAILED;
                            }
                        }
                        else {
                            peg$currPos = s0;
                            s0 = peg$FAILED;
                        }
                    }
                    else {
                        peg$currPos = s0;
                        s0 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parsehex4() {
        var s0, s1, s2, s3, s4;
        s0 = peg$currPos;
        s1 = peg$parseHEXDIG();
        if (s1 !== peg$FAILED) {
            s2 = peg$parseHEXDIG();
            if (s2 !== peg$FAILED) {
                s3 = peg$parseHEXDIG();
                if (s3 !== peg$FAILED) {
                    s4 = peg$parseHEXDIG();
                    if (s4 !== peg$FAILED) {
                        s1 = [s1, s2, s3, s4];
                        s0 = s1;
                    }
                    else {
                        peg$currPos = s0;
                        s0 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parsehex8() {
        var s0, s1, s2;
        s0 = peg$currPos;
        s1 = peg$parsehex4();
        if (s1 !== peg$FAILED) {
            s2 = peg$parsehex4();
            if (s2 !== peg$FAILED) {
                s1 = [s1, s2];
                s0 = s1;
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parsehex12() {
        var s0, s1, s2, s3;
        s0 = peg$currPos;
        s1 = peg$parsehex4();
        if (s1 !== peg$FAILED) {
            s2 = peg$parsehex4();
            if (s2 !== peg$FAILED) {
                s3 = peg$parsehex4();
                if (s3 !== peg$FAILED) {
                    s1 = [s1, s2, s3];
                    s0 = s1;
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parsesipfrag() {
        var s0, s1, s2, s3, s4, s5;
        s0 = peg$currPos;
        s1 = peg$parseRequest_Response();
        if (s1 !== peg$FAILED) {
            s2 = [];
            s3 = peg$parseheader();
            while (s3 !== peg$FAILED) {
                s2.push(s3);
                s3 = peg$parseheader();
            }
            if (s2 !== peg$FAILED) {
                s3 = peg$currPos;
                s4 = peg$parseCRLF();
                if (s4 !== peg$FAILED) {
                    s5 = peg$parsemessage_body();
                    if (s5 !== peg$FAILED) {
                        s4 = [s4, s5];
                        s3 = s4;
                    }
                    else {
                        peg$currPos = s3;
                        s3 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s3;
                    s3 = peg$FAILED;
                }
                if (s3 === peg$FAILED) {
                    s3 = null;
                }
                if (s3 !== peg$FAILED) {
                    s1 = [s1, s2, s3];
                    s0 = s1;
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parseReferred_By() {
        var s0, s1, s2, s3, s4, s5, s6, s7;
        s0 = peg$currPos;
        if (input.substr(peg$currPos, 11) === peg$c395) {
            s1 = peg$c395;
            peg$currPos += 11;
        }
        else {
            s1 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c396);
            }
        }
        if (s1 === peg$FAILED) {
            if (input.charCodeAt(peg$currPos) === 98) {
                s1 = peg$c397;
                peg$currPos++;
            }
            else {
                s1 = peg$FAILED;
                if (peg$silentFails === 0) {
                    peg$fail(peg$c398);
                }
            }
        }
        if (s1 !== peg$FAILED) {
            s2 = peg$parseHCOLON();
            if (s2 !== peg$FAILED) {
                s3 = peg$parsereferrer_uri();
                if (s3 !== peg$FAILED) {
                    s4 = [];
                    s5 = peg$currPos;
                    s6 = peg$parseSEMI();
                    if (s6 !== peg$FAILED) {
                        s7 = peg$parsereferredby_id_param();
                        if (s7 === peg$FAILED) {
                            s7 = peg$parsegeneric_param();
                        }
                        if (s7 !== peg$FAILED) {
                            s6 = [s6, s7];
                            s5 = s6;
                        }
                        else {
                            peg$currPos = s5;
                            s5 = peg$FAILED;
                        }
                    }
                    else {
                        peg$currPos = s5;
                        s5 = peg$FAILED;
                    }
                    while (s5 !== peg$FAILED) {
                        s4.push(s5);
                        s5 = peg$currPos;
                        s6 = peg$parseSEMI();
                        if (s6 !== peg$FAILED) {
                            s7 = peg$parsereferredby_id_param();
                            if (s7 === peg$FAILED) {
                                s7 = peg$parsegeneric_param();
                            }
                            if (s7 !== peg$FAILED) {
                                s6 = [s6, s7];
                                s5 = s6;
                            }
                            else {
                                peg$currPos = s5;
                                s5 = peg$FAILED;
                            }
                        }
                        else {
                            peg$currPos = s5;
                            s5 = peg$FAILED;
                        }
                    }
                    if (s4 !== peg$FAILED) {
                        s1 = [s1, s2, s3, s4];
                        s0 = s1;
                    }
                    else {
                        peg$currPos = s0;
                        s0 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parsereferrer_uri() {
        var s0;
        s0 = peg$parsename_addr();
        if (s0 === peg$FAILED) {
            s0 = peg$parseSIP_URI_noparams();
        }
        return s0;
    }
    function peg$parsereferredby_id_param() {
        var s0, s1, s2, s3;
        s0 = peg$currPos;
        if (input.substr(peg$currPos, 3) === peg$c399) {
            s1 = peg$c399;
            peg$currPos += 3;
        }
        else {
            s1 = peg$FAILED;
            if (peg$silentFails === 0) {
                peg$fail(peg$c400);
            }
        }
        if (s1 !== peg$FAILED) {
            s2 = peg$parseEQUAL();
            if (s2 !== peg$FAILED) {
                s3 = peg$parsesip_clean_msg_id();
                if (s3 !== peg$FAILED) {
                    s1 = [s1, s2, s3];
                    s0 = s1;
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    function peg$parsesip_clean_msg_id() {
        var s0, s1, s2, s3, s4, s5;
        s0 = peg$currPos;
        s1 = peg$parseLDQUOT();
        if (s1 !== peg$FAILED) {
            s2 = peg$parsemark();
            if (s2 !== peg$FAILED) {
                if (input.charCodeAt(peg$currPos) === 64) {
                    s3 = peg$c26;
                    peg$currPos++;
                }
                else {
                    s3 = peg$FAILED;
                    if (peg$silentFails === 0) {
                        peg$fail(peg$c27);
                    }
                }
                if (s3 !== peg$FAILED) {
                    s4 = peg$parsemark();
                    if (s4 === peg$FAILED) {
                        s4 = peg$parsehost();
                    }
                    if (s4 !== peg$FAILED) {
                        s5 = peg$parseRDQUOT();
                        if (s5 !== peg$FAILED) {
                            s1 = [s1, s2, s3, s4, s5];
                            s0 = s1;
                        }
                        else {
                            peg$currPos = s0;
                            s0 = peg$FAILED;
                        }
                    }
                    else {
                        peg$currPos = s0;
                        s0 = peg$FAILED;
                    }
                }
                else {
                    peg$currPos = s0;
                    s0 = peg$FAILED;
                }
            }
            else {
                peg$currPos = s0;
                s0 = peg$FAILED;
            }
        }
        else {
            peg$currPos = s0;
            s0 = peg$FAILED;
        }
        return s0;
    }
    options.data = {}; // Object to which header attributes will be assigned during parsing
    function list(head, tail) {
        return [head].concat(tail);
    }
    peg$result = peg$startRuleFunction();
    if (peg$result !== peg$FAILED && peg$currPos === input.length) {
        return peg$result;
    }
    else {
        if (peg$result !== peg$FAILED && peg$currPos < input.length) {
            peg$fail(peg$endExpectation());
        }
        throw peg$buildStructuredError(peg$maxFailExpected, peg$maxFailPos < input.length ? input.charAt(peg$maxFailPos) : null, peg$maxFailPos < input.length
            ? peg$computeLocation(peg$maxFailPos, peg$maxFailPos + 1)
            : peg$computeLocation(peg$maxFailPos, peg$maxFailPos));
    }
}
exports.parse = peg$parse;


/***/ }),
/* 13 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";

var __extends = (this && this.__extends) || (function () {
    var extendStatics = function (d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
var Enums_1 = __webpack_require__(5);
var URI_1 = __webpack_require__(14);
/**
 * @class Class creating a Name Address SIP header.
 *
 * @param {SIP.URI} uri
 * @param {String} [displayName]
 * @param {Object} [parameters]
 *
 */
var NameAddrHeader = /** @class */ (function (_super) {
    __extends(NameAddrHeader, _super);
    function NameAddrHeader(uri, displayName, parameters) {
        var _this = _super.call(this, parameters) || this;
        _this.type = Enums_1.TypeStrings.NameAddrHeader;
        // Checks
        if (!uri || !(uri.type === Enums_1.TypeStrings.URI)) {
            throw new TypeError('missing or invalid "uri" parameter');
        }
        _this.uri = uri;
        _this._displayName = displayName;
        return _this;
    }
    Object.defineProperty(NameAddrHeader.prototype, "friendlyName", {
        get: function () {
            return this.displayName || this.uri.aor;
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(NameAddrHeader.prototype, "displayName", {
        get: function () { return this._displayName; },
        set: function (value) {
            this._displayName = value;
        },
        enumerable: true,
        configurable: true
    });
    NameAddrHeader.prototype.clone = function () {
        return new NameAddrHeader(this.uri.clone(), this._displayName, JSON.parse(JSON.stringify(this.parameters)));
    };
    NameAddrHeader.prototype.toString = function () {
        var body = (this.displayName || this.displayName === "0") ? '"' + this.displayName + '" ' : "";
        body += "<" + this.uri.toString() + ">";
        for (var parameter in this.parameters) {
            if (this.parameters.hasOwnProperty(parameter)) {
                body += ";" + parameter;
                if (this.parameters[parameter] !== null) {
                    body += "=" + this.parameters[parameter];
                }
            }
        }
        return body;
    };
    return NameAddrHeader;
}(URI_1.Parameters));
exports.NameAddrHeader = NameAddrHeader;


/***/ }),
/* 14 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";

var __extends = (this && this.__extends) || (function () {
    var extendStatics = function (d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
var Constants_1 = __webpack_require__(3);
var Enums_1 = __webpack_require__(5);
var Parameters = /** @class */ (function () {
    function Parameters(parameters) {
        this.parameters = {};
        this.type = Enums_1.TypeStrings.Parameters;
        for (var param in parameters) {
            if (parameters.hasOwnProperty(param)) {
                this.setParam(param, parameters[param]);
            }
        }
    }
    Parameters.prototype.setParam = function (key, value) {
        if (key) {
            this.parameters[key.toLowerCase()] = (typeof value === "undefined" || value === null) ? null : value.toString();
        }
    };
    Parameters.prototype.getParam = function (key) {
        if (key) {
            return this.parameters[key.toLowerCase()];
        }
    };
    Parameters.prototype.hasParam = function (key) {
        if (key) {
            return !!this.parameters.hasOwnProperty(key.toLowerCase());
        }
        return false;
    };
    Parameters.prototype.deleteParam = function (parameter) {
        parameter = parameter.toLowerCase();
        if (this.parameters.hasOwnProperty(parameter)) {
            var value = this.parameters[parameter];
            delete this.parameters[parameter];
            return value;
        }
    };
    Parameters.prototype.clearParams = function () {
        this.parameters = {};
    };
    return Parameters;
}());
exports.Parameters = Parameters;
/**
 * @class Class creating a SIP URI.
 *
 * @param {String} [scheme]
 * @param {String} [user]
 * @param {String} host
 * @param {String} [port]
 * @param {Object} [parameters]
 * @param {Object} [headers]
 *
 */
// tslint:disable-next-line:max-classes-per-file
var URI = /** @class */ (function (_super) {
    __extends(URI, _super);
    function URI(scheme, user, host, port, parameters, headers) {
        var _this = _super.call(this, parameters) || this;
        _this.headers = {};
        _this.type = Enums_1.TypeStrings.URI;
        // Checks
        if (!host) {
            throw new TypeError('missing or invalid "host" parameter');
        }
        // Initialize parameters
        scheme = scheme || Constants_1.C.SIP;
        for (var header in headers) {
            if (headers.hasOwnProperty(header)) {
                _this.setHeader(header, headers[header]);
            }
        }
        // Raw URI
        _this.raw = {
            scheme: scheme,
            user: user,
            host: host,
            port: port
        };
        // Normalized URI
        _this.normal = {
            scheme: scheme.toLowerCase(),
            user: user,
            host: host.toLowerCase(),
            port: port
        };
        return _this;
    }
    Object.defineProperty(URI.prototype, "_normal", {
        get: function () { return this.normal; },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(URI.prototype, "_raw", {
        get: function () { return this.raw; },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(URI.prototype, "scheme", {
        get: function () { return this.normal.scheme; },
        set: function (value) {
            this.raw.scheme = value;
            this.normal.scheme = value.toLowerCase();
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(URI.prototype, "user", {
        get: function () { return this.normal.user; },
        set: function (value) {
            this.normal.user = this.raw.user = value;
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(URI.prototype, "host", {
        get: function () { return this.normal.host; },
        set: function (value) {
            this.raw.host = value;
            this.normal.host = value.toLowerCase();
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(URI.prototype, "aor", {
        get: function () { return this.normal.user + "@" + this.normal.host; },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(URI.prototype, "port", {
        get: function () { return this.normal.port; },
        set: function (value) {
            this.normal.port = this.raw.port = value === 0 ? value : value;
        },
        enumerable: true,
        configurable: true
    });
    URI.prototype.setHeader = function (name, value) {
        this.headers[this.headerize(name)] = (value instanceof Array) ? value : [value];
    };
    URI.prototype.getHeader = function (name) {
        if (name) {
            return this.headers[this.headerize(name)];
        }
    };
    URI.prototype.hasHeader = function (name) {
        return !!name && !!this.headers.hasOwnProperty(this.headerize(name));
    };
    URI.prototype.deleteHeader = function (header) {
        header = this.headerize(header);
        if (this.headers.hasOwnProperty(header)) {
            var value = this.headers[header];
            delete this.headers[header];
            return value;
        }
    };
    URI.prototype.clearHeaders = function () {
        this.headers = {};
    };
    URI.prototype.clone = function () {
        return new URI(this._raw.scheme, this._raw.user || "", this._raw.host, this._raw.port, JSON.parse(JSON.stringify(this.parameters)), JSON.parse(JSON.stringify(this.headers)));
    };
    URI.prototype.toRaw = function () {
        return this._toString(this._raw);
    };
    URI.prototype.toString = function () {
        return this._toString(this._normal);
    };
    URI.prototype._toString = function (uri) {
        var uriString = uri.scheme + ":";
        // add slashes if it's not a sip(s) URI
        if (!uri.scheme.toLowerCase().match("^sips?$")) {
            uriString += "//";
        }
        if (uri.user) {
            uriString += this.escapeUser(uri.user) + "@";
        }
        uriString += uri.host;
        if (uri.port || uri.port === 0) {
            uriString += ":" + uri.port;
        }
        for (var parameter in this.parameters) {
            if (this.parameters.hasOwnProperty(parameter)) {
                uriString += ";" + parameter;
                if (this.parameters[parameter] !== null) {
                    uriString += "=" + this.parameters[parameter];
                }
            }
        }
        var headers = [];
        for (var header in this.headers) {
            if (this.headers.hasOwnProperty(header)) {
                for (var idx in this.headers[header]) {
                    if (this.headers[header].hasOwnProperty(idx)) {
                        headers.push(header + "=" + this.headers[header][idx]);
                    }
                }
            }
        }
        if (headers.length > 0) {
            uriString += "?" + headers.join("&");
        }
        return uriString;
    };
    // The following two functions were copied from Utils to break a circular dependency
    /*
     * Hex-escape a SIP URI user.
     * @private
     * @param {String} user
     */
    URI.prototype.escapeUser = function (user) {
        // Don't hex-escape ':' (%3A), '+' (%2B), '?' (%3F"), '/' (%2F).
        return encodeURIComponent(decodeURIComponent(user))
            .replace(/%3A/ig, ":")
            .replace(/%2B/ig, "+")
            .replace(/%3F/ig, "?")
            .replace(/%2F/ig, "/");
    };
    URI.prototype.headerize = function (str) {
        var exceptions = {
            "Call-Id": "Call-ID",
            "Cseq": "CSeq",
            "Min-Se": "Min-SE",
            "Rack": "RAck",
            "Rseq": "RSeq",
            "Www-Authenticate": "WWW-Authenticate",
        };
        var name = str.toLowerCase().replace(/_/g, "-").split("-");
        var parts = name.length;
        var hname = "";
        for (var 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;
    };
    return URI;
}(Parameters));
exports.URI = URI;


/***/ }),
/* 15 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";

Object.defineProperty(exports, "__esModule", { value: true });
var Constants_1 = __webpack_require__(3);
var Enums_1 = __webpack_require__(5);
var Grammar_1 = __webpack_require__(11);
var Utils;
(function (Utils) {
    function defer() {
        var deferred = {};
        deferred.promise = new Promise(function (resolve, reject) {
            deferred.resolve = resolve;
            deferred.reject = reject;
        });
        return deferred;
    }
    Utils.defer = defer;
    function reducePromises(arr, val) {
        return arr.reduce(function (acc, fn) {
            acc = acc.then(fn);
            return acc;
        }, Promise.resolve(val));
    }
    Utils.reducePromises = reducePromises;
    function str_utf8_length(str) {
        return encodeURIComponent(str).replace(/%[A-F\d]{2}/g, "U").length;
    }
    Utils.str_utf8_length = str_utf8_length;
    function generateFakeSDP(body) {
        if (!body) {
            return;
        }
        var start = body.indexOf("o=");
        var end = body.indexOf("\r\n", start);
        return "v=0\r\n" + body.slice(start, end) + "\r\ns=-\r\nt=0 0\r\nc=IN IP4 0.0.0.0";
    }
    Utils.generateFakeSDP = generateFakeSDP;
    function isDecimal(num) {
        var numAsNum = parseInt(num, 10);
        return !isNaN(numAsNum) && (parseFloat(num) === numAsNum);
    }
    Utils.isDecimal = isDecimal;
    function createRandomToken(size, base) {
        if (base === void 0) { base = 32; }
        var token = "";
        for (var i = 0; i < size; i++) {
            var r = Math.floor(Math.random() * base);
            token += r.toString(base);
        }
        return token;
    }
    Utils.createRandomToken = createRandomToken;
    function newTag() {
        // used to use the constant in UA
        return Utils.createRandomToken(10);
    }
    Utils.newTag = newTag;
    // http://stackoverflow.com/users/109538/broofa
    function newUUID() {
        var UUID = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
            var r = Math.floor(Math.random() * 16);
            var v = c === "x" ? r : (r % 4 + 8);
            return v.toString(16);
        });
        return UUID;
    }
    Utils.newUUID = newUUID;
    /*
     * 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.
     * @private
     * @param {String} target
     * @param {String} [domain]
     */
    function normalizeTarget(target, domain) {
        // If no target is given then raise an error.
        if (!target) {
            return;
            // If a SIP.URI instance is given then return it.
        }
        else if (target.type === Enums_1.TypeStrings.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 targetArray = target.split("@");
            var targetUser = void 0;
            var targetDomain = void 0;
            switch (targetArray.length) {
                case 1:
                    if (!domain) {
                        return;
                    }
                    targetUser = target;
                    targetDomain = domain;
                    break;
                case 2:
                    targetUser = targetArray[0];
                    targetDomain = targetArray[1];
                    break;
                default:
                    targetUser = targetArray.slice(0, targetArray.length - 1).join("@");
                    targetDomain = targetArray[targetArray.length - 1];
            }
            // Remove the URI scheme (if present).
            targetUser = targetUser.replace(/^(sips?|tel):/i, "");
            // Remove 'tel' visual separators if the user portion just contains 'tel' number symbols.
            if (/^[\-\.\(\)]*\+?[0-9\-\.\(\)]+$/.test(targetUser)) {
                targetUser = targetUser.replace(/[\-\.\(\)]/g, "");
            }
            // Build the complete SIP URI.
            target = Constants_1.C.SIP + ":" + Utils.escapeUser(targetUser) + "@" + targetDomain;
            // Finally parse the resulting URI.
            return Grammar_1.Grammar.URIParse(target);
        }
        else {
            return;
        }
    }
    Utils.normalizeTarget = normalizeTarget;
    /*
     * Hex-escape a SIP URI user.
     * @private
     * @param {String} user
     */
    function escapeUser(user) {
        // Don't hex-escape ':' (%3A), '+' (%2B), '?' (%3F"), '/' (%2F).
        return encodeURIComponent(decodeURIComponent(user))
            .replace(/%3A/ig, ":")
            .replace(/%2B/ig, "+")
            .replace(/%3F/ig, "?")
            .replace(/%2F/ig, "/");
    }
    Utils.escapeUser = escapeUser;
    function headerize(str) {
        var exceptions = {
            "Call-Id": "Call-ID",
            "Cseq": "CSeq",
            "Min-Se": "Min-SE",
            "Rack": "RAck",
            "Rseq": "RSeq",
            "Www-Authenticate": "WWW-Authenticate",
        };
        var name = str.toLowerCase().replace(/_/g, "-").split("-");
        var parts = name.length;
        var hname = "";
        for (var 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;
    }
    Utils.headerize = headerize;
    function sipErrorCause(statusCode) {
        for (var cause in Constants_1.C.SIP_ERROR_CAUSES) {
            if (Constants_1.C.SIP_ERROR_CAUSES[cause].indexOf(statusCode) !== -1) {
                return Constants_1.C.causes[cause];
            }
        }
        return Constants_1.C.causes.SIP_FAILURE_CODE;
    }
    Utils.sipErrorCause = sipErrorCause;
    function getReasonPhrase(code, specific) {
        return specific || Constants_1.C.REASON_PHRASE[code] || "";
    }
    Utils.getReasonPhrase = getReasonPhrase;
    function getReasonHeaderValue(code, reason) {
        reason = Utils.getReasonPhrase(code, reason);
        return "SIP;cause=" + code + ';text="' + reason + '"';
    }
    Utils.getReasonHeaderValue = getReasonHeaderValue;
    function getCancelReason(code, reason) {
        if (code && code < 200 || code > 699) {
            throw new TypeError("Invalid statusCode: " + code);
        }
        else if (code) {
            return Utils.getReasonHeaderValue(code, reason);
        }
    }
    Utils.getCancelReason = getCancelReason;
    function buildStatusLine(code, reason) {
        // Validate code and reason values
        if (!code || (code < 100 || code > 699)) {
            throw new TypeError("Invalid statusCode: " + code);
        }
        else if (reason && typeof reason !== "string" && !(reason instanceof String)) {
            throw new TypeError("Invalid reason: " + reason);
        }
        reason = Utils.getReasonPhrase(code, reason);
        return "SIP/2.0 " + code + " " + reason + "\r\n";
    }
    Utils.buildStatusLine = buildStatusLine;
})(Utils = exports.Utils || (exports.Utils = {}));


/***/ }),
/* 16 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";

Object.defineProperty(exports, "__esModule", { value: true });
var Constants_1 = __webpack_require__(3);
var Enums_1 = __webpack_require__(5);
var RequestSender_1 = __webpack_require__(6);
var SIPMessage_1 = __webpack_require__(10);
var Transactions_1 = __webpack_require__(7);
/*
 * @augments SIP
 * @class Class creating a SIP dialog. RFC 3261 12.1
 * @param {SIP.RTCSession} owner
 * @param {SIP.IncomingRequest|SIP.IncomingResponse} message
 * @param {Enum} type UAC / UAS
 * @param {Enum} state SIP.Dialog.C.STATUS_EARLY / SIP.Dialog.C.STATUS_CONFIRMED
 */
var Dialog = /** @class */ (function () {
    function Dialog(owner, message, type, state) {
        this.pracked = [];
        this.uacPendingReply = false;
        this.uasPendingReply = false;
        this.type = Enums_1.TypeStrings.Dialog;
        if (!message.hasHeader("contact")) {
            throw new Error("unable to create a Dialog without Contact header field");
        }
        if (message.type === Enums_1.TypeStrings.IncomingResponse) {
            var statusCode = message.statusCode;
            state = (statusCode && statusCode < 200) ?
                Enums_1.DialogStatus.STATUS_EARLY : Enums_1.DialogStatus.STATUS_CONFIRMED;
        }
        else {
            // Create confirmed dialog if state is not defined
            state = state || Enums_1.DialogStatus.STATUS_CONFIRMED;
        }
        var contact = message.parseHeader("contact");
        // RFC 3261 12.1.1
        if (type === "UAS" && message.type === Enums_1.TypeStrings.IncomingRequest) {
            this.id = {
                callId: message.callId,
                localTag: message.toTag,
                remoteTag: message.fromTag,
                toString: function () {
                    return message.callId + message.toTag + message.fromTag;
                }
            };
            this.state = state;
            this.remoteSeqnum = message.cseq;
            this.localUri = (message.parseHeader("to") || {}).uri;
            this.remoteUri = (message.parseHeader("from") || {}).uri;
            this.remoteTarget = contact.uri;
            this.routeSet = message.getHeaders("record-route");
            this.inviteSeqnum = message.cseq;
            this.localSeqnum = message.cseq;
        }
        else { // type is UAC, RFC 3261 12.1.2
            this.id = {
                callId: message.callId,
                localTag: message.fromTag,
                remoteTag: message.toTag,
                toString: function () {
                    return message.callId + message.fromTag + message.toTag;
                }
            };
            this.state = state;
            this.inviteSeqnum = message.cseq;
            this.localSeqnum = message.cseq;
            this.localUri = message.parseHeader("from").uri;
            this.pracked = [];
            this.remoteUri = message.parseHeader("to").uri;
            this.remoteTarget = contact.uri;
            this.routeSet = message.getHeaders("record-route").reverse();
        }
        this.logger = owner.ua.getLogger("sip.dialog", this.id.toString());
        this.owner = owner;
        owner.ua.dialogs[this.id.toString()] = this;
        this.logger.log("new " + type + " dialog created with status " +
            (this.state === Enums_1.DialogStatus.STATUS_EARLY ? "EARLY" : "CONFIRMED"));
        owner.emit("dialog", this);
    }
    /**
     * @param {SIP.IncomingMessage} message
     * @param {Enum} UAC/UAS
     */
    Dialog.prototype.update = function (message, type) {
        this.state = Enums_1.DialogStatus.STATUS_CONFIRMED;
        this.logger.log("dialog " + this.id.toString() + "  changed to CONFIRMED state");
        if (type === "UAC") {
            // RFC 3261 13.2.2.4
            this.routeSet = message.getHeaders("record-route").reverse();
        }
    };
    Dialog.prototype.terminate = function () {
        this.logger.log("dialog " + this.id.toString() + " deleted");
        if (this.sessionDescriptionHandler && this.state !== Enums_1.DialogStatus.STATUS_CONFIRMED) {
            // TODO: This should call .close() on the handler when implemented
            this.sessionDescriptionHandler.close();
        }
        delete this.owner.ua.dialogs[this.id.toString()];
    };
    /**
     * @param {String} method request method
     * @param {Object} extraHeaders extra headers
     * @returns {SIP.OutgoingRequest}
     */
    // RFC 3261 12.2.1.1
    Dialog.prototype.createRequest = function (method, extraHeaders, body) {
        if (extraHeaders === void 0) { extraHeaders = []; }
        extraHeaders = extraHeaders.slice();
        if (!this.localSeqnum) {
            this.localSeqnum = Math.floor(Math.random() * 10000);
        }
        var cseq = (method === Constants_1.C.CANCEL || method === Constants_1.C.ACK) ? this.inviteSeqnum : this.localSeqnum += 1;
        var request = new SIPMessage_1.OutgoingRequest(method, this.remoteTarget, this.owner.ua, {
            cseq: cseq,
            callId: this.id.callId,
            fromUri: this.localUri,
            fromTag: this.id.localTag,
            toIri: this.remoteUri,
            toTag: this.id.remoteTag,
            routeSet: this.routeSet
        }, extraHeaders, body);
        request.dialog = this;
        return request;
    };
    /**
     * @param {SIP.IncomingRequest} request
     * @returns {Boolean}
     */
    // RFC 3261 12.2.2
    Dialog.prototype.checkInDialogRequest = function (request) {
        var _this = this;
        if (!this.remoteSeqnum) {
            this.remoteSeqnum = request.cseq;
        }
        else if (request.cseq < this.remoteSeqnum) {
            // Do not try to reply to an ACK request.
            if (request.method !== Constants_1.C.ACK) {
                request.reply(500);
            }
            return request.cseq === this.inviteSeqnum;
        }
        switch (request.method) {
            // RFC3261 14.2 Modifying an Existing Session -UAS BEHAVIOR-
            case Constants_1.C.INVITE:
                if (this.uacPendingReply === true) {
                    request.reply(491);
                }
                else if (this.uasPendingReply === true && request.cseq > this.remoteSeqnum) {
                    var retryAfter = Math.floor((Math.random() * 10)) + 1;
                    request.reply(500, undefined, ["Retry-After:" + retryAfter]);
                    this.remoteSeqnum = request.cseq;
                    return false;
                }
                else {
                    this.uasPendingReply = true;
                    var stateChanged_1 = function () {
                        if (request.transaction &&
                            (request.transaction.state === Transactions_1.TransactionState.Accepted ||
                                request.transaction.state === Transactions_1.TransactionState.Completed ||
                                request.transaction.state === Transactions_1.TransactionState.Terminated)) {
                            request.transaction.removeListener("stateChanged", stateChanged_1);
                            _this.uasPendingReply = false;
                        }
                    };
                    if (request.transaction) {
                        request.transaction.on("stateChanged", stateChanged_1);
                    }
                }
                // RFC3261 12.2.2 Replace the dialog`s remote target URI if the request is accepted
                if (request.hasHeader("contact") && request.transaction) {
                    request.transaction.on("stateChanged", function () {
                        if (request.transaction && request.transaction.state === Transactions_1.TransactionState.Accepted) {
                            _this.remoteTarget = request.parseHeader("contact").uri;
                        }
                    });
                }
                break;
            case Constants_1.C.NOTIFY:
                // RFC6665 3.2 Replace the dialog`s remote target URI if the request is accepted
                if (request.hasHeader("contact") && request.transaction) {
                    request.transaction.on("stateChanged", function () {
                        if (request.transaction && request.transaction.state === Transactions_1.TransactionState.Completed) {
                            _this.remoteTarget = request.parseHeader("contact").uri;
                        }
                    });
                }
                break;
        }
        if (request.cseq > this.remoteSeqnum) {
            this.remoteSeqnum = request.cseq;
        }
        return true;
    };
    Dialog.prototype.sendRequest = function (applicant, method, options) {
        var _this = this;
        if (options === void 0) { options = {}; }
        var extraHeaders = (options.extraHeaders || []).slice();
        var body;
        if (options.body) {
            if (options.body.body) {
                body = options.body;
            }
            else {
                body = {};
                body.body = options.body;
                if (options.contentType) {
                    body.contentType = options.contentType;
                }
            }
        }
        var request = this.createRequest(method, extraHeaders, body);
        var dialogSend = function (reattempt) {
            var requestSender = new RequestSender_1.RequestSender({
                request: request,
                onRequestTimeout: applicant.onRequestTimeout.bind(applicant),
                onTransportError: applicant.onTransportError.bind(applicant),
                receiveResponse: function (response) {
                    // RFC3261 12.2.1.2 408 or 481 is received for a request within a dialog.
                    if (response.statusCode === 408 || response.statusCode === 481) {
                        applicant.onDialogError(response);
                    }
                    else if (response.method === Constants_1.C.INVITE && response.statusCode === 491) {
                        if (reattempt) {
                            applicant.receiveResponse(response);
                        }
                        else {
                            request.cseq = _this.localSeqnum += 1;
                            setTimeout(function () {
                                // first check is to determine !Subscription (remove circular dependency)
                                if (_this.owner.status !== undefined &&
                                    _this.owner.status
                                        !== Enums_1.SessionStatus.STATUS_TERMINATED) {
                                    // RFC3261 14.1 Modifying an Existing Session. UAC Behavior.
                                    dialogSend(true);
                                }
                            }, 1000);
                        }
                    }
                    else {
                        applicant.receiveResponse(response);
                    }
                }
            }, _this.owner.ua);
            requestSender.send();
            // RFC3261 14.2 Modifying an Existing Session -UAC BEHAVIOR-
            if (!requestSender.clientTransaction) {
                return;
            }
            else if (request.method === Constants_1.C.INVITE &&
                requestSender.clientTransaction &&
                requestSender.clientTransaction.state
                    !== Transactions_1.TransactionState.Terminated) {
                _this.uacPendingReply = true;
                var stateChanged_2 = function () {
                    var state = requestSender.clientTransaction.state;
                    if (!requestSender.clientTransaction) {
                        return;
                    }
                    else if (requestSender.clientTransaction &&
                        (state === Transactions_1.TransactionState.Accepted ||
                            state === Transactions_1.TransactionState.Completed ||
                            state === Transactions_1.TransactionState.Terminated)) {
                        requestSender.clientTransaction.removeListener("stateChanged", stateChanged_2);
                        _this.uacPendingReply = false;
                    }
                };
                requestSender.clientTransaction.on("stateChanged", stateChanged_2);
            }
        };
        dialogSend(false);
        return request;
    };
    /**
     * @param {SIP.IncomingRequest} request
     */
    Dialog.prototype.receiveRequest = function (request) {
        // Check in-dialog request
        if (!this.checkInDialogRequest(request)) {
            return;
        }
        this.owner.receiveRequest(request);
    };
    Dialog.C = Enums_1.DialogStatus;
    return Dialog;
}());
exports.Dialog = Dialog;


/***/ }),
/* 17 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";

Object.defineProperty(exports, "__esModule", { value: true });
var MD5 = __webpack_require__(18);
var Enums_1 = __webpack_require__(5);
var Utils_1 = __webpack_require__(15);
/**
 * SIP Digest Authentication.
 * @function Digest Authentication
 * @param {SIP.UA} ua
 */
var DigestAuthentication = /** @class */ (function () {
    function DigestAuthentication(ua) {
        this.type = Enums_1.TypeStrings.DigestAuthentication;
        this.logger = ua.getLogger("sipjs.digestauthentication");
        this.username = ua.configuration.authorizationUser;
        this.password = ua.configuration.password;
        this.nc = 0;
        this.ncHex = "00000000";
    }
    /**
     * Performs Digest authentication given a SIP request and the challenge
     * received in a response to that request.
     * Returns true if credentials were successfully generated, false otherwise.
     *
     * @param {SIP.OutgoingRequest} request
     * @param {Object} challenge
     */
    DigestAuthentication.prototype.authenticate = function (request, challenge, body) {
        // Inspect and validate the challenge.
        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") {
                this.logger.warn("challenge with Digest algorithm different than 'MD5', authentication aborted");
                return false;
            }
        }
        else {
            this.algorithm = "MD5";
        }
        if (!this.realm) {
            this.logger.warn("challenge without Digest realm, authentication aborted");
            return false;
        }
        if (!this.nonce) {
            this.logger.warn("challenge without Digest nonce, authentication aborted");
            return false;
        }
        // 'qop' can contain a list of values (Array). Let's choose just one.
        if (challenge.qop) {
            if (challenge.qop.indexOf("auth") > -1) {
                this.qop = "auth";
            }
            else if (challenge.qop.indexOf("auth-int") > -1) {
                this.qop = "auth-int";
            }
            else {
                // Otherwise 'qop' is present but does not contain 'auth' or 'auth-int', so abort here.
                this.logger.warn("challenge without Digest qop different than 'auth' or 'auth-int', authentication aborted");
                return false;
            }
        }
        else {
            this.qop = undefined;
        }
        // Fill other attributes.
        this.method = request.method;
        this.uri = request.ruri;
        this.cnonce = Utils_1.Utils.createRandomToken(12);
        this.nc += 1;
        this.updateNcHex();
        // nc-value = 8LHEX. Max value = 'FFFFFFFF'.
        if (this.nc === 4294967296) {
            this.nc = 1;
            this.ncHex = "00000001";
        }
        // Calculate the Digest "response" value.
        this.calculateResponse(body);
        return true;
    };
    /**
     * Return the Proxy-Authorization or WWW-Authorization header value.
     */
    DigestAuthentication.prototype.toString = function () {
        var authParams = [];
        if (!this.response) {
            throw new Error("response field does not exist, cannot generate Authorization header");
        }
        authParams.push("algorithm=" + this.algorithm);
        authParams.push('username="' + this.username + '"');
        authParams.push('realm="' + this.realm + '"');
        authParams.push('nonce="' + this.nonce + '"');
        authParams.push('uri="' + this.uri + '"');
        authParams.push('response="' + this.response + '"');
        if (this.opaque) {
            authParams.push('opaque="' + this.opaque + '"');
        }
        if (this.qop) {
            authParams.push("qop=" + this.qop);
            authParams.push('cnonce="' + this.cnonce + '"');
            authParams.push("nc=" + this.ncHex);
        }
        return "Digest " + authParams.join(", ");
    };
    /**
     * Generate the 'nc' value as required by Digest in this.ncHex by reading this.nc.
     * @private
     */
    DigestAuthentication.prototype.updateNcHex = function () {
        var hex = Number(this.nc).toString(16);
        this.ncHex = "00000000".substr(0, 8 - hex.length) + hex;
    };
    /**
     * Generate Digest 'response' value.
     * @private
     */
    DigestAuthentication.prototype.calculateResponse = function (body) {
        var ha2;
        // HA1 = MD5(A1) = MD5(username:realm:password)
        var ha1 = MD5(this.username + ":" + this.realm + ":" + this.password);
        if (this.qop === "auth") {
            // HA2 = MD5(A2) = MD5(method:digestURI)
            ha2 = MD5(this.method + ":" + this.uri);
            // response = MD5(HA1:nonce:nonceCount:credentialsNonce:qop:HA2)
            this.response = MD5(ha1 + ":" + this.nonce + ":" + this.ncHex + ":" + this.cnonce + ":auth:" + ha2);
        }
        else if (this.qop === "auth-int") {
            // HA2 = MD5(A2) = MD5(method:digestURI:MD5(entityBody))
            ha2 = MD5(this.method + ":" + this.uri + ":" + MD5(body ? body : ""));
            // response = MD5(HA1:nonce:nonceCount:credentialsNonce:qop:HA2)
            this.response = MD5(ha1 + ":" + this.nonce + ":" + this.ncHex + ":" + this.cnonce + ":auth-int:" + ha2);
        }
        else if (this.qop === undefined) {
            // HA2 = MD5(A2) = MD5(method:digestURI)
            ha2 = MD5(this.method + ":" + this.uri);
            // response = MD5(HA1:nonce:HA2)
            this.response = MD5(ha1 + ":" + this.nonce + ":" + ha2);
        }
    };
    return DigestAuthentication;
}());
exports.DigestAuthentication = DigestAuthentication;


/***/ }),
/* 18 */
/***/ (function(module, exports, __webpack_require__) {

;(function (root, factory) {
	if (true) {
		// CommonJS
		module.exports = exports = factory(__webpack_require__(19));
	}
	else {}
}(this, function (CryptoJS) {

	(function (Math) {
	    // Shortcuts
	    var C = CryptoJS;
	    var C_lib = C.lib;
	    var WordArray = C_lib.WordArray;
	    var Hasher = C_lib.Hasher;
	    var C_algo = C.algo;

	    // Constants table
	    var T = [];

	    // Compute constants
	    (function () {
	        for (var i = 0; i < 64; i++) {
	            T[i] = (Math.abs(Math.sin(i + 1)) * 0x100000000) | 0;
	        }
	    }());

	    /**
	     * MD5 hash algorithm.
	     */
	    var MD5 = C_algo.MD5 = Hasher.extend({
	        _doReset: function () {
	            this._hash = new WordArray.init([
	                0x67452301, 0xefcdab89,
	                0x98badcfe, 0x10325476
	            ]);
	        },

	        _doProcessBlock: function (M, offset) {
	            // Swap endian
	            for (var i = 0; i < 16; i++) {
	                // Shortcuts
	                var offset_i = offset + i;
	                var M_offset_i = M[offset_i];

	                M[offset_i] = (
	                    (((M_offset_i << 8)  | (M_offset_i >>> 24)) & 0x00ff00ff) |
	                    (((M_offset_i << 24) | (M_offset_i >>> 8))  & 0xff00ff00)
	                );
	            }

	            // Shortcuts
	            var H = this._hash.words;

	            var M_offset_0  = M[offset + 0];
	            var M_offset_1  = M[offset + 1];
	            var M_offset_2  = M[offset + 2];
	            var M_offset_3  = M[offset + 3];
	            var M_offset_4  = M[offset + 4];
	            var M_offset_5  = M[offset + 5];
	            var M_offset_6  = M[offset + 6];
	            var M_offset_7  = M[offset + 7];
	            var M_offset_8  = M[offset + 8];
	            var M_offset_9  = M[offset + 9];
	            var M_offset_10 = M[offset + 10];
	            var M_offset_11 = M[offset + 11];
	            var M_offset_12 = M[offset + 12];
	            var M_offset_13 = M[offset + 13];
	            var M_offset_14 = M[offset + 14];
	            var M_offset_15 = M[offset + 15];

	            // Working varialbes
	            var a = H[0];
	            var b = H[1];
	            var c = H[2];
	            var d = H[3];

	            // Computation
	            a = FF(a, b, c, d, M_offset_0,  7,  T[0]);
	            d = FF(d, a, b, c, M_offset_1,  12, T[1]);
	            c = FF(c, d, a, b, M_offset_2,  17, T[2]);
	            b = FF(b, c, d, a, M_offset_3,  22, T[3]);
	            a = FF(a, b, c, d, M_offset_4,  7,  T[4]);
	            d = FF(d, a, b, c, M_offset_5,  12, T[5]);
	            c = FF(c, d, a, b, M_offset_6,  17, T[6]);
	            b = FF(b, c, d, a, M_offset_7,  22, T[7]);
	            a = FF(a, b, c, d, M_offset_8,  7,  T[8]);
	            d = FF(d, a, b, c, M_offset_9,  12, T[9]);
	            c = FF(c, d, a, b, M_offset_10, 17, T[10]);
	            b = FF(b, c, d, a, M_offset_11, 22, T[11]);
	            a = FF(a, b, c, d, M_offset_12, 7,  T[12]);
	            d = FF(d, a, b, c, M_offset_13, 12, T[13]);
	            c = FF(c, d, a, b, M_offset_14, 17, T[14]);
	            b = FF(b, c, d, a, M_offset_15, 22, T[15]);

	            a = GG(a, b, c, d, M_offset_1,  5,  T[16]);
	            d = GG(d, a, b, c, M_offset_6,  9,  T[17]);
	            c = GG(c, d, a, b, M_offset_11, 14, T[18]);
	            b = GG(b, c, d, a, M_offset_0,  20, T[19]);
	            a = GG(a, b, c, d, M_offset_5,  5,  T[20]);
	            d = GG(d, a, b, c, M_offset_10, 9,  T[21]);
	            c = GG(c, d, a, b, M_offset_15, 14, T[22]);
	            b = GG(b, c, d, a, M_offset_4,  20, T[23]);
	            a = GG(a, b, c, d, M_offset_9,  5,  T[24]);
	            d = GG(d, a, b, c, M_offset_14, 9,  T[25]);
	            c = GG(c, d, a, b, M_offset_3,  14, T[26]);
	            b = GG(b, c, d, a, M_offset_8,  20, T[27]);
	            a = GG(a, b, c, d, M_offset_13, 5,  T[28]);
	            d = GG(d, a, b, c, M_offset_2,  9,  T[29]);
	            c = GG(c, d, a, b, M_offset_7,  14, T[30]);
	            b = GG(b, c, d, a, M_offset_12, 20, T[31]);

	            a = HH(a, b, c, d, M_offset_5,  4,  T[32]);
	            d = HH(d, a, b, c, M_offset_8,  11, T[33]);
	            c = HH(c, d, a, b, M_offset_11, 16, T[34]);
	            b = HH(b, c, d, a, M_offset_14, 23, T[35]);
	            a = HH(a, b, c, d, M_offset_1,  4,  T[36]);
	            d = HH(d, a, b, c, M_offset_4,  11, T[37]);
	            c = HH(c, d, a, b, M_offset_7,  16, T[38]);
	            b = HH(b, c, d, a, M_offset_10, 23, T[39]);
	            a = HH(a, b, c, d, M_offset_13, 4,  T[40]);
	            d = HH(d, a, b, c, M_offset_0,  11, T[41]);
	            c = HH(c, d, a, b, M_offset_3,  16, T[42]);
	            b = HH(b, c, d, a, M_offset_6,  23, T[43]);
	            a = HH(a, b, c, d, M_offset_9,  4,  T[44]);
	            d = HH(d, a, b, c, M_offset_12, 11, T[45]);
	            c = HH(c, d, a, b, M_offset_15, 16, T[46]);
	            b = HH(b, c, d, a, M_offset_2,  23, T[47]);

	            a = II(a, b, c, d, M_offset_0,  6,  T[48]);
	            d = II(d, a, b, c, M_offset_7,  10, T[49]);
	            c = II(c, d, a, b, M_offset_14, 15, T[50]);
	            b = II(b, c, d, a, M_offset_5,  21, T[51]);
	            a = II(a, b, c, d, M_offset_12, 6,  T[52]);
	            d = II(d, a, b, c, M_offset_3,  10, T[53]);
	            c = II(c, d, a, b, M_offset_10, 15, T[54]);
	            b = II(b, c, d, a, M_offset_1,  21, T[55]);
	            a = II(a, b, c, d, M_offset_8,  6,  T[56]);
	            d = II(d, a, b, c, M_offset_15, 10, T[57]);
	            c = II(c, d, a, b, M_offset_6,  15, T[58]);
	            b = II(b, c, d, a, M_offset_13, 21, T[59]);
	            a = II(a, b, c, d, M_offset_4,  6,  T[60]);
	            d = II(d, a, b, c, M_offset_11, 10, T[61]);
	            c = II(c, d, a, b, M_offset_2,  15, T[62]);
	            b = II(b, c, d, a, M_offset_9,  21, T[63]);

	            // Intermediate hash value
	            H[0] = (H[0] + a) | 0;
	            H[1] = (H[1] + b) | 0;
	            H[2] = (H[2] + c) | 0;
	            H[3] = (H[3] + d) | 0;
	        },

	        _doFinalize: function () {
	            // Shortcuts
	            var data = this._data;
	            var dataWords = data.words;

	            var nBitsTotal = this._nDataBytes * 8;
	            var nBitsLeft = data.sigBytes * 8;

	            // Add padding
	            dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32);

	            var nBitsTotalH = Math.floor(nBitsTotal / 0x100000000);
	            var nBitsTotalL = nBitsTotal;
	            dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = (
	                (((nBitsTotalH << 8)  | (nBitsTotalH >>> 24)) & 0x00ff00ff) |
	                (((nBitsTotalH << 24) | (nBitsTotalH >>> 8))  & 0xff00ff00)
	            );
	            dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = (
	                (((nBitsTotalL << 8)  | (nBitsTotalL >>> 24)) & 0x00ff00ff) |
	                (((nBitsTotalL << 24) | (nBitsTotalL >>> 8))  & 0xff00ff00)
	            );

	            data.sigBytes = (dataWords.length + 1) * 4;

	            // Hash final blocks
	            this._process();

	            // Shortcuts
	            var hash = this._hash;
	            var H = hash.words;

	            // Swap endian
	            for (var i = 0; i < 4; i++) {
	                // Shortcut
	                var H_i = H[i];

	                H[i] = (((H_i << 8)  | (H_i >>> 24)) & 0x00ff00ff) |
	                       (((H_i << 24) | (H_i >>> 8))  & 0xff00ff00);
	            }

	            // Return final computed hash
	            return hash;
	        },

	        clone: function () {
	            var clone = Hasher.clone.call(this);
	            clone._hash = this._hash.clone();

	            return clone;
	        }
	    });

	    function FF(a, b, c, d, x, s, t) {
	        var n = a + ((b & c) | (~b & d)) + x + t;
	        return ((n << s) | (n >>> (32 - s))) + b;
	    }

	    function GG(a, b, c, d, x, s, t) {
	        var n = a + ((b & d) | (c & ~d)) + x + t;
	        return ((n << s) | (n >>> (32 - s))) + b;
	    }

	    function HH(a, b, c, d, x, s, t) {
	        var n = a + (b ^ c ^ d) + x + t;
	        return ((n << s) | (n >>> (32 - s))) + b;
	    }

	    function II(a, b, c, d, x, s, t) {
	        var n = a + (c ^ (b | ~d)) + x + t;
	        return ((n << s) | (n >>> (32 - s))) + b;
	    }

	    /**
	     * Shortcut function to the hasher's object interface.
	     *
	     * @param {WordArray|string} message The message to hash.
	     *
	     * @return {WordArray} The hash.
	     *
	     * @static
	     *
	     * @example
	     *
	     *     var hash = CryptoJS.MD5('message');
	     *     var hash = CryptoJS.MD5(wordArray);
	     */
	    C.MD5 = Hasher._createHelper(MD5);

	    /**
	     * Shortcut function to the HMAC's object interface.
	     *
	     * @param {WordArray|string} message The message to hash.
	     * @param {WordArray|string} key The secret key.
	     *
	     * @return {WordArray} The HMAC.
	     *
	     * @static
	     *
	     * @example
	     *
	     *     var hmac = CryptoJS.HmacMD5(message, key);
	     */
	    C.HmacMD5 = Hasher._createHmacHelper(MD5);
	}(Math));


	return CryptoJS.MD5;

}));

/***/ }),
/* 19 */
/***/ (function(module, exports, __webpack_require__) {

;(function (root, factory) {
	if (true) {
		// CommonJS
		module.exports = exports = factory();
	}
	else {}
}(this, function () {

	/**
	 * CryptoJS core components.
	 */
	var CryptoJS = CryptoJS || (function (Math, undefined) {
	    /*
	     * Local polyfil of Object.create
	     */
	    var create = Object.create || (function () {
	        function F() {};

	        return function (obj) {
	            var subtype;

	            F.prototype = obj;

	            subtype = new F();

	            F.prototype = null;

	            return subtype;
	        };
	    }())

	    /**
	     * CryptoJS namespace.
	     */
	    var C = {};

	    /**
	     * Library namespace.
	     */
	    var C_lib = C.lib = {};

	    /**
	     * Base object for prototypal inheritance.
	     */
	    var Base = C_lib.Base = (function () {


	        return {
	            /**
	             * Creates a new object that inherits from this object.
	             *
	             * @param {Object} overrides Properties to copy into the new object.
	             *
	             * @return {Object} The new object.
	             *
	             * @static
	             *
	             * @example
	             *
	             *     var MyType = CryptoJS.lib.Base.extend({
	             *         field: 'value',
	             *
	             *         method: function () {
	             *         }
	             *     });
	             */
	            extend: function (overrides) {
	                // Spawn
	                var subtype = create(this);

	                // Augment
	                if (overrides) {
	                    subtype.mixIn(overrides);
	                }

	                // Create default initializer
	                if (!subtype.hasOwnProperty('init') || this.init === subtype.init) {
	                    subtype.init = function () {
	                        subtype.$super.init.apply(this, arguments);
	                    };
	                }

	                // Initializer's prototype is the subtype object
	                subtype.init.prototype = subtype;

	                // Reference supertype
	                subtype.$super = this;

	                return subtype;
	            },

	            /**
	             * Extends this object and runs the init method.
	             * Arguments to create() will be passed to init().
	             *
	             * @return {Object} The new object.
	             *
	             * @static
	             *
	             * @example
	             *
	             *     var instance = MyType.create();
	             */
	            create: function () {
	                var instance = this.extend();
	                instance.init.apply(instance, arguments);

	                return instance;
	            },

	            /**
	             * Initializes a newly created object.
	             * Override this method to add some logic when your objects are created.
	             *
	             * @example
	             *
	             *     var MyType = CryptoJS.lib.Base.extend({
	             *         init: function () {
	             *             // ...
	             *         }
	             *     });
	             */
	            init: function () {
	            },

	            /**
	             * Copies properties into this object.
	             *
	             * @param {Object} properties The properties to mix in.
	             *
	             * @example
	             *
	             *     MyType.mixIn({
	             *         field: 'value'
	             *     });
	             */
	            mixIn: function (properties) {
	                for (var propertyName in properties) {
	                    if (properties.hasOwnProperty(propertyName)) {
	                        this[propertyName] = properties[propertyName];
	                    }
	                }

	                // IE won't copy toString using the loop above
	                if (properties.hasOwnProperty('toString')) {
	                    this.toString = properties.toString;
	                }
	            },

	            /**
	             * Creates a copy of this object.
	             *
	             * @return {Object} The clone.
	             *
	             * @example
	             *
	             *     var clone = instance.clone();
	             */
	            clone: function () {
	                return this.init.prototype.extend(this);
	            }
	        };
	    }());

	    /**
	     * An array of 32-bit words.
	     *
	     * @property {Array} words The array of 32-bit words.
	     * @property {number} sigBytes The number of significant bytes in this word array.
	     */
	    var WordArray = C_lib.WordArray = Base.extend({
	        /**
	         * Initializes a newly created word array.
	         *
	         * @param {Array} words (Optional) An array of 32-bit words.
	         * @param {number} sigBytes (Optional) The number of significant bytes in the words.
	         *
	         * @example
	         *
	         *     var wordArray = CryptoJS.lib.WordArray.create();
	         *     var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607]);
	         *     var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607], 6);
	         */
	        init: function (words, sigBytes) {
	            words = this.words = words || [];

	            if (sigBytes != undefined) {
	                this.sigBytes = sigBytes;
	            } else {
	                this.sigBytes = words.length * 4;
	            }
	        },

	        /**
	         * Converts this word array to a string.
	         *
	         * @param {Encoder} encoder (Optional) The encoding strategy to use. Default: CryptoJS.enc.Hex
	         *
	         * @return {string} The stringified word array.
	         *
	         * @example
	         *
	         *     var string = wordArray + '';
	         *     var string = wordArray.toString();
	         *     var string = wordArray.toString(CryptoJS.enc.Utf8);
	         */
	        toString: function (encoder) {
	            return (encoder || Hex).stringify(this);
	        },

	        /**
	         * Concatenates a word array to this word array.
	         *
	         * @param {WordArray} wordArray The word array to append.
	         *
	         * @return {WordArray} This word array.
	         *
	         * @example
	         *
	         *     wordArray1.concat(wordArray2);
	         */
	        concat: function (wordArray) {
	            // Shortcuts
	            var thisWords = this.words;
	            var thatWords = wordArray.words;
	            var thisSigBytes = this.sigBytes;
	            var thatSigBytes = wordArray.sigBytes;

	            // Clamp excess bits
	            this.clamp();

	            // Concat
	            if (thisSigBytes % 4) {
	                // Copy one byte at a time
	                for (var i = 0; i < thatSigBytes; i++) {
	                    var thatByte = (thatWords[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;
	                    thisWords[(thisSigBytes + i) >>> 2] |= thatByte << (24 - ((thisSigBytes + i) % 4) * 8);
	                }
	            } else {
	                // Copy one word at a time
	                for (var i = 0; i < thatSigBytes; i += 4) {
	                    thisWords[(thisSigBytes + i) >>> 2] = thatWords[i >>> 2];
	                }
	            }
	            this.sigBytes += thatSigBytes;

	            // Chainable
	            return this;
	        },

	        /**
	         * Removes insignificant bits.
	         *
	         * @example
	         *
	         *     wordArray.clamp();
	         */
	        clamp: function () {
	            // Shortcuts
	            var words = this.words;
	            var sigBytes = this.sigBytes;

	            // Clamp
	            words[sigBytes >>> 2] &= 0xffffffff << (32 - (sigBytes % 4) * 8);
	            words.length = Math.ceil(sigBytes / 4);
	        },

	        /**
	         * Creates a copy of this word array.
	         *
	         * @return {WordArray} The clone.
	         *
	         * @example
	         *
	         *     var clone = wordArray.clone();
	         */
	        clone: function () {
	            var clone = Base.clone.call(this);
	            clone.words = this.words.slice(0);

	            return clone;
	        },

	        /**
	         * Creates a word array filled with random bytes.
	         *
	         * @param {number} nBytes The number of random bytes to generate.
	         *
	         * @return {WordArray} The random word array.
	         *
	         * @static
	         *
	         * @example
	         *
	         *     var wordArray = CryptoJS.lib.WordArray.random(16);
	         */
	        random: function (nBytes) {
	            var words = [];

	            var r = (function (m_w) {
	                var m_w = m_w;
	                var m_z = 0x3ade68b1;
	                var mask = 0xffffffff;

	                return function () {
	                    m_z = (0x9069 * (m_z & 0xFFFF) + (m_z >> 0x10)) & mask;
	                    m_w = (0x4650 * (m_w & 0xFFFF) + (m_w >> 0x10)) & mask;
	                    var result = ((m_z << 0x10) + m_w) & mask;
	                    result /= 0x100000000;
	                    result += 0.5;
	                    return result * (Math.random() > .5 ? 1 : -1);
	                }
	            });

	            for (var i = 0, rcache; i < nBytes; i += 4) {
	                var _r = r((rcache || Math.random()) * 0x100000000);

	                rcache = _r() * 0x3ade67b7;
	                words.push((_r() * 0x100000000) | 0);
	            }

	            return new WordArray.init(words, nBytes);
	        }
	    });

	    /**
	     * Encoder namespace.
	     */
	    var C_enc = C.enc = {};

	    /**
	     * Hex encoding strategy.
	     */
	    var Hex = C_enc.Hex = {
	        /**
	         * Converts a word array to a hex string.
	         *
	         * @param {WordArray} wordArray The word array.
	         *
	         * @return {string} The hex string.
	         *
	         * @static
	         *
	         * @example
	         *
	         *     var hexString = CryptoJS.enc.Hex.stringify(wordArray);
	         */
	        stringify: function (wordArray) {
	            // Shortcuts
	            var words = wordArray.words;
	            var sigBytes = wordArray.sigBytes;

	            // Convert
	            var hexChars = [];
	            for (var i = 0; i < sigBytes; i++) {
	                var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;
	                hexChars.push((bite >>> 4).toString(16));
	                hexChars.push((bite & 0x0f).toString(16));
	            }

	            return hexChars.join('');
	        },

	        /**
	         * Converts a hex string to a word array.
	         *
	         * @param {string} hexStr The hex string.
	         *
	         * @return {WordArray} The word array.
	         *
	         * @static
	         *
	         * @example
	         *
	         *     var wordArray = CryptoJS.enc.Hex.parse(hexString);
	         */
	        parse: function (hexStr) {
	            // Shortcut
	            var hexStrLength = hexStr.length;

	            // Convert
	            var words = [];
	            for (var i = 0; i < hexStrLength; i += 2) {
	                words[i >>> 3] |= parseInt(hexStr.substr(i, 2), 16) << (24 - (i % 8) * 4);
	            }

	            return new WordArray.init(words, hexStrLength / 2);
	        }
	    };

	    /**
	     * Latin1 encoding strategy.
	     */
	    var Latin1 = C_enc.Latin1 = {
	        /**
	         * Converts a word array to a Latin1 string.
	         *
	         * @param {WordArray} wordArray The word array.
	         *
	         * @return {string} The Latin1 string.
	         *
	         * @static
	         *
	         * @example
	         *
	         *     var latin1String = CryptoJS.enc.Latin1.stringify(wordArray);
	         */
	        stringify: function (wordArray) {
	            // Shortcuts
	            var words = wordArray.words;
	            var sigBytes = wordArray.sigBytes;

	            // Convert
	            var latin1Chars = [];
	            for (var i = 0; i < sigBytes; i++) {
	                var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;
	                latin1Chars.push(String.fromCharCode(bite));
	            }

	            return latin1Chars.join('');
	        },

	        /**
	         * Converts a Latin1 string to a word array.
	         *
	         * @param {string} latin1Str The Latin1 string.
	         *
	         * @return {WordArray} The word array.
	         *
	         * @static
	         *
	         * @example
	         *
	         *     var wordArray = CryptoJS.enc.Latin1.parse(latin1String);
	         */
	        parse: function (latin1Str) {
	            // Shortcut
	            var latin1StrLength = latin1Str.length;

	            // Convert
	            var words = [];
	            for (var i = 0; i < latin1StrLength; i++) {
	                words[i >>> 2] |= (latin1Str.charCodeAt(i) & 0xff) << (24 - (i % 4) * 8);
	            }

	            return new WordArray.init(words, latin1StrLength);
	        }
	    };

	    /**
	     * UTF-8 encoding strategy.
	     */
	    var Utf8 = C_enc.Utf8 = {
	        /**
	         * Converts a word array to a UTF-8 string.
	         *
	         * @param {WordArray} wordArray The word array.
	         *
	         * @return {string} The UTF-8 string.
	         *
	         * @static
	         *
	         * @example
	         *
	         *     var utf8String = CryptoJS.enc.Utf8.stringify(wordArray);
	         */
	        stringify: function (wordArray) {
	            try {
	                return decodeURIComponent(escape(Latin1.stringify(wordArray)));
	            } catch (e) {
	                throw new Error('Malformed UTF-8 data');
	            }
	        },

	        /**
	         * Converts a UTF-8 string to a word array.
	         *
	         * @param {string} utf8Str The UTF-8 string.
	         *
	         * @return {WordArray} The word array.
	         *
	         * @static
	         *
	         * @example
	         *
	         *     var wordArray = CryptoJS.enc.Utf8.parse(utf8String);
	         */
	        parse: function (utf8Str) {
	            return Latin1.parse(unescape(encodeURIComponent(utf8Str)));
	        }
	    };

	    /**
	     * Abstract buffered block algorithm template.
	     *
	     * The property blockSize must be implemented in a concrete subtype.
	     *
	     * @property {number} _minBufferSize The number of blocks that should be kept unprocessed in the buffer. Default: 0
	     */
	    var BufferedBlockAlgorithm = C_lib.BufferedBlockAlgorithm = Base.extend({
	        /**
	         * Resets this block algorithm's data buffer to its initial state.
	         *
	         * @example
	         *
	         *     bufferedBlockAlgorithm.reset();
	         */
	        reset: function () {
	            // Initial values
	            this._data = new WordArray.init();
	            this._nDataBytes = 0;
	        },

	        /**
	         * Adds new data to this block algorithm's buffer.
	         *
	         * @param {WordArray|string} data The data to append. Strings are converted to a WordArray using UTF-8.
	         *
	         * @example
	         *
	         *     bufferedBlockAlgorithm._append('data');
	         *     bufferedBlockAlgorithm._append(wordArray);
	         */
	        _append: function (data) {
	            // Convert string to WordArray, else assume WordArray already
	            if (typeof data == 'string') {
	                data = Utf8.parse(data);
	            }

	            // Append
	            this._data.concat(data);
	            this._nDataBytes += data.sigBytes;
	        },

	        /**
	         * Processes available data blocks.
	         *
	         * This method invokes _doProcessBlock(offset), which must be implemented by a concrete subtype.
	         *
	         * @param {boolean} doFlush Whether all blocks and partial blocks should be processed.
	         *
	         * @return {WordArray} The processed data.
	         *
	         * @example
	         *
	         *     var processedData = bufferedBlockAlgorithm._process();
	         *     var processedData = bufferedBlockAlgorithm._process(!!'flush');
	         */
	        _process: function (doFlush) {
	            // Shortcuts
	            var data = this._data;
	            var dataWords = data.words;
	            var dataSigBytes = data.sigBytes;
	            var blockSize = this.blockSize;
	            var blockSizeBytes = blockSize * 4;

	            // Count blocks ready
	            var nBlocksReady = dataSigBytes / blockSizeBytes;
	            if (doFlush) {
	                // Round up to include partial blocks
	                nBlocksReady = Math.ceil(nBlocksReady);
	            } else {
	                // Round down to include only full blocks,
	                // less the number of blocks that must remain in the buffer
	                nBlocksReady = Math.max((nBlocksReady | 0) - this._minBufferSize, 0);
	            }

	            // Count words ready
	            var nWordsReady = nBlocksReady * blockSize;

	            // Count bytes ready
	            var nBytesReady = Math.min(nWordsReady * 4, dataSigBytes);

	            // Process blocks
	            if (nWordsReady) {
	                for (var offset = 0; offset < nWordsReady; offset += blockSize) {
	                    // Perform concrete-algorithm logic
	                    this._doProcessBlock(dataWords, offset);
	                }

	                // Remove processed words
	                var processedWords = dataWords.splice(0, nWordsReady);
	                data.sigBytes -= nBytesReady;
	            }

	            // Return processed words
	            return new WordArray.init(processedWords, nBytesReady);
	        },

	        /**
	         * Creates a copy of this object.
	         *
	         * @return {Object} The clone.
	         *
	         * @example
	         *
	         *     var clone = bufferedBlockAlgorithm.clone();
	         */
	        clone: function () {
	            var clone = Base.clone.call(this);
	            clone._data = this._data.clone();

	            return clone;
	        },

	        _minBufferSize: 0
	    });

	    /**
	     * Abstract hasher template.
	     *
	     * @property {number} blockSize The number of 32-bit words this hasher operates on. Default: 16 (512 bits)
	     */
	    var Hasher = C_lib.Hasher = BufferedBlockAlgorithm.extend({
	        /**
	         * Configuration options.
	         */
	        cfg: Base.extend(),

	        /**
	         * Initializes a newly created hasher.
	         *
	         * @param {Object} cfg (Optional) The configuration options to use for this hash computation.
	         *
	         * @example
	         *
	         *     var hasher = CryptoJS.algo.SHA256.create();
	         */
	        init: function (cfg) {
	            // Apply config defaults
	            this.cfg = this.cfg.extend(cfg);

	            // Set initial values
	            this.reset();
	        },

	        /**
	         * Resets this hasher to its initial state.
	         *
	         * @example
	         *
	         *     hasher.reset();
	         */
	        reset: function () {
	            // Reset data buffer
	            BufferedBlockAlgorithm.reset.call(this);

	            // Perform concrete-hasher logic
	            this._doReset();
	        },

	        /**
	         * Updates this hasher with a message.
	         *
	         * @param {WordArray|string} messageUpdate The message to append.
	         *
	         * @return {Hasher} This hasher.
	         *
	         * @example
	         *
	         *     hasher.update('message');
	         *     hasher.update(wordArray);
	         */
	        update: function (messageUpdate) {
	            // Append
	            this._append(messageUpdate);

	            // Update the hash
	            this._process();

	            // Chainable
	            return this;
	        },

	        /**
	         * Finalizes the hash computation.
	         * Note that the finalize operation is effectively a destructive, read-once operation.
	         *
	         * @param {WordArray|string} messageUpdate (Optional) A final message update.
	         *
	         * @return {WordArray} The hash.
	         *
	         * @example
	         *
	         *     var hash = hasher.finalize();
	         *     var hash = hasher.finalize('message');
	         *     var hash = hasher.finalize(wordArray);
	         */
	        finalize: function (messageUpdate) {
	            // Final message update
	            if (messageUpdate) {
	                this._append(messageUpdate);
	            }

	            // Perform concrete-hasher logic
	            var hash = this._doFinalize();

	            return hash;
	        },

	        blockSize: 512/32,

	        /**
	         * Creates a shortcut function to a hasher's object interface.
	         *
	         * @param {Hasher} hasher The hasher to create a helper for.
	         *
	         * @return {Function} The shortcut function.
	         *
	         * @static
	         *
	         * @example
	         *
	         *     var SHA256 = CryptoJS.lib.Hasher._createHelper(CryptoJS.algo.SHA256);
	         */
	        _createHelper: function (hasher) {
	            return function (message, cfg) {
	                return new hasher.init(cfg).finalize(message);
	            };
	        },

	        /**
	         * Creates a shortcut function to the HMAC's object interface.
	         *
	         * @param {Hasher} hasher The hasher to use in this HMAC helper.
	         *
	         * @return {Function} The shortcut function.
	         *
	         * @static
	         *
	         * @example
	         *
	         *     var HmacSHA256 = CryptoJS.lib.Hasher._createHmacHelper(CryptoJS.algo.SHA256);
	         */
	        _createHmacHelper: function (hasher) {
	            return function (message, key) {
	                return new C_algo.HMAC.init(hasher, key).finalize(message);
	            };
	        }
	    });

	    /**
	     * Algorithm namespace.
	     */
	    var C_algo = C.algo = {};

	    return C;
	}(Math));


	return CryptoJS;

}));

/***/ }),
/* 20 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";

Object.defineProperty(exports, "__esModule", { value: true });
var Enums_1 = __webpack_require__(5);
var Levels;
(function (Levels) {
    Levels[Levels["error"] = 0] = "error";
    Levels[Levels["warn"] = 1] = "warn";
    Levels[Levels["log"] = 2] = "log";
    Levels[Levels["debug"] = 3] = "debug";
})(Levels = exports.Levels || (exports.Levels = {}));
var LoggerFactory = /** @class */ (function () {
    function LoggerFactory() {
        this.builtinEnabled = true;
        // tslint:disable-next-line:variable-name
        this._level = Levels.log;
        this.loggers = {};
        this.type = Enums_1.TypeStrings.LoggerFactory;
        this.logger = this.getLogger("sip:loggerfactory");
    }
    Object.defineProperty(LoggerFactory.prototype, "level", {
        get: function () { return this._level; },
        set: function (newLevel) {
            if (newLevel >= 0 && newLevel <= 3) {
                this._level = newLevel;
            }
            else if (newLevel > 3) {
                this._level = 3;
            }
            else if (Levels.hasOwnProperty(newLevel)) {
                this._level = newLevel;
            }
            else {
                this.logger.error("invalid 'level' parameter value: " + JSON.stringify(newLevel));
            }
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(LoggerFactory.prototype, "connector", {
        get: function () {
            return this._connector;
        },
        set: function (value) {
            if (!value) {
                this._connector = undefined;
            }
            else if (typeof value === "function") {
                this._connector = value;
            }
            else {
                this.logger.error("invalid 'connector' parameter value: " + JSON.stringify(value));
            }
        },
        enumerable: true,
        configurable: true
    });
    LoggerFactory.prototype.getLogger = function (category, label) {
        if (label && this.level === 3) {
            return new Logger(this, category, label);
        }
        else if (this.loggers[category]) {
            return this.loggers[category];
        }
        else {
            var logger = new Logger(this, category);
            this.loggers[category] = logger;
            return logger;
        }
    };
    LoggerFactory.prototype.genericLog = function (levelToLog, category, label, content) {
        if (this.level >= levelToLog) {
            if (this.builtinEnabled) {
                this.print(console[Levels[levelToLog]], category, label, content);
            }
        }
        if (this.connector) {
            this.connector(Levels[levelToLog], category, label, content);
        }
    };
    LoggerFactory.prototype.print = function (target, category, label, content) {
        if (typeof content === "string") {
            var prefix = [new Date(), category];
            if (label) {
                prefix.push(label);
            }
            content = prefix.concat(content).join(" | ");
        }
        target.call(console, content);
    };
    return LoggerFactory;
}());
exports.LoggerFactory = LoggerFactory;
// tslint:disable-next-line:max-classes-per-file
var Logger = /** @class */ (function () {
    function Logger(logger, category, label) {
        this.type = Enums_1.TypeStrings.Logger;
        this.logger = logger;
        this.category = category;
        this.label = label;
    }
    Logger.prototype.error = function (content) { this.genericLog(Levels.error, content); };
    Logger.prototype.warn = function (content) { this.genericLog(Levels.warn, content); };
    Logger.prototype.log = function (content) { this.genericLog(Levels.log, content); };
    Logger.prototype.debug = function (content) { this.genericLog(Levels.debug, content); };
    Logger.prototype.genericLog = function (level, content) {
        this.logger.genericLog(level, this.category, this.label, content);
    };
    return Logger;
}());
exports.Logger = Logger;


/***/ }),
/* 21 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";

Object.defineProperty(exports, "__esModule", { value: true });
var Enums_1 = __webpack_require__(5);
var Grammar_1 = __webpack_require__(11);
var SIPMessage_1 = __webpack_require__(10);
// SIP.Parser = Parser;
/**
 * Extract and parse every header of a SIP message.
 * @namespace
 */
var Parser;
(function (Parser) {
    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;
    }
    Parser.getHeader = getHeader;
    function parseHeader(message, data, headerStart, headerEnd) {
        var hcolonIndex = data.indexOf(":", headerStart);
        var headerName = data.substring(headerStart, hcolonIndex).trim();
        var headerValue = data.substring(hcolonIndex + 1, headerEnd).trim();
        var parsed;
        // 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.viaBranch = parsed.branch;
                    }
                }
                else {
                    parsed = 0;
                }
                break;
            case "from":
            case "f":
                message.setHeader("from", headerValue);
                parsed = message.parseHeader("from");
                if (parsed) {
                    message.from = parsed;
                    message.fromTag = parsed.getParam("tag");
                }
                break;
            case "to":
            case "t":
                message.setHeader("to", headerValue);
                parsed = message.parseHeader("to");
                if (parsed) {
                    message.to = parsed;
                    message.toTag = parsed.getParam("tag");
                }
                break;
            case "record-route":
                parsed = Grammar_1.Grammar.parse(headerValue, "Record_Route");
                if (parsed === -1) {
                    parsed = undefined;
                    break;
                }
                for (var header in parsed) {
                    if (parsed[header]) {
                        message.addHeader("record-route", headerValue.substring(parsed[header].position, parsed[header].offset));
                        message.headers["Record-Route"][message.getHeaders("record-route").length - 1].parsed =
                            parsed[header].parsed;
                    }
                }
                break;
            case "call-id":
            case "i":
                message.setHeader("call-id", headerValue);
                parsed = message.parseHeader("call-id");
                if (parsed) {
                    message.callId = headerValue;
                }
                break;
            case "contact":
            case "m":
                parsed = Grammar_1.Grammar.parse(headerValue, "Contact");
                if (parsed === -1) {
                    parsed = undefined;
                    break;
                }
                if (!(parsed instanceof Array)) {
                    parsed = undefined;
                    break;
                }
                parsed.forEach(function (header) {
                    message.addHeader("contact", headerValue.substring(header.position, header.offset));
                    message.headers.Contact[message.getHeaders("contact").length - 1].parsed = header.parsed;
                });
                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.type === Enums_1.TypeStrings.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 "refer-to":
            case "r":
                message.setHeader("refer-to", headerValue);
                parsed = message.parseHeader("refer-to");
                if (parsed) {
                    message.referTo = parsed;
                }
                break;
            default:
                // Do not parse this header.
                message.setHeader(headerName, headerValue);
                parsed = 0;
        }
        if (parsed === undefined) {
            return {
                error: "error parsing header '" + headerName + "'"
            };
        }
        else {
            return true;
        }
    }
    Parser.parseHeader = parseHeader;
    /** Parse SIP Message
     * @function
     * @param {String} message SIP message.
     * @param {Object} logger object.
     * @returns {SIP.IncomingRequest|SIP.IncomingResponse|undefined}
     */
    function parseMessage(data, ua) {
        var headerStart = 0;
        var headerEnd = data.indexOf("\r\n");
        var logger = ua.getLogger("sip.parser");
        if (headerEnd === -1) {
            logger.warn("no CRLF found, not a SIP message, discarded");
            return;
        }
        // Parse first line. Check if it is a Request or a Reply.
        var firstLine = data.substring(0, headerEnd);
        var parsed = Grammar_1.Grammar.parse(firstLine, "Request_Response");
        var message;
        if (parsed === -1) {
            logger.warn('error parsing first line of SIP message: "' + firstLine + '"');
            return;
        }
        else if (!parsed.status_code) {
            message = new SIPMessage_1.IncomingRequest(ua);
            message.method = parsed.method;
            message.ruri = parsed.uri;
        }
        else {
            message = new SIPMessage_1.IncomingResponse(ua);
            message.statusCode = parsed.status_code;
            message.reasonPhrase = parsed.reason_phrase;
        }
        message.data = data;
        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.
        */
        var bodyStart;
        while (true) {
            headerEnd = getHeader(data, headerStart);
            // The SIP message has normally finished.
            if (headerEnd === -2) {
                bodyStart = headerStart + 2;
                break;
            }
            else if (headerEnd === -1) {
                // data.indexOf returned -1 due to a malformed message.
                logger.error("malformed message");
                return;
            }
            var parsedHeader = parseHeader(message, data, headerStart, headerEnd);
            if (parsedHeader !== true) {
                logger.error(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")) {
            message.body = data.substr(bodyStart, Number(message.getHeader("content-length")));
        }
        else {
            message.body = data.substring(bodyStart);
        }
        return message;
    }
    Parser.parseMessage = parseMessage;
})(Parser = exports.Parser || (exports.Parser = {}));


/***/ }),
/* 22 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";

var __extends = (this && this.__extends) || (function () {
    var extendStatics = function (d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
var ClientContext_1 = __webpack_require__(1);
var Constants_1 = __webpack_require__(3);
var Enums_1 = __webpack_require__(5);
var Exceptions_1 = __webpack_require__(8);
var SIPMessage_1 = __webpack_require__(10);
var Utils_1 = __webpack_require__(15);
/**
 * SIP Publish (SIP Extension for Event State Publication RFC3903)
 * @class Class creating a SIP PublishContext.
 */
var PublishContext = /** @class */ (function (_super) {
    __extends(PublishContext, _super);
    function PublishContext(ua, target, event, options) {
        if (options === void 0) { options = {}; }
        var _this = this;
        options.extraHeaders = (options.extraHeaders || []).slice();
        options.contentType = (options.contentType || "text/plain");
        if (typeof options.expires !== "number" || (options.expires % 1) !== 0) {
            options.expires = 3600;
        }
        else {
            options.expires = Number(options.expires);
        }
        if (typeof (options.unpublishOnClose) !== "boolean") {
            options.unpublishOnClose = true;
        }
        if (target === undefined || target === null || target === "") {
            throw new Exceptions_1.Exceptions.MethodParameterError("Publish", "Target", target);
        }
        else {
            target = ua.normalizeTarget(target);
            if (target === undefined) {
                throw new Exceptions_1.Exceptions.MethodParameterError("Publish", "Target", target);
            }
        }
        _this = _super.call(this, ua, Constants_1.C.PUBLISH, target, options) || this;
        _this.type = Enums_1.TypeStrings.PublishContext;
        _this.options = options;
        _this.target = target;
        if (event === undefined || event === null || event === "") {
            throw new Exceptions_1.Exceptions.MethodParameterError("Publish", "Event", event);
        }
        else {
            _this.event = event;
        }
        _this.logger = ua.getLogger("sip.publish");
        _this.pubRequestExpires = _this.options.expires;
        ua.on("transportCreated", function (transport) {
            transport.on("transportError", function () { return _this.onTransportError(); });
        });
        return _this;
    }
    /**
     * Publish
     * @param {string} Event body to publish, optional
     */
    PublishContext.prototype.publish = function (body) {
        // Clean up before the run
        if (this.publishRefreshTimer) {
            clearTimeout(this.publishRefreshTimer);
            this.publishRefreshTimer = undefined;
        }
        // is Inital or Modify request
        this.options.body = body;
        this.pubRequestBody = this.options.body;
        if (this.pubRequestExpires === 0) {
            // This is Initial request after unpublish
            this.pubRequestExpires = this.options.expires;
            this.pubRequestEtag = undefined;
        }
        if (!(this.ua.publishers[this.target.toString() + ":" + this.event])) {
            this.ua.publishers[this.target.toString() + ":" + this.event] = this;
        }
        this.sendPublishRequest();
    };
    /**
     * Unpublish
     */
    PublishContext.prototype.unpublish = function () {
        // Clean up before the run
        if (this.publishRefreshTimer) {
            clearTimeout(this.publishRefreshTimer);
            this.publishRefreshTimer = undefined;
        }
        this.pubRequestBody = undefined;
        this.pubRequestExpires = 0;
        if (this.pubRequestEtag !== undefined) {
            this.sendPublishRequest();
        }
    };
    /**
     * Close
     */
    PublishContext.prototype.close = function () {
        // Send unpublish, if requested
        if (this.options.unpublishOnClose) {
            this.unpublish();
        }
        else {
            if (this.publishRefreshTimer) {
                clearTimeout(this.publishRefreshTimer);
                this.publishRefreshTimer = undefined;
            }
            this.pubRequestBody = undefined;
            this.pubRequestExpires = 0;
            this.pubRequestEtag = undefined;
        }
        if (this.ua.publishers[this.target.toString() + ":" + this.event]) {
            delete this.ua.publishers[this.target.toString() + ":" + this.event];
        }
    };
    PublishContext.prototype.onRequestTimeout = function () {
        _super.prototype.onRequestTimeout.call(this);
        this.emit("unpublished", undefined, Constants_1.C.causes.REQUEST_TIMEOUT);
    };
    PublishContext.prototype.onTransportError = function () {
        _super.prototype.onTransportError.call(this);
        this.emit("unpublished", undefined, Constants_1.C.causes.CONNECTION_ERROR);
    };
    PublishContext.prototype.receiveResponse = function (response) {
        var _this = this;
        var statusCode = response.statusCode || 0;
        var cause = Utils_1.Utils.getReasonPhrase(statusCode);
        switch (true) {
            case /^1[0-9]{2}$/.test(statusCode.toString()):
                this.emit("progress", response, cause);
                break;
            case /^2[0-9]{2}$/.test(statusCode.toString()):
                // Set SIP-Etag
                if (response.hasHeader("SIP-ETag")) {
                    this.pubRequestEtag = response.getHeader("SIP-ETag");
                }
                else {
                    this.logger.warn("SIP-ETag header missing in a 200-class response to PUBLISH");
                }
                // Update Expire
                if (response.hasHeader("Expires")) {
                    var expires = Number(response.getHeader("Expires"));
                    if (typeof expires === "number" && expires >= 0 && expires <= this.pubRequestExpires) {
                        this.pubRequestExpires = expires;
                    }
                    else {
                        this.logger.warn("Bad Expires header in a 200-class response to PUBLISH");
                    }
                }
                else {
                    this.logger.warn("Expires header missing in a 200-class response to PUBLISH");
                }
                if (this.pubRequestExpires !== 0) {
                    // Schedule refresh
                    this.publishRefreshTimer = setTimeout(function () { return _this.refreshRequest(); }, this.pubRequestExpires * 900);
                    this.emit("published", response, cause);
                }
                else {
                    this.emit("unpublished", response, cause);
                }
                break;
            case /^412$/.test(statusCode.toString()):
                // 412 code means no matching ETag - possibly the PUBLISH expired
                // Resubmit as new request, if the current request is not a "remove"
                if (this.pubRequestEtag !== undefined && this.pubRequestExpires !== 0) {
                    this.logger.warn("412 response to PUBLISH, recovering");
                    this.pubRequestEtag = undefined;
                    this.emit("progress", response, cause);
                    this.publish(this.options.body);
                }
                else {
                    this.logger.warn("412 response to PUBLISH, recovery failed");
                    this.pubRequestExpires = 0;
                    this.emit("failed", response, cause);
                    this.emit("unpublished", response, cause);
                }
                break;
            case /^423$/.test(statusCode.toString()):
                // 423 code means we need to adjust the Expires interval up
                if (this.pubRequestExpires !== 0 && response.hasHeader("Min-Expires")) {
                    var minExpires = Number(response.getHeader("Min-Expires"));
                    if (typeof minExpires === "number" || minExpires > this.pubRequestExpires) {
                        this.logger.warn("423 code in response to PUBLISH, adjusting the Expires value and trying to recover");
                        this.pubRequestExpires = minExpires;
                        this.emit("progress", response, cause);
                        this.publish(this.options.body);
                    }
                    else {
                        this.logger.warn("Bad 423 response Min-Expires header received for PUBLISH");
                        this.pubRequestExpires = 0;
                        this.emit("failed", response, cause);
                        this.emit("unpublished", response, cause);
                    }
                }
                else {
                    this.logger.warn("423 response to PUBLISH, recovery failed");
                    this.pubRequestExpires = 0;
                    this.emit("failed", response, cause);
                    this.emit("unpublished", response, cause);
                }
                break;
            default:
                this.pubRequestExpires = 0;
                this.emit("failed", response, cause);
                this.emit("unpublished", response, cause);
                break;
        }
        // Do the cleanup
        if (this.pubRequestExpires === 0) {
            if (this.publishRefreshTimer) {
                clearTimeout(this.publishRefreshTimer);
                this.publishRefreshTimer = undefined;
            }
            this.pubRequestBody = undefined;
            this.pubRequestEtag = undefined;
        }
    };
    PublishContext.prototype.refreshRequest = function () {
        // Clean up before the run
        if (this.publishRefreshTimer) {
            clearTimeout(this.publishRefreshTimer);
            this.publishRefreshTimer = undefined;
        }
        // This is Refresh request
        this.pubRequestBody = undefined;
        if (this.pubRequestEtag === undefined) {
            // Request not valid
            throw new Exceptions_1.Exceptions.MethodParameterError("Publish", "Body", undefined);
        }
        if (this.pubRequestExpires === 0) {
            // Request not valid
            throw new Exceptions_1.Exceptions.MethodParameterError("Publish", "Expire", this.pubRequestExpires);
        }
        this.sendPublishRequest();
    };
    PublishContext.prototype.sendPublishRequest = function () {
        var reqOptions = Object.create(this.options || Object.prototype);
        reqOptions.extraHeaders = (this.options.extraHeaders || []).slice();
        reqOptions.extraHeaders.push("Event: " + this.event);
        reqOptions.extraHeaders.push("Expires: " + this.pubRequestExpires);
        if (this.pubRequestEtag !== undefined) {
            reqOptions.extraHeaders.push("SIP-If-Match: " + this.pubRequestEtag);
        }
        this.request = new SIPMessage_1.OutgoingRequest(Constants_1.C.PUBLISH, this.target, this.ua, this.options.params, reqOptions.extraHeaders);
        if (this.pubRequestBody !== undefined) {
            this.request.body = {
                body: this.pubRequestBody,
                contentType: this.options.contentType
            };
        }
        this.send();
    };
    return PublishContext;
}(ClientContext_1.ClientContext));
exports.PublishContext = PublishContext;


/***/ }),
/* 23 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";

var __extends = (this && this.__extends) || (function () {
    var extendStatics = function (d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
var __assign = (this && this.__assign) || function () {
    __assign = Object.assign || function(t) {
        for (var s, i = 1, n = arguments.length; i < n; i++) {
            s = arguments[i];
            for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
                t[p] = s[p];
        }
        return t;
    };
    return __assign.apply(this, arguments);
};
Object.defineProperty(exports, "__esModule", { value: true });
var ClientContext_1 = __webpack_require__(1);
var Constants_1 = __webpack_require__(3);
var Enums_1 = __webpack_require__(5);
var Exceptions_1 = __webpack_require__(8);
var Grammar_1 = __webpack_require__(11);
var Utils_1 = __webpack_require__(15);
/**
 * Configuration load.
 * @private
 * returns {any}
 */
function loadConfig(configuration) {
    var settings = {
        expires: 600,
        extraContactHeaderParams: [],
        instanceId: undefined,
        params: {},
        regId: undefined,
        registrar: undefined,
    };
    var configCheck = getConfigurationCheck();
    // Check Mandatory parameters
    for (var parameter in configCheck.mandatory) {
        if (!configuration.hasOwnProperty(parameter)) {
            throw new Exceptions_1.Exceptions.ConfigurationError(parameter);
        }
        else {
            var value = configuration[parameter];
            var checkedValue = configCheck.mandatory[parameter](value);
            if (checkedValue !== undefined) {
                settings[parameter] = checkedValue;
            }
            else {
                throw new Exceptions_1.Exceptions.ConfigurationError(parameter, value);
            }
        }
    }
    // Check Optional parameters
    for (var parameter in configCheck.optional) {
        if (configuration.hasOwnProperty(parameter)) {
            var value = configuration[parameter];
            // If the parameter value is an empty array, but shouldn't be, apply its default value.
            if (value instanceof Array && value.length === 0) {
                continue;
            }
            // If the parameter value is null, empty string, or undefined then apply its default value.
            // If it's a number with NaN value then also apply its default value.
            // NOTE: JS does not allow "value === NaN", the following does the work:
            if (value === null || value === "" || value === undefined ||
                (typeof (value) === "number" && isNaN(value))) {
                continue;
            }
            var checkedValue = configCheck.optional[parameter](value);
            if (checkedValue !== undefined) {
                settings[parameter] = checkedValue;
            }
            else {
                throw new Exceptions_1.Exceptions.ConfigurationError(parameter, value);
            }
        }
    }
    return settings;
}
function getConfigurationCheck() {
    return {
        mandatory: {},
        optional: {
            expires: function (expires) {
                if (Utils_1.Utils.isDecimal(expires)) {
                    var value = Number(expires);
                    if (value >= 0) {
                        return value;
                    }
                }
            },
            extraContactHeaderParams: function (extraContactHeaderParams) {
                if (extraContactHeaderParams instanceof Array) {
                    return extraContactHeaderParams.filter(function (contactHeaderParam) { return (typeof contactHeaderParam === "string"); });
                }
            },
            instanceId: function (instanceId) {
                if (typeof instanceId !== "string") {
                    return;
                }
                if ((/^uuid:/i.test(instanceId))) {
                    instanceId = instanceId.substr(5);
                }
                if (Grammar_1.Grammar.parse(instanceId, "uuid") === -1) {
                    return;
                }
                else {
                    return instanceId;
                }
            },
            params: function (params) {
                if (typeof params === "object") {
                    return params;
                }
            },
            regId: function (regId) {
                if (Utils_1.Utils.isDecimal(regId)) {
                    var value = Number(regId);
                    if (value >= 0) {
                        return value;
                    }
                }
            },
            registrar: function (registrar) {
                if (typeof registrar !== "string") {
                    return;
                }
                if (!/^sip:/i.test(registrar)) {
                    registrar = Constants_1.C.SIP + ":" + registrar;
                }
                var parsed = Grammar_1.Grammar.URIParse(registrar);
                if (!parsed) {
                    return;
                }
                else if (parsed.user) {
                    return;
                }
                else {
                    return parsed;
                }
            }
        }
    };
}
var RegisterContext = /** @class */ (function (_super) {
    __extends(RegisterContext, _super);
    function RegisterContext(ua, options) {
        if (options === void 0) { options = {}; }
        var _this = this;
        var settings = loadConfig(options);
        if (settings.regId && !settings.instanceId) {
            settings.instanceId = Utils_1.Utils.newUUID();
        }
        else if (!settings.regId && settings.instanceId) {
            settings.regId = 1;
        }
        settings.params.toUri = settings.params.toUri || ua.configuration.uri;
        settings.params.toDisplayName = settings.params.toDisplayName || ua.configuration.displayName;
        settings.params.callId = settings.params.callId || Utils_1.Utils.createRandomToken(22);
        settings.params.cseq = settings.params.cseq || Math.floor(Math.random() * 10000);
        /* If no 'registrarServer' is set use the 'uri' value without user portion. */
        if (!settings.registrar) {
            var registrarServer = {};
            if (typeof ua.configuration.uri === "object") {
                registrarServer = ua.configuration.uri.clone();
                registrarServer.user = undefined;
            }
            else {
                registrarServer = ua.configuration.uri;
            }
            settings.registrar = registrarServer;
        }
        _this = _super.call(this, ua, Constants_1.C.REGISTER, settings.registrar, settings) || this;
        _this.type = Enums_1.TypeStrings.RegisterContext;
        _this.options = settings;
        _this.logger = ua.getLogger("sip.registercontext");
        _this.logger.log("configuration parameters for RegisterContext after validation:");
        for (var parameter in settings) {
            if (settings.hasOwnProperty(parameter)) {
                _this.logger.log("· " + parameter + ": " + JSON.stringify(settings[parameter]));
            }
        }
        // Registration expires
        _this.expires = settings.expires;
        // Cseq
        _this.cseq = settings.params.cseq;
        // Contact header
        _this.contact = ua.contact.toString();
        // Set status
        _this.registered = false;
        ua.on("transportCreated", function (transport) {
            transport.on("disconnected", function () { return _this.onTransportDisconnected(); });
        });
        return _this;
    }
    RegisterContext.prototype.register = function (options) {
        var _this = this;
        if (options === void 0) { options = {}; }
        // Handle Options
        this.options = __assign({}, this.options, options);
        var extraHeaders = (this.options.extraHeaders || []).slice();
        extraHeaders.push("Contact: " + this.generateContactHeader(this.expires));
        // this is UA.C.ALLOWED_METHODS, removed to get around circular dependency
        extraHeaders.push("Allow: " + [
            "ACK",
            "CANCEL",
            "INVITE",
            "MESSAGE",
            "BYE",
            "OPTIONS",
            "INFO",
            "NOTIFY",
            "REFER"
        ].toString());
        // Save original extraHeaders to be used in .close
        this.closeHeaders = this.options.closeWithHeaders ?
            (this.options.extraHeaders || []).slice() : [];
        this.receiveResponse = function (response) {
            // Discard responses to older REGISTER/un-REGISTER requests.
            if (response.cseq !== _this.cseq) {
                return;
            }
            // Clear registration timer
            if (_this.registrationTimer !== undefined) {
                clearTimeout(_this.registrationTimer);
                _this.registrationTimer = undefined;
            }
            var statusCode = (response.statusCode || 0).toString();
            switch (true) {
                case /^1[0-9]{2}$/.test(statusCode):
                    _this.emit("progress", response);
                    break;
                case /^2[0-9]{2}$/.test(statusCode):
                    _this.emit("accepted", response);
                    var expires = void 0;
                    if (response.hasHeader("expires")) {
                        expires = Number(response.getHeader("expires"));
                    }
                    if (_this.registrationExpiredTimer !== undefined) {
                        clearTimeout(_this.registrationExpiredTimer);
                        _this.registrationExpiredTimer = undefined;
                    }
                    // Search the Contact pointing to us and update the expires value accordingly.
                    var contacts = response.getHeaders("contact").length;
                    if (!contacts) {
                        _this.logger.warn("no Contact header in response to REGISTER, response ignored");
                        break;
                    }
                    var contact = void 0;
                    while (contacts--) {
                        contact = response.parseHeader("contact", contacts);
                        if (contact.uri.user === _this.ua.contact.uri.user) {
                            expires = contact.getParam("expires");
                            break;
                        }
                        else {
                            contact = undefined;
                        }
                    }
                    if (!contact) {
                        _this.logger.warn("no Contact header pointing to us, response ignored");
                        break;
                    }
                    if (expires === undefined) {
                        expires = _this.expires;
                    }
                    // Re-Register before the expiration interval has elapsed.
                    // For that, decrease the expires value. ie: 3 seconds
                    _this.registrationTimer = setTimeout(function () {
                        _this.registrationTimer = undefined;
                        _this.register(_this.options);
                    }, (expires * 1000) - 5000);
                    _this.registrationExpiredTimer = setTimeout(function () {
                        _this.logger.warn("registration expired");
                        if (_this.registered) {
                            _this.unregistered(undefined, Constants_1.C.causes.EXPIRES);
                        }
                    }, expires * 1000);
                    // Save gruu values
                    if (contact.hasParam("temp-gruu")) {
                        _this.ua.contact.tempGruu = Grammar_1.Grammar.URIParse(contact.getParam("temp-gruu").replace(/"/g, ""));
                    }
                    if (contact.hasParam("pub-gruu")) {
                        _this.ua.contact.pubGruu = Grammar_1.Grammar.URIParse(contact.getParam("pub-gruu").replace(/"/g, ""));
                    }
                    _this.registered = true;
                    _this.emit("registered", response || undefined);
                    break;
                // Interval too brief RFC3261 10.2.8
                case /^423$/.test(statusCode):
                    if (response.hasHeader("min-expires")) {
                        // Increase our registration interval to the suggested minimum
                        _this.expires = Number(response.getHeader("min-expires"));
                        // Attempt the registration again immediately
                        _this.register(_this.options);
                    }
                    else { // This response MUST contain a Min-Expires header field
                        _this.logger.warn("423 response received for REGISTER without Min-Expires");
                        _this.registrationFailure(response, Constants_1.C.causes.SIP_FAILURE_CODE);
                    }
                    break;
                default:
                    _this.registrationFailure(response, Utils_1.Utils.sipErrorCause(response.statusCode || 0));
            }
        };
        this.onRequestTimeout = function () {
            _this.registrationFailure(undefined, Constants_1.C.causes.REQUEST_TIMEOUT);
        };
        this.onTransportError = function () {
            _this.registrationFailure(undefined, Constants_1.C.causes.CONNECTION_ERROR);
        };
        this.cseq++;
        if (this.request) {
            this.request.cseq = this.cseq;
            this.request.setHeader("cseq", this.cseq + " REGISTER");
            this.request.extraHeaders = extraHeaders;
        }
        this.send();
    };
    RegisterContext.prototype.close = function () {
        var options = {
            all: false,
            extraHeaders: this.closeHeaders
        };
        this.registeredBefore = this.registered;
        if (this.registered) {
            this.unregister(options);
        }
    };
    RegisterContext.prototype.unregister = function (options) {
        var _this = this;
        if (options === void 0) { options = {}; }
        if (!this.registered && !options.all) {
            this.logger.warn("Already unregistered, but sending an unregister anyways.");
        }
        var extraHeaders = (options.extraHeaders || []).slice();
        this.registered = false;
        // Clear the registration timer.
        if (this.registrationTimer !== undefined) {
            clearTimeout(this.registrationTimer);
            this.registrationTimer = undefined;
        }
        if (options.all) {
            extraHeaders.push("Contact: *");
            extraHeaders.push("Expires: 0");
        }
        else {
            extraHeaders.push("Contact: " + this.generateContactHeader(0));
        }
        this.receiveResponse = function (response) {
            var statusCode = (response && response.statusCode) ? response.statusCode.toString() : "";
            switch (true) {
                case /^1[0-9]{2}$/.test(statusCode):
                    _this.emit("progress", response);
                    break;
                case /^2[0-9]{2}$/.test(statusCode):
                    _this.emit("accepted", response);
                    if (_this.registrationExpiredTimer !== undefined) {
                        clearTimeout(_this.registrationExpiredTimer);
                        _this.registrationExpiredTimer = undefined;
                    }
                    _this.unregistered(response);
                    break;
                default:
                    _this.unregistered(response, Utils_1.Utils.sipErrorCause(response.statusCode || 0));
            }
        };
        this.onRequestTimeout = function () {
            // Not actually unregistered...
            // this.unregistered(undefined, SIP.C.causes.REQUEST_TIMEOUT);
        };
        this.cseq++;
        if (this.request) {
            this.request.cseq = this.cseq;
            this.request.setHeader("cseq", this.cseq + " REGISTER");
            this.request.extraHeaders = extraHeaders;
        }
        this.send();
    };
    RegisterContext.prototype.unregistered = function (response, cause) {
        this.registered = false;
        this.emit("unregistered", response || undefined, cause || undefined);
    };
    RegisterContext.prototype.registrationFailure = function (response, cause) {
        this.emit("failed", response || undefined, cause || undefined);
    };
    RegisterContext.prototype.onTransportDisconnected = function () {
        this.registeredBefore = this.registered;
        if (this.registrationTimer !== undefined) {
            clearTimeout(this.registrationTimer);
            this.registrationTimer = undefined;
        }
        if (this.registrationExpiredTimer !== undefined) {
            clearTimeout(this.registrationExpiredTimer);
            this.registrationExpiredTimer = undefined;
        }
        if (this.registered) {
            this.unregistered(undefined, Constants_1.C.causes.CONNECTION_ERROR);
        }
    };
    /**
     * Helper Function to generate Contact Header
     * @private
     * returns {String}
     */
    RegisterContext.prototype.generateContactHeader = function (expires) {
        if (expires === void 0) { expires = 0; }
        var contact = this.contact;
        if (this.options.regId && this.options.instanceId) {
            contact += ";reg-id=" + this.options.regId;
            contact += ';+sip.instance="<urn:uuid:' + this.options.instanceId + '>"';
        }
        if (this.options.extraContactHeaderParams) {
            this.options.extraContactHeaderParams.forEach(function (header) {
                contact += ";" + header;
            });
        }
        contact += ";expires=" + expires;
        return contact;
    };
    return RegisterContext;
}(ClientContext_1.ClientContext));
exports.RegisterContext = RegisterContext;


/***/ }),
/* 24 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";

Object.defineProperty(exports, "__esModule", { value: true });
var Constants_1 = __webpack_require__(3);
var Enums_1 = __webpack_require__(5);
var Utils_1 = __webpack_require__(15);
/**
 * Incoming SIP message sanity check.
 * @function
 * @param {SIP.IncomingMessage} message
 * @param {SIP.UA} ua
 * @param {SIP.Transport} transport
 * @returns {Boolean}
 */
var SanityCheck;
(function (SanityCheck) {
    // Reply
    function reply(statusCode, message, transport) {
        var response = Utils_1.Utils.buildStatusLine(statusCode);
        var vias = message.getHeaders("via");
        for (var _i = 0, vias_1 = vias; _i < vias_1.length; _i++) {
            var via = vias_1[_i];
            response += "Via: " + via + "\r\n";
        }
        var to = message.getHeader("To") || "";
        if (!message.toTag) {
            to += ";tag=" + Utils_1.Utils.newTag();
        }
        response += "To: " + to + "\r\n";
        response += "From: " + message.getHeader("From") + "\r\n";
        response += "Call-ID: " + message.callId + "\r\n";
        response += "CSeq: " + message.cseq + " " + message.method + "\r\n";
        response += "\r\n";
        transport.send(response);
    }
    SanityCheck.reply = reply;
    /*
    * 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 sipjsId, 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_1_2_ sent-by mismatch
    *  - _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(message, ua, transport) {
        if (!message.ruri || message.ruri.scheme !== "sip") {
            reply(416, message, transport);
            return false;
        }
        return true;
    }
    SanityCheck.rfc3261_8_2_2_1 = rfc3261_8_2_2_1;
    function rfc3261_16_3_4(message, ua, transport) {
        if (!message.toTag) {
            if (message.callId.substr(0, 5) === ua.configuration.sipjsId) {
                reply(482, message, transport);
                return false;
            }
        }
        return true;
    }
    SanityCheck.rfc3261_16_3_4 = rfc3261_16_3_4;
    function rfc3261_18_3_request(message, ua, transport) {
        var len = Utils_1.Utils.str_utf8_length(message.body);
        var contentLength = message.getHeader("content-length");
        if (contentLength && len < Number(contentLength)) {
            reply(400, message, transport);
            return false;
        }
        return true;
    }
    SanityCheck.rfc3261_18_3_request = rfc3261_18_3_request;
    /**
     * 8.2.2.2 Merged Requests
     *
     * If the request has no tag in the To header field, the UAS core MUST
     * check the request against ongoing transactions.  If the From tag,
     * Call-ID, and CSeq exactly match those associated with an ongoing
     * transaction, but the request does not match that transaction (based
     * on the matching rules in Section 17.2.3), the UAS core SHOULD
     * generate a 482 (Loop Detected) response and pass it to the server
     * transaction.
     *
     *    The same request has arrived at the UAS more than once, following
     *    different paths, most likely due to forking.  The UAS processes
     *    the first such request received and responds with a 482 (Loop
     *    Detected) to the rest of them.
     *
     * @param message Incoming request message.
     * @param ua User agent.
     * @param transport Transport.
     */
    function rfc3261_8_2_2_2(message, ua, transport) {
        var fromTag = message.fromTag;
        var callId = message.callId;
        var cseq = message.cseq;
        if (!message.toTag) {
            if (message.method === Constants_1.C.INVITE) {
                if (ua.transactions.ist[message.viaBranch]) {
                    return true;
                }
                else {
                    for (var idx in ua.transactions.ist) {
                        if (ua.transactions.ist.hasOwnProperty(idx)) {
                            var tr = ua.transactions.ist[idx];
                            if (tr && tr.request.fromTag === fromTag && tr.request.callId === callId && tr.request.cseq === cseq) {
                                reply(482, message, transport);
                                return false;
                            }
                        }
                    }
                }
            }
            else {
                if (ua.transactions.nist[message.viaBranch]) {
                    return true;
                }
                else {
                    for (var idx in ua.transactions.nist) {
                        if (ua.transactions.nist.hasOwnProperty(idx)) {
                            var tr = ua.transactions.nist[idx];
                            if (tr && tr.request.fromTag === fromTag && tr.request.callId === callId && tr.request.cseq === cseq) {
                                reply(482, message, transport);
                                return false;
                            }
                        }
                    }
                }
            }
        }
        return true;
    }
    SanityCheck.rfc3261_8_2_2_2 = rfc3261_8_2_2_2;
    // Sanity Check functions for responses
    function rfc3261_8_1_3_3(message, ua) {
        if (message.getHeaders("via").length > 1) {
            ua.getLogger("sip.sanitycheck").warn("More than one Via header field present in the response." +
                " Dropping the response");
            return false;
        }
        return true;
    }
    SanityCheck.rfc3261_8_1_3_3 = rfc3261_8_1_3_3;
    function rfc3261_18_1_2(message, ua) {
        if (message.via.host !== ua.configuration.viaHost || message.via.port !== undefined) {
            ua.getLogger("sip.sanitycheck").warn("Via sent-by in the response does not match UA Via host value." +
                " Dropping the response");
            return false;
        }
        return true;
    }
    SanityCheck.rfc3261_18_1_2 = rfc3261_18_1_2;
    function rfc3261_18_3_response(message, ua) {
        var len = Utils_1.Utils.str_utf8_length(message.body);
        var contentLength = message.getHeader("content-length");
        if (contentLength && len < Number(contentLength)) {
            ua.getLogger("sip.sanitycheck").warn("Message body length is lower than the value in" +
                " Content-Length header field. Dropping the response");
            return false;
        }
        return true;
    }
    SanityCheck.rfc3261_18_3_response = rfc3261_18_3_response;
    // Sanity Check functions for requests and responses
    function minimumHeaders(message, ua) {
        var mandatoryHeaders = ["from", "to", "call_id", "cseq", "via"];
        for (var _i = 0, mandatoryHeaders_1 = mandatoryHeaders; _i < mandatoryHeaders_1.length; _i++) {
            var header = mandatoryHeaders_1[_i];
            if (!message.hasHeader(header)) {
                ua.getLogger("sip.sanitycheck").warn("Missing mandatory header field : " +
                    header + ". Dropping the response");
                return false;
            }
        }
        return true;
    }
    SanityCheck.minimumHeaders = minimumHeaders;
    function sanityCheck(message, ua, transport) {
        var requests = [
            rfc3261_8_2_2_1,
            rfc3261_16_3_4,
            rfc3261_18_3_request,
            rfc3261_8_2_2_2
        ];
        var responses = [
            rfc3261_8_1_3_3,
            rfc3261_18_1_2,
            rfc3261_18_3_response
        ];
        var all = [
            minimumHeaders
        ];
        for (var _i = 0, all_1 = all; _i < all_1.length; _i++) {
            var checkFunction = all_1[_i];
            if (!checkFunction(message, ua, transport)) {
                return false;
            }
        }
        if (message.type === Enums_1.TypeStrings.IncomingRequest) {
            for (var _a = 0, requests_1 = requests; _a < requests_1.length; _a++) {
                var checkFunction = requests_1[_a];
                if (!checkFunction(message, ua, transport)) {
                    return false;
                }
            }
        }
        else if (message.type === Enums_1.TypeStrings.IncomingResponse) {
            for (var _b = 0, responses_1 = responses; _b < responses_1.length; _b++) {
                var checkFunction = responses_1[_b];
                if (!checkFunction(message, ua, transport)) {
                    return false;
                }
            }
        }
        // Everything is OK
        return true;
    }
    SanityCheck.sanityCheck = sanityCheck;
})(SanityCheck = exports.SanityCheck || (exports.SanityCheck = {}));


/***/ }),
/* 25 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";

var __extends = (this && this.__extends) || (function () {
    var extendStatics = function (d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
var events_1 = __webpack_require__(2);
var Constants_1 = __webpack_require__(3);
var Enums_1 = __webpack_require__(5);
var Grammar_1 = __webpack_require__(11);
var Transactions_1 = __webpack_require__(7);
var Utils_1 = __webpack_require__(15);
var ServerContext = /** @class */ (function (_super) {
    __extends(ServerContext, _super);
    function ServerContext(ua, request) {
        var _this = _super.call(this) || this;
        _this.data = {};
        ServerContext.initializer(_this, ua, request);
        return _this;
    }
    // hack to get around our multiple inheritance issues
    ServerContext.initializer = function (objectToConstruct, ua, request) {
        objectToConstruct.type = Enums_1.TypeStrings.ServerContext;
        objectToConstruct.ua = ua;
        objectToConstruct.logger = ua.getLogger("sip.servercontext");
        objectToConstruct.request = request;
        var transport = ua.transport;
        if (!transport) {
            throw new Error("Transport undefined.");
        }
        var user = {
            loggerFactory: ua.getLoggerFactory(),
            onStateChange: function (newState) {
                if (newState === Transactions_1.TransactionState.Terminated) {
                    ua.destroyTransaction(objectToConstruct.transaction);
                }
            },
            onTransportError: function (error) {
                objectToConstruct.logger.error(error.message);
                objectToConstruct.onTransportError();
            }
        };
        if (request.method === Constants_1.C.INVITE) {
            objectToConstruct.transaction = new Transactions_1.InviteServerTransaction(request, transport, user);
        }
        else {
            objectToConstruct.transaction = new Transactions_1.NonInviteServerTransaction(request, transport, user);
        }
        ua.newTransaction(objectToConstruct.transaction);
        if (request.body) {
            objectToConstruct.body = request.body;
        }
        if (request.hasHeader("Content-Type")) {
            objectToConstruct.contentType = request.getHeader("Content-Type");
        }
        objectToConstruct.method = request.method;
        objectToConstruct.localIdentity = request.to;
        objectToConstruct.remoteIdentity = request.from;
        var hasAssertedIdentity = request.hasHeader("P-Asserted-Identity");
        if (hasAssertedIdentity) {
            var assertedIdentity = request.getHeader("P-Asserted-Identity");
            if (assertedIdentity) {
                objectToConstruct.assertedIdentity = Grammar_1.Grammar.nameAddrHeaderParse(assertedIdentity);
            }
        }
    };
    ServerContext.prototype.progress = function (options) {
        if (options === void 0) { options = {}; }
        options.statusCode = options.statusCode || 180;
        options.minCode = 100;
        options.maxCode = 199;
        options.events = ["progress"];
        return this.reply(options);
    };
    ServerContext.prototype.accept = function (options) {
        if (options === void 0) { options = {}; }
        options.statusCode = options.statusCode || 200;
        options.minCode = 200;
        options.maxCode = 299;
        options.events = ["accepted"];
        return this.reply(options);
    };
    ServerContext.prototype.reject = function (options) {
        if (options === void 0) { options = {}; }
        options.statusCode = options.statusCode || 480;
        options.minCode = 300;
        options.maxCode = 699;
        options.events = ["rejected", "failed"];
        return this.reply(options);
    };
    ServerContext.prototype.reply = function (options) {
        var _this = this;
        if (options === void 0) { options = {}; }
        var statusCode = options.statusCode || 100;
        var minCode = options.minCode || 100;
        var maxCode = options.maxCode || 699;
        var reasonPhrase = Utils_1.Utils.getReasonPhrase(statusCode, options.reasonPhrase);
        var extraHeaders = options.extraHeaders || [];
        var body = options.body;
        var events = options.events || [];
        if (statusCode < minCode || statusCode > maxCode) {
            throw new TypeError("Invalid statusCode: " + statusCode);
        }
        var response = this.request.reply(statusCode, reasonPhrase, extraHeaders, body);
        events.forEach(function (event) {
            _this.emit(event, response, reasonPhrase);
        });
        return this;
    };
    ServerContext.prototype.onRequestTimeout = function () {
        this.emit("failed", undefined, Constants_1.C.causes.REQUEST_TIMEOUT);
    };
    ServerContext.prototype.onTransportError = function () {
        this.emit("failed", undefined, Constants_1.C.causes.CONNECTION_ERROR);
    };
    return ServerContext;
}(events_1.EventEmitter));
exports.ServerContext = ServerContext;


/***/ }),
/* 26 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";

var __extends = (this && this.__extends) || (function () {
    var extendStatics = function (d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
var events_1 = __webpack_require__(2);
var ClientContext_1 = __webpack_require__(1);
var Constants_1 = __webpack_require__(3);
var Dialogs_1 = __webpack_require__(16);
var Enums_1 = __webpack_require__(5);
var Exceptions_1 = __webpack_require__(8);
var Grammar_1 = __webpack_require__(11);
var RequestSender_1 = __webpack_require__(6);
var ServerContext_1 = __webpack_require__(25);
var DTMF_1 = __webpack_require__(27);
var SIPMessage_1 = __webpack_require__(10);
var Timers_1 = __webpack_require__(9);
var Transactions_1 = __webpack_require__(7);
var Utils_1 = __webpack_require__(15);
/*
 * @param {function returning SIP.sessionDescriptionHandler} [sessionDescriptionHandlerFactory]
 *        (See the documentation for the sessionDescriptionHandlerFactory argument of the UA constructor.)
 */
var Session = /** @class */ (function (_super) {
    __extends(Session, _super);
    function Session(sessionDescriptionHandlerFactory) {
        var _this = _super.call(this) || this;
        _this.data = {};
        _this.type = Enums_1.TypeStrings.Session;
        if (!sessionDescriptionHandlerFactory) {
            throw new Exceptions_1.Exceptions.SessionDescriptionHandlerError("A session description handler is required for the session to function");
        }
        _this.status = Session.C.STATUS_NULL;
        _this.dialog = undefined;
        _this.pendingReinvite = false;
        _this.earlyDialogs = {};
        _this.sessionDescriptionHandlerFactory = sessionDescriptionHandlerFactory;
        _this.hasOffer = false;
        _this.hasAnswer = false;
        // Session Timers
        _this.timers = {
            ackTimer: undefined,
            expiresTimer: undefined,
            invite2xxTimer: undefined,
            userNoAnswerTimer: undefined,
            rel1xxTimer: undefined,
            prackTimer: undefined
        };
        // Session info
        _this.startTime = undefined;
        _this.endTime = undefined;
        _this.tones = undefined;
        // Hold state
        _this.localHold = false;
        _this.earlySdp = undefined;
        _this.rel100 = Constants_1.C.supported.UNSUPPORTED;
        _this.originalReceiveRequest = _this.receiveRequest;
        return _this;
    }
    Session.prototype.dtmf = function (tones, options) {
        var _this = this;
        if (options === void 0) { options = {}; }
        // Check Session Status
        if (this.status !== Enums_1.SessionStatus.STATUS_CONFIRMED && this.status !== Enums_1.SessionStatus.STATUS_WAITING_FOR_ACK) {
            throw new Exceptions_1.Exceptions.InvalidStateError(this.status);
        }
        // Check tones
        if (!tones || !tones.toString().match(/^[0-9A-D#*,]+$/i)) {
            throw new TypeError("Invalid tones: " + tones);
        }
        var sendDTMF = function () {
            if (_this.status === Enums_1.SessionStatus.STATUS_TERMINATED || !_this.tones || _this.tones.length === 0) {
                // Stop sending DTMF
                _this.tones = undefined;
                return;
            }
            var dtmf = _this.tones.shift();
            var timeout;
            if (dtmf.tone === ",") {
                timeout = 2000;
            }
            else {
                dtmf.on("failed", function () { _this.tones = undefined; });
                dtmf.send(options);
                timeout = dtmf.duration + dtmf.interToneGap;
            }
            // Set timeout for the next tone
            setTimeout(sendDTMF, timeout);
        };
        tones = tones.toString();
        var dtmfType = this.ua.configuration.dtmfType;
        if (this.sessionDescriptionHandler && dtmfType === Constants_1.C.dtmfType.RTP) {
            var sent = this.sessionDescriptionHandler.sendDtmf(tones, options);
            if (!sent) {
                this.logger.warn("Attempt to use dtmfType 'RTP' has failed, falling back to INFO packet method");
                dtmfType = Constants_1.C.dtmfType.INFO;
            }
        }
        if (dtmfType === Constants_1.C.dtmfType.INFO) {
            var dtmfs = [];
            var tonesArray = tones.split("");
            while (tonesArray.length > 0) {
                dtmfs.push(new DTMF_1.DTMF(this, tonesArray.shift(), options));
            }
            if (this.tones) {
                // Tones are already queued, just add to the queue
                this.tones = this.tones.concat(dtmfs);
                return this;
            }
            this.tones = dtmfs;
            sendDTMF();
        }
        return this;
    };
    Session.prototype.bye = function (options) {
        if (options === void 0) { options = {}; }
        // Check Session Status
        if (this.status === Enums_1.SessionStatus.STATUS_TERMINATED) {
            this.logger.error("Error: Attempted to send BYE in a terminated session.");
            return this;
        }
        this.logger.log("terminating Session");
        var statusCode = options.statusCode;
        if (statusCode && (statusCode < 200 || statusCode >= 700)) {
            throw new TypeError("Invalid statusCode: " + statusCode);
        }
        options.receiveResponse = function () { };
        return this.sendRequest(Constants_1.C.BYE, options).terminated();
    };
    Session.prototype.refer = function (target, options) {
        if (options === void 0) { options = {}; }
        // Check Session Status
        if (this.status !== Enums_1.SessionStatus.STATUS_CONFIRMED) {
            throw new Exceptions_1.Exceptions.InvalidStateError(this.status);
        }
        this.referContext = new ReferClientContext(this.ua, this, target, options);
        this.emit("referRequested", this.referContext);
        this.referContext.refer(options);
        return this.referContext;
    };
    Session.prototype.sendRequest = function (method, options) {
        var _this = this;
        if (options === void 0) { options = {}; }
        options = options || {};
        if (!this.dialog) {
            throw new Error("sending request without a dialog");
        }
        var request = new SIPMessage_1.OutgoingRequest(method, this.dialog.remoteTarget, this.ua, {
            cseq: options.cseq || (this.dialog.localSeqnum += 1),
            callId: this.dialog.id.callId,
            fromUri: this.dialog.localUri,
            fromTag: this.dialog.id.localTag,
            ToUri: this.dialog.remoteUri,
            toTag: this.dialog.id.remoteTag,
            routeSet: this.dialog.routeSet,
            statusCode: options.statusCode,
            reasonPhrase: options.reasonPhrase
        }, options.extraHeaders || [], options.body);
        new RequestSender_1.RequestSender({
            request: request,
            onRequestTimeout: function () { return _this.onRequestTimeout(); },
            onTransportError: function () { return _this.onTransportError(); },
            receiveResponse: function (response) {
                return (options.receiveResponse || _this.receiveNonInviteResponse.bind(_this))(response);
            }
        }, this.ua).send();
        // Emit the request event
        this.emit(method.toLowerCase(), request);
        return this;
    };
    Session.prototype.close = function () {
        if (this.status === Enums_1.SessionStatus.STATUS_TERMINATED) {
            return this;
        }
        this.logger.log("closing INVITE session " + this.id);
        // 1st Step. Terminate media.
        if (this.sessionDescriptionHandler) {
            this.sessionDescriptionHandler.close();
        }
        // 2nd Step. Terminate signaling.
        // Clear session timers
        for (var timer in this.timers) {
            if (this.timers[timer]) {
                clearTimeout(this.timers[timer]);
            }
        }
        // Terminate dialogs
        // Terminate confirmed dialog
        if (this.dialog) {
            this.dialog.terminate();
            delete this.dialog;
        }
        // Terminate early dialogs
        for (var idx in this.earlyDialogs) {
            if (this.earlyDialogs.hasOwnProperty(idx)) {
                this.earlyDialogs[idx].terminate();
                delete this.earlyDialogs[idx];
            }
        }
        this.status = Enums_1.SessionStatus.STATUS_TERMINATED;
        if (this.ua.transport) {
            this.ua.transport.removeListener("transportError", this.errorListener);
        }
        delete this.ua.sessions[this.id];
        return this;
    };
    Session.prototype.createDialog = function (message, type, early) {
        if (early === void 0) { early = false; }
        var localTag = message[(type === "UAS") ? "toTag" : "fromTag"];
        var remoteTag = message[(type === "UAS") ? "fromTag" : "toTag"];
        var id = message.callId + localTag + remoteTag;
        if (early) { // Early Dialog
            if (this.earlyDialogs[id]) {
                return true;
            }
            else {
                var earlyDialog = new Dialogs_1.Dialog(this, message, type, Dialogs_1.Dialog.C.STATUS_EARLY);
                // Dialog has been successfully created.
                if (earlyDialog.error) {
                    this.logger.error(earlyDialog.error);
                    this.failed(message, Constants_1.C.causes.INTERNAL_ERROR);
                    return false;
                }
                else {
                    this.earlyDialogs[id] = earlyDialog;
                    return true;
                }
            }
        }
        else { // Confirmed Dialog
            // In case the dialog is in _early_ state, update it
            var earlyDialog = this.earlyDialogs[id];
            if (earlyDialog) {
                earlyDialog.update(message, type);
                this.dialog = earlyDialog;
                delete this.earlyDialogs[id];
                for (var idx in this.earlyDialogs) {
                    if (this.earlyDialogs.hasOwnProperty(idx)) {
                        this.earlyDialogs[idx].terminate();
                        delete this.earlyDialogs[idx];
                    }
                }
                return true;
            }
            // Otherwise, create a _confirmed_ dialog
            var dialog = new Dialogs_1.Dialog(this, message, type);
            if (dialog.error) {
                this.logger.error(dialog.error);
                this.failed(message, Constants_1.C.causes.INTERNAL_ERROR);
                return false;
            }
            else {
                this.toTag = message.toTag;
                this.dialog = dialog;
                return true;
            }
        }
    };
    Session.prototype.hold = function (options, modifiers) {
        if (options === void 0) { options = {}; }
        if (modifiers === void 0) { modifiers = []; }
        if (this.status !== Enums_1.SessionStatus.STATUS_WAITING_FOR_ACK && this.status !== Enums_1.SessionStatus.STATUS_CONFIRMED) {
            throw new Exceptions_1.Exceptions.InvalidStateError(this.status);
        }
        if (this.localHold) {
            this.logger.log("Session is already on hold, cannot put it on hold again");
            return;
        }
        options.modifiers = modifiers;
        if (this.sessionDescriptionHandler) {
            options.modifiers.push(this.sessionDescriptionHandler.holdModifier);
        }
        this.localHold = true;
        this.sendReinvite(options);
    };
    Session.prototype.unhold = function (options, modifiers) {
        if (options === void 0) { options = {}; }
        if (modifiers === void 0) { modifiers = []; }
        if (this.status !== Enums_1.SessionStatus.STATUS_WAITING_FOR_ACK && this.status !== Enums_1.SessionStatus.STATUS_CONFIRMED) {
            throw new Exceptions_1.Exceptions.InvalidStateError(this.status);
        }
        if (!this.localHold) {
            this.logger.log("Session is not on hold, cannot unhold it");
            return;
        }
        options.modifiers = modifiers;
        this.localHold = false;
        this.sendReinvite(options);
    };
    Session.prototype.reinvite = function (options, modifiers) {
        if (options === void 0) { options = {}; }
        if (modifiers === void 0) { modifiers = []; }
        options.modifiers = modifiers;
        return this.sendReinvite(options);
    };
    Session.prototype.receiveRequest = function (request) {
        switch (request.method) { // TODO: This needs a default case
            case Constants_1.C.BYE:
                request.reply(200);
                if (this.status === Enums_1.SessionStatus.STATUS_CONFIRMED) {
                    this.emit("bye", request);
                    this.terminated(request, Constants_1.C.BYE);
                }
                break;
            case Constants_1.C.INVITE:
                if (this.status === Enums_1.SessionStatus.STATUS_CONFIRMED) {
                    this.logger.log("re-INVITE received");
                    this.receiveReinvite(request);
                }
                break;
            case Constants_1.C.INFO:
                if (this.status === Enums_1.SessionStatus.STATUS_CONFIRMED || this.status === Enums_1.SessionStatus.STATUS_WAITING_FOR_ACK) {
                    if (this.onInfo) {
                        return this.onInfo(request);
                    }
                    var contentType = request.getHeader("content-type");
                    if (contentType) {
                        if (contentType.match(/^application\/dtmf-relay/i)) {
                            if (request.body) {
                                var body = request.body.split("\r\n", 2);
                                if (body.length === 2) {
                                    var tone = void 0;
                                    var duration = void 0;
                                    var regTone = /^(Signal\s*?=\s*?)([0-9A-D#*]{1})(\s)?.*/;
                                    if (regTone.test(body[0])) {
                                        tone = body[0].replace(regTone, "$2");
                                    }
                                    var regDuration = /^(Duration\s?=\s?)([0-9]{1,4})(\s)?.*/;
                                    if (regDuration.test(body[1])) {
                                        duration = parseInt(body[1].replace(regDuration, "$2"), 10);
                                    }
                                    if (tone && duration) {
                                        new DTMF_1.DTMF(this, tone, { duration: duration }).init_incoming(request);
                                    }
                                }
                            }
                        }
                        else {
                            request.reply(415, undefined, ["Accept: application/dtmf-relay"]);
                        }
                    }
                }
                break;
            case Constants_1.C.REFER:
                if (this.status === Enums_1.SessionStatus.STATUS_CONFIRMED) {
                    this.logger.log("REFER received");
                    this.referContext = new ReferServerContext(this.ua, request);
                    if (this.listeners("referRequested").length) {
                        this.emit("referRequested", this.referContext);
                    }
                    else {
                        this.logger.log("No referRequested listeners, automatically accepting and following the refer");
                        var options = { followRefer: true };
                        if (this.passedOptions) {
                            options.inviteOptions = this.passedOptions;
                        }
                        this.referContext.accept(options, this.modifiers);
                    }
                }
                break;
            case Constants_1.C.NOTIFY:
                if ((this.referContext && this.referContext.type === Enums_1.TypeStrings.ReferClientContext) &&
                    request.hasHeader("event") && /^refer(;.*)?$/.test(request.getHeader("event"))) {
                    this.referContext.receiveNotify(request);
                    return;
                }
                request.reply(200, "OK");
                this.emit("notify", request);
                break;
        }
    };
    Session.prototype.terminate = function (options) {
        // here for types and to be overridden
        return this;
    };
    Session.prototype.onTransportError = function () {
        if (this.status !== Enums_1.SessionStatus.STATUS_CONFIRMED && this.status !== Enums_1.SessionStatus.STATUS_TERMINATED) {
            this.failed(undefined, Constants_1.C.causes.CONNECTION_ERROR);
        }
    };
    Session.prototype.onRequestTimeout = function () {
        if (this.status === Enums_1.SessionStatus.STATUS_CONFIRMED) {
            this.terminated(undefined, Constants_1.C.causes.REQUEST_TIMEOUT);
        }
        else if (this.status !== Enums_1.SessionStatus.STATUS_TERMINATED) {
            this.failed(undefined, Constants_1.C.causes.REQUEST_TIMEOUT);
            this.terminated(undefined, Constants_1.C.causes.REQUEST_TIMEOUT);
        }
    };
    Session.prototype.onDialogError = function (response) {
        if (this.status === Enums_1.SessionStatus.STATUS_CONFIRMED) {
            this.terminated(response, Constants_1.C.causes.DIALOG_ERROR);
        }
        else if (this.status !== Enums_1.SessionStatus.STATUS_TERMINATED) {
            this.failed(response, Constants_1.C.causes.DIALOG_ERROR);
            this.terminated(response, Constants_1.C.causes.DIALOG_ERROR);
        }
    };
    Session.prototype.on = function (name, callback) {
        return _super.prototype.on.call(this, name, callback);
    };
    // In dialog INVITE Reception
    Session.prototype.receiveReinvite = function (request) {
        // TODO: Should probably check state of the session
        var _this = this;
        this.emit("reinvite", this, request);
        if (request.hasHeader("P-Asserted-Identity")) {
            this.assertedIdentity = Grammar_1.Grammar.nameAddrHeaderParse(request.getHeader("P-Asserted-Identity"));
        }
        var promise;
        if (!this.sessionDescriptionHandler) {
            this.logger.warn("No SessionDescriptionHandler to reinvite");
            return;
        }
        if (request.getHeader("Content-Length") === "0" && !request.getHeader("Content-Type")) { // Invite w/o SDP
            promise = this.sessionDescriptionHandler.getDescription(this.sessionDescriptionHandlerOptions, this.modifiers);
        }
        else if (this.sessionDescriptionHandler.hasDescription(request.getHeader("Content-Type") || "")) {
            // Invite w/ SDP
            promise = this.sessionDescriptionHandler.setDescription(request.body, this.sessionDescriptionHandlerOptions, this.modifiers).then(this.sessionDescriptionHandler.getDescription.bind(this.sessionDescriptionHandler, this.sessionDescriptionHandlerOptions, this.modifiers));
        }
        else { // Bad Packet (should never get hit)
            request.reply(415);
            this.emit("reinviteFailed", this);
            return;
        }
        this.receiveRequest = function (incRequest) {
            if (incRequest.method === Constants_1.C.ACK && _this.status === Enums_1.SessionStatus.STATUS_WAITING_FOR_ACK) {
                if (_this.sessionDescriptionHandler &&
                    _this.sessionDescriptionHandler.hasDescription(incRequest.getHeader("Content-Type") || "")) {
                    _this.hasAnswer = true;
                    _this.sessionDescriptionHandler.setDescription(incRequest.body, _this.sessionDescriptionHandlerOptions, _this.modifiers).then(function () {
                        clearTimeout(_this.timers.ackTimer);
                        clearTimeout(_this.timers.invite2xxTimer);
                        _this.status = Enums_1.SessionStatus.STATUS_CONFIRMED;
                        _this.emit("confirmed", incRequest);
                    });
                }
                else {
                    clearTimeout(_this.timers.ackTimer);
                    clearTimeout(_this.timers.invite2xxTimer);
                    _this.status = Enums_1.SessionStatus.STATUS_CONFIRMED;
                    _this.emit("confirmed", incRequest);
                }
            }
            else {
                _this.originalReceiveRequest(incRequest);
            }
        };
        promise.catch(function (e) {
            var statusCode;
            if (e.type === Enums_1.TypeStrings.SessionDescriptionHandlerError) {
                statusCode = 500;
            }
            else if (e.type === Enums_1.TypeStrings.RenegotiationError) {
                _this.emit("renegotiationError", e);
                _this.logger.warn(e.toString());
                statusCode = 488;
            }
            else {
                _this.logger.error(e);
                statusCode = 488;
            }
            request.reply(statusCode);
            _this.emit("reinviteFailed", _this);
            // TODO: This could be better
            throw e;
        }).then(function (description) {
            var extraHeaders = ["Contact: " + _this.contact];
            request.reply(200, undefined, extraHeaders, description);
            _this.status = Enums_1.SessionStatus.STATUS_WAITING_FOR_ACK;
            _this.setACKTimer();
            _this.emit("reinviteAccepted", _this);
        });
    };
    Session.prototype.sendReinvite = function (options) {
        var _this = this;
        if (options === void 0) { options = {}; }
        if (this.pendingReinvite) {
            this.logger.warn("Reinvite in progress. Please wait until complete, then try again.");
            return;
        }
        if (!this.sessionDescriptionHandler) {
            this.logger.warn("No SessionDescriptionHandler, can't reinvite..");
            return;
        }
        this.pendingReinvite = true;
        options.modifiers = options.modifiers || [];
        var extraHeaders = (options.extraHeaders || []).slice();
        extraHeaders.push("Contact: " + this.contact);
        // this is UA.C.ALLOWED_METHODS, removed to get around circular dependency
        extraHeaders.push("Allow: " + [
            "ACK",
            "CANCEL",
            "INVITE",
            "MESSAGE",
            "BYE",
            "OPTIONS",
            "INFO",
            "NOTIFY",
            "REFER"
        ].toString());
        this.sessionDescriptionHandler.getDescription(options.sessionDescriptionHandlerOptions, options.modifiers)
            .then(function (description) {
            _this.sendRequest(Constants_1.C.INVITE, {
                extraHeaders: extraHeaders,
                body: description,
                receiveResponse: function (response) { return _this.receiveReinviteResponse(response); }
            });
        }).catch(function (e) {
            if (e.type === Enums_1.TypeStrings.RenegotiationError) {
                _this.pendingReinvite = false;
                _this.emit("renegotiationError", e);
                _this.logger.warn("Renegotiation Error");
                _this.logger.warn(e.toString());
                throw e;
            }
            _this.logger.error("sessionDescriptionHandler error");
            _this.logger.error(e);
            throw e;
        });
    };
    // Reception of Response for in-dialog INVITE
    Session.prototype.receiveReinviteResponse = function (response) {
        var _this = this;
        if (this.status === Enums_1.SessionStatus.STATUS_TERMINATED) {
            this.logger.error("Received reinvite response, but in STATUS_TERMINATED");
            // TODO: Do we need to send a SIP response?
            return;
        }
        if (!this.pendingReinvite) {
            this.logger.error("Received reinvite response, but have no pending reinvite");
            // TODO: Do we need to send a SIP response?
            return;
        }
        var statusCode = response && response.statusCode ? response.statusCode.toString() : "";
        switch (true) {
            case /^1[0-9]{2}$/.test(statusCode):
                break;
            case /^2[0-9]{2}$/.test(statusCode):
                this.status = Enums_1.SessionStatus.STATUS_CONFIRMED;
                // 17.1.1.1 - For each final response that is received at the client transaction,
                // the client transaction sends an ACK,
                this.emit("ack", response.ack());
                this.pendingReinvite = false;
                // TODO: All of these timers should move into the Transaction layer
                clearTimeout(this.timers.invite2xxTimer);
                if (!this.sessionDescriptionHandler ||
                    !this.sessionDescriptionHandler.hasDescription(response.getHeader("Content-Type") || "")) {
                    this.logger.error("2XX response received to re-invite but did not have a description");
                    this.emit("reinviteFailed", this);
                    this.emit("renegotiationError", new Exceptions_1.Exceptions.RenegotiationError("2XX response received to re-invite but did not have a description"));
                    break;
                }
                this.sessionDescriptionHandler
                    .setDescription(response.body, this.sessionDescriptionHandlerOptions, this.modifiers)
                    .catch(function (e) {
                    _this.logger.error("Could not set the description in 2XX response");
                    _this.logger.error(e);
                    _this.emit("reinviteFailed", _this);
                    _this.emit("renegotiationError", e);
                    _this.sendRequest(Constants_1.C.BYE, {
                        extraHeaders: ["Reason: " + Utils_1.Utils.getReasonHeaderValue(488, "Not Acceptable Here")]
                    });
                    _this.terminated(undefined, Constants_1.C.causes.INCOMPATIBLE_SDP);
                    throw e;
                })
                    .then(function () {
                    _this.emit("reinviteAccepted", _this);
                });
                break;
            default:
                this.pendingReinvite = false;
                this.logger.log("Received a non 1XX or 2XX response to a re-invite");
                this.emit("reinviteFailed", this);
                this.emit("renegotiationError", new Exceptions_1.Exceptions.RenegotiationError("Invalid response to a re-invite"));
        }
    };
    Session.prototype.acceptAndTerminate = function (response, statusCode, reasonPhrase) {
        var extraHeaders = [];
        if (statusCode) {
            extraHeaders.push("Reason: " + Utils_1.Utils.getReasonHeaderValue(statusCode, reasonPhrase));
        }
        // An error on dialog creation will fire 'failed' event
        if (this.dialog || this.createDialog(response, "UAC")) {
            this.emit("ack", response.ack());
            this.sendRequest(Constants_1.C.BYE, { extraHeaders: extraHeaders });
        }
        return this;
    };
    /**
     * RFC3261 13.3.1.4
     * Response retransmissions cannot be accomplished by transaction layer
     *  since it is destroyed when receiving the first 2xx answer
     */
    Session.prototype.setInvite2xxTimer = function (request, description) {
        var _this = this;
        var timeout = Timers_1.Timers.T1;
        var invite2xxRetransmission = function () {
            if (_this.status !== Enums_1.SessionStatus.STATUS_WAITING_FOR_ACK) {
                return;
            }
            _this.logger.log("no ACK received, attempting to retransmit OK");
            var extraHeaders = ["Contact: " + _this.contact];
            request.reply(200, undefined, extraHeaders, description);
            timeout = Math.min(timeout * 2, Timers_1.Timers.T2);
            _this.timers.invite2xxTimer = setTimeout(invite2xxRetransmission, timeout);
        };
        this.timers.invite2xxTimer = setTimeout(invite2xxRetransmission, 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.
     */
    Session.prototype.setACKTimer = function () {
        var _this = this;
        this.timers.ackTimer = setTimeout(function () {
            if (_this.status === Enums_1.SessionStatus.STATUS_WAITING_FOR_ACK) {
                _this.logger.log("no ACK received for an extended period of time, terminating the call");
                clearTimeout(_this.timers.invite2xxTimer);
                _this.sendRequest(Constants_1.C.BYE);
                _this.terminated(undefined, Constants_1.C.causes.NO_ACK);
            }
        }, Timers_1.Timers.TIMER_H);
    };
    Session.prototype.failed = function (response, cause) {
        if (this.status === Enums_1.SessionStatus.STATUS_TERMINATED) {
            return this;
        }
        this.emit("failed", response, cause);
        return this;
    };
    Session.prototype.rejected = function (response, cause) {
        this.emit("rejected", response, cause);
        return this;
    };
    Session.prototype.canceled = function () {
        if (this.sessionDescriptionHandler) {
            this.sessionDescriptionHandler.close();
        }
        this.emit("cancel");
        return this;
    };
    Session.prototype.accepted = function (response, cause) {
        if (!(response instanceof String)) {
            cause = Utils_1.Utils.getReasonPhrase((response && response.statusCode) || 0, cause);
        }
        this.startTime = new Date();
        if (this.replacee) {
            this.replacee.emit("replaced", this);
            this.replacee.terminate();
        }
        this.emit("accepted", response, cause);
        return this;
    };
    Session.prototype.terminated = function (message, cause) {
        if (this.status === Enums_1.SessionStatus.STATUS_TERMINATED) {
            return this;
        }
        this.endTime = new Date();
        this.close();
        this.emit("terminated", message, cause);
        return this;
    };
    Session.prototype.connecting = function (request) {
        this.emit("connecting", { request: request });
        return this;
    };
    Session.prototype.receiveNonInviteResponse = function (response) {
        // blank, to be overridden
    };
    Session.C = Enums_1.SessionStatus;
    return Session;
}(events_1.EventEmitter));
exports.Session = Session;
// tslint:disable-next-line:max-classes-per-file
var InviteServerContext = /** @class */ (function (_super) {
    __extends(InviteServerContext, _super);
    function InviteServerContext(ua, request) {
        var _this = this;
        if (!ua.configuration.sessionDescriptionHandlerFactory) {
            ua.logger.warn("Can't build ISC without SDH Factory");
            throw new Error("ISC Constructor Failed");
        }
        _this = _super.call(this, ua.configuration.sessionDescriptionHandlerFactory) || this;
        ServerContext_1.ServerContext.initializer(_this, ua, request);
        _this.type = Enums_1.TypeStrings.InviteServerContext;
        var contentDisp = request.parseHeader("Content-Disposition");
        if (contentDisp && contentDisp.type === "render") {
            _this.renderbody = request.body;
            _this.rendertype = request.getHeader("Content-Type");
        }
        _this.status = Enums_1.SessionStatus.STATUS_INVITE_RECEIVED;
        _this.fromTag = request.fromTag;
        _this.id = request.callId + _this.fromTag;
        _this.request = request;
        _this.contact = _this.ua.contact.toString();
        _this.receiveNonInviteResponse = function () { };
        _this.logger = ua.getLogger("sip.inviteservercontext", _this.id);
        // Save the session into the ua sessions collection.
        _this.ua.sessions[_this.id] = _this;
        // Set 100rel if necessary
        var set100rel = function (header, relSetting) {
            if (request.hasHeader(header) && request.getHeader(header).toLowerCase().indexOf("100rel") >= 0) {
                _this.rel100 = relSetting;
            }
        };
        set100rel("require", Constants_1.C.supported.REQUIRED);
        set100rel("supported", Constants_1.C.supported.SUPPORTED);
        /* Set the toTag before
        * replying a response code that will create a dialog.
        */
        request.toTag = Utils_1.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;
        }
        var options = { extraHeaders: ["Contact: " + _this.contact] };
        if (_this.rel100 !== Constants_1.C.supported.REQUIRED) {
            _this.progress(options);
        }
        _this.status = Enums_1.SessionStatus.STATUS_WAITING_FOR_ANSWER;
        // Set userNoAnswerTimer
        _this.timers.userNoAnswerTimer = setTimeout(function () {
            request.reply(408);
            _this.failed(request, Constants_1.C.causes.NO_ANSWER);
            _this.terminated(request, Constants_1.C.causes.NO_ANSWER);
        }, _this.ua.configuration.noAnswerTimeout || 60);
        /* Set expiresTimer
        * RFC3261 13.3.1
        */
        // Get the Expires header value if exists
        if (request.hasHeader("expires")) {
            var expires = Number(request.getHeader("expires") || 0) * 1000;
            _this.timers.expiresTimer = setTimeout(function () {
                if (_this.status === Enums_1.SessionStatus.STATUS_WAITING_FOR_ANSWER) {
                    request.reply(487);
                    _this.failed(request, Constants_1.C.causes.EXPIRES);
                    _this.terminated(request, Constants_1.C.causes.EXPIRES);
                }
            }, expires);
        }
        _this.errorListener = _this.onTransportError.bind(_this);
        if (ua.transport) {
            ua.transport.on("transportError", _this.errorListener);
        }
        return _this;
    }
    // typing note: this was the only function using its super in ServerContext
    // so the bottom half of this function is copied and paired down from that
    InviteServerContext.prototype.reject = function (options) {
        var _this = this;
        if (options === void 0) { options = {}; }
        // Check Session Status
        if (this.status === Enums_1.SessionStatus.STATUS_TERMINATED) {
            throw new Exceptions_1.Exceptions.InvalidStateError(this.status);
        }
        this.logger.log("rejecting RTCSession");
        var statusCode = options.statusCode || 480;
        var reasonPhrase = Utils_1.Utils.getReasonPhrase(statusCode, options.reasonPhrase);
        var extraHeaders = options.extraHeaders || [];
        if (statusCode < 300 || statusCode > 699) {
            throw new TypeError("Invalid statusCode: " + statusCode);
        }
        var response = this.request.reply(statusCode, reasonPhrase, extraHeaders, options.body);
        (["rejected", "failed"]).forEach(function (event) {
            _this.emit(event, response, reasonPhrase);
        });
        return this.terminated();
    };
    // type hack for servercontext interface
    InviteServerContext.prototype.reply = function (options) {
        if (options === void 0) { options = {}; }
        return this;
    };
    InviteServerContext.prototype.terminate = function (options) {
        var _this = this;
        if (options === void 0) { options = {}; }
        var extraHeaders = (options.extraHeaders || []).slice();
        if (this.status === Enums_1.SessionStatus.STATUS_WAITING_FOR_ACK &&
            this.request.transaction &&
            this.request.transaction.state !== Transactions_1.TransactionState.Terminated) {
            var dialog = this.dialog;
            this.receiveRequest = function (request) {
                if (request.method === Constants_1.C.ACK) {
                    _this.sendRequest(Constants_1.C.BYE, { extraHeaders: extraHeaders });
                    if (_this.dialog) {
                        _this.dialog.terminate();
                    }
                }
            };
            this.request.transaction.on("stateChanged", function () {
                if (_this.request.transaction &&
                    _this.request.transaction.state === Transactions_1.TransactionState.Terminated &&
                    _this.dialog) {
                    _this.bye();
                    _this.dialog.terminate();
                }
            });
            this.emit("bye", this.request);
            this.terminated();
            // Restore the dialog into 'ua' so the ACK can reach 'this' session
            this.dialog = dialog;
            if (this.dialog) {
                this.ua.dialogs[this.dialog.id.toString()] = this.dialog;
            }
        }
        else if (this.status === Enums_1.SessionStatus.STATUS_CONFIRMED) {
            this.bye(options);
        }
        else {
            this.reject(options);
        }
        return this;
    };
    // @param {Object} [options.sessionDescriptionHandlerOptions]
    // gets passed to SIP.SessionDescriptionHandler.getDescription as options
    InviteServerContext.prototype.progress = function (options) {
        var _this = this;
        if (options === void 0) { options = {}; }
        var statusCode = options.statusCode || 180;
        var extraHeaders = (options.extraHeaders || []).slice();
        if (statusCode < 100 || statusCode > 199) {
            throw new TypeError("Invalid statusCode: " + statusCode);
        }
        if (this.status === Enums_1.SessionStatus.STATUS_TERMINATED) {
            return this;
        }
        var do100rel = function () {
            var relStatusCode = options.statusCode || 183;
            // Set status and add extra headers
            _this.status = Enums_1.SessionStatus.STATUS_WAITING_FOR_PRACK;
            extraHeaders.push("Contact: " + _this.contact);
            extraHeaders.push("Require: 100rel");
            extraHeaders.push("RSeq: " + Math.floor(Math.random() * 10000));
            if (!_this.sessionDescriptionHandler) {
                _this.logger.warn("No SessionDescriptionHandler, can't do 100rel");
                return;
            }
            // Get the session description to add to preaccept with
            _this.sessionDescriptionHandler.getDescription(options.sessionDescriptionHandlerOptions, options.modifiers)
                .then(function (description) {
                if (_this.status === Enums_1.SessionStatus.STATUS_TERMINATED) {
                    return;
                }
                _this.earlySdp = description.body;
                _this[_this.hasOffer ? "hasAnswer" : "hasOffer"] = true;
                // Retransmit until we get a response or we time out (see prackTimer below)
                var timeout = Timers_1.Timers.T1;
                var rel1xxRetransmission = function () {
                    _this.request.reply(relStatusCode, undefined, extraHeaders, description);
                    timeout *= 2;
                    _this.timers.rel1xxTimer = setTimeout(rel1xxRetransmission, timeout);
                };
                _this.timers.rel1xxTimer = setTimeout(rel1xxRetransmission, timeout);
                // Timeout and reject INVITE if no response
                _this.timers.prackTimer = setTimeout(function () {
                    if (_this.status !== Enums_1.SessionStatus.STATUS_WAITING_FOR_PRACK) {
                        return;
                    }
                    _this.logger.log("no PRACK received, rejecting the call");
                    clearTimeout(_this.timers.rel1xxTimer);
                    _this.request.reply(504);
                    _this.terminated(undefined, Constants_1.C.causes.NO_PRACK);
                }, Timers_1.Timers.T1 * 64);
                // Send the initial response
                var response = _this.request.reply(relStatusCode, options.reasonPhrase, extraHeaders, description);
                _this.emit("progress", response, options.reasonPhrase);
            }, function () {
                _this.request.reply(480);
                _this.failed(undefined, Constants_1.C.causes.WEBRTC_ERROR);
                _this.terminated(undefined, Constants_1.C.causes.WEBRTC_ERROR);
            });
        }; // end do100rel
        var normalReply = function () {
            var response = _this.request.reply(statusCode, options.reasonPhrase, extraHeaders, options.body);
            _this.emit("progress", response, options.reasonPhrase);
        };
        if (options.statusCode !== 100 &&
            (this.rel100 === Constants_1.C.supported.REQUIRED ||
                (this.rel100 === Constants_1.C.supported.SUPPORTED && options.rel100) ||
                (this.rel100 === Constants_1.C.supported.SUPPORTED && (this.ua.configuration.rel100 === Constants_1.C.supported.REQUIRED)))) {
            this.sessionDescriptionHandler = this.setupSessionDescriptionHandler();
            this.emit("SessionDescriptionHandler-created", this.sessionDescriptionHandler);
            if (this.sessionDescriptionHandler.hasDescription(this.request.getHeader("Content-Type") || "")) {
                this.hasOffer = true;
                this.sessionDescriptionHandler.setDescription(this.request.body, options.sessionDescriptionHandlerOptions, options.modifiers).then(do100rel)
                    .catch(function (e) {
                    _this.logger.warn("invalid description");
                    _this.logger.warn(e);
                    _this.failed(undefined, Constants_1.C.causes.WEBRTC_ERROR);
                    _this.terminated(undefined, Constants_1.C.causes.WEBRTC_ERROR);
                    throw e;
                });
            }
            else {
                do100rel();
            }
        }
        else {
            normalReply();
        }
        return this;
    };
    // @param {Object} [options.sessionDescriptionHandlerOptions] gets passed
    // to SIP.SessionDescriptionHandler.getDescription as options
    InviteServerContext.prototype.accept = function (options) {
        var _this = this;
        if (options === void 0) { options = {}; }
        this.onInfo = options.onInfo;
        var extraHeaders = (options.extraHeaders || []).slice();
        var descriptionCreationSucceeded = function (description) {
            extraHeaders.push("Contact: " + _this.contact);
            // this is UA.C.ALLOWED_METHODS, removed to get around circular dependency
            extraHeaders.push("Allow: " + [
                "ACK",
                "CANCEL",
                "INVITE",
                "MESSAGE",
                "BYE",
                "OPTIONS",
                "INFO",
                "NOTIFY",
                "REFER"
            ].toString());
            if (!_this.hasOffer) {
                _this.hasOffer = true;
            }
            else {
                _this.hasAnswer = true;
            }
            var response = _this.request.reply(200, undefined, extraHeaders, description);
            _this.status = Enums_1.SessionStatus.STATUS_WAITING_FOR_ACK;
            _this.setInvite2xxTimer(_this.request, description);
            _this.setACKTimer();
            _this.accepted(response, Utils_1.Utils.getReasonPhrase(200));
        };
        var descriptionCreationFailed = function (err) {
            if (err.type === Enums_1.TypeStrings.SessionDescriptionHandlerError) {
                _this.logger.log(err.message);
                if (err.error) {
                    _this.logger.log(err.error);
                }
            }
            _this.request.reply(480);
            _this.failed(undefined, Constants_1.C.causes.WEBRTC_ERROR);
            _this.terminated(undefined, Constants_1.C.causes.WEBRTC_ERROR);
            throw err;
        };
        // Check Session Status
        if (this.status === Enums_1.SessionStatus.STATUS_WAITING_FOR_PRACK) {
            this.status = Enums_1.SessionStatus.STATUS_ANSWERED_WAITING_FOR_PRACK;
            return this;
        }
        else if (this.status === Enums_1.SessionStatus.STATUS_WAITING_FOR_ANSWER) {
            this.status = Enums_1.SessionStatus.STATUS_ANSWERED;
        }
        else if (this.status !== Enums_1.SessionStatus.STATUS_EARLY_MEDIA) {
            throw new Exceptions_1.Exceptions.InvalidStateError(this.status);
        }
        // An error on dialog creation will fire 'failed' event
        if (!this.createDialog(this.request, "UAS")) {
            this.request.reply(500, "Missing Contact header field");
            return this;
        }
        clearTimeout(this.timers.userNoAnswerTimer);
        if (this.status === Enums_1.SessionStatus.STATUS_EARLY_MEDIA) {
            descriptionCreationSucceeded({});
        }
        else {
            this.sessionDescriptionHandler = this.setupSessionDescriptionHandler();
            this.emit("SessionDescriptionHandler-created", this.sessionDescriptionHandler);
            if (this.request.getHeader("Content-Length") === "0" && !this.request.getHeader("Content-Type")) {
                this.sessionDescriptionHandler.getDescription(options.sessionDescriptionHandlerOptions, options.modifiers)
                    .catch(descriptionCreationFailed)
                    .then(descriptionCreationSucceeded);
            }
            else if (this.sessionDescriptionHandler.hasDescription(this.request.getHeader("Content-Type") || "")) {
                this.hasOffer = true;
                this.sessionDescriptionHandler.setDescription(this.request.body, options.sessionDescriptionHandlerOptions, options.modifiers).then(function () {
                    if (!_this.sessionDescriptionHandler) {
                        throw new Error("No SDH");
                    }
                    return _this.sessionDescriptionHandler.getDescription(options.sessionDescriptionHandlerOptions, options.modifiers);
                })
                    .catch(descriptionCreationFailed)
                    .then(descriptionCreationSucceeded);
            }
            else {
                this.request.reply(415);
                // TODO: Events
                return this;
            }
        }
        return this;
    };
    // ISC RECEIVE REQUEST
    InviteServerContext.prototype.receiveRequest = function (request) {
        var _this = this;
        var confirmSession = function () {
            clearTimeout(_this.timers.ackTimer);
            clearTimeout(_this.timers.invite2xxTimer);
            _this.status = Enums_1.SessionStatus.STATUS_CONFIRMED;
            var contentDisp = request.getHeader("Content-Disposition");
            if (contentDisp && contentDisp.type === "render") {
                _this.renderbody = request.body;
                _this.rendertype = request.getHeader("Content-Type");
            }
            _this.emit("confirmed", request);
        };
        switch (request.method) {
            case Constants_1.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. SIP 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 to send the answer) nor reject the
                *request opening the session.
                */
                if (this.status === Enums_1.SessionStatus.STATUS_WAITING_FOR_ANSWER ||
                    this.status === Enums_1.SessionStatus.STATUS_WAITING_FOR_PRACK ||
                    this.status === Enums_1.SessionStatus.STATUS_ANSWERED_WAITING_FOR_PRACK ||
                    this.status === Enums_1.SessionStatus.STATUS_EARLY_MEDIA ||
                    this.status === Enums_1.SessionStatus.STATUS_ANSWERED) {
                    this.status = Enums_1.SessionStatus.STATUS_CANCELED;
                    this.request.reply(487);
                    this.canceled();
                    this.rejected(request, Constants_1.C.causes.CANCELED);
                    this.failed(request, Constants_1.C.causes.CANCELED);
                    this.terminated(request, Constants_1.C.causes.CANCELED);
                }
                break;
            case Constants_1.C.ACK:
                if (this.status === Enums_1.SessionStatus.STATUS_WAITING_FOR_ACK) {
                    this.status = Enums_1.SessionStatus.STATUS_CONFIRMED;
                    if (this.sessionDescriptionHandler &&
                        this.sessionDescriptionHandler.hasDescription(request.getHeader("Content-Type") || "")) {
                        // ACK contains answer to an INVITE w/o SDP negotiation
                        this.hasAnswer = true;
                        this.sessionDescriptionHandler.setDescription(request.body, this.sessionDescriptionHandlerOptions, this.modifiers).catch(function (e) {
                            _this.logger.warn(e);
                            _this.terminate({
                                statusCode: "488",
                                reasonPhrase: "Bad Media Description"
                            });
                            _this.failed(request, Constants_1.C.causes.BAD_MEDIA_DESCRIPTION);
                            _this.terminated(request, Constants_1.C.causes.BAD_MEDIA_DESCRIPTION);
                            throw e;
                        }).then(function () { return confirmSession(); });
                    }
                    else {
                        confirmSession();
                    }
                }
                break;
            case Constants_1.C.PRACK:
                if (this.status === Enums_1.SessionStatus.STATUS_WAITING_FOR_PRACK ||
                    this.status === Enums_1.SessionStatus.STATUS_ANSWERED_WAITING_FOR_PRACK) {
                    if (!this.hasAnswer) {
                        this.sessionDescriptionHandler = this.setupSessionDescriptionHandler();
                        this.emit("SessionDescriptionHandler-created", this.sessionDescriptionHandler);
                        if (this.sessionDescriptionHandler.hasDescription(request.getHeader("Content-Type") || "")) {
                            this.hasAnswer = true;
                            this.sessionDescriptionHandler.setDescription(request.body, this.sessionDescriptionHandlerOptions, this.modifiers).then(function () {
                                clearTimeout(_this.timers.rel1xxTimer);
                                clearTimeout(_this.timers.prackTimer);
                                request.reply(200);
                                if (_this.status === Enums_1.SessionStatus.STATUS_ANSWERED_WAITING_FOR_PRACK) {
                                    _this.status = Enums_1.SessionStatus.STATUS_EARLY_MEDIA;
                                    _this.accept();
                                }
                                _this.status = Enums_1.SessionStatus.STATUS_EARLY_MEDIA;
                            }, function (e) {
                                _this.logger.warn(e);
                                _this.terminate({
                                    statusCode: "488",
                                    reasonPhrase: "Bad Media Description"
                                });
                                _this.failed(request, Constants_1.C.causes.BAD_MEDIA_DESCRIPTION);
                                _this.terminated(request, Constants_1.C.causes.BAD_MEDIA_DESCRIPTION);
                            });
                        }
                        else {
                            this.terminate({
                                statusCode: "488",
                                reasonPhrase: "Bad Media Description"
                            });
                            this.failed(request, Constants_1.C.causes.BAD_MEDIA_DESCRIPTION);
                            this.terminated(request, Constants_1.C.causes.BAD_MEDIA_DESCRIPTION);
                        }
                    }
                    else {
                        clearTimeout(this.timers.rel1xxTimer);
                        clearTimeout(this.timers.prackTimer);
                        request.reply(200);
                        if (this.status === Enums_1.SessionStatus.STATUS_ANSWERED_WAITING_FOR_PRACK) {
                            this.status = Enums_1.SessionStatus.STATUS_EARLY_MEDIA;
                            this.accept();
                        }
                        this.status = Enums_1.SessionStatus.STATUS_EARLY_MEDIA;
                    }
                }
                else if (this.status === Enums_1.SessionStatus.STATUS_EARLY_MEDIA) {
                    request.reply(200);
                }
                break;
            default:
                Session.prototype.receiveRequest.apply(this, [request]);
                break;
        }
    };
    // Internal Function to setup the handler consistently
    InviteServerContext.prototype.setupSessionDescriptionHandler = function () {
        if (this.sessionDescriptionHandler) {
            return this.sessionDescriptionHandler;
        }
        return this.sessionDescriptionHandlerFactory(this, this.ua.configuration.sessionDescriptionHandlerFactoryOptions);
    };
    return InviteServerContext;
}(Session));
exports.InviteServerContext = InviteServerContext;
// tslint:disable-next-line:max-classes-per-file
var InviteClientContext = /** @class */ (function (_super) {
    __extends(InviteClientContext, _super);
    function InviteClientContext(ua, target, options, modifiers) {
        if (options === void 0) { options = {}; }
        if (modifiers === void 0) { modifiers = []; }
        var _this = this;
        if (!ua.configuration.sessionDescriptionHandlerFactory) {
            ua.logger.warn("Can't build ISC without SDH Factory");
            throw new Error("ICC Constructor Failed");
        }
        options.params = options.params || {};
        var anonymous = options.anonymous || false;
        var fromTag = Utils_1.Utils.newTag();
        options.params.fromTag = fromTag;
        /* Do not add ;ob in initial forming dialog requests if the registration over
        *  the current connection got a GRUU URI.
        */
        var contact = ua.contact.toString({
            anonymous: anonymous,
            outbound: anonymous ? !ua.contact.tempGruu : !ua.contact.pubGruu
        });
        var extraHeaders = (options.extraHeaders || []).slice();
        if (anonymous && ua.configuration.uri) {
            options.params.from_displayName = "Anonymous";
            options.params.from_uri = "sip:anonymous@anonymous.invalid";
            extraHeaders.push("P-Preferred-Identity: " + ua.configuration.uri.toString());
            extraHeaders.push("Privacy: id");
        }
        extraHeaders.push("Contact: " + contact);
        // this is UA.C.ALLOWED_METHODS, removed to get around circular dependency
        extraHeaders.push("Allow: " + [
            "ACK",
            "CANCEL",
            "INVITE",
            "MESSAGE",
            "BYE",
            "OPTIONS",
            "INFO",
            "NOTIFY",
            "REFER"
        ].toString());
        if (ua.configuration.rel100 === Constants_1.C.supported.REQUIRED) {
            extraHeaders.push("Require: 100rel");
        }
        if (ua.configuration.replaces === Constants_1.C.supported.REQUIRED) {
            extraHeaders.push("Require: replaces");
        }
        options.extraHeaders = extraHeaders;
        _this = _super.call(this, ua.configuration.sessionDescriptionHandlerFactory) || this;
        ClientContext_1.ClientContext.initializer(_this, ua, Constants_1.C.INVITE, target, options);
        _this.type = Enums_1.TypeStrings.InviteClientContext;
        _this.passedOptions = options; // Save for later to use with refer
        _this.sessionDescriptionHandlerOptions = options.sessionDescriptionHandlerOptions || {};
        _this.modifiers = modifiers;
        _this.inviteWithoutSdp = options.inviteWithoutSdp || false;
        // Set anonymous property
        _this.anonymous = options.anonymous || false;
        // Custom data to be sent either in INVITE or in ACK
        _this.renderbody = options.renderbody || undefined;
        _this.rendertype = options.rendertype || "text/plain";
        // Session parameter initialization
        _this.fromTag = fromTag;
        _this.contact = contact;
        // Check Session Status
        if (_this.status !== Enums_1.SessionStatus.STATUS_NULL) {
            throw new Exceptions_1.Exceptions.InvalidStateError(_this.status);
        }
        // OutgoingSession specific parameters
        _this.isCanceled = false;
        _this.received100 = false;
        _this.method = Constants_1.C.INVITE;
        _this.logger = ua.getLogger("sip.inviteclientcontext");
        ua.applicants[_this.toString()] = _this;
        _this.id = _this.request.callId + _this.fromTag;
        _this.onInfo = options.onInfo;
        _this.errorListener = _this.onTransportError.bind(_this);
        if (ua.transport) {
            ua.transport.on("transportError", _this.errorListener);
        }
        return _this;
    }
    InviteClientContext.prototype.receiveNonInviteResponse = function (response) {
        this.receiveInviteResponse(response);
    };
    InviteClientContext.prototype.receiveResponse = function (response) {
        this.receiveInviteResponse(response);
    };
    // hack for getting around ClientContext interface
    InviteClientContext.prototype.send = function () {
        var sender = new RequestSender_1.RequestSender(this, this.ua);
        sender.send();
        return this;
    };
    InviteClientContext.prototype.invite = function () {
        var _this = this;
        // Save the session into the ua sessions collection.
        // Note: placing in constructor breaks call to request.cancel on close... User does not need this anyway
        this.ua.sessions[this.id] = this;
        // This should allow the function to return so that listeners can be set up for these events
        Promise.resolve().then(function () {
            if (_this.inviteWithoutSdp) {
                // just send an invite with no sdp...
                _this.request.body = _this.renderbody;
                _this.status = Enums_1.SessionStatus.STATUS_INVITE_SENT;
                _this.send();
            }
            else {
                // Initialize Media Session
                _this.sessionDescriptionHandler = _this.sessionDescriptionHandlerFactory(_this, _this.ua.configuration.sessionDescriptionHandlerFactoryOptions || {});
                _this.emit("SessionDescriptionHandler-created", _this.sessionDescriptionHandler);
                _this.sessionDescriptionHandler.getDescription(_this.sessionDescriptionHandlerOptions, _this.modifiers)
                    .then(function (description) {
                    if (_this.isCanceled || _this.status === Enums_1.SessionStatus.STATUS_TERMINATED) {
                        return;
                    }
                    _this.hasOffer = true;
                    _this.request.body = description;
                    _this.status = Enums_1.SessionStatus.STATUS_INVITE_SENT;
                    _this.send();
                }, function (err) {
                    if (err.type === Enums_1.TypeStrings.SessionDescriptionHandlerError) {
                        _this.logger.log(err.message);
                        if (err.error) {
                            _this.logger.log(err.error);
                        }
                    }
                    if (_this.status === Enums_1.SessionStatus.STATUS_TERMINATED) {
                        return;
                    }
                    _this.failed(undefined, Constants_1.C.causes.WEBRTC_ERROR);
                    _this.terminated(undefined, Constants_1.C.causes.WEBRTC_ERROR);
                });
            }
        });
        return this;
    };
    InviteClientContext.prototype.receiveInviteResponse = function (response) {
        var _this = this;
        if (this.status === Enums_1.SessionStatus.STATUS_TERMINATED || response.method !== Constants_1.C.INVITE) {
            return;
        }
        var id = response.callId + response.fromTag + response.toTag;
        var extraHeaders = [];
        if (this.dialog && (response.statusCode && response.statusCode >= 200 && response.statusCode <= 299)) {
            if (id !== this.dialog.id.toString()) {
                if (!this.createDialog(response, "UAC", true)) {
                    return;
                }
                this.emit("ack", response.ack({ body: Utils_1.Utils.generateFakeSDP(response.body) }));
                this.earlyDialogs[id].sendRequest(this, Constants_1.C.BYE);
                /* NOTE: This fails because the forking proxy does not recognize that an unanswerable
                 * leg (due to peerConnection limitations) has been answered first. If your forking
                 * proxy does not hang up all unanswered branches on the first branch answered, remove this.
                 */
                if (this.status !== Enums_1.SessionStatus.STATUS_CONFIRMED) {
                    this.failed(response, Constants_1.C.causes.WEBRTC_ERROR);
                    this.terminated(response, Constants_1.C.causes.WEBRTC_ERROR);
                }
                return;
            }
            else if (this.status === Enums_1.SessionStatus.STATUS_CONFIRMED) {
                this.emit("ack", response.ack(response));
                return;
            }
            else if (!this.hasAnswer) {
                // invite w/o sdp is waiting for callback
                // an invite with sdp must go on, and hasAnswer is true
                return;
            }
        }
        var statusCode = response && response.statusCode;
        if (this.dialog && statusCode && statusCode < 200) {
            /*
              Early media has been set up with at least one other different branch,
              but a final 2xx response hasn't been received
            */
            var rseq = response.getHeader("rseq");
            if (rseq && (this.dialog.pracked.indexOf(rseq) !== -1 ||
                (Number(this.dialog.pracked[this.dialog.pracked.length - 1]) >= Number(rseq) &&
                    this.dialog.pracked.length > 0))) {
                return;
            }
            if (!this.earlyDialogs[id] && !this.createDialog(response, "UAC", true)) {
                return;
            }
            if (this.earlyDialogs[id].pracked.indexOf(response.getHeader("rseq")) !== -1 ||
                (this.earlyDialogs[id].pracked[this.earlyDialogs[id].pracked.length - 1] >= Number(rseq) &&
                    this.earlyDialogs[id].pracked.length > 0)) {
                return;
            }
            extraHeaders.push("RAck: " + response.getHeader("rseq") + " " + response.getHeader("cseq"));
            this.earlyDialogs[id].pracked.push(response.getHeader("rseq"));
            this.earlyDialogs[id].sendRequest(this, Constants_1.C.PRACK, {
                extraHeaders: extraHeaders,
                body: Utils_1.Utils.generateFakeSDP(response.body)
            });
            return;
        }
        // Proceed to cancellation if the user requested.
        if (this.isCanceled) {
            if (statusCode && statusCode >= 100 && statusCode < 200) {
                this.request.cancel(this.cancelReason, extraHeaders);
                this.canceled();
            }
            else if (statusCode && statusCode >= 200 && statusCode < 299) {
                this.acceptAndTerminate(response);
                this.emit("bye", this.request);
            }
            else if (statusCode && statusCode >= 300) {
                var cause = Constants_1.C.REASON_PHRASE[response.statusCode || 0] || Constants_1.C.causes.CANCELED;
                this.rejected(response, cause);
                this.failed(response, cause);
                this.terminated(response, cause);
            }
            return;
        }
        var codeString = statusCode ? statusCode.toString() : "";
        switch (true) {
            case /^100$/.test(codeString):
                this.received100 = true;
                this.emit("progress", response);
                break;
            case (/^1[0-9]{2}$/.test(codeString)):
                // Do nothing with 1xx responses without To tag.
                if (!response.toTag) {
                    this.logger.warn("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 = Enums_1.SessionStatus.STATUS_1XX_RECEIVED;
                if (response.hasHeader("P-Asserted-Identity")) {
                    this.assertedIdentity = Grammar_1.Grammar.nameAddrHeaderParse(response.getHeader("P-Asserted-Identity"));
                }
                if (response.hasHeader("require") &&
                    response.getHeader("require").indexOf("100rel") !== -1) {
                    // Do nothing if this.dialog is already confirmed
                    if (this.dialog || !this.earlyDialogs[id]) {
                        break;
                    }
                    var rseq_1 = response.getHeader("rseq");
                    if (this.earlyDialogs[id].pracked.indexOf(rseq_1) !== -1 ||
                        (this.earlyDialogs[id].pracked[this.earlyDialogs[id].pracked.length - 1] >= Number(rseq_1) &&
                            this.earlyDialogs[id].pracked.length > 0)) {
                        return;
                    }
                    // TODO: This may be broken. It may have to be on the early dialog
                    this.sessionDescriptionHandler = this.sessionDescriptionHandlerFactory(this, this.ua.configuration.sessionDescriptionHandlerFactoryOptions || {});
                    this.emit("SessionDescriptionHandler-created", this.sessionDescriptionHandler);
                    if (!this.sessionDescriptionHandler.hasDescription(response.getHeader("Content-Type") || "")) {
                        extraHeaders.push("RAck: " + response.getHeader("rseq") + " " + response.getHeader("cseq"));
                        this.earlyDialogs[id].pracked.push(response.getHeader("rseq"));
                        this.earlyDialogs[id].sendRequest(this, Constants_1.C.PRACK, {
                            extraHeaders: extraHeaders
                        });
                        this.emit("progress", response);
                    }
                    else if (this.hasOffer) {
                        if (!this.createDialog(response, "UAC")) {
                            break;
                        }
                        this.hasAnswer = true;
                        if (this.dialog !== undefined && rseq_1) {
                            this.dialog.pracked.push(rseq_1);
                        }
                        this.sessionDescriptionHandler.setDescription(response.body, this.sessionDescriptionHandlerOptions, this.modifiers).then(function () {
                            extraHeaders.push("RAck: " + response.getHeader("rseq") + " " + response.getHeader("cseq"));
                            _this.sendRequest(Constants_1.C.PRACK, {
                                extraHeaders: extraHeaders,
                                // tslint:disable-next-line:no-empty
                                receiveResponse: function () { }
                            });
                            _this.status = Enums_1.SessionStatus.STATUS_EARLY_MEDIA;
                            _this.emit("progress", response);
                        }, function (e) {
                            _this.logger.warn(e);
                            _this.acceptAndTerminate(response, 488, "Not Acceptable Here");
                            _this.failed(response, Constants_1.C.causes.BAD_MEDIA_DESCRIPTION);
                        });
                    }
                    else {
                        var earlyDialog_1 = this.earlyDialogs[id];
                        earlyDialog_1.sessionDescriptionHandler = this.sessionDescriptionHandlerFactory(this, this.ua.configuration.sessionDescriptionHandlerFactoryOptions || {});
                        this.emit("SessionDescriptionHandler-created", earlyDialog_1.sessionDescriptionHandler);
                        if (rseq_1) {
                            earlyDialog_1.pracked.push(rseq_1);
                        }
                        if (earlyDialog_1.sessionDescriptionHandler) {
                            earlyDialog_1.sessionDescriptionHandler.setDescription(response.body, this.sessionDescriptionHandlerOptions, this.modifiers).then(function () { return earlyDialog_1.sessionDescriptionHandler.getDescription(_this.sessionDescriptionHandlerOptions, _this.modifiers); }).then(function (description) {
                                extraHeaders.push("RAck: " + rseq_1 + " " + response.getHeader("cseq"));
                                earlyDialog_1.sendRequest(_this, Constants_1.C.PRACK, {
                                    extraHeaders: extraHeaders,
                                    body: description
                                });
                                _this.status = Enums_1.SessionStatus.STATUS_EARLY_MEDIA;
                                _this.emit("progress", response);
                            }).catch(function (e) {
                                // TODO: This is a bit wonky
                                if (rseq_1 && e.type === Enums_1.TypeStrings.SessionDescriptionHandlerError) {
                                    earlyDialog_1.pracked.push(rseq_1);
                                    if (_this.status === Enums_1.SessionStatus.STATUS_TERMINATED) {
                                        return;
                                    }
                                    _this.failed(undefined, Constants_1.C.causes.WEBRTC_ERROR);
                                    _this.terminated(undefined, Constants_1.C.causes.WEBRTC_ERROR);
                                }
                                else {
                                    if (rseq_1) {
                                        earlyDialog_1.pracked.splice(earlyDialog_1.pracked.indexOf(rseq_1), 1);
                                    }
                                    // Could not set remote description
                                    _this.logger.warn("invalid description");
                                    _this.logger.warn(e);
                                }
                                // FIXME: DON'T EAT UNHANDLED ERRORS!
                            });
                        }
                    }
                }
                else {
                    this.emit("progress", response);
                }
                break;
            case /^2[0-9]{2}$/.test(codeString):
                var cseq = this.request.cseq + " " + this.request.method;
                if (cseq !== response.getHeader("cseq")) {
                    break;
                }
                if (response.hasHeader("P-Asserted-Identity")) {
                    this.assertedIdentity = Grammar_1.Grammar.nameAddrHeaderParse(response.getHeader("P-Asserted-Identity"));
                }
                if (this.status === Enums_1.SessionStatus.STATUS_EARLY_MEDIA && this.dialog) {
                    this.status = Enums_1.SessionStatus.STATUS_CONFIRMED;
                    var options = {};
                    if (this.renderbody) {
                        extraHeaders.push("Content-Type: " + this.rendertype);
                        options.extraHeaders = extraHeaders;
                        options.body = this.renderbody;
                    }
                    this.emit("ack", response.ack(options));
                    this.accepted(response);
                    break;
                }
                // Do nothing if this.dialog is already confirmed
                if (this.dialog) {
                    break;
                }
                // This is an invite without sdp
                if (!this.hasOffer) {
                    if (this.earlyDialogs[id] && this.earlyDialogs[id].sessionDescriptionHandler) {
                        // REVISIT
                        this.hasOffer = true;
                        this.hasAnswer = true;
                        this.sessionDescriptionHandler = this.earlyDialogs[id].sessionDescriptionHandler;
                        if (!this.createDialog(response, "UAC")) {
                            break;
                        }
                        this.status = Enums_1.SessionStatus.STATUS_CONFIRMED;
                        this.emit("ack", response.ack());
                        this.accepted(response);
                    }
                    else {
                        this.sessionDescriptionHandler = this.sessionDescriptionHandlerFactory(this, this.ua.configuration.sessionDescriptionHandlerFactoryOptions || {});
                        this.emit("SessionDescriptionHandler-created", this.sessionDescriptionHandler);
                        if (!this.sessionDescriptionHandler.hasDescription(response.getHeader("Content-Type") || "")) {
                            this.acceptAndTerminate(response, 400, "Missing session description");
                            this.failed(response, Constants_1.C.causes.BAD_MEDIA_DESCRIPTION);
                            break;
                        }
                        if (!this.createDialog(response, "UAC")) {
                            break;
                        }
                        this.hasOffer = true;
                        this.sessionDescriptionHandler.setDescription(response.body, this.sessionDescriptionHandlerOptions, this.modifiers).then(function () { return _this.sessionDescriptionHandler.getDescription(_this.sessionDescriptionHandlerOptions, _this.modifiers); }).then(function (description) {
                            if (_this.isCanceled || _this.status === Enums_1.SessionStatus.STATUS_TERMINATED) {
                                return;
                            }
                            _this.status = Enums_1.SessionStatus.STATUS_CONFIRMED;
                            _this.hasAnswer = true;
                            _this.emit("ack", response.ack({ body: description }));
                            _this.accepted(response);
                        }).catch(function (e) {
                            if (e.type === Enums_1.TypeStrings.SessionDescriptionHandlerError) {
                                _this.logger.warn("invalid description");
                                _this.logger.warn(e.toString());
                                // TODO: This message is inconsistent
                                _this.acceptAndTerminate(response, 488, "Invalid session description");
                                _this.failed(response, Constants_1.C.causes.BAD_MEDIA_DESCRIPTION);
                            }
                            else {
                                throw e;
                            }
                        });
                    }
                }
                else if (this.hasAnswer) {
                    var options = {};
                    if (this.renderbody) {
                        extraHeaders.push("Content-Type: " + this.rendertype);
                        options.extraHeaders = extraHeaders;
                        options.body = this.renderbody;
                    }
                    this.emit("ack", response.ack(options));
                }
                else {
                    if (!this.sessionDescriptionHandler ||
                        !this.sessionDescriptionHandler.hasDescription(response.getHeader("Content-Type") || "")) {
                        this.acceptAndTerminate(response, 400, "Missing session description");
                        this.failed(response, Constants_1.C.causes.BAD_MEDIA_DESCRIPTION);
                        break;
                    }
                    if (!this.createDialog(response, "UAC")) {
                        break;
                    }
                    this.hasAnswer = true;
                    this.sessionDescriptionHandler.setDescription(response.body, this.sessionDescriptionHandlerOptions, this.modifiers).then(function () {
                        var options = {};
                        _this.status = Enums_1.SessionStatus.STATUS_CONFIRMED;
                        if (_this.renderbody) {
                            extraHeaders.push("Content-Type: " + _this.rendertype);
                            options.extraHeaders = extraHeaders;
                            options.body = _this.renderbody;
                        }
                        _this.emit("ack", response.ack(options));
                        _this.accepted(response);
                    }, function (e) {
                        _this.logger.warn(e);
                        _this.acceptAndTerminate(response, 488, "Not Acceptable Here");
                        _this.failed(response, Constants_1.C.causes.BAD_MEDIA_DESCRIPTION);
                        // FIME: DON'T EAT UNHANDLED ERRORS!
                    });
                }
                break;
            default:
                var cause = Utils_1.Utils.sipErrorCause(statusCode || 0);
                this.rejected(response, cause);
                this.failed(response, cause);
                this.terminated(response, cause);
        }
    };
    InviteClientContext.prototype.cancel = function (options) {
        if (options === void 0) { options = {}; }
        options.extraHeaders = (options.extraHeaders || []).slice();
        if (this.isCanceled) {
            throw new Exceptions_1.Exceptions.InvalidStateError(Enums_1.SessionStatus.STATUS_CANCELED);
        }
        // Check Session Status
        if (this.status === Enums_1.SessionStatus.STATUS_TERMINATED || this.status === Enums_1.SessionStatus.STATUS_CONFIRMED) {
            throw new Exceptions_1.Exceptions.InvalidStateError(this.status);
        }
        this.logger.log("canceling RTCSession");
        this.isCanceled = true;
        var cancelReason = Utils_1.Utils.getCancelReason(options.statusCode, options.reasonPhrase);
        // Check Session Status
        if (this.status === Enums_1.SessionStatus.STATUS_NULL ||
            (this.status === Enums_1.SessionStatus.STATUS_INVITE_SENT && !this.received100)) {
            this.cancelReason = cancelReason;
        }
        else if (this.status === Enums_1.SessionStatus.STATUS_INVITE_SENT ||
            this.status === Enums_1.SessionStatus.STATUS_1XX_RECEIVED ||
            this.status === Enums_1.SessionStatus.STATUS_EARLY_MEDIA) {
            this.request.cancel(cancelReason, options.extraHeaders);
        }
        return this.canceled();
    };
    InviteClientContext.prototype.terminate = function (options) {
        if (this.status === Enums_1.SessionStatus.STATUS_TERMINATED) {
            return this;
        }
        if (this.status === Enums_1.SessionStatus.STATUS_WAITING_FOR_ACK || this.status === Enums_1.SessionStatus.STATUS_CONFIRMED) {
            this.bye(options);
        }
        else {
            this.cancel(options);
        }
        return this;
    };
    // ICC RECEIVE REQUEST
    InviteClientContext.prototype.receiveRequest = function (request) {
        // Reject CANCELs
        if (request.method === Constants_1.C.CANCEL) {
            // TODO; make this a switch when it gets added
        }
        if (request.method === Constants_1.C.ACK && this.status === Enums_1.SessionStatus.STATUS_WAITING_FOR_ACK) {
            clearTimeout(this.timers.ackTimer);
            clearTimeout(this.timers.invite2xxTimer);
            this.status = Enums_1.SessionStatus.STATUS_CONFIRMED;
            this.accepted();
        }
        return _super.prototype.receiveRequest.call(this, request);
    };
    return InviteClientContext;
}(Session));
exports.InviteClientContext = InviteClientContext;
// tslint:disable-next-line:max-classes-per-file
var ReferClientContext = /** @class */ (function (_super) {
    __extends(ReferClientContext, _super);
    function ReferClientContext(ua, applicant, target, options) {
        if (options === void 0) { options = {}; }
        var _this = this;
        if (ua === undefined || applicant === undefined || target === undefined) {
            throw new TypeError("Not enough arguments");
        }
        _this = _super.call(this, ua, Constants_1.C.REFER, applicant.remoteIdentity.uri.toString(), options) || this;
        _this.type = Enums_1.TypeStrings.ReferClientContext;
        _this.options = options;
        _this.extraHeaders = (_this.options.extraHeaders || []).slice();
        _this.applicant = applicant;
        if (!(typeof target === "string") &&
            (target.type === Enums_1.TypeStrings.InviteServerContext || target.type === Enums_1.TypeStrings.InviteClientContext)) {
            // Attended Transfer (with replaces)
            // All of these fields should be defined based on the check above
            var dialog = target.dialog;
            if (dialog) {
                _this.target = '"' + target.remoteIdentity.friendlyName + '" ' +
                    "<" + dialog.remoteTarget.toString() +
                    "?Replaces=" + encodeURIComponent(dialog.id.callId +
                    ";to-tag=" + dialog.id.remoteTag +
                    ";from-tag=" + dialog.id.localTag) + ">";
            }
            else {
                throw new TypeError("Invalid target due to no dialog: " + target);
            }
        }
        else {
            // Blind Transfer
            // Refer-To: <sip:bob@example.com>
            var targetString = Grammar_1.Grammar.parse(target, "Refer_To");
            _this.target = targetString && targetString.uri ? targetString.uri : target;
            // Check target validity
            var targetUri = _this.ua.normalizeTarget(_this.target);
            if (!targetUri) {
                throw new TypeError("Invalid target: " + target);
            }
            _this.target = targetUri;
        }
        if (_this.ua) {
            _this.extraHeaders.push("Referred-By: <" + _this.ua.configuration.uri + ">");
        }
        // TODO: Check that this is correct isc/icc
        _this.extraHeaders.push("Contact: " + applicant.contact);
        // this is UA.C.ALLOWED_METHODS, removed to get around circular dependency
        _this.extraHeaders.push("Allow: " + [
            "ACK",
            "CANCEL",
            "INVITE",
            "MESSAGE",
            "BYE",
            "OPTIONS",
            "INFO",
            "NOTIFY",
            "REFER"
        ].toString());
        _this.extraHeaders.push("Refer-To: " + _this.target);
        _this.errorListener = _this.onTransportError.bind(_this);
        if (ua.transport) {
            ua.transport.on("transportError", _this.errorListener);
        }
        return _this;
    }
    ReferClientContext.prototype.refer = function (options) {
        var _this = this;
        if (options === void 0) { options = {}; }
        var extraHeaders = (this.extraHeaders || []).slice();
        if (options.extraHeaders) {
            extraHeaders.concat(options.extraHeaders);
        }
        this.applicant.sendRequest(Constants_1.C.REFER, {
            extraHeaders: this.extraHeaders,
            receiveResponse: function (response) {
                var statusCode = response && response.statusCode ? response.statusCode.toString() : "";
                if (/^1[0-9]{2}$/.test(statusCode)) {
                    _this.emit("referRequestProgress", _this);
                }
                else if (/^2[0-9]{2}$/.test(statusCode)) {
                    _this.emit("referRequestAccepted", _this);
                }
                else if (/^[4-6][0-9]{2}$/.test(statusCode)) {
                    _this.emit("referRequestRejected", _this);
                }
                if (options.receiveResponse) {
                    options.receiveResponse(response);
                }
            }
        });
        return this;
    };
    ReferClientContext.prototype.receiveNotify = function (request) {
        // If we can correctly handle this, then we need to send a 200 OK!
        var contentType = request.hasHeader("Content-Type") ?
            request.getHeader("Content-Type") : undefined;
        if (contentType && contentType.search(/^message\/sipfrag/) !== -1) {
            var messageBody = Grammar_1.Grammar.parse(request.body, "sipfrag");
            if (messageBody === -1) {
                request.reply(489, "Bad Event");
                return;
            }
            switch (true) {
                case (/^1[0-9]{2}$/.test(messageBody.status_code)):
                    this.emit("referProgress", this);
                    break;
                case (/^2[0-9]{2}$/.test(messageBody.status_code)):
                    this.emit("referAccepted", this);
                    if (!this.options.activeAfterTransfer && this.applicant.terminate) {
                        this.applicant.terminate();
                    }
                    break;
                default:
                    this.emit("referRejected", this);
                    break;
            }
            request.reply(200);
            this.emit("notify", request);
            return;
        }
        request.reply(489, "Bad Event");
    };
    return ReferClientContext;
}(ClientContext_1.ClientContext));
exports.ReferClientContext = ReferClientContext;
// tslint:disable-next-line:max-classes-per-file
var ReferServerContext = /** @class */ (function (_super) {
    __extends(ReferServerContext, _super);
    function ReferServerContext(ua, request) {
        var _this = _super.call(this, ua, request) || this;
        _this.type = Enums_1.TypeStrings.ReferServerContext;
        _this.ua = ua;
        _this.status = Enums_1.SessionStatus.STATUS_INVITE_RECEIVED;
        _this.fromTag = request.fromTag;
        _this.id = request.callId + _this.fromTag;
        _this.request = request;
        _this.contact = _this.ua.contact.toString();
        _this.logger = ua.getLogger("sip.referservercontext", _this.id);
        // Needed to send the NOTIFY's
        _this.cseq = Math.floor(Math.random() * 10000);
        _this.callId = _this.request.callId;
        _this.fromUri = _this.request.to.uri;
        _this.fromTag = _this.request.to.parameters.tag;
        _this.remoteTarget = _this.request.headers.Contact[0].parsed.uri;
        _this.toUri = _this.request.from.uri;
        _this.toTag = _this.request.fromTag;
        _this.routeSet = _this.request.getHeaders("record-route");
        // RFC 3515 2.4.1
        if (!_this.request.hasHeader("refer-to")) {
            _this.logger.warn("Invalid REFER packet. A refer-to header is required. Rejecting refer.");
            _this.reject();
            return _this;
        }
        _this.referTo = _this.request.parseHeader("refer-to");
        // TODO: Must set expiration timer and send 202 if there is no response by then
        _this.referredSession = _this.ua.findSession(request);
        if (_this.request.hasHeader("referred-by")) {
            _this.referredBy = _this.request.getHeader("referred-by");
        }
        if (_this.referTo.uri.hasHeader("replaces")) {
            _this.replaces = _this.referTo.uri.getHeader("replaces");
        }
        _this.errorListener = _this.onTransportError.bind(_this);
        if (ua.transport) {
            ua.transport.on("transportError", _this.errorListener);
        }
        _this.status = Enums_1.SessionStatus.STATUS_WAITING_FOR_ANSWER;
        return _this;
    }
    ReferServerContext.prototype.receiveNonInviteResponse = function (response) { };
    ReferServerContext.prototype.progress = function () {
        if (this.status !== Enums_1.SessionStatus.STATUS_WAITING_FOR_ANSWER) {
            throw new Exceptions_1.Exceptions.InvalidStateError(this.status);
        }
        this.request.reply(100);
    };
    ReferServerContext.prototype.reject = function (options) {
        if (options === void 0) { options = {}; }
        if (this.status === Enums_1.SessionStatus.STATUS_TERMINATED) {
            throw new Exceptions_1.Exceptions.InvalidStateError(this.status);
        }
        this.logger.log("Rejecting refer");
        this.status = Enums_1.SessionStatus.STATUS_TERMINATED;
        _super.prototype.reject.call(this, options);
        this.emit("referRequestRejected", this);
    };
    ReferServerContext.prototype.accept = function (options, modifiers) {
        var _this = this;
        if (options === void 0) { options = {}; }
        if (this.status === Enums_1.SessionStatus.STATUS_WAITING_FOR_ANSWER) {
            this.status = Enums_1.SessionStatus.STATUS_ANSWERED;
        }
        else {
            throw new Exceptions_1.Exceptions.InvalidStateError(this.status);
        }
        this.request.reply(202, "Accepted");
        this.emit("referRequestAccepted", this);
        if (options.followRefer) {
            this.logger.log("Accepted refer, attempting to automatically follow it");
            var target = this.referTo.uri;
            if (!target.scheme || !target.scheme.match("^sips?$")) {
                this.logger.error("SIP.js can only automatically follow SIP refer target");
                this.reject();
                return;
            }
            var inviteOptions = options.inviteOptions || {};
            var extraHeaders = (inviteOptions.extraHeaders || []).slice();
            if (this.replaces) {
                // decodeURIComponent is a holdover from 2c086eb4. Not sure that it is actually necessary
                extraHeaders.push("Replaces: " + decodeURIComponent(this.replaces));
            }
            if (this.referredBy) {
                extraHeaders.push("Referred-By: " + this.referredBy);
            }
            inviteOptions.extraHeaders = extraHeaders;
            target.clearHeaders();
            this.targetSession = this.ua.invite(target.toString(), inviteOptions, modifiers);
            this.emit("referInviteSent", this);
            if (this.targetSession) {
                this.targetSession.once("progress", function (response) {
                    var statusCode = response.statusCode || 100;
                    var reasonPhrase = response.reasonPhrase;
                    _this.sendNotify(("SIP/2.0 " + statusCode + " " + reasonPhrase).trim());
                    _this.emit("referProgress", _this);
                    if (_this.referredSession) {
                        _this.referredSession.emit("referProgress", _this);
                    }
                });
                this.targetSession.once("accepted", function () {
                    _this.logger.log("Successfully followed the refer");
                    _this.sendNotify("SIP/2.0 200 OK");
                    _this.emit("referAccepted", _this);
                    if (_this.referredSession) {
                        _this.referredSession.emit("referAccepted", _this);
                    }
                });
                var referFailed = function (response) {
                    if (_this.status === Enums_1.SessionStatus.STATUS_TERMINATED) {
                        return; // No throw here because it is possible this gets called multiple times
                    }
                    _this.logger.log("Refer was not successful. Resuming session");
                    if (response && response.statusCode === 429) {
                        _this.logger.log("Alerting referrer that identity is required.");
                        _this.sendNotify("SIP/2.0 429 Provide Referrer Identity");
                        return;
                    }
                    _this.sendNotify("SIP/2.0 603 Declined");
                    // Must change the status after sending the final Notify or it will not send due to check
                    _this.status = Enums_1.SessionStatus.STATUS_TERMINATED;
                    _this.emit("referRejected", _this);
                    if (_this.referredSession) {
                        _this.referredSession.emit("referRejected");
                    }
                };
                this.targetSession.once("rejected", referFailed);
                this.targetSession.once("failed", referFailed);
            }
        }
        else {
            this.logger.log("Accepted refer, but did not automatically follow it");
            this.sendNotify("SIP/2.0 200 OK");
            this.emit("referAccepted", this);
            if (this.referredSession) {
                this.referredSession.emit("referAccepted", this);
            }
        }
    };
    ReferServerContext.prototype.sendNotify = function (body) {
        if (this.status !== Enums_1.SessionStatus.STATUS_ANSWERED) {
            throw new Exceptions_1.Exceptions.InvalidStateError(this.status);
        }
        if (Grammar_1.Grammar.parse(body, "sipfrag") === -1) {
            throw new Error("sipfrag body is required to send notify for refer");
        }
        var request = new SIPMessage_1.OutgoingRequest(Constants_1.C.NOTIFY, this.remoteTarget, this.ua, {
            cseq: this.cseq += 1,
            callId: this.callId,
            fromUri: this.fromUri,
            fromTag: this.fromTag,
            toUri: this.toUri,
            toTag: this.toTag,
            routeSet: this.routeSet
        }, [
            "Event: refer",
            "Subscription-State: terminated",
            "Content-Type: message/sipfrag"
        ], body);
        new RequestSender_1.RequestSender({
            request: request,
            onRequestTimeout: function () {
                return;
            },
            onTransportError: function () {
                return;
            },
            receiveResponse: function () {
                return;
            }
        }, this.ua).send();
    };
    ReferServerContext.prototype.on = function (name, callback) { return _super.prototype.on.call(this, name, callback); };
    return ReferServerContext;
}(ServerContext_1.ServerContext));
exports.ReferServerContext = ReferServerContext;


/***/ }),
/* 27 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";

var __extends = (this && this.__extends) || (function () {
    var extendStatics = function (d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
var events_1 = __webpack_require__(2);
var Constants_1 = __webpack_require__(3);
var Enums_1 = __webpack_require__(5);
var Exceptions_1 = __webpack_require__(8);
var Utils_1 = __webpack_require__(15);
/**
 * @class DTMF
 * @param {SIP.Session} session
 */
var DTMF = /** @class */ (function (_super) {
    __extends(DTMF, _super);
    function DTMF(session, tone, options) {
        if (options === void 0) { options = {}; }
        var _this = _super.call(this) || this;
        _this.C = {
            MIN_DURATION: 70,
            MAX_DURATION: 6000,
            DEFAULT_DURATION: 100,
            MIN_INTER_TONE_GAP: 50,
            DEFAULT_INTER_TONE_GAP: 500
        };
        _this.type = Enums_1.TypeStrings.DTMF;
        if (tone === undefined) {
            throw new TypeError("Not enough arguments");
        }
        _this.logger = session.ua.getLogger("sip.invitecontext.dtmf", session.id);
        _this.owner = session;
        // Check tone type
        if (typeof tone === "string") {
            tone = tone.toUpperCase();
        }
        else if (typeof tone === "number") {
            tone = tone.toString();
        }
        else {
            throw new TypeError("Invalid tone: " + tone);
        }
        // Check tone value
        if (!tone.match(/^[0-9A-D#*]$/)) {
            throw new TypeError("Invalid tone: " + tone);
        }
        else {
            _this.tone = tone;
        }
        var duration = options.duration;
        var interToneGap = options.interToneGap;
        // Check duration
        if (duration && !Utils_1.Utils.isDecimal(duration)) {
            throw new TypeError("Invalid tone duration: " + duration);
        }
        else if (!duration) {
            duration = _this.C.DEFAULT_DURATION;
        }
        else if (duration < _this.C.MIN_DURATION) {
            _this.logger.warn("'duration' value is lower than the minimum allowed, setting it to " +
                _this.C.MIN_DURATION + " milliseconds");
            duration = _this.C.MIN_DURATION;
        }
        else if (duration > _this.C.MAX_DURATION) {
            _this.logger.warn("'duration' value is greater than the maximum allowed, setting it to " +
                _this.C.MAX_DURATION + " milliseconds");
            duration = _this.C.MAX_DURATION;
        }
        else {
            duration = Math.abs(duration);
        }
        _this.duration = duration;
        // Check interToneGap
        if (interToneGap && !Utils_1.Utils.isDecimal(interToneGap)) {
            throw new TypeError("Invalid interToneGap: " + interToneGap);
        }
        else if (!interToneGap) {
            interToneGap = _this.C.DEFAULT_INTER_TONE_GAP;
        }
        else if (interToneGap < _this.C.MIN_INTER_TONE_GAP) {
            _this.logger.warn("'interToneGap' value is lower than the minimum allowed, setting it to " +
                _this.C.MIN_INTER_TONE_GAP + " milliseconds");
            interToneGap = _this.C.MIN_INTER_TONE_GAP;
        }
        else {
            interToneGap = Math.abs(interToneGap);
        }
        _this.interToneGap = interToneGap;
        return _this;
    }
    DTMF.prototype.send = function (options) {
        if (options === void 0) { options = {}; }
        // Check RTCSession Status
        if (this.owner.status !== Enums_1.SessionStatus.STATUS_CONFIRMED &&
            this.owner.status !== Enums_1.SessionStatus.STATUS_WAITING_FOR_ACK) {
            throw new Exceptions_1.Exceptions.InvalidStateError(this.owner.status);
        }
        // Get DTMF options
        var extraHeaders = options.extraHeaders ? options.extraHeaders.slice() : [];
        var body = {
            contentType: "application/dtmf-relay",
            body: "Signal= " + this.tone + "\r\nDuration= " + this.duration
        };
        if (this.owner.dialog) {
            var request = this.owner.dialog.sendRequest(this, Constants_1.C.INFO, {
                extraHeaders: extraHeaders,
                body: body
            });
            this.owner.emit("dtmf", request, this);
        }
    };
    DTMF.prototype.init_incoming = function (request) {
        request.reply(200);
        if (!this.tone || !this.duration) {
            this.logger.warn("invalid INFO DTMF received, discarded");
        }
        else {
            this.owner.emit("dtmf", request, this);
        }
    };
    DTMF.prototype.receiveResponse = function (response) {
        var statusCode = response && response.statusCode ? response.statusCode : 0;
        switch (true) {
            case /^1[0-9]{2}$/.test(statusCode.toString()):
                // Ignore provisional responses.
                break;
            case /^2[0-9]{2}$/.test(statusCode.toString()):
                this.emit("succeeded", {
                    originator: "remote",
                    response: response
                });
                break;
            default:
                var cause = Utils_1.Utils.sipErrorCause(statusCode);
                this.emit("failed", response, cause);
                break;
        }
    };
    DTMF.prototype.onRequestTimeout = function () {
        this.emit("failed", undefined, Constants_1.C.causes.REQUEST_TIMEOUT);
        this.owner.onRequestTimeout();
    };
    DTMF.prototype.onTransportError = function () {
        this.emit("failed", undefined, Constants_1.C.causes.CONNECTION_ERROR);
        this.owner.onTransportError();
    };
    DTMF.prototype.onDialogError = function (response) {
        this.emit("failed", response, Constants_1.C.causes.DIALOG_ERROR);
        this.owner.onDialogError(response);
    };
    return DTMF;
}(events_1.EventEmitter));
exports.DTMF = DTMF;


/***/ }),
/* 28 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";

var __extends = (this && this.__extends) || (function () {
    var extendStatics = function (d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
var ClientContext_1 = __webpack_require__(1);
var Constants_1 = __webpack_require__(3);
var Dialogs_1 = __webpack_require__(16);
var Enums_1 = __webpack_require__(5);
var Timers_1 = __webpack_require__(9);
var Utils_1 = __webpack_require__(15);
/**
 * SIP Subscriber (SIP-Specific Event Notifications RFC6665)
 * @class Class creating a SIP Subscription.
 */
var Subscription = /** @class */ (function (_super) {
    __extends(Subscription, _super);
    function Subscription(ua, target, event, options) {
        if (options === void 0) { options = {}; }
        var _this = this;
        if (!event) {
            throw new TypeError("Event necessary to create a subscription.");
        }
        options.extraHeaders = (options.extraHeaders || []).slice();
        var expires;
        if (typeof options.expires !== "number") {
            ua.logger.warn("expires must be a number. Using default of 3600.");
            expires = 3600;
        }
        else {
            expires = options.expires;
        }
        options.extraHeaders.push("Event: " + event);
        options.extraHeaders.push("Expires: " + expires);
        options.extraHeaders.push("Contact: " + ua.contact.toString());
        // was UA.C.ALLOWED_METHODS, removed due to circular dependency
        options.extraHeaders.push("Allow: " + [
            "ACK",
            "CANCEL",
            "INVITE",
            "MESSAGE",
            "BYE",
            "OPTIONS",
            "INFO",
            "NOTIFY",
            "REFER"
        ].toString());
        _this = _super.call(this, ua, Constants_1.C.SUBSCRIBE, target, options) || this;
        _this.type = Enums_1.TypeStrings.Subscription;
        // TODO: check for valid events here probably make a list in SIP.C; or leave it up to app to check?
        // The check may need to/should probably occur on the other side,
        _this.event = event;
        _this.requestedExpires = expires;
        _this.state = "init";
        _this.contact = ua.contact.toString();
        _this.extraHeaders = options.extraHeaders;
        _this.logger = ua.getLogger("sip.subscription");
        _this.expires = expires;
        _this.timers = { N: undefined, subDuration: undefined };
        _this.errorCodes = [404, 405, 410, 416, 480, 481, 482, 483, 484, 485, 489, 501, 604];
        return _this;
    }
    Subscription.prototype.subscribe = function () {
        var _this = this;
        // these states point to an existing subscription, no subscribe is necessary
        if (this.state === "active") {
            this.refresh();
            return this;
        }
        else if (this.state === "notify_wait") {
            return this;
        }
        clearTimeout(this.timers.subDuration);
        clearTimeout(this.timers.N);
        this.timers.N = setTimeout(function () { return _this.timer_fire(); }, Timers_1.Timers.TIMER_N);
        if (this.request && this.request.from) {
            this.ua.earlySubscriptions[this.request.callId + this.request.from.parameters.tag + this.event] = this;
        }
        this.send();
        this.state = "notify_wait";
        return this;
    };
    Subscription.prototype.refresh = function () {
        if (this.state === "terminated" || this.state === "pending" || this.state === "notify_wait" || !this.dialog) {
            return;
        }
        this.dialog.sendRequest(this, Constants_1.C.SUBSCRIBE, {
            extraHeaders: this.extraHeaders,
            body: this.body
        });
    };
    Subscription.prototype.receiveResponse = function (response) {
        var _this = this;
        var statusCode = response.statusCode ? response.statusCode : 0;
        var cause = Utils_1.Utils.getReasonPhrase(statusCode);
        if ((this.state === "notify_wait" && statusCode >= 300) ||
            (this.state !== "notify_wait" && this.errorCodes.indexOf(statusCode) !== -1)) {
            this.failed(response, undefined);
        }
        else if (/^2[0-9]{2}$/.test(statusCode.toString())) {
            this.emit("accepted", response, cause);
            // As we don't support RFC 5839 or other extensions where the NOTIFY is optional, timer N will not be cleared
            // clearTimeout(this.timers.N);
            var expires = response.getHeader("Expires");
            if (expires && Number(expires) <= this.requestedExpires) {
                // Preserve new expires value for subsequent requests
                this.expires = Number(expires);
                this.timers.subDuration = setTimeout(function () { return _this.refresh(); }, Number(expires) * 900);
            }
            else {
                if (!expires) {
                    this.logger.warn("Expires header missing in a 200-class response to SUBSCRIBE");
                    this.failed(response, "Expires Header Missing");
                }
                else {
                    this.logger.warn("Expires header in a 200-class response to" +
                        " SUBSCRIBE with a higher value than the one in the request");
                    this.failed(response, "Invalid Expires Header");
                }
            }
        }
        else if (statusCode > 300) {
            this.emit("failed", response, cause);
            this.emit("rejected", response, cause);
        }
    };
    Subscription.prototype.unsubscribe = function () {
        var _this = this;
        var extraHeaders = [];
        this.state = "terminated";
        extraHeaders.push("Event: " + this.event);
        extraHeaders.push("Expires: 0");
        extraHeaders.push("Contact: " + this.contact);
        // was UA.C.ALLOWED_METHODS, removed due to circular dependency
        extraHeaders.push("Allow: " + [
            "ACK",
            "CANCEL",
            "INVITE",
            "MESSAGE",
            "BYE",
            "OPTIONS",
            "INFO",
            "NOTIFY",
            "REFER"
        ].toString());
        // makes sure expires isn't set, and other typical resubscribe behavior
        this.receiveResponse = function () { };
        if (this.dialog) {
            this.dialog.sendRequest(this, Constants_1.C.SUBSCRIBE, {
                extraHeaders: extraHeaders,
                body: this.body
            });
        }
        clearTimeout(this.timers.subDuration);
        clearTimeout(this.timers.N);
        this.timers.N = setTimeout(function () { return _this.timer_fire(); }, Timers_1.Timers.TIMER_N);
        this.emit("terminated");
    };
    Subscription.prototype.receiveRequest = function (request) {
        var _this = this;
        var subState;
        var setExpiresTimeout = function () {
            if (subState.expires) {
                clearTimeout(_this.timers.subDuration);
                subState.expires = Math.min(_this.expires, Math.max(subState.expires, 0));
                _this.timers.subDuration = setTimeout(function () { return _this.refresh(); }, subState.expires * 900);
            }
        };
        if (!this.matchEvent(request)) { // checks event and subscription_state headers
            request.reply(489);
            return;
        }
        if (!this.dialog) {
            if (this.createConfirmedDialog(request, "UAS")) {
                if (this.dialog) {
                    this.id = this.dialog.id.toString();
                    if (this.request && this.request.from) {
                        delete this.ua.earlySubscriptions[this.request.callId + this.request.from.parameters.tag + this.event];
                        this.ua.subscriptions[this.id || ""] = this;
                        // UPDATE ROUTE SET TO BE BACKWARDS COMPATIBLE?
                    }
                }
            }
        }
        subState = request.parseHeader("Subscription-State");
        request.reply(200);
        clearTimeout(this.timers.N);
        this.emit("notify", { request: request });
        // if we've set state to terminated, no further processing should take place
        // and we are only interested in cleaning up after the appropriate NOTIFY
        if (this.state === "terminated") {
            if (subState.state === "terminated") {
                this.terminateDialog();
                clearTimeout(this.timers.N);
                clearTimeout(this.timers.subDuration);
                delete this.ua.subscriptions[this.id || ""];
            }
            return;
        }
        switch (subState.state) {
            case "active":
                this.state = "active";
                setExpiresTimeout();
                break;
            case "pending":
                if (this.state === "notify_wait") {
                    setExpiresTimeout();
                }
                this.state = "pending";
                break;
            case "terminated":
                clearTimeout(this.timers.subDuration);
                if (subState.reason) {
                    this.logger.log("terminating subscription with reason " + subState.reason);
                    switch (subState.reason) {
                        case "deactivated":
                        case "timeout":
                            this.subscribe();
                            return;
                        case "probation":
                        case "giveup":
                            if (subState.params && subState.params["retry-after"]) {
                                this.timers.subDuration = setTimeout(function () { return _this.subscribe(); }, subState.params["retry-after"]);
                            }
                            else {
                                this.subscribe();
                            }
                            return;
                        case "rejected":
                        case "noresource":
                        case "invariant":
                            break;
                    }
                }
                this.close();
                break;
        }
    };
    Subscription.prototype.close = function () {
        if (this.state === "notify_wait") {
            this.state = "terminated";
            clearTimeout(this.timers.N);
            clearTimeout(this.timers.subDuration);
            this.receiveResponse = function () { };
            if (this.request && this.request.from) {
                delete this.ua.earlySubscriptions[this.request.callId + this.request.from.parameters.tag + this.event];
            }
            this.emit("terminated");
        }
        else if (this.state !== "terminated") {
            this.unsubscribe();
        }
    };
    Subscription.prototype.onDialogError = function (response) {
        this.failed(response, Constants_1.C.causes.DIALOG_ERROR);
    };
    Subscription.prototype.on = function (name, callback) { return _super.prototype.on.call(this, name, callback); };
    Subscription.prototype.timer_fire = function () {
        if (this.state === "terminated") {
            this.terminateDialog();
            clearTimeout(this.timers.N);
            clearTimeout(this.timers.subDuration);
            delete this.ua.subscriptions[this.id || ""];
        }
        else if (this.state === "notify_wait" || this.state === "pending") {
            this.close();
        }
        else {
            this.refresh();
        }
    };
    Subscription.prototype.createConfirmedDialog = function (message, type) {
        this.terminateDialog();
        var dialog = new Dialogs_1.Dialog(this, message, type);
        if (this.request) {
            dialog.inviteSeqnum = this.request.cseq;
            dialog.localSeqnum = this.request.cseq;
        }
        if (!dialog.error) {
            this.dialog = dialog;
            return true;
        }
        else {
            // Dialog not created due to an errora
            return false;
        }
    };
    Subscription.prototype.terminateDialog = function () {
        if (this.dialog) {
            delete this.ua.subscriptions[this.id || ""];
            this.dialog.terminate();
            delete this.dialog;
        }
    };
    Subscription.prototype.failed = function (response, cause) {
        this.close();
        this.emit("failed", response, cause);
        this.emit("rejected", response, cause);
        return this;
    };
    Subscription.prototype.matchEvent = function (request) {
        // Check mandatory header Event
        if (!request.hasHeader("Event")) {
            this.logger.warn("missing Event header");
            return false;
        }
        // Check mandatory header Subscription-State
        if (!request.hasHeader("Subscription-State")) {
            this.logger.warn("missing Subscription-State header");
            return false;
        }
        // Check whether the event in NOTIFY matches the event in SUBSCRIBE
        var event = request.parseHeader("event").event;
        if (this.event !== event) {
            this.logger.warn("event match failed");
            request.reply(481, "Event Match Failed");
            return false;
        }
        else {
            return true;
        }
    };
    return Subscription;
}(ClientContext_1.ClientContext));
exports.Subscription = Subscription;


/***/ }),
/* 29 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";

var __extends = (this && this.__extends) || (function () {
    var extendStatics = function (d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
var events_1 = __webpack_require__(2);
var Enums_1 = __webpack_require__(5);
/* Transport
 * @class Abstract transport layer parent class
 * @param {Logger} logger
 * @param {Object} [options]
 */
var Transport = /** @class */ (function (_super) {
    __extends(Transport, _super);
    function Transport(logger, options) {
        var _this = _super.call(this) || this;
        _this.type = Enums_1.TypeStrings.Transport;
        _this.logger = logger;
        return _this;
    }
    /**
     * Returns the promise designated by the child layer then emits a connected event.
     * Automatically emits an event upon resolution, unless overrideEvent is set. If you
     * override the event in this fashion, you should emit it in your implementation of connectPromise
     * @param {Object} [options]
     * @returns {Promise}
     */
    Transport.prototype.connect = function (options) {
        var _this = this;
        if (options === void 0) { options = {}; }
        return this.connectPromise(options).then(function (data) {
            if (!data.overrideEvent) {
                _this.emit("connected");
            }
        });
    };
    /**
     * Sends a message then emits a 'messageSent' event. Automatically emits an
     * event upon resolution, unless data.overrideEvent is set. If you override
     * the event in this fashion, you should emit it in your implementation of sendPromise
     * @param {String} msg
     * @param {Object} options
     * @returns {Promise}
     */
    Transport.prototype.send = function (msg, options) {
        var _this = this;
        if (options === void 0) { options = {}; }
        return this.sendPromise(msg).then(function (data) {
            if (!data.overrideEvent) {
                _this.emit("messageSent", data.msg);
            }
        });
    };
    /**
     * Returns the promise designated by the child layer then emits a
     * disconnected event. Automatically emits an event upon resolution,
     * unless overrideEvent is set. If you override the event in this fashion,
     * you should emit it in your implementation of disconnectPromise
     * @param {Object} [options]
     * @returns {Promise}
     */
    Transport.prototype.disconnect = function (options) {
        var _this = this;
        if (options === void 0) { options = {}; }
        return this.disconnectPromise(options).then(function (data) {
            if (!data.overrideEvent) {
                _this.emit("disconnected");
            }
        });
    };
    Transport.prototype.afterConnected = function (callback) {
        if (this.isConnected()) {
            callback();
        }
        else {
            this.once("connected", callback);
        }
    };
    /**
     * Returns a promise which resolves once the UA is connected. DEPRECATION WARNING: just use afterConnected()
     * @returns {Promise}
     */
    Transport.prototype.waitForConnected = function () {
        var _this = this;
        // tslint:disable-next-line:no-console
        console.warn("DEPRECATION WARNING Transport.waitForConnected(): use afterConnected() instead");
        return new Promise(function (resolve) {
            _this.afterConnected(resolve);
        });
    };
    return Transport;
}(events_1.EventEmitter));
exports.Transport = Transport;


/***/ }),
/* 30 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/* WEBPACK VAR INJECTION */(function(global) {
var __extends = (this && this.__extends) || (function () {
    var extendStatics = function (d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
var events_1 = __webpack_require__(2);
var ClientContext_1 = __webpack_require__(1);
var Constants_1 = __webpack_require__(3);
var DigestAuthentication_1 = __webpack_require__(17);
var Enums_1 = __webpack_require__(5);
var Exceptions_1 = __webpack_require__(8);
var Grammar_1 = __webpack_require__(11);
var LoggerFactory_1 = __webpack_require__(20);
var Parser_1 = __webpack_require__(21);
var PublishContext_1 = __webpack_require__(22);
var RegisterContext_1 = __webpack_require__(23);
var SanityCheck_1 = __webpack_require__(24);
var ServerContext_1 = __webpack_require__(25);
var Session_1 = __webpack_require__(26);
var SIPMessage_1 = __webpack_require__(10);
var Subscription_1 = __webpack_require__(28);
var Transactions_1 = __webpack_require__(7);
var URI_1 = __webpack_require__(14);
var Utils_1 = __webpack_require__(15);
var SessionDescriptionHandler_1 = __webpack_require__(32);
var Transport_1 = __webpack_require__(35);
var environment = global.window || global;
/**
 * @class Class creating a SIP User Agent.
 * @param {function returning SIP.sessionDescriptionHandler} [configuration.sessionDescriptionHandlerFactory]
 *  A function will be invoked by each of the UA's Sessions to build the sessionDescriptionHandler for that Session.
 *  If no (or a falsy) value is provided, each Session will use a default (WebRTC) sessionDescriptionHandler.
 */
var UA = /** @class */ (function (_super) {
    __extends(UA, _super);
    function UA(configuration) {
        var _this = _super.call(this) || this;
        _this.type = Enums_1.TypeStrings.UA;
        _this.log = new LoggerFactory_1.LoggerFactory();
        _this.logger = _this.getLogger("sip.ua");
        _this.cache = {
            credentials: {}
        };
        _this.configuration = {};
        _this.dialogs = {};
        // User actions outside any session/dialog (MESSAGE)
        _this.applicants = {};
        _this.data = {};
        _this.sessions = {};
        _this.subscriptions = {};
        _this.earlySubscriptions = {};
        _this.publishers = {};
        _this.status = Enums_1.UAStatus.STATUS_INIT;
        _this.transactions = {
            nist: {},
            nict: {},
            ist: {},
            ict: {}
        };
        /**
         * Load configuration
         *
         * @throws {SIP.Exceptions.ConfigurationError}
         * @throws {TypeError}
         */
        if (configuration === undefined) {
            configuration = {};
        }
        else if (typeof configuration === "string" || configuration instanceof String) {
            configuration = {
                uri: configuration
            };
        }
        // Apply log configuration if present
        if (configuration.log) {
            if (configuration.log.hasOwnProperty("builtinEnabled")) {
                _this.log.builtinEnabled = configuration.log.builtinEnabled;
            }
            if (configuration.log.hasOwnProperty("connector")) {
                _this.log.connector = configuration.log.connector;
            }
            if (configuration.log.hasOwnProperty("level")) {
                var level = configuration.log.level;
                var normalized = typeof level === "string" ? LoggerFactory_1.Levels[level] : level;
                // avoid setting level when invalid, use default level instead
                if (!normalized) {
                    _this.logger.error("Invalid \"level\" parameter value: " + JSON.stringify(level));
                }
                else {
                    _this.log.level = normalized;
                }
            }
        }
        try {
            _this.loadConfig(configuration);
        }
        catch (e) {
            _this.status = Enums_1.UAStatus.STATUS_NOT_READY;
            _this.error = UA.C.CONFIGURATION_ERROR;
            throw e;
        }
        // Initialize registerContext
        _this.registerContext = new RegisterContext_1.RegisterContext(_this, configuration.registerOptions);
        _this.registerContext.on("failed", _this.emit.bind(_this, "registrationFailed"));
        _this.registerContext.on("registered", _this.emit.bind(_this, "registered"));
        _this.registerContext.on("unregistered", _this.emit.bind(_this, "unregistered"));
        if (_this.configuration.autostart) {
            _this.start();
        }
        return _this;
    }
    Object.defineProperty(UA.prototype, "transactionsCount", {
        get: function () {
            var count = 0;
            for (var _i = 0, _a = ["nist", "nict", "ist", "ict"]; _i < _a.length; _i++) {
                var type = _a[_i];
                count += Object.keys(this.transactions[type]).length;
            }
            return count;
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(UA.prototype, "nictTransactionsCount", {
        get: function () {
            return Object.keys(this.transactions.nict).length;
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(UA.prototype, "nistTransactionsCount", {
        get: function () {
            return Object.keys(this.transactions.nist).length;
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(UA.prototype, "ictTransactionsCount", {
        get: function () {
            return Object.keys(this.transactions.ict).length;
        },
        enumerable: true,
        configurable: true
    });
    Object.defineProperty(UA.prototype, "istTransactionsCount", {
        get: function () {
            return Object.keys(this.transactions.ist).length;
        },
        enumerable: true,
        configurable: true
    });
    // =================
    //  High Level API
    // =================
    UA.prototype.register = function (options) {
        if (options === void 0) { options = {}; }
        if (options.register) {
            this.configuration.register = true;
        }
        this.registerContext.register(options);
        return this;
    };
    /**
     * Unregister.
     *
     * @param {Boolean} [all] unregister all user bindings.
     *
     */
    UA.prototype.unregister = function (options) {
        var _this = this;
        this.configuration.register = false;
        if (this.transport) {
            this.transport.afterConnected(function () {
                _this.registerContext.unregister(options);
            });
        }
        return this;
    };
    UA.prototype.isRegistered = function () {
        return this.registerContext.registered;
    };
    /**
     * Make an outgoing call.
     *
     * @param {String} target
     * @param {Object} views
     * @param {Object} [options.media] gets passed to SIP.sessionDescriptionHandler.getDescription as mediaHint
     *
     * @throws {TypeError}
     *
     */
    UA.prototype.invite = function (target, options, modifiers) {
        var _this = this;
        var context = new Session_1.InviteClientContext(this, target, options, modifiers);
        // Delay sending actual invite until the next 'tick' if we are already
        // connected, so that API consumers can register to events fired by the
        // the session.
        if (this.transport) {
            this.transport.afterConnected(function () {
                context.invite();
                _this.emit("inviteSent", context);
            });
        }
        return context;
    };
    UA.prototype.subscribe = function (target, event, options) {
        var sub = new Subscription_1.Subscription(this, target, event, options);
        if (this.transport) {
            this.transport.afterConnected(function () { return sub.subscribe(); });
        }
        return sub;
    };
    /**
     * Send PUBLISH Event State Publication (RFC3903)
     *
     * @param {String} target
     * @param {String} event
     * @param {String} body
     * @param {Object} [options]
     *
     * @throws {SIP.Exceptions.MethodParameterError}
     */
    UA.prototype.publish = function (target, event, body, options) {
        var pub = new PublishContext_1.PublishContext(this, target, event, options);
        if (this.transport) {
            this.transport.afterConnected(function () {
                pub.publish(body);
            });
        }
        return pub;
    };
    /**
     * Send a message.
     *
     * @param {String} target
     * @param {String} body
     * @param {Object} [options]
     *
     * @throws {TypeError}
     */
    UA.prototype.message = function (target, body, options) {
        if (options === void 0) { options = {}; }
        if (body === undefined) {
            throw new TypeError("Not enough arguments");
        }
        // There is no Message module, so it is okay that the UA handles defaults here.
        options.contentType = options.contentType || "text/plain";
        options.body = body;
        return this.request(Constants_1.C.MESSAGE, target, options);
    };
    UA.prototype.request = function (method, target, options) {
        var req = new ClientContext_1.ClientContext(this, method, target, options);
        if (this.transport) {
            this.transport.afterConnected(function () { return req.send(); });
        }
        return req;
    };
    /**
     * Gracefully close.
     */
    UA.prototype.stop = function () {
        var _this = this;
        this.logger.log("user requested closure...");
        if (this.status === Enums_1.UAStatus.STATUS_USER_CLOSED) {
            this.logger.warn("UA already closed");
            return this;
        }
        // Close registerContext
        this.logger.log("closing registerContext");
        this.registerContext.close();
        // Run  _terminate_ on every Session
        for (var session in this.sessions) {
            if (this.sessions[session]) {
                this.logger.log("closing session " + session);
                this.sessions[session].terminate();
            }
        }
        // Run _close_ on every confirmed Subscription
        for (var subscription in this.subscriptions) {
            if (this.subscriptions[subscription]) {
                this.logger.log("unsubscribing from subscription " + subscription);
                this.subscriptions[subscription].close();
            }
        }
        // Run _close_ on every early Subscription
        for (var earlySubscription in this.earlySubscriptions) {
            if (this.earlySubscriptions[earlySubscription]) {
                this.logger.log("unsubscribing from early subscription " + earlySubscription);
                this.earlySubscriptions[earlySubscription].close();
            }
        }
        // Run _close_ on every Publisher
        for (var publisher in this.publishers) {
            if (this.publishers[publisher]) {
                this.logger.log("unpublish " + publisher);
                this.publishers[publisher].close();
            }
        }
        // Run  _close_ on every applicant
        for (var applicant in this.applicants) {
            if (this.applicants[applicant]) {
                this.applicants[applicant].close();
            }
        }
        this.status = Enums_1.UAStatus.STATUS_USER_CLOSED;
        /*
         * If the remaining transactions are all INVITE transactions, there is no need to
         * wait anymore because every session has already been closed by this method.
         * - locally originated sessions where terminated (CANCEL or BYE)
         * - remotely originated sessions where rejected (4XX) or terminated (BYE)
         * Remaining INVITE transactions belong tho sessions that where answered. This are in
         * 'accepted' state due to timers 'L' and 'M' defined in [RFC 6026]
         */
        if (this.nistTransactionsCount === 0 && this.nictTransactionsCount === 0 && this.transport) {
            this.transport.disconnect();
        }
        else {
            var transactionsListener_1 = function () {
                if (_this.nistTransactionsCount === 0 && _this.nictTransactionsCount === 0) {
                    _this.removeListener("transactionDestroyed", transactionsListener_1);
                    if (_this.transport) {
                        _this.transport.disconnect();
                    }
                }
            };
            this.on("transactionDestroyed", transactionsListener_1);
        }
        if (typeof environment.removeEventListener === "function") {
            // Google Chrome Packaged Apps don't allow 'unload' listeners:
            // unload is not available in packaged apps
            if (!(global.chrome && global.chrome.app && global.chrome.app.runtime)) {
                environment.removeEventListener("unload", this.environListener);
            }
        }
        return this;
    };
    /**
     * Connect to the WS server if status = STATUS_INIT.
     * Resume UA after being closed.
     *
     */
    UA.prototype.start = function () {
        var _this = this;
        this.logger.log("user requested startup...");
        if (this.status === Enums_1.UAStatus.STATUS_INIT) {
            this.status = Enums_1.UAStatus.STATUS_STARTING;
            if (!this.configuration.transportConstructor) {
                throw new Exceptions_1.Exceptions.TransportError("Transport constructor not set");
            }
            this.transport = new this.configuration.transportConstructor(this.getLogger("sip.transport"), this.configuration.transportOptions);
            this.setTransportListeners();
            this.emit("transportCreated", this.transport);
            this.transport.connect();
        }
        else if (this.status === Enums_1.UAStatus.STATUS_USER_CLOSED) {
            this.logger.log("resuming");
            this.status = Enums_1.UAStatus.STATUS_READY;
            if (this.transport) {
                this.transport.connect();
            }
        }
        else if (this.status === Enums_1.UAStatus.STATUS_STARTING) {
            this.logger.log("UA is in STARTING status, not opening new connection");
        }
        else if (this.status === Enums_1.UAStatus.STATUS_READY) {
            this.logger.log("UA is in READY status, not resuming");
        }
        else {
            this.logger.error("Connection is down. Auto-Recovery system is trying to connect");
        }
        if (this.configuration.autostop && typeof environment.addEventListener === "function") {
            // Google Chrome Packaged Apps don't allow 'unload' listeners:
            // unload is not available in packaged apps
            if (!(global.chrome && global.chrome.app && global.chrome.app.runtime)) {
                this.environListener = this.stop;
                environment.addEventListener("unload", function () { return _this.environListener(); });
            }
        }
        return this;
    };
    /**
     * Normalize a string into a valid SIP request URI
     *
     * @param {String} target
     *
     * @returns {SIP.URI|undefined}
     */
    UA.prototype.normalizeTarget = function (target) {
        return Utils_1.Utils.normalizeTarget(target, this.configuration.hostportParams);
    };
    UA.prototype.getLogger = function (category, label) {
        return this.log.getLogger(category, label);
    };
    UA.prototype.getLoggerFactory = function () {
        return this.log;
    };
    // TODO: Transaction matching currently works circumstanially.
    //
    // 17.1.3 Matching Responses to Client Transactions
    //
    // When the transport layer in the client receives a response, it has to
    // determine which client transaction will handle the response, so that
    // the processing of Sections 17.1.1 and 17.1.2 can take place.  The
    // branch parameter in the top Via header field is used for this
    // purpose.  A response matches a client transaction under two
    // conditions:
    //
    //    1.  If the response has the same value of the branch parameter in
    //        the top Via header field as the branch parameter in the top
    //        Via header field of the request that created the transaction.
    //
    //    2.  If the method parameter in the CSeq header field matches the
    //        method of the request that created the transaction.  The
    //        method is needed since a CANCEL request constitutes a
    //        different transaction, but shares the same value of the branch
    //        parameter.
    /**
     * new Transaction
     * @private
     * @param {SIP.Transaction} transaction.
     */
    UA.prototype.newTransaction = function (transaction) {
        this.transactions[transaction.kind][transaction.id] = transaction;
        this.emit("newTransaction", { transaction: transaction });
    };
    /**
     * destroy Transaction
     * @param {SIP.Transaction} transaction.
     */
    UA.prototype.destroyTransaction = function (transaction) {
        delete this.transactions[transaction.kind][transaction.id];
        this.emit("transactionDestroyed", { transaction: transaction });
    };
    /**
     * Get the session to which the request belongs to, if any.
     * @param {SIP.IncomingRequest} request.
     * @returns {SIP.OutgoingSession|SIP.IncomingSession|undefined}
     */
    UA.prototype.findSession = function (request) {
        return this.sessions[request.callId + request.fromTag] ||
            this.sessions[request.callId + request.toTag] ||
            undefined;
    };
    UA.prototype.on = function (name, callback) { return _super.prototype.on.call(this, name, callback); };
    // ===============================
    //  Private (For internal use)
    // ===============================
    UA.prototype.saveCredentials = function (credentials) {
        this.cache.credentials[credentials.realm] = this.cache.credentials[credentials.realm] || {};
        this.cache.credentials[credentials.realm][credentials.uri] = credentials;
        return this;
    };
    UA.prototype.getCredentials = function (request) {
        var realm = request.ruri.type === Enums_1.TypeStrings.URI ? request.ruri.host : "";
        if (realm && this.cache.credentials[realm] && this.cache.credentials[realm][request.ruri.toString()]) {
            var credentials = this.cache.credentials[realm][request.ruri.toString()];
            credentials.method = request.method;
            return credentials;
        }
    };
    // ==============================
    // Event Handlers
    // ==============================
    UA.prototype.onTransportError = function () {
        if (this.status === Enums_1.UAStatus.STATUS_USER_CLOSED) {
            return;
        }
        if (!this.error || this.error !== UA.C.NETWORK_ERROR) {
            this.status = Enums_1.UAStatus.STATUS_NOT_READY;
            this.error = UA.C.NETWORK_ERROR;
        }
    };
    /**
     * Helper function. Sets transport listeners
     */
    UA.prototype.setTransportListeners = function () {
        var _this = this;
        if (this.transport) {
            this.transport.on("connected", function () { return _this.onTransportConnected(); });
            this.transport.on("message", function (message) { return _this.onTransportReceiveMsg(message); });
            this.transport.on("transportError", function () { return _this.onTransportError(); });
        }
    };
    /**
     * Transport connection event.
     * @event
     * @param {SIP.Transport} transport.
     */
    UA.prototype.onTransportConnected = function () {
        var _this = this;
        if (this.configuration.register) {
            // In an effor to maintain behavior from when we "initialized" an
            // authentication factory, this is in a Promise.then
            Promise.resolve().then(function () { return _this.registerContext.register(); });
        }
    };
    /**
     * Handle SIP message received from the transport.
     * @param messageString The message.
     */
    UA.prototype.onTransportReceiveMsg = function (messageString) {
        var message = Parser_1.Parser.parseMessage(messageString, this);
        if (!message) {
            this.logger.warn("UA failed to parse incoming SIP message - discarding.");
            return;
        }
        if (this.status === Enums_1.UAStatus.STATUS_USER_CLOSED && message instanceof SIPMessage_1.IncomingRequest) {
            this.logger.warn("UA received message when status = USER_CLOSED - aborting");
            return;
        }
        if (!this.transport) {
            this.logger.warn("UA received message without transport - aborting");
            return;
        }
        if (!SanityCheck_1.SanityCheck.sanityCheck(message, this, this.transport)) {
            return;
        }
        if (message instanceof SIPMessage_1.IncomingRequest) {
            this.receiveRequestFromTransport(message);
            return;
        }
        if (message instanceof SIPMessage_1.IncomingResponse) {
            this.receiveResponseFromTransport(message);
            return;
        }
        throw new Error("Invalid message type.");
    };
    UA.prototype.receiveRequestFromTransport = function (request) {
        // FIXME: Bad hack. SIPMessage needs refactor.
        request.transport = this.transport;
        // FIXME: Configuration URI is a bad mix of tyes currently and needs to exist.
        if (!(this.configuration.uri instanceof URI_1.URI)) {
            throw new Error("Configuration URI not instance of URI.");
        }
        // FIXME: A request should always have an ruri
        if (!request.ruri) {
            throw new Error("Request ruri undefined.");
        }
        // If the Request-URI uses a scheme not supported by the UAS, it SHOULD
        // reject the request with a 416 (Unsupported URI Scheme) response.
        // https://tools.ietf.org/html/rfc3261#section-8.2.2.1
        if (request.ruri.scheme !== Constants_1.C.SIP) {
            request.reply_sl(416);
            return;
        }
        // If the Request-URI does not identify an address that the
        // UAS is willing to accept requests for, it SHOULD reject
        // the request with a 404 (Not Found) response.
        // https://tools.ietf.org/html/rfc3261#section-8.2.2.1
        var ruri = request.ruri;
        var ruriMatches = function (uri) {
            return !!uri && uri.user === ruri.user;
        };
        if (!ruriMatches(this.configuration.uri) &&
            !(ruriMatches(this.contact.uri) || ruriMatches(this.contact.pubGruu) || ruriMatches(this.contact.tempGruu))) {
            this.logger.warn("Request-URI does not point to us");
            if (request.method !== Constants_1.C.ACK) {
                request.reply_sl(404);
            }
            return;
        }
        // When a request is received from the network by the server, it has to
        // be matched to an existing transaction.  This is accomplished in the
        // following manner.
        //
        // The branch parameter in the topmost Via header field of the request
        // is examined.  If it is present and begins with the magic cookie
        // "z9hG4bK", the request was generated by a client transaction
        // compliant to this specification.  Therefore, the branch parameter
        // will be unique across all transactions sent by that client.  The
        // request matches a transaction if:
        //
        //    1. the branch parameter in the request is equal to the one in the
        //       top Via header field of the request that created the
        //       transaction, and
        //
        //    2. the sent-by value in the top Via of the request is equal to the
        //       one in the request that created the transaction, and
        //
        //    3. the method of the request matches the one that created the
        //       transaction, except for ACK, where the method of the request
        //       that created the transaction is INVITE.
        //
        // This matching rule applies to both INVITE and non-INVITE transactions
        // alike.
        //
        //    The sent-by value is used as part of the matching process because
        //    there could be accidental or malicious duplication of branch
        //    parameters from different clients.
        // https://tools.ietf.org/html/rfc3261#section-17.2.3
        // FIXME: The current transaction layer curently only matches on branch parameter.
        // Request matches branch parameter of an existing invite server transaction.
        var ist = this.transactions.ist[request.viaBranch];
        // Request matches branch parameter of an existing non-invite server transaction.
        var nist = this.transactions.nist[request.viaBranch];
        // The CANCEL method requests that the TU at the server side cancel a
        // pending transaction.  The TU determines the transaction to be
        // cancelled by taking the CANCEL request, and then assuming that the
        // request method is anything but CANCEL or ACK and applying the
        // transaction matching procedures of Section 17.2.3.  The matching
        // transaction is the one to be cancelled.
        // https://tools.ietf.org/html/rfc3261#section-9.2
        if (request.method === Constants_1.C.CANCEL) {
            if (ist || nist) {
                // Regardless of the method of the original request, as long as the
                // CANCEL matched an existing transaction, the UAS answers the CANCEL
                // request itself with a 200 (OK) response.
                // https://tools.ietf.org/html/rfc3261#section-9.2
                request.reply_sl(200);
                // If the transaction for the original request still exists, the behavior
                // of the UAS on receiving a CANCEL request depends on whether it has already
                // sent a final response for the original request. If it has, the CANCEL
                // request has no effect on the processing of the original request, no
                // effect on any session state, and no effect on the responses generated
                // for the original request. If the UAS has not issued a final response
                // for the original request, its behavior depends on the method of the
                // original request. If the original request was an INVITE, the UAS
                // SHOULD immediately respond to the INVITE with a 487 (Request
                // Terminated). A CANCEL request has no impact on the processing of
                // transactions with any other method defined in this specification.
                // https://tools.ietf.org/html/rfc3261#section-9.2
                if (ist && ist.state === Transactions_1.TransactionState.Proceeding) {
                    // TODO: Review this.
                    // The cancel request has been replied to, which is an exception.
                    this.receiveRequest(request);
                }
            }
            else {
                // If the UAS did not find a matching transaction for the CANCEL
                // according to the procedure above, it SHOULD respond to the CANCEL
                // with a 481 (Call Leg/Transaction Does Not Exist).
                // https://tools.ietf.org/html/rfc3261#section-9.2
                request.reply_sl(481);
            }
            return;
        }
        // When receiving an ACK that matches an existing INVITE server
        // transaction and that does not contain a branch parameter containing
        // the magic cookie defined in RFC 3261, the matching transaction MUST
        // be checked to see if it is in the "Accepted" state.  If it is, then
        // the ACK must be passed directly to the transaction user instead of
        // being absorbed by the transaction state machine.  This is necessary
        // as requests from RFC 2543 clients will not include a unique branch
        // parameter, and the mechanisms for calculating the transaction ID from
        // such a request will be the same for both INVITE and ACKs.
        // https://tools.ietf.org/html/rfc6026#section-6
        // Any ACKs received from the network while in the "Accepted" state MUST be
        // passed directly to the TU and not absorbed.
        // https://tools.ietf.org/html/rfc6026#section-7.1
        if (request.method === Constants_1.C.ACK) {
            if (ist && ist.state === Transactions_1.TransactionState.Accepted) {
                this.receiveRequest(request);
                return;
            }
        }
        // If a matching server transaction is found, the request is passed to that
        // transaction for processing.
        // https://tools.ietf.org/html/rfc6026#section-8.10
        if (ist) {
            ist.receiveRequest(request);
            return;
        }
        if (nist) {
            nist.receiveRequest(request);
            return;
        }
        // If no match is found, the request is passed to the core, which may decide to
        // construct a new server transaction for that request.
        // https://tools.ietf.org/html/rfc6026#section-8.10
        this.receiveRequest(request);
    };
    UA.prototype.receiveResponseFromTransport = function (response) {
        // When the transport layer in the client receives a response, it has to
        // determine which client transaction will handle the response, so that
        // the processing of Sections 17.1.1 and 17.1.2 can take place.  The
        // branch parameter in the top Via header field is used for this
        // purpose.  A response matches a client transaction under two
        // conditions:
        //
        //    1.  If the response has the same value of the branch parameter in
        //        the top Via header field as the branch parameter in the top
        //        Via header field of the request that created the transaction.
        //
        //    2.  If the method parameter in the CSeq header field matches the
        //        method of the request that created the transaction.  The
        //        method is needed since a CANCEL request constitutes a
        //        different transaction, but shares the same value of the branch
        //        parameter.
        // https://tools.ietf.org/html/rfc3261#section-17.1.3
        // The client transport uses the matching procedures of Section
        // 17.1.3 to attempt to match the response to an existing
        // transaction.  If there is a match, the response MUST be passed to
        // that transaction.  Otherwise, any element other than a stateless
        // proxy MUST silently discard the response.
        // https://tools.ietf.org/html/rfc6026#section-8.9
        var transaction;
        switch (response.method) {
            case Constants_1.C.INVITE:
                transaction = this.transactions.ict[response.viaBranch];
                break;
            case Constants_1.C.ACK:
                // Just in case ;-)
                break;
            default:
                transaction = this.transactions.nict[response.viaBranch];
                break;
        }
        if (!transaction) {
            var message = "Discarding unmatched " + response.statusCode + " response to " + response.method + " " + response.viaBranch + ".";
            this.logger.warn(message);
            return;
        }
        // FIXME: Bad hack. Potentially creating circular dependancy. SIPMessage needs refactor.
        response.transaction = transaction;
        // Pass incoming response to matching transaction.
        transaction.receiveResponse(response);
    };
    /**
     * Request reception
     * @private
     * @param {SIP.IncomingRequest} request.
     */
    UA.prototype.receiveRequest = function (request) {
        var _this = this;
        /* 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.
        */
        var method = request.method;
        var message;
        if (method === Constants_1.C.OPTIONS) {
            var transport = this.transport;
            if (!transport) {
                throw new Error("Transport undefined.");
            }
            var user = {
                loggerFactory: this.getLoggerFactory(),
                onStateChange: function (newState) {
                    if (newState === Transactions_1.TransactionState.Terminated) {
                        _this.destroyTransaction(optionsTransaction_1);
                    }
                },
                onTransportError: function (error) {
                    _this.logger.error(error.message);
                }
            };
            var optionsTransaction_1 = new Transactions_1.NonInviteServerTransaction(request, transport, user);
            this.newTransaction(optionsTransaction_1);
            request.reply(200, undefined, [
                "Allow: " + UA.C.ALLOWED_METHODS.toString(),
                "Accept: " + UA.C.ACCEPTED_BODY_TYPES.toString()
            ]);
        }
        else if (method === Constants_1.C.MESSAGE) {
            message = new ServerContext_1.ServerContext(this, request);
            message.body = request.body;
            message.contentType = request.getHeader("Content-Type") || "text/plain";
            request.reply(200, undefined);
            this.emit("message", message);
        }
        else if (method !== Constants_1.C.INVITE &&
            method !== Constants_1.C.ACK) {
            // Let those methods pass through to normal processing for now.
            message = new ServerContext_1.ServerContext(this, request);
        }
        // Initial Request
        if (!request.toTag) {
            switch (method) {
                case Constants_1.C.INVITE:
                    var replaces = this.configuration.replaces !== Constants_1.C.supported.UNSUPPORTED &&
                        request.parseHeader("replaces");
                    var replacedDialog = void 0;
                    if (replaces) {
                        replacedDialog = this.dialogs[replaces.call_id + replaces.replaces_to_tag + replaces.replaces_from_tag];
                        if (!replacedDialog) {
                            // Replaced header without a matching dialog, reject
                            request.reply_sl(481, undefined);
                            return;
                        }
                        else if (!(replacedDialog.owner.type === Enums_1.TypeStrings.Subscription) &&
                            replacedDialog.owner.status
                                === Enums_1.SessionStatus.STATUS_TERMINATED) {
                            request.reply_sl(603, undefined);
                            return;
                        }
                        else if (replacedDialog.state === Enums_1.DialogStatus.STATUS_CONFIRMED && replaces.earlyOnly) {
                            request.reply_sl(486, undefined);
                            return;
                        }
                    }
                    var newSession = new Session_1.InviteServerContext(this, request);
                    if (replacedDialog && !(replacedDialog.owner.type === Enums_1.TypeStrings.Subscription)) {
                        newSession.replacee = replacedDialog && replacedDialog.owner;
                    }
                    this.emit("invite", newSession);
                    break;
                case Constants_1.C.BYE:
                    // Out of dialog BYE received
                    request.reply(481);
                    break;
                case Constants_1.C.CANCEL:
                    var session = this.findSession(request);
                    if (session) {
                        session.receiveRequest(request);
                    }
                    else {
                        this.logger.warn("received CANCEL request for a non existent session");
                    }
                    break;
                case Constants_1.C.ACK:
                    /* Absorb it.
                    * ACK request without a corresponding Invite Transaction
                    * and without To tag.
                    */
                    break;
                case Constants_1.C.NOTIFY:
                    if (this.configuration.allowLegacyNotifications && this.listeners("notify").length > 0) {
                        request.reply(200, undefined);
                        this.emit("notify", { request: request });
                    }
                    else {
                        request.reply(481, "Subscription does not exist");
                    }
                    break;
                case Constants_1.C.REFER:
                    this.logger.log("Received an out of dialog refer");
                    if (this.configuration.allowOutOfDialogRefers) {
                        this.logger.log("Allow out of dialog refers is enabled on the UA");
                        var referContext = new Session_1.ReferServerContext(this, request);
                        if (this.listeners("outOfDialogReferRequested").length) {
                            this.emit("outOfDialogReferRequested", referContext);
                        }
                        else {
                            this.logger.log("No outOfDialogReferRequest listeners," +
                                " automatically accepting and following the out of dialog refer");
                            referContext.accept({ followRefer: true });
                        }
                        break;
                    }
                    request.reply(405);
                    break;
                default:
                    request.reply(405);
                    break;
            }
        }
        else { // In-dialog request
            var dialog_1 = this.findDialog(request);
            if (dialog_1) {
                if (method === Constants_1.C.INVITE) {
                    var transport = this.transport;
                    if (!transport) {
                        throw new Error("Transport undefined.");
                    }
                    var user = {
                        loggerFactory: this.log,
                        onStateChange: function (newState) {
                            if (newState === Transactions_1.TransactionState.Terminated) {
                                _this.destroyTransaction(ist_1);
                            }
                        },
                        onTransportError: function (error) {
                            _this.logger.error(error.message);
                            dialog_1.owner.onTransportError();
                        }
                    };
                    var ist_1 = new Transactions_1.InviteServerTransaction(request, transport, user);
                    this.newTransaction(ist_1);
                }
                dialog_1.receiveRequest(request);
            }
            else if (method === Constants_1.C.NOTIFY) {
                var session = this.findSession(request);
                var earlySubscription = this.findEarlySubscription(request);
                if (session) {
                    session.receiveRequest(request);
                }
                else if (earlySubscription) {
                    earlySubscription.receiveRequest(request);
                }
                else {
                    this.logger.warn("received NOTIFY request for a non existent session or subscription");
                    request.reply(481, "Subscription does not exist");
                }
            }
            else {
                /* 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.
                 */
                if (method !== Constants_1.C.ACK) {
                    request.reply(481);
                }
            }
        }
    };
    // =================
    // Utils
    // =================
    /**
     * Get the dialog to which the request belongs to, if any.
     * @param {SIP.IncomingRequest}
     * @returns {SIP.Dialog|undefined}
     */
    UA.prototype.findDialog = function (request) {
        return this.dialogs[request.callId + request.fromTag + request.toTag] ||
            this.dialogs[request.callId + request.toTag + request.fromTag] ||
            undefined;
    };
    /**
     * Get the subscription which has not been confirmed to which the request belongs to, if any
     * @param {SIP.IncomingRequest}
     * @returns {SIP.Subscription|undefined}
     */
    UA.prototype.findEarlySubscription = function (request) {
        return this.earlySubscriptions[request.callId + request.toTag + request.getHeader("event")] || undefined;
    };
    UA.prototype.checkAuthenticationFactory = function (authenticationFactory) {
        if (!(authenticationFactory instanceof Function)) {
            return;
        }
        if (!authenticationFactory.initialize) {
            authenticationFactory.initialize = function () {
                return Promise.resolve();
            };
        }
        return authenticationFactory;
    };
    /**
     * Configuration load.
     * returns {void}
     */
    UA.prototype.loadConfig = function (configuration) {
        var _this = this;
        // Settings and default values
        var settings = {
            /* Host address
             * Value to be set in Via sent_by and host part of Contact FQDN
             */
            viaHost: Utils_1.Utils.createRandomToken(12) + ".invalid",
            uri: new URI_1.URI("sip", "anonymous." + Utils_1.Utils.createRandomToken(6), "anonymous.invalid", undefined, undefined),
            // Custom Configuration Settings
            custom: {},
            // Display name
            displayName: "",
            // Password
            password: undefined,
            register: true,
            // Registration parameters
            registerOptions: {},
            // Transport related parameters
            transportConstructor: Transport_1.Transport,
            transportOptions: {},
            // string to be inserted into User-Agent request header
            userAgentString: Constants_1.C.USER_AGENT,
            // Session parameters
            noAnswerTimeout: 60,
            // Hacks
            hackViaTcp: false,
            iceServers: configuration.iceServers,
            hackIpInContact: false,
            hackWssInTransport: false,
            hackAllowUnregisteredOptionTags: false,
            // Session Description Handler Options
            sessionDescriptionHandlerFactoryOptions: {
                constraints: {},
                peerConnectionOptions: {}
            },
            extraSupported: [],
            contactName: configuration.authorizationUser,
            contactTransport: "ws",
            forceRport: false,
            // autostarting
            autostart: true,
            autostop: true,
            // Reliable Provisional Responses
            rel100: Constants_1.C.supported.UNSUPPORTED,
            // DTMF type: 'info' or 'rtp' (RFC 4733)
            // RTP Payload Spec: https://tools.ietf.org/html/rfc4733
            // WebRTC Audio Spec: https://tools.ietf.org/html/rfc7874
            dtmfType: Constants_1.C.dtmfType.INFO,
            // Replaces header (RFC 3891)
            // http://tools.ietf.org/html/rfc3891
            replaces: Constants_1.C.supported.UNSUPPORTED,
            sessionDescriptionHandlerFactory: SessionDescriptionHandler_1.SessionDescriptionHandler.defaultFactory,
            authenticationFactory: this.checkAuthenticationFactory(function (ua) {
                return new DigestAuthentication_1.DigestAuthentication(ua);
            }),
            allowLegacyNotifications: false,
            allowOutOfDialogRefers: false,
        };
        var configCheck = this.getConfigurationCheck();
        // Check Mandatory parameters
        for (var parameter in configCheck.mandatory) {
            if (!configuration.hasOwnProperty(parameter)) {
                throw new Exceptions_1.Exceptions.ConfigurationError(parameter);
            }
            else {
                var value = configuration[parameter];
                var checkedValue = configCheck.mandatory[parameter](value);
                if (checkedValue !== undefined) {
                    settings[parameter] = checkedValue;
                }
                else {
                    throw new Exceptions_1.Exceptions.ConfigurationError(parameter, value);
                }
            }
        }
        // Check Optional parameters
        for (var parameter in configCheck.optional) {
            if (configuration.hasOwnProperty(parameter)) {
                var value = configuration[parameter];
                // If the parameter value is an empty array, but shouldn't be, apply its default value.
                // If the parameter value is null, empty string, or undefined then apply its default value.
                // If it's a number with NaN value then also apply its default value.
                // NOTE: JS does not allow "value === NaN", the following does the work:
                if ((value instanceof Array && value.length === 0) ||
                    (value === null || value === "" || value === undefined) ||
                    (typeof (value) === "number" && isNaN(value))) {
                    continue;
                }
                var checkedValue = configCheck.optional[parameter](value);
                if (checkedValue !== undefined) {
                    settings[parameter] = checkedValue;
                }
                else {
                    throw new Exceptions_1.Exceptions.ConfigurationError(parameter, value);
                }
            }
        }
        // Post Configuration Process
        // Allow passing 0 number as displayName.
        if (settings.displayName === 0) {
            settings.displayName = "0";
        }
        // sipjsId instance parameter. Static random tag of length 5
        settings.sipjsId = Utils_1.Utils.createRandomToken(5);
        // String containing settings.uri without scheme and user.
        var hostportParams = settings.uri.clone();
        hostportParams.user = undefined;
        settings.hostportParams = hostportParams.toRaw().replace(/^sip:/i, "");
        /* Check whether authorizationUser is explicitly defined.
         * Take 'settings.uri.user' value if not.
         */
        if (!settings.authorizationUser) {
            settings.authorizationUser = settings.uri.user;
        }
        // User noAnswerTimeout
        settings.noAnswerTimeout = settings.noAnswerTimeout * 1000;
        // Via Host
        if (settings.hackIpInContact) {
            if (typeof settings.hackIpInContact === "boolean") {
                var from = 1;
                var to = 254;
                var octet = Math.floor(Math.random() * (to - from + 1) + from);
                // random Test-Net IP (http://tools.ietf.org/html/rfc5735)
                settings.viaHost = "192.0.2." + octet;
            }
            else if (typeof settings.hackIpInContact === "string") {
                settings.viaHost = settings.hackIpInContact;
            }
        }
        // Contact transport parameter
        if (settings.hackWssInTransport) {
            settings.contactTransport = "wss";
        }
        this.contact = {
            pubGruu: undefined,
            tempGruu: undefined,
            uri: new URI_1.URI("sip", settings.contactName, settings.viaHost, undefined, { transport: settings.contactTransport }),
            toString: function (options) {
                if (options === void 0) { options = {}; }
                var anonymous = options.anonymous || false;
                var outbound = options.outbound || false;
                var contact = "<";
                if (anonymous) {
                    contact += (_this.contact.tempGruu ||
                        ("sip:anonymous@anonymous.invalid;transport=" + settings.contactTransport)).toString();
                }
                else {
                    contact += (_this.contact.pubGruu || _this.contact.uri).toString();
                }
                if (outbound) {
                    contact += ";ob";
                }
                contact += ">";
                return contact;
            }
        };
        var skeleton = {};
        // Fill the value of the configuration_skeleton
        for (var parameter in settings) {
            if (settings.hasOwnProperty(parameter)) {
                skeleton[parameter] = settings[parameter];
            }
        }
        Object.assign(this.configuration, skeleton);
        this.logger.log("configuration parameters after validation:");
        for (var parameter in settings) {
            if (settings.hasOwnProperty(parameter)) {
                switch (parameter) {
                    case "uri":
                    case "sessionDescriptionHandlerFactory":
                        this.logger.log("· " + parameter + ": " + settings[parameter]);
                        break;
                    case "password":
                        this.logger.log("· " + parameter + ": " + "NOT SHOWN");
                        break;
                    case "transportConstructor":
                        this.logger.log("· " + parameter + ": " + settings[parameter].name);
                        break;
                    default:
                        this.logger.log("· " + parameter + ": " + JSON.stringify(settings[parameter]));
                }
            }
        }
        return;
    };
    /**
     * Configuration checker.
     * @return {Boolean}
     */
    UA.prototype.getConfigurationCheck = function () {
        return {
            mandatory: {},
            optional: {
                uri: function (uri) {
                    if (!(/^sip:/i).test(uri)) {
                        uri = Constants_1.C.SIP + ":" + uri;
                    }
                    var parsed = Grammar_1.Grammar.URIParse(uri);
                    if (!parsed || !parsed.user) {
                        return;
                    }
                    else {
                        return parsed;
                    }
                },
                transportConstructor: function (transportConstructor) {
                    if (transportConstructor instanceof Function) {
                        return transportConstructor;
                    }
                },
                transportOptions: function (transportOptions) {
                    if (typeof transportOptions === "object") {
                        return transportOptions;
                    }
                },
                authorizationUser: function (authorizationUser) {
                    if (Grammar_1.Grammar.parse('"' + authorizationUser + '"', "quoted_string") === -1) {
                        return;
                    }
                    else {
                        return authorizationUser;
                    }
                },
                displayName: function (displayName) {
                    if (Grammar_1.Grammar.parse('"' + displayName + '"', "displayName") === -1) {
                        return;
                    }
                    else {
                        return displayName;
                    }
                },
                dtmfType: function (dtmfType) {
                    switch (dtmfType) {
                        case Constants_1.C.dtmfType.RTP:
                            return Constants_1.C.dtmfType.RTP;
                        case Constants_1.C.dtmfType.INFO:
                        // Fall through
                        default:
                            return Constants_1.C.dtmfType.INFO;
                    }
                },
                hackViaTcp: function (hackViaTcp) {
                    if (typeof hackViaTcp === "boolean") {
                        return hackViaTcp;
                    }
                },
                hackIpInContact: function (hackIpInContact) {
                    if (typeof hackIpInContact === "boolean") {
                        return hackIpInContact;
                    }
                    else if (typeof hackIpInContact === "string" && Grammar_1.Grammar.parse(hackIpInContact, "host") !== -1) {
                        return hackIpInContact;
                    }
                },
                hackWssInTransport: function (hackWssInTransport) {
                    if (typeof hackWssInTransport === "boolean") {
                        return hackWssInTransport;
                    }
                },
                hackAllowUnregisteredOptionTags: function (hackAllowUnregisteredOptionTags) {
                    if (typeof hackAllowUnregisteredOptionTags === "boolean") {
                        return hackAllowUnregisteredOptionTags;
                    }
                },
                contactTransport: function (contactTransport) {
                    if (typeof contactTransport === "string") {
                        return contactTransport;
                    }
                },
                extraSupported: function (optionTags) {
                    if (!(optionTags instanceof Array)) {
                        return;
                    }
                    for (var _i = 0, optionTags_1 = optionTags; _i < optionTags_1.length; _i++) {
                        var tag = optionTags_1[_i];
                        if (typeof tag !== "string") {
                            return;
                        }
                    }
                    return optionTags;
                },
                forceRport: function (forceRport) {
                    if (typeof forceRport === "boolean") {
                        return forceRport;
                    }
                },
                noAnswerTimeout: function (noAnswerTimeout) {
                    if (Utils_1.Utils.isDecimal(noAnswerTimeout)) {
                        var value = Number(noAnswerTimeout);
                        if (value > 0) {
                            return value;
                        }
                    }
                },
                password: function (password) {
                    return String(password);
                },
                rel100: function (rel100) {
                    if (rel100 === Constants_1.C.supported.REQUIRED) {
                        return Constants_1.C.supported.REQUIRED;
                    }
                    else if (rel100 === Constants_1.C.supported.SUPPORTED) {
                        return Constants_1.C.supported.SUPPORTED;
                    }
                    else {
                        return Constants_1.C.supported.UNSUPPORTED;
                    }
                },
                replaces: function (replaces) {
                    if (replaces === Constants_1.C.supported.REQUIRED) {
                        return Constants_1.C.supported.REQUIRED;
                    }
                    else if (replaces === Constants_1.C.supported.SUPPORTED) {
                        return Constants_1.C.supported.SUPPORTED;
                    }
                    else {
                        return Constants_1.C.supported.UNSUPPORTED;
                    }
                },
                register: function (register) {
                    if (typeof register === "boolean") {
                        return register;
                    }
                },
                registerOptions: function (registerOptions) {
                    if (typeof registerOptions === "object") {
                        return registerOptions;
                    }
                },
                userAgentString: function (userAgentString) {
                    if (typeof userAgentString === "string") {
                        return userAgentString;
                    }
                },
                autostart: function (autostart) {
                    if (typeof autostart === "boolean") {
                        return autostart;
                    }
                },
                autostop: function (autostop) {
                    if (typeof autostop === "boolean") {
                        return autostop;
                    }
                },
                sessionDescriptionHandlerFactory: function (sessionDescriptionHandlerFactory) {
                    if (sessionDescriptionHandlerFactory instanceof Function) {
                        return sessionDescriptionHandlerFactory;
                    }
                },
                sessionDescriptionHandlerFactoryOptions: function (options) {
                    if (typeof options === "object") {
                        return options;
                    }
                },
                authenticationFactory: this.checkAuthenticationFactory,
                allowLegacyNotifications: function (allowLegacyNotifications) {
                    if (typeof allowLegacyNotifications === "boolean") {
                        return allowLegacyNotifications;
                    }
                },
                custom: function (custom) {
                    if (typeof custom === "object") {
                        return custom;
                    }
                },
                contactName: function (contactName) {
                    if (typeof contactName === "string") {
                        return contactName;
                    }
                },
            }
        };
    };
    UA.C = {
        // UA status codes
        STATUS_INIT: 0,
        STATUS_STARTING: 1,
        STATUS_READY: 2,
        STATUS_USER_CLOSED: 3,
        STATUS_NOT_READY: 4,
        // UA error codes
        CONFIGURATION_ERROR: 1,
        NETWORK_ERROR: 2,
        ALLOWED_METHODS: [
            "ACK",
            "CANCEL",
            "INVITE",
            "MESSAGE",
            "BYE",
            "OPTIONS",
            "INFO",
            "NOTIFY",
            "REFER"
        ],
        ACCEPTED_BODY_TYPES: [
            "application/sdp",
            "application/dtmf-relay"
        ],
        MAX_FORWARDS: 70,
        TAG_LENGTH: 10
    };
    return UA;
}(events_1.EventEmitter));
exports.UA = UA;
(function (UA) {
    var DtmfType;
    (function (DtmfType) {
        DtmfType["RTP"] = "rtp";
        DtmfType["INFO"] = "info";
    })(DtmfType = UA.DtmfType || (UA.DtmfType = {}));
})(UA = exports.UA || (exports.UA = {}));
exports.UA = UA;

/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(31)))

/***/ }),
/* 31 */
/***/ (function(module, exports) {

var g;

// This works in non-strict mode
g = (function() {
	return this;
})();

try {
	// This works if eval is allowed (see CSP)
	g = g || new Function("return this")();
} catch (e) {
	// This works if the window reference is available
	if (typeof window === "object") g = window;
}

// g can still be undefined, but nothing to do about it...
// We return undefined, instead of nothing here, so it's
// easier to handle this case. if(!global) { ...}

module.exports = g;


/***/ }),
/* 32 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/* WEBPACK VAR INJECTION */(function(global) {
var __extends = (this && this.__extends) || (function () {
    var extendStatics = function (d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
var events_1 = __webpack_require__(2);
var Enums_1 = __webpack_require__(5);
var Exceptions_1 = __webpack_require__(8);
var Utils_1 = __webpack_require__(15);
var Modifiers = __webpack_require__(33);
var SessionDescriptionHandlerObserver_1 = __webpack_require__(34);
/* SessionDescriptionHandler
 * @class PeerConnection helper Class.
 * @param {SIP.Session} session
 * @param {Object} [options]
 */
var SessionDescriptionHandler = /** @class */ (function (_super) {
    __extends(SessionDescriptionHandler, _super);
    function SessionDescriptionHandler(logger, observer, options) {
        var _this = _super.call(this) || this;
        _this.type = Enums_1.TypeStrings.SessionDescriptionHandler;
        // TODO: Validate the options
        _this.options = options || {};
        _this.logger = logger;
        _this.observer = observer;
        _this.dtmfSender = undefined;
        _this.shouldAcquireMedia = true;
        _this.CONTENT_TYPE = "application/sdp";
        _this.C = {
            DIRECTION: {
                NULL: null,
                SENDRECV: "sendrecv",
                SENDONLY: "sendonly",
                RECVONLY: "recvonly",
                INACTIVE: "inactive"
            }
        };
        _this.logger.log("SessionDescriptionHandlerOptions: " + JSON.stringify(_this.options));
        _this.direction = _this.C.DIRECTION.NULL;
        _this.modifiers = _this.options.modifiers || [];
        if (!Array.isArray(_this.modifiers)) {
            _this.modifiers = [_this.modifiers];
        }
        var environment = global.window || global;
        _this.WebRTC = {
            MediaStream: environment.MediaStream,
            getUserMedia: environment.navigator.mediaDevices.getUserMedia.bind(environment.navigator.mediaDevices),
            RTCPeerConnection: environment.RTCPeerConnection
        };
        _this.iceGatheringTimeout = false;
        _this.initPeerConnection(_this.options.peerConnectionOptions);
        _this.constraints = _this.checkAndDefaultConstraints(_this.options.constraints);
        return _this;
    }
    /**
     * @param {SIP.Session} session
     * @param {Object} [options]
     */
    SessionDescriptionHandler.defaultFactory = function (session, options) {
        var logger = session.ua.getLogger("sip.invitecontext.sessionDescriptionHandler", session.id);
        var observer = new SessionDescriptionHandlerObserver_1.SessionDescriptionHandlerObserver(session, options);
        return new SessionDescriptionHandler(logger, observer, options);
    };
    // Functions the sesssion can use
    /**
     * Destructor
     */
    SessionDescriptionHandler.prototype.close = function () {
        this.logger.log("closing PeerConnection");
        // have to check signalingState since this.close() gets called multiple times
        if (this.peerConnection && this.peerConnection.signalingState !== "closed") {
            if (this.peerConnection.getSenders) {
                this.peerConnection.getSenders().forEach(function (sender) {
                    if (sender.track) {
                        sender.track.stop();
                    }
                });
            }
            else {
                this.logger.warn("Using getLocalStreams which is deprecated");
                this.peerConnection.getLocalStreams().forEach(function (stream) {
                    stream.getTracks().forEach(function (track) {
                        track.stop();
                    });
                });
            }
            if (this.peerConnection.getReceivers) {
                this.peerConnection.getReceivers().forEach(function (receiver) {
                    if (receiver.track) {
                        receiver.track.stop();
                    }
                });
            }
            else {
                this.logger.warn("Using getRemoteStreams which is deprecated");
                this.peerConnection.getRemoteStreams().forEach(function (stream) {
                    stream.getTracks().forEach(function (track) {
                        track.stop();
                    });
                });
            }
            this.resetIceGatheringComplete();
            this.peerConnection.close();
        }
    };
    /**
     * Gets the local description from the underlying media implementation
     * @param {Object} [options] Options object to be used by getDescription
     * @param {MediaStreamConstraints} [options.constraints] MediaStreamConstraints
     *   https://developer.mozilla.org/en-US/docs/Web/API/MediaStreamConstraints
     * @param {Object} [options.peerConnectionOptions] If this is set it will recreate the peer
     *   connection with the new options
     * @param {Array} [modifiers] Array with one time use description modifiers
     * @returns {Promise} Promise that resolves with the local description to be used for the session
     */
    SessionDescriptionHandler.prototype.getDescription = function (options, modifiers) {
        var _this = this;
        if (options === void 0) { options = {}; }
        if (modifiers === void 0) { modifiers = []; }
        if (options.peerConnectionOptions) {
            this.initPeerConnection(options.peerConnectionOptions);
        }
        // Merge passed constraints with saved constraints and save
        var newConstraints = Object.assign({}, this.constraints, options.constraints);
        newConstraints = this.checkAndDefaultConstraints(newConstraints);
        if (JSON.stringify(newConstraints) !== JSON.stringify(this.constraints)) {
            this.constraints = newConstraints;
            this.shouldAcquireMedia = true;
        }
        if (!Array.isArray(modifiers)) {
            modifiers = [modifiers];
        }
        modifiers = modifiers.concat(this.modifiers);
        return Promise.resolve().then(function () {
            if (_this.shouldAcquireMedia) {
                return _this.acquire(_this.constraints).then(function () {
                    _this.shouldAcquireMedia = false;
                });
            }
        }).then(function () { return _this.createOfferOrAnswer(options.RTCOfferOptions, modifiers); })
            .then(function (description) {
            if (description.sdp === undefined) {
                throw new Exceptions_1.Exceptions.SessionDescriptionHandlerError("getDescription", undefined, "SDP undefined");
            }
            _this.emit("getDescription", description);
            return {
                body: description.sdp,
                contentType: _this.CONTENT_TYPE
            };
        });
    };
    /**
     * Check if the Session Description Handler can handle the Content-Type described by a SIP Message
     * @param {String} contentType The content type that is in the SIP Message
     * @returns {boolean}
     */
    SessionDescriptionHandler.prototype.hasDescription = function (contentType) {
        return contentType === this.CONTENT_TYPE;
    };
    /**
     * The modifier that should be used when the session would like to place the call on hold
     * @param {String} [sdp] The description that will be modified
     * @returns {Promise} Promise that resolves with modified SDP
     */
    SessionDescriptionHandler.prototype.holdModifier = function (description) {
        if (!description.sdp) {
            return Promise.resolve(description);
        }
        if (!(/a=(sendrecv|sendonly|recvonly|inactive)/).test(description.sdp)) {
            description.sdp = description.sdp.replace(/(m=[^\r]*\r\n)/g, "$1a=sendonly\r\n");
        }
        else {
            description.sdp = description.sdp.replace(/a=sendrecv\r\n/g, "a=sendonly\r\n");
            description.sdp = description.sdp.replace(/a=recvonly\r\n/g, "a=inactive\r\n");
        }
        return Promise.resolve(description);
    };
    /**
     * Set the remote description to the underlying media implementation
     * @param {String} sessionDescription The description provided by a SIP message to be set on the media implementation
     * @param {Object} [options] Options object to be used by getDescription
     * @param {MediaStreamConstraints} [options.constraints] MediaStreamConstraints
     *   https://developer.mozilla.org/en-US/docs/Web/API/MediaStreamConstraints
     * @param {Object} [options.peerConnectionOptions] If this is set it will recreate the peer
     *   connection with the new options
     * @param {Array} [modifiers] Array with one time use description modifiers
     * @returns {Promise} Promise that resolves once the description is set
     */
    SessionDescriptionHandler.prototype.setDescription = function (sessionDescription, options, modifiers) {
        var _this = this;
        if (options === void 0) { options = {}; }
        if (modifiers === void 0) { modifiers = []; }
        if (options.peerConnectionOptions) {
            this.initPeerConnection(options.peerConnectionOptions);
        }
        if (!Array.isArray(modifiers)) {
            modifiers = [modifiers];
        }
        modifiers = modifiers.concat(this.modifiers);
        var description = {
            type: this.hasOffer("local") ? "answer" : "offer",
            sdp: sessionDescription
        };
        return Promise.resolve().then(function () {
            // Media should be acquired in getDescription unless we need to do it sooner for some reason (FF61+)
            if (_this.shouldAcquireMedia && _this.options.alwaysAcquireMediaFirst) {
                return _this.acquire(_this.constraints).then(function () {
                    _this.shouldAcquireMedia = false;
                });
            }
        }).then(function () { return Utils_1.Utils.reducePromises(modifiers, description); })
            .catch(function (e) {
            if (e.type === Enums_1.TypeStrings.SessionDescriptionHandlerError) {
                throw e;
            }
            var error = new Exceptions_1.Exceptions.SessionDescriptionHandlerError("setDescription", e, "The modifiers did not resolve successfully");
            _this.logger.error(error.message);
            _this.emit("peerConnection-setRemoteDescriptionFailed", error);
            throw error;
        }).then(function (modifiedDescription) {
            _this.emit("setDescription", modifiedDescription);
            return _this.peerConnection.setRemoteDescription(modifiedDescription);
        }).catch(function (e) {
            if (e.type === Enums_1.TypeStrings.SessionDescriptionHandlerError) {
                throw e;
            }
            // Check the original SDP for video, and ensure that we have want to do audio fallback
            if ((/^m=video.+$/gm).test(sessionDescription) && !options.disableAudioFallback) {
                // Do not try to audio fallback again
                options.disableAudioFallback = true;
                // Remove video first, then do the other modifiers
                return _this.setDescription(sessionDescription, options, [Modifiers.stripVideo].concat(modifiers));
            }
            var error = new Exceptions_1.Exceptions.SessionDescriptionHandlerError("setDescription", e);
            if (error.error) {
                _this.logger.error(error.error);
            }
            _this.emit("peerConnection-setRemoteDescriptionFailed", error);
            throw error;
        }).then(function () {
            if (_this.peerConnection.getReceivers) {
                _this.emit("setRemoteDescription", _this.peerConnection.getReceivers());
            }
            else {
                _this.emit("setRemoteDescription", _this.peerConnection.getRemoteStreams());
            }
            _this.emit("confirmed", _this);
        });
    };
    /**
     * Send DTMF via RTP (RFC 4733)
     * @param {String} tones A string containing DTMF digits
     * @param {Object} [options] Options object to be used by sendDtmf
     * @returns {boolean} true if DTMF send is successful, false otherwise
     */
    SessionDescriptionHandler.prototype.sendDtmf = function (tones, options) {
        if (options === void 0) { options = {}; }
        if (!this.dtmfSender && this.hasBrowserGetSenderSupport()) {
            var senders = this.peerConnection.getSenders();
            if (senders.length > 0) {
                this.dtmfSender = senders[0].dtmf;
            }
        }
        if (!this.dtmfSender && this.hasBrowserTrackSupport()) {
            var streams = this.peerConnection.getLocalStreams();
            if (streams.length > 0) {
                var audioTracks = streams[0].getAudioTracks();
                if (audioTracks.length > 0) {
                    this.dtmfSender = this.peerConnection.createDTMFSender(audioTracks[0]);
                }
            }
        }
        if (!this.dtmfSender) {
            return false;
        }
        try {
            this.dtmfSender.insertDTMF(tones, options.duration, options.interToneGap);
        }
        catch (e) {
            if (e.type === "InvalidStateError" || e.type === "InvalidCharacterError") {
                this.logger.error(e);
                return false;
            }
            else {
                throw e;
            }
        }
        this.logger.log("DTMF sent via RTP: " + tones.toString());
        return true;
    };
    /**
     * Get the direction of the session description
     * @returns {String} direction of the description
     */
    SessionDescriptionHandler.prototype.getDirection = function () {
        return this.direction;
    };
    SessionDescriptionHandler.prototype.on = function (name, callback) { return _super.prototype.on.call(this, name, callback); };
    // Internal functions
    SessionDescriptionHandler.prototype.createOfferOrAnswer = function (RTCOfferOptions, modifiers) {
        var _this = this;
        if (RTCOfferOptions === void 0) { RTCOfferOptions = {}; }
        if (modifiers === void 0) { modifiers = []; }
        var methodName = this.hasOffer("remote") ? "createAnswer" : "createOffer";
        var pc = this.peerConnection;
        this.logger.log(methodName);
        return pc[methodName](RTCOfferOptions).catch(function (e) {
            if (e.type === Enums_1.TypeStrings.SessionDescriptionHandlerError) {
                throw e;
            }
            var error = new Exceptions_1.Exceptions.SessionDescriptionHandlerError("createOfferOrAnswer", e, "peerConnection-" + methodName + "Failed");
            _this.emit("peerConnection-" + methodName + "Failed", error);
            throw error;
        }).then(function (sdp) {
            return Utils_1.Utils.reducePromises(modifiers, _this.createRTCSessionDescriptionInit(sdp));
        }).then(function (sdp) {
            _this.resetIceGatheringComplete();
            _this.logger.log("Setting local sdp.");
            _this.logger.log("sdp is " + sdp.sdp || false);
            return pc.setLocalDescription(sdp);
        }).catch(function (e) {
            if (e.type === Enums_1.TypeStrings.SessionDescriptionHandlerError) {
                throw e;
            }
            var error = new Exceptions_1.Exceptions.SessionDescriptionHandlerError("createOfferOrAnswer", e, "peerConnection-SetLocalDescriptionFailed");
            _this.emit("peerConnection-SetLocalDescriptionFailed", error);
            throw error;
        }).then(function () { return _this.waitForIceGatheringComplete(); })
            .then(function () {
            var localDescription = _this.createRTCSessionDescriptionInit(_this.peerConnection.localDescription);
            return Utils_1.Utils.reducePromises(modifiers, localDescription);
        }).then(function (localDescription) {
            _this.setDirection(localDescription.sdp || "");
            return localDescription;
        }).catch(function (e) {
            if (e.type === Enums_1.TypeStrings.SessionDescriptionHandlerError) {
                throw e;
            }
            var error = new Exceptions_1.Exceptions.SessionDescriptionHandlerError("createOfferOrAnswer", e);
            _this.logger.error(error.toString());
            throw error;
        });
    };
    // Creates an RTCSessionDescriptionInit from an RTCSessionDescription
    SessionDescriptionHandler.prototype.createRTCSessionDescriptionInit = function (RTCSessionDescription) {
        return {
            type: RTCSessionDescription.type,
            sdp: RTCSessionDescription.sdp
        };
    };
    SessionDescriptionHandler.prototype.addDefaultIceCheckingTimeout = function (peerConnectionOptions) {
        if (peerConnectionOptions.iceCheckingTimeout === undefined) {
            peerConnectionOptions.iceCheckingTimeout = 5000;
        }
        return peerConnectionOptions;
    };
    SessionDescriptionHandler.prototype.addDefaultIceServers = function (rtcConfiguration) {
        if (!ua.configuration.iceServers) {
            rtcConfiguration.iceServers = [{ urls: "stun:stun.xten.com" }];
        } else {
            rtcConfiguration.iceServers = [ua.configuration.iceServers];
        }
        return rtcConfiguration;
    };
    SessionDescriptionHandler.prototype.checkAndDefaultConstraints = function (constraints) {
        var defaultConstraints = { audio: true, video: !this.options.alwaysAcquireMediaFirst };
        constraints = constraints || defaultConstraints;
        // Empty object check
        if (Object.keys(constraints).length === 0 && constraints.constructor === Object) {
            return defaultConstraints;
        }
        return constraints;
    };
    SessionDescriptionHandler.prototype.hasBrowserTrackSupport = function () {
        return Boolean(this.peerConnection.addTrack);
    };
    SessionDescriptionHandler.prototype.hasBrowserGetSenderSupport = function () {
        return Boolean(this.peerConnection.getSenders);
    };
    SessionDescriptionHandler.prototype.initPeerConnection = function (options) {
        var _this = this;
        if (options === void 0) { options = {}; }
        options = this.addDefaultIceCheckingTimeout(options);
        options.rtcConfiguration = options.rtcConfiguration || {};
        options.rtcConfiguration = this.addDefaultIceServers(options.rtcConfiguration);
        this.logger.log("initPeerConnection");
        if (this.peerConnection) {
            this.logger.log("Already have a peer connection for this session. Tearing down.");
            this.resetIceGatheringComplete();
            this.peerConnection.close();
        }
        this.peerConnection = new this.WebRTC.RTCPeerConnection(options.rtcConfiguration);
        this.logger.log("New peer connection created");
        if ("ontrack" in this.peerConnection) {
            this.peerConnection.addEventListener("track", function (e) {
                _this.logger.log("track added");
                _this.observer.trackAdded();
                _this.emit("addTrack", e);
            });
        }
        else {
            this.logger.warn("Using onaddstream which is deprecated");
            this.peerConnection.onaddstream = function (e) {
                _this.logger.log("stream added");
                _this.emit("addStream", e);
            };
        }
        this.peerConnection.onicecandidate = function (e) {
            _this.emit("iceCandidate", e);
            if (e.candidate) {
                _this.logger.log("ICE candidate received: " +
                    (e.candidate.candidate === null ? null : e.candidate.candidate.trim()));
            }
            else if (e.candidate === null) {
                // indicates the end of candidate gathering
                _this.logger.log("ICE candidate gathering complete");
                _this.triggerIceGatheringComplete();
            }
        };
        this.peerConnection.onicegatheringstatechange = function () {
            _this.logger.log("RTCIceGatheringState changed: " + _this.peerConnection.iceGatheringState);
            switch (_this.peerConnection.iceGatheringState) {
                case "gathering":
                    _this.emit("iceGathering", _this);
                    if (!_this.iceGatheringTimer && options.iceCheckingTimeout) {
                        _this.iceGatheringTimeout = false;
                        _this.iceGatheringTimer = setTimeout(function () {
                            _this.logger.log("RTCIceChecking Timeout Triggered after " + options.iceCheckingTimeout + " milliseconds");
                            _this.iceGatheringTimeout = true;
                            _this.triggerIceGatheringComplete();
                        }, options.iceCheckingTimeout);
                    }
                    break;
                case "complete":
                    _this.triggerIceGatheringComplete();
                    break;
            }
        };
        this.peerConnection.oniceconnectionstatechange = function () {
            var stateEvent;
            switch (_this.peerConnection.iceConnectionState) {
                case "new":
                    stateEvent = "iceConnection";
                    break;
                case "checking":
                    stateEvent = "iceConnectionChecking";
                    break;
                case "connected":
                    stateEvent = "iceConnectionConnected";
                    break;
                case "completed":
                    stateEvent = "iceConnectionCompleted";
                    break;
                case "failed":
                    stateEvent = "iceConnectionFailed";
                    break;
                case "disconnected":
                    stateEvent = "iceConnectionDisconnected";
                    break;
                case "closed":
                    stateEvent = "iceConnectionClosed";
                    break;
                default:
                    _this.logger.warn("Unknown iceConnection state: " + _this.peerConnection.iceConnectionState);
                    return;
            }
            _this.logger.log("ICE Connection State changed to " + stateEvent);
            _this.emit(stateEvent, _this);
        };
    };
    SessionDescriptionHandler.prototype.acquire = function (constraints) {
        var _this = this;
        // Default audio & video to true
        constraints = this.checkAndDefaultConstraints(constraints);
        return new Promise(function (resolve, reject) {
            /*
             * Make the call asynchronous, so that ICCs have a chance
             * to define callbacks to `userMediaRequest`
             */
            _this.logger.log("acquiring local media");
            _this.emit("userMediaRequest", constraints);
            if (!hasCameras){
                if (hasVideo != undefined && hasAudio != undefined){
                    constraints.audio = hasAudio
                    constraints.video = hasVideo
                }
            }
            if (constraints.audio || constraints.video) {
                _this.WebRTC.getUserMedia(constraints).then(function (streams) {
                    _this.observer.trackAdded();
                    _this.emit("userMedia", streams);
                    resolve(streams);
                }).catch(function (e) {
                    _this.emit("userMediaFailed", e);
                    reject(e);
                });
            }
            else {
                // Local streams were explicitly excluded.
                resolve([]);
            }
        }).catch(function (e) {
            if (e.type === Enums_1.TypeStrings.SessionDescriptionHandlerError) {
                throw e;
            }
            var error = new Exceptions_1.Exceptions.SessionDescriptionHandlerError("acquire", e, "unable to acquire streams");
            _this.logger.error(error.message);
            if (error.error) {
                _this.logger.error(error.error);
            }
            throw error;
        }).then(function (streams) {
            _this.logger.log("acquired local media streams");
            try {
                // Remove old tracks
                if (_this.peerConnection.removeTrack) {
                    _this.peerConnection.getSenders().forEach(function (sender) {
                        _this.peerConnection.removeTrack(sender);
                    });
                }
                return streams;
            }
            catch (e) {
                return Promise.reject(e);
            }
        }).catch(function (e) {
            if (e.type === Enums_1.TypeStrings.SessionDescriptionHandlerError) {
                throw e;
            }
            var error = new Exceptions_1.Exceptions.SessionDescriptionHandlerError("acquire", e, "error removing streams");
            _this.logger.error(error.message);
            if (error.error) {
                _this.logger.error(error.error);
            }
            throw error;
        }).then(function (streams) {
            try {
                streams = [].concat(streams);
                streams.forEach(function (stream) {
                    if (_this.peerConnection.addTrack) {
                        stream.getTracks().forEach(function (track) {
                            _this.peerConnection.addTrack(track, stream);
                        });
                    }
                    else {
                        // Chrome 59 does not support addTrack
                        _this.peerConnection.addStream(stream);
                    }
                });
            }
            catch (e) {
                return Promise.reject(e);
            }
            return Promise.resolve();
        }).catch(function (e) {
            if (e.type === Enums_1.TypeStrings.SessionDescriptionHandlerError) {
                throw e;
            }
            var error = new Exceptions_1.Exceptions.SessionDescriptionHandlerError("acquire", e, "error adding stream");
            _this.logger.error(error.message);
            if (error.error) {
                _this.logger.error(error.error);
            }
            throw error;
        });
    };
    SessionDescriptionHandler.prototype.hasOffer = function (where) {
        var offerState = "have-" + where + "-offer";
        return this.peerConnection.signalingState === offerState;
    };
    // ICE gathering state handling
    SessionDescriptionHandler.prototype.isIceGatheringComplete = function () {
        return this.peerConnection.iceGatheringState === "complete" || this.iceGatheringTimeout;
    };
    SessionDescriptionHandler.prototype.resetIceGatheringComplete = function () {
        this.iceGatheringTimeout = false;
        this.logger.log("resetIceGatheringComplete");
        if (this.iceGatheringTimer) {
            clearTimeout(this.iceGatheringTimer);
            this.iceGatheringTimer = undefined;
        }
        if (this.iceGatheringDeferred) {
            this.iceGatheringDeferred.reject();
            this.iceGatheringDeferred = undefined;
        }
    };
    SessionDescriptionHandler.prototype.setDirection = function (sdp) {
        var match = sdp.match(/a=(sendrecv|sendonly|recvonly|inactive)/);
        if (match === null) {
            this.direction = this.C.DIRECTION.NULL;
            this.observer.directionChanged();
            return;
        }
        var direction = match[1];
        switch (direction) {
            case this.C.DIRECTION.SENDRECV:
            case this.C.DIRECTION.SENDONLY:
            case this.C.DIRECTION.RECVONLY:
            case this.C.DIRECTION.INACTIVE:
                this.direction = direction;
                break;
            default:
                this.direction = this.C.DIRECTION.NULL;
                break;
        }
        this.observer.directionChanged();
    };
    SessionDescriptionHandler.prototype.triggerIceGatheringComplete = function () {
        if (this.isIceGatheringComplete()) {
            this.emit("iceGatheringComplete", this);
            if (this.iceGatheringTimer) {
                clearTimeout(this.iceGatheringTimer);
                this.iceGatheringTimer = undefined;
            }
            if (this.iceGatheringDeferred) {
                this.iceGatheringDeferred.resolve();
                this.iceGatheringDeferred = undefined;
            }
        }
    };
    SessionDescriptionHandler.prototype.waitForIceGatheringComplete = function () {
        this.logger.log("waitForIceGatheringComplete");
        if (this.isIceGatheringComplete()) {
            this.logger.log("ICE is already complete. Return resolved.");
            return Promise.resolve();
        }
        else if (!this.iceGatheringDeferred) {
            this.iceGatheringDeferred = Utils_1.Utils.defer();
        }
        this.logger.log("ICE is not complete. Returning promise");
        return this.iceGatheringDeferred ? this.iceGatheringDeferred.promise : Promise.resolve();
    };
    return SessionDescriptionHandler;
}(events_1.EventEmitter));
exports.SessionDescriptionHandler = SessionDescriptionHandler;

/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(31)))

/***/ }),
/* 33 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";

Object.defineProperty(exports, "__esModule", { value: true });
var stripPayload = function (sdp, payload) {
    var mediaDescs = [];
    var lines = sdp.split(/\r\n/);
    var currentMediaDesc;
    for (var i = 0; i < lines.length;) {
        var line = lines[i];
        if (/^m=(?:audio|video)/.test(line)) {
            currentMediaDesc = {
                index: i,
                stripped: []
            };
            mediaDescs.push(currentMediaDesc);
        }
        else if (currentMediaDesc) {
            var rtpmap = /^a=rtpmap:(\d+) ([^/]+)\//.exec(line);
            if (rtpmap && payload === rtpmap[2]) {
                lines.splice(i, 1);
                currentMediaDesc.stripped.push(rtpmap[1]);
                continue; // Don't increment 'i'
            }
        }
        i++;
    }
    for (var _i = 0, mediaDescs_1 = mediaDescs; _i < mediaDescs_1.length; _i++) {
        var mediaDesc = mediaDescs_1[_i];
        var mline = lines[mediaDesc.index].split(" ");
        // Ignore the first 3 parameters of the mline. The codec information is after that
        for (var j = 3; j < mline.length;) {
            if (mediaDesc.stripped.indexOf(mline[j]) !== -1) {
                mline.splice(j, 1);
                continue;
            }
            j++;
        }
        lines[mediaDesc.index] = mline.join(" ");
    }
    return lines.join("\r\n");
};
var stripMediaDescription = function (sdp, description) {
    var descriptionRegExp = new RegExp("m=" + description + ".*$", "gm");
    var groupRegExp = new RegExp("^a=group:.*$", "gm");
    if (descriptionRegExp.test(sdp)) {
        var midLineToRemove_1;
        sdp = sdp.split(/^m=/gm).filter(function (section) {
            if (section.substr(0, description.length) === description) {
                midLineToRemove_1 = section.match(/^a=mid:.*$/gm);
                if (midLineToRemove_1) {
                    var step = midLineToRemove_1[0].match(/:.+$/g);
                    if (step) {
                        midLineToRemove_1 = step[0].substr(1);
                    }
                }
                return false;
            }
            return true;
        }).join("m=");
        var groupLine = sdp.match(groupRegExp);
        if (groupLine && groupLine.length === 1) {
            var groupLinePortion = groupLine[0];
            var groupRegExpReplace = new RegExp("\ *" + midLineToRemove_1 + "[^\ ]*", "g");
            groupLinePortion = groupLinePortion.replace(groupRegExpReplace, "");
            sdp = sdp.split(groupRegExp).join(groupLinePortion);
        }
    }
    return sdp;
};
function stripTcpCandidates(description) {
    description.sdp = (description.sdp || "").replace(/^a=candidate:\d+ \d+ tcp .*?\r\n/img, "");
    return Promise.resolve(description);
}
exports.stripTcpCandidates = stripTcpCandidates;
function stripTelephoneEvent(description) {
    description.sdp = stripPayload(description.sdp || "", "telephone-event");
    return Promise.resolve(description);
}
exports.stripTelephoneEvent = stripTelephoneEvent;
function cleanJitsiSdpImageattr(description) {
    description.sdp = (description.sdp || "").replace(/^(a=imageattr:.*?)(x|y)=\[0-/gm, "$1$2=[1:");
    return Promise.resolve(description);
}
exports.cleanJitsiSdpImageattr = cleanJitsiSdpImageattr;
function stripG722(description) {
    description.sdp = stripPayload(description.sdp || "", "G722");
    return Promise.resolve(description);
}
exports.stripG722 = stripG722;
function stripRtpPayload(payload) {
    return function (description) {
        description.sdp = stripPayload(description.sdp || "", payload);
        return Promise.resolve(description);
    };
}
exports.stripRtpPayload = stripRtpPayload;
function stripVideo(description) {
    description.sdp = stripMediaDescription(description.sdp || "", "video");
    return Promise.resolve(description);
}
exports.stripVideo = stripVideo;
function addMidLines(description) {
    var sdp = description.sdp || "";
    if (sdp.search(/^a=mid.*$/gm) === -1) {
        var mlines_1 = sdp.match(/^m=.*$/gm);
        var sdpArray_1 = sdp.split(/^m=.*$/gm);
        if (mlines_1) {
            mlines_1.forEach(function (elem, idx) {
                mlines_1[idx] = elem + "\na=mid:" + idx;
            });
        }
        sdpArray_1.forEach(function (elem, idx) {
            if (mlines_1 && mlines_1[idx]) {
                sdpArray_1[idx] = elem + mlines_1[idx];
            }
        });
        sdp = sdpArray_1.join("");
        description.sdp = sdp;
    }
    return Promise.resolve(description);
}
exports.addMidLines = addMidLines;


/***/ }),
/* 34 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";

Object.defineProperty(exports, "__esModule", { value: true });
var Enums_1 = __webpack_require__(5);
/* SessionDescriptionHandlerObserver
 * @class SessionDescriptionHandler Observer Class.
 * @param {SIP.Session} session
 * @param {Object} [options]
 */
var SessionDescriptionHandlerObserver = /** @class */ (function () {
    function SessionDescriptionHandlerObserver(session, options) {
        this.type = Enums_1.TypeStrings.SessionDescriptionHandlerObserver;
        this.session = session;
        this.options = options;
    }
    SessionDescriptionHandlerObserver.prototype.trackAdded = function () {
        this.session.emit("trackAdded");
    };
    SessionDescriptionHandlerObserver.prototype.directionChanged = function () {
        this.session.emit("directionChanged");
    };
    return SessionDescriptionHandlerObserver;
}());
exports.SessionDescriptionHandlerObserver = SessionDescriptionHandlerObserver;


/***/ }),
/* 35 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/* WEBPACK VAR INJECTION */(function(global) {
var __extends = (this && this.__extends) || (function () {
    var extendStatics = function (d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
var Enums_1 = __webpack_require__(5);
var Exceptions_1 = __webpack_require__(8);
var Grammar_1 = __webpack_require__(11);
var Transport_1 = __webpack_require__(29);
var Utils_1 = __webpack_require__(15);
var TransportStatus;
(function (TransportStatus) {
    TransportStatus[TransportStatus["STATUS_CONNECTING"] = 0] = "STATUS_CONNECTING";
    TransportStatus[TransportStatus["STATUS_OPEN"] = 1] = "STATUS_OPEN";
    TransportStatus[TransportStatus["STATUS_CLOSING"] = 2] = "STATUS_CLOSING";
    TransportStatus[TransportStatus["STATUS_CLOSED"] = 3] = "STATUS_CLOSED";
})(TransportStatus = exports.TransportStatus || (exports.TransportStatus = {}));
/**
 * Compute an amount of time in seconds to wait before sending another
 * keep-alive.
 * @returns {Number}
 */
var computeKeepAliveTimeout = function (upperBound) {
    var lowerBound = upperBound * 0.8;
    return 1000 * (Math.random() * (upperBound - lowerBound) + lowerBound);
};
/**
 * @class Transport
 * @param {Object} options
 */
var Transport = /** @class */ (function (_super) {
    __extends(Transport, _super);
    function Transport(logger, options) {
        if (options === void 0) { options = {}; }
        var _this = _super.call(this, logger, options) || this;
        _this.WebSocket = (global.window || global).WebSocket;
        _this.type = Enums_1.TypeStrings.Transport;
        _this.reconnectionAttempts = 0;
        _this.status = TransportStatus.STATUS_CONNECTING;
        _this.configuration = _this.loadConfig(options);
        _this.server = _this.configuration.wsServers[0];
        return _this;
    }
    /**
     * @returns {Boolean}
     */
    Transport.prototype.isConnected = function () {
        return this.status === TransportStatus.STATUS_OPEN;
    };
    /**
     * Send a message.
     * @param {SIP.OutgoingRequest|String} msg
     * @param {Object} [options]
     * @returns {Promise}
     */
    Transport.prototype.sendPromise = function (msg, options) {
        if (options === void 0) { options = {}; }
        if (!this.statusAssert(TransportStatus.STATUS_OPEN, options.force)) {
            this.onError("unable to send message - WebSocket not open");
            return Promise.reject();
        }
        var message = msg.toString();
        if (this.ws) {
            if (this.configuration.traceSip === true) {
                this.logger.log("sending WebSocket message:\n\n" + message + "\n");
            }
            this.ws.send(message);
            return Promise.resolve({ msg: message });
        }
        else {
            this.onError("unable to send message - WebSocket does not exist");
            return Promise.reject();
        }
    };
    /**
     * Disconnect socket.
     */
    Transport.prototype.disconnectPromise = function (options) {
        var _this = this;
        if (options === void 0) { options = {}; }
        if (this.disconnectionPromise) { // Already disconnecting. Just return this.
            return this.disconnectionPromise;
        }
        options.code = options.code || 1000;
        if (!this.statusTransition(TransportStatus.STATUS_CLOSING, options.force)) {
            if (this.status === TransportStatus.STATUS_CLOSED) { // Websocket is already closed
                return Promise.resolve({ overrideEvent: true });
            }
            else if (this.connectionPromise) { // Websocket is connecting, cannot move to disconneting yet
                return this.connectionPromise.then(function () { return Promise.reject("The websocket did not disconnect"); })
                    .catch(function () { return Promise.resolve({ overrideEvent: true }); });
            }
            else {
                // Cannot move to disconnecting, but not in connecting state.
                return Promise.reject("The websocket did not disconnect");
            }
        }
        this.emit("disconnecting");
        this.disconnectionPromise = new Promise(function (resolve, reject) {
            _this.disconnectDeferredResolve = resolve;
            if (_this.reconnectTimer) {
                clearTimeout(_this.reconnectTimer);
                _this.reconnectTimer = undefined;
            }
            if (_this.ws) {
                _this.stopSendingKeepAlives();
                _this.logger.log("closing WebSocket " + _this.server.wsUri);
                _this.ws.close(options.code, options.reason);
            }
            else {
                reject("Attempted to disconnect but the websocket doesn't exist");
            }
        });
        return this.disconnectionPromise;
    };
    /**
     * Connect socket.
     */
    Transport.prototype.connectPromise = function (options) {
        var _this = this;
        if (options === void 0) { options = {}; }
        if (this.status === TransportStatus.STATUS_CLOSING && !options.force) {
            return Promise.reject("WebSocket " + this.server.wsUri + " is closing");
        }
        if (this.connectionPromise) {
            return this.connectionPromise;
        }
        this.server = this.server || this.getNextWsServer(options.force);
        this.connectionPromise = new Promise(function (resolve, reject) {
            if ((_this.status === TransportStatus.STATUS_OPEN || _this.status === TransportStatus.STATUS_CLOSING)
                && !options.force) {
                _this.logger.warn("WebSocket " + _this.server.wsUri + " is already connected");
                reject("Failed status check - attempted to open a connection but already open/closing");
                return;
            }
            _this.connectDeferredResolve = resolve;
            _this.status = TransportStatus.STATUS_CONNECTING;
            _this.emit("connecting");
            _this.logger.log("connecting to WebSocket " + _this.server.wsUri);
            _this.disposeWs();
            try {
                _this.ws = new WebSocket(_this.server.wsUri, "sip");
            }
            catch (e) {
                _this.ws = null;
                _this.status = TransportStatus.STATUS_CLOSED; // force status to closed in error case
                _this.onError("error connecting to WebSocket " + _this.server.wsUri + ":" + e);
                reject("Failed to create a websocket");
                return;
            }
            if (!_this.ws) {
                reject("Unexpected instance websocket not set");
                return;
            }
            _this.connectionTimeout = setTimeout(function () {
                _this.statusTransition(TransportStatus.STATUS_CLOSED);
                _this.logger.warn("took too long to connect - exceeded time set in configuration.connectionTimeout: " +
                    _this.configuration.connectionTimeout + "s");
                _this.emit("disconnected", { code: 1000 });
                _this.connectionPromise = undefined;
                reject("Connection timeout");
            }, _this.configuration.connectionTimeout * 1000);
            _this.boundOnOpen = _this.onOpen.bind(_this);
            _this.boundOnMessage = _this.onMessage.bind(_this);
            _this.boundOnClose = _this.onClose.bind(_this);
            _this.boundOnError = _this.onWebsocketError.bind(_this);
            _this.ws.addEventListener("open", _this.boundOnOpen);
            _this.ws.addEventListener("message", _this.boundOnMessage);
            _this.ws.addEventListener("close", _this.boundOnClose);
            _this.ws.addEventListener("error", _this.boundOnError);
        });
        return this.connectionPromise;
    };
    /**
     * @event
     * @param {event} e
     */
    Transport.prototype.onMessage = function (e) {
        var data = e.data;
        var finishedData;
        // CRLF Keep Alive response from server. Clear our keep alive timeout.
        if (/^(\r\n)+$/.test(data)) {
            this.clearKeepAliveTimeout();
            if (this.configuration.traceSip === true) {
                this.logger.log("received WebSocket message with CRLF Keep Alive response");
            }
            return;
        }
        else if (!data) {
            this.logger.warn("received empty message, message discarded");
            return;
        }
        else if (typeof data !== "string") { // WebSocket binary message.
            try {
                // the UInt8Data was here prior to types, and doesn't check
                finishedData = String.fromCharCode.apply(null, new Uint8Array(data));
            }
            catch (err) {
                this.logger.warn("received WebSocket binary message failed to be converted into string, message discarded");
                return;
            }
            if (this.configuration.traceSip === true) {
                this.logger.log("received WebSocket binary message:\n\n" + data + "\n");
            }
        }
        else { // WebSocket text message.
            if (this.configuration.traceSip === true) {
                this.logger.log("received WebSocket text message:\n\n" + data + "\n");
            }
            finishedData = data;
        }
        this.emit("message", finishedData);
    };
    // Transport Event Handlers
    /**
     * @event
     * @param {event} e
     */
    Transport.prototype.onOpen = function () {
        if (this.status === TransportStatus.STATUS_CLOSED) { // Indicated that the transport thinks the ws is dead already
            var ws = this.ws;
            this.disposeWs();
            ws.close(1000);
            return;
        }
        this.status = TransportStatus.STATUS_OPEN; // quietly force status to open
        this.emit("connected");
        if (this.connectionTimeout) {
            clearTimeout(this.connectionTimeout);
            this.connectionTimeout = undefined;
        }
        this.logger.log("WebSocket " + this.server.wsUri + " connected");
        // Clear reconnectTimer since we are not disconnected
        if (this.reconnectTimer !== undefined) {
            clearTimeout(this.reconnectTimer);
            this.reconnectTimer = undefined;
        }
        // Reset reconnectionAttempts
        this.reconnectionAttempts = 0;
        // Reset disconnection promise so we can disconnect from a fresh state
        this.disconnectionPromise = undefined;
        this.disconnectDeferredResolve = undefined;
        // Start sending keep-alives
        this.startSendingKeepAlives();
        if (this.connectDeferredResolve) {
            this.connectDeferredResolve({ overrideEvent: true });
        }
        else {
            this.logger.warn("Unexpected websocket.onOpen with no connectDeferredResolve");
        }
    };
    /**
     * @event
     * @param {event} e
     */
    Transport.prototype.onClose = function (e) {
        this.logger.log("WebSocket disconnected (code: " + e.code + (e.reason ? "| reason: " + e.reason : "") + ")");
        if (this.status !== TransportStatus.STATUS_CLOSING) {
            this.logger.warn("WebSocket closed without SIP.js requesting it");
            this.emit("transportError");
        }
        this.stopSendingKeepAlives();
        // Clean up connection variables so we can connect again from a fresh state
        if (this.connectionTimeout) {
            clearTimeout(this.connectionTimeout);
        }
        this.connectionTimeout = undefined;
        this.connectionPromise = undefined;
        this.connectDeferredResolve = undefined;
        // Check whether the user requested to close.
        if (this.disconnectDeferredResolve) {
            this.disconnectDeferredResolve({ overrideEvent: true });
            this.statusTransition(TransportStatus.STATUS_CLOSED);
            this.disconnectDeferredResolve = undefined;
            return;
        }
        this.status = TransportStatus.STATUS_CLOSED; // quietly force status to closed
        this.emit("disconnected", { code: e.code, reason: e.reason });
        this.reconnect();
    };
    /**
     * Removes event listeners and clears the instance ws
     */
    Transport.prototype.disposeWs = function () {
        if (this.ws) {
            this.ws.removeEventListener("open", this.boundOnOpen);
            this.ws.removeEventListener("message", this.boundOnMessage);
            this.ws.removeEventListener("close", this.boundOnClose);
            this.ws.removeEventListener("error", this.boundOnError);
            this.ws = undefined;
        }
    };
    /**
     * @event
     * @param {string} e
     */
    Transport.prototype.onError = function (e) {
        this.logger.warn("Transport error: " + e);
        this.emit("transportError");
    };
    /**
     * @event
     * @private
     */
    Transport.prototype.onWebsocketError = function () {
        this.onError("The Websocket had an error");
    };
    /**
     * Reconnection attempt logic.
     */
    Transport.prototype.reconnect = function () {
        var _this = this;
        if (this.reconnectionAttempts > 0) {
            this.logger.log("Reconnection attempt " + this.reconnectionAttempts + " failed");
        }
        if (this.noAvailableServers()) {
            this.logger.warn("attempted to get next ws server but there are no available ws servers left");
            this.logger.warn("no available ws servers left - going to closed state");
            this.status = TransportStatus.STATUS_CLOSED;
            this.emit("closed");
            this.resetServerErrorStatus();
            return;
        }
        if (this.isConnected()) {
            this.logger.warn("attempted to reconnect while connected - forcing disconnect");
            this.disconnect({ force: true });
        }
        this.reconnectionAttempts += 1;
        if (this.reconnectionAttempts > this.configuration.maxReconnectionAttempts) {
            this.logger.warn("maximum reconnection attempts for WebSocket " + this.server.wsUri);
            this.logger.log("transport " + this.server.wsUri + " failed | connection state set to 'error'");
            this.server.isError = true;
            this.emit("transportError");
            if (!this.noAvailableServers()) {
                this.server = this.getNextWsServer();
            }
            // When there are no available servers, the reconnect function ends on the next recursive call
            // after checking for no available servers again.
            this.reconnectionAttempts = 0;
            this.reconnect();
        }
        else {
            this.logger.log("trying to reconnect to WebSocket " +
                this.server.wsUri + " (reconnection attempt " + this.reconnectionAttempts + ")");
            this.reconnectTimer = setTimeout(function () {
                _this.connect();
                _this.reconnectTimer = undefined;
            }, (this.reconnectionAttempts === 1) ? 0 : this.configuration.reconnectionTimeout * 1000);
        }
    };
    /**
     * Resets the error state of all servers in the configuration
     */
    Transport.prototype.resetServerErrorStatus = function () {
        for (var _i = 0, _a = this.configuration.wsServers; _i < _a.length; _i++) {
            var websocket = _a[_i];
            websocket.isError = false;
        }
    };
    /**
     * Retrieve the next server to which connect.
     * @param {Boolean} force allows bypass of server error status checking
     * @returns {Object} WsServer
     */
    Transport.prototype.getNextWsServer = function (force) {
        if (force === void 0) { force = false; }
        if (this.noAvailableServers()) {
            this.logger.warn("attempted to get next ws server but there are no available ws servers left");
            throw new Error("Attempted to get next ws server, but there are no available ws servers left.");
        }
        // Order servers by weight
        var candidates = [];
        for (var _i = 0, _a = this.configuration.wsServers; _i < _a.length; _i++) {
            var wsServer = _a[_i];
            if (wsServer.isError && !force) {
                continue;
            }
            else if (candidates.length === 0) {
                candidates.push(wsServer);
            }
            else if (wsServer.weight > candidates[0].weight) {
                candidates = [wsServer];
            }
            else if (wsServer.weight === candidates[0].weight) {
                candidates.push(wsServer);
            }
        }
        var idx = Math.floor(Math.random() * candidates.length);
        return candidates[idx];
    };
    /**
     * Checks all configuration servers, returns true if all of them have isError: true and false otherwise
     * @returns {Boolean}
     */
    Transport.prototype.noAvailableServers = function () {
        for (var _i = 0, _a = this.configuration.wsServers; _i < _a.length; _i++) {
            var server = _a[_i];
            if (!server.isError) {
                return false;
            }
        }
        return true;
    };
    // ==============================
    // KeepAlive Stuff
    // ==============================
    /**
     * Send a keep-alive (a double-CRLF sequence).
     * @returns {Boolean}
     */
    Transport.prototype.sendKeepAlive = function () {
        var _this = this;
        if (this.keepAliveDebounceTimeout) {
            // We already have an outstanding keep alive, do not send another.
            return;
        }
        this.keepAliveDebounceTimeout = setTimeout(function () {
            _this.emit("keepAliveDebounceTimeout");
            _this.clearKeepAliveTimeout();
        }, this.configuration.keepAliveDebounce * 1000);
        return this.send("\r\n\r\n");
    };
    Transport.prototype.clearKeepAliveTimeout = function () {
        if (this.keepAliveDebounceTimeout) {
            clearTimeout(this.keepAliveDebounceTimeout);
        }
        this.keepAliveDebounceTimeout = undefined;
    };
    /**
     * Start sending keep-alives.
     */
    Transport.prototype.startSendingKeepAlives = function () {
        var _this = this;
        if (this.configuration.keepAliveInterval && !this.keepAliveInterval) {
            this.keepAliveInterval = setInterval(function () {
                _this.sendKeepAlive();
                _this.startSendingKeepAlives();
            }, computeKeepAliveTimeout(this.configuration.keepAliveInterval));
        }
    };
    /**
     * Stop sending keep-alives.
     */
    Transport.prototype.stopSendingKeepAlives = function () {
        if (this.keepAliveInterval) {
            clearInterval(this.keepAliveInterval);
        }
        if (this.keepAliveDebounceTimeout) {
            clearTimeout(this.keepAliveDebounceTimeout);
        }
        this.keepAliveInterval = undefined;
        this.keepAliveDebounceTimeout = undefined;
    };
    // ==============================
    // Status Stuff
    // ==============================
    /**
     * Checks given status against instance current status. Returns true if they match
     * @param {Number} status
     * @param {Boolean} [force]
     * @returns {Boolean}
     */
    Transport.prototype.statusAssert = function (status, force) {
        if (status === this.status) {
            return true;
        }
        else {
            if (force) {
                this.logger.warn("Attempted to assert " +
                    Object.keys(TransportStatus)[this.status] + " as " +
                    Object.keys(TransportStatus)[status] + "- continuing with option: 'force'");
                return true;
            }
            else {
                this.logger.warn("Tried to assert " +
                    Object.keys(TransportStatus)[status] + " but is currently " +
                    Object.keys(TransportStatus)[this.status]);
                return false;
            }
        }
    };
    /**
     * Transitions the status. Checks for legal transition via assertion beforehand
     * @param {Number} status
     * @param {Boolean} [force]
     * @returns {Boolean}
     */
    Transport.prototype.statusTransition = function (status, force) {
        if (force === void 0) { force = false; }
        this.logger.log("Attempting to transition status from " +
            Object.keys(TransportStatus)[this.status] + " to " +
            Object.keys(TransportStatus)[status]);
        if ((status === TransportStatus.STATUS_CONNECTING && this.statusAssert(TransportStatus.STATUS_CLOSED, force)) ||
            (status === TransportStatus.STATUS_OPEN && this.statusAssert(TransportStatus.STATUS_CONNECTING, force)) ||
            (status === TransportStatus.STATUS_CLOSING && this.statusAssert(TransportStatus.STATUS_OPEN, force)) ||
            (status === TransportStatus.STATUS_CLOSED)) {
            this.status = status;
            return true;
        }
        else {
            this.logger.warn("Status transition failed - result: no-op - reason:" +
                " either gave an nonexistent status or attempted illegal transition");
            return false;
        }
    };
    // ==============================
    // Configuration Handling
    // ==============================
    /**
     * Configuration load.
     * returns {Configuration}
     */
    Transport.prototype.loadConfig = function (configuration) {
        var settings = {
            wsServers: [{
                    scheme: "WSS",
                    sipUri: "<sip:edge.sip.onsip.com;transport=ws;lr>",
                    weight: 0,
                    wsUri: "wss://edge.sip.onsip.com",
                    isError: false
                }],
            connectionTimeout: 5,
            maxReconnectionAttempts: 3,
            reconnectionTimeout: 4,
            keepAliveInterval: 0,
            keepAliveDebounce: 10,
            // Logging
            traceSip: false
        };
        var configCheck = this.getConfigurationCheck();
        // Check Mandatory parameters
        for (var parameter in configCheck.mandatory) {
            if (!configuration.hasOwnProperty(parameter)) {
                throw new Exceptions_1.Exceptions.ConfigurationError(parameter);
            }
            else {
                var value = configuration[parameter];
                var checkedValue = configCheck.mandatory[parameter](value);
                if (checkedValue !== undefined) {
                    settings[parameter] = checkedValue;
                }
                else {
                    throw new Exceptions_1.Exceptions.ConfigurationError(parameter, value);
                }
            }
        }
        // Check Optional parameters
        for (var parameter in configCheck.optional) {
            if (configuration.hasOwnProperty(parameter)) {
                var value = configuration[parameter];
                // If the parameter value is an empty array, but shouldn't be, apply its default value.
                // If the parameter value is null, empty string, or undefined then apply its default value.
                // If it's a number with NaN value then also apply its default value.
                // NOTE: JS does not allow "value === NaN", the following does the work:
                if ((value instanceof Array && value.length === 0) ||
                    (value === null || value === "" || value === undefined) ||
                    (typeof (value) === "number" && isNaN(value))) {
                    continue;
                }
                var checkedValue = configCheck.optional[parameter](value);
                if (checkedValue !== undefined) {
                    settings[parameter] = checkedValue;
                }
                else {
                    throw new Exceptions_1.Exceptions.ConfigurationError(parameter, value);
                }
            }
        }
        var skeleton = {}; // Fill the value of the configuration_skeleton
        for (var parameter in settings) {
            if (settings.hasOwnProperty(parameter)) {
                skeleton[parameter] = {
                    value: settings[parameter],
                };
            }
        }
        var returnConfiguration = Object.defineProperties({}, skeleton);
        this.logger.log("configuration parameters after validation:");
        for (var parameter in settings) {
            if (settings.hasOwnProperty(parameter)) {
                this.logger.log("· " + parameter + ": " + JSON.stringify(settings[parameter]));
            }
        }
        return returnConfiguration;
    };
    /**
     * Configuration checker.
     * @return {Boolean}
     */
    Transport.prototype.getConfigurationCheck = function () {
        return {
            mandatory: {},
            optional: {
                // Note: this function used to call 'this.logger.error' but calling 'this' with anything here is invalid
                wsServers: function (wsServers) {
                    /* Allow defining wsServers parameter as:
                     *  String: "host"
                     *  Array of Strings: ["host1", "host2"]
                     *  Array of Objects: [{wsUri:"host1", weight:1}, {wsUri:"host2", weight:0}]
                     *  Array of Objects and Strings: [{wsUri:"host1"}, "host2"]
                     */
                    if (typeof wsServers === "string") {
                        wsServers = [{ wsUri: wsServers }];
                    }
                    else if (wsServers instanceof Array) {
                        for (var idx = 0; idx < wsServers.length; idx++) {
                            if (typeof wsServers[idx] === "string") {
                                wsServers[idx] = { wsUri: wsServers[idx] };
                            }
                        }
                    }
                    else {
                        return;
                    }
                    if (wsServers.length === 0) {
                        return false;
                    }
                    for (var _i = 0, wsServers_1 = wsServers; _i < wsServers_1.length; _i++) {
                        var wsServer = wsServers_1[_i];
                        if (!wsServer.wsUri) {
                            return;
                        }
                        if (wsServer.weight && !Number(wsServer.weight)) {
                            return;
                        }
                        var url = Grammar_1.Grammar.parse(wsServer.wsUri, "absoluteURI");
                        if (url === -1) {
                            return;
                        }
                        else if (["wss", "ws", "udp"].indexOf(url.scheme) < 0) {
                            return;
                        }
                        else {
                            wsServer.sipUri = "<sip:" + url.host +
                                (url.port ? ":" + url.port : "") + ";transport=" + url.scheme.replace(/^wss$/i, "ws") + ";lr>";
                            if (!wsServer.weight) {
                                wsServer.weight = 0;
                            }
                            wsServer.isError = false;
                            wsServer.scheme = url.scheme.toUpperCase();
                        }
                    }
                    return wsServers;
                },
                keepAliveInterval: function (keepAliveInterval) {
                    if (Utils_1.Utils.isDecimal(keepAliveInterval)) {
                        var value = Number(keepAliveInterval);
                        if (value > 0) {
                            return value;
                        }
                    }
                },
                keepAliveDebounce: function (keepAliveDebounce) {
                    if (Utils_1.Utils.isDecimal(keepAliveDebounce)) {
                        var value = Number(keepAliveDebounce);
                        if (value > 0) {
                            return value;
                        }
                    }
                },
                traceSip: function (traceSip) {
                    if (typeof traceSip === "boolean") {
                        return traceSip;
                    }
                },
                connectionTimeout: function (connectionTimeout) {
                    if (Utils_1.Utils.isDecimal(connectionTimeout)) {
                        var value = Number(connectionTimeout);
                        if (value > 0) {
                            return value;
                        }
                    }
                },
                maxReconnectionAttempts: function (maxReconnectionAttempts) {
                    if (Utils_1.Utils.isDecimal(maxReconnectionAttempts)) {
                        var value = Number(maxReconnectionAttempts);
                        if (value >= 0) {
                            return value;
                        }
                    }
                },
                reconnectionTimeout: function (reconnectionTimeout) {
                    if (Utils_1.Utils.isDecimal(reconnectionTimeout)) {
                        var value = Number(reconnectionTimeout);
                        if (value > 0) {
                            return value;
                        }
                    }
                }
            }
        };
    };
    Transport.C = TransportStatus;
    return Transport;
}(Transport_1.Transport));
exports.Transport = Transport;

/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(31)))

/***/ }),
/* 36 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";

Object.defineProperty(exports, "__esModule", { value: true });
var Modifiers = __webpack_require__(33);
exports.Modifiers = Modifiers;
var Simple_1 = __webpack_require__(37);
exports.Simple = Simple_1.Simple;
var SessionDescriptionHandler_1 = __webpack_require__(32);
exports.SessionDescriptionHandler = SessionDescriptionHandler_1.SessionDescriptionHandler;
var Transport_1 = __webpack_require__(35);
exports.Transport = Transport_1.Transport;


/***/ }),
/* 37 */
/***/ (function(module, exports, __webpack_require__) {

"use strict";
/* WEBPACK VAR INJECTION */(function(global) {
var __extends = (this && this.__extends) || (function () {
    var extendStatics = function (d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };
    return function (d, b) {
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
var events_1 = __webpack_require__(2);
var UA_1 = __webpack_require__(30);
var Modifiers = __webpack_require__(33);
/* Simple
 * @class Simple
 */
var SimpleStatus;
(function (SimpleStatus) {
    SimpleStatus[SimpleStatus["STATUS_NULL"] = 0] = "STATUS_NULL";
    SimpleStatus[SimpleStatus["STATUS_NEW"] = 1] = "STATUS_NEW";
    SimpleStatus[SimpleStatus["STATUS_CONNECTING"] = 2] = "STATUS_CONNECTING";
    SimpleStatus[SimpleStatus["STATUS_CONNECTED"] = 3] = "STATUS_CONNECTED";
    SimpleStatus[SimpleStatus["STATUS_COMPLETED"] = 4] = "STATUS_COMPLETED";
})(SimpleStatus = exports.SimpleStatus || (exports.SimpleStatus = {}));
var Simple = /** @class */ (function (_super) {
    __extends(Simple, _super);
    function Simple(options) {
        var _this = _super.call(this) || this;
        /*
        *  {
        *    media: {
        *      remote: {
        *        audio: <DOM element>,
        *        video: <DOM element>
        *      },
        *      local: {
        *        video: <DOM element>
        *      }
        *    },
        *    ua: {
        *       <UA Configuration Options>
        *    }
        *  }
        */
        if (options.media.remote.video) {
            _this.video = true;
        }
        else {
            _this.video = false;
        }
        if (options.media.remote.audio) {
            _this.audio = true;
        }
        else {
            _this.audio = false;
        }
        if (!_this.audio && !_this.video) {
            // Need to do at least audio or video
            // Error
            throw new Error("At least one remote audio or video element is required for Simple.");
        }
        _this.options = options;
        // https://stackoverflow.com/questions/7944460/detect-safari-browser
        var browserUa = global.navigator.userAgent.toLowerCase();
        var isSafari = false;
        var isFirefox = false;
        if (browserUa.indexOf("safari") > -1 && browserUa.indexOf("chrome") < 0) {
            isSafari = true;
        }
        else if (browserUa.indexOf("firefox") > -1 && browserUa.indexOf("chrome") < 0) {
            isFirefox = true;
        }
        var sessionDescriptionHandlerFactoryOptions = {};
        if (isSafari) {
            sessionDescriptionHandlerFactoryOptions.modifiers = [Modifiers.stripG722];
        }
        if (isFirefox) {
            sessionDescriptionHandlerFactoryOptions.alwaysAcquireMediaFirst = true;
        }
        if (!_this.options.ua.uri) {
            _this.anonymous = true;
        }
        else {
            _this.anonymous = false;
        }
        _this.ua = new UA_1.UA({
            // User Configurable Options
            uri: _this.options.ua.uri,
            authorizationUser: _this.options.ua.authorizationUser,
            password: _this.options.ua.password,
            displayName: _this.options.ua.displayName,
            // Undocumented "Advanced" Options
            userAgentString: _this.options.ua.userAgentString,
            // Fixed Options
            register: true,
            sessionDescriptionHandlerFactoryOptions: sessionDescriptionHandlerFactoryOptions,
            transportOptions: {
                traceSip: _this.options.ua.traceSip,
                wsServers: _this.options.ua.wsServers
            }
        });
        _this.state = SimpleStatus.STATUS_NULL;
        _this.logger = _this.ua.getLogger("sip.simple");
        _this.ua.on("registered", function () {
            _this.emit("registered", _this.ua);
        });
        _this.ua.on("unregistered", function () {
            _this.emit("unregistered", _this.ua);
        });
        _this.ua.on("registrationFailed", function () {
            _this.emit("unregistered", _this.ua);
        });
        _this.ua.on("invite", function (session) {
            // If there is already an active session reject the incoming session
            if (_this.state !== SimpleStatus.STATUS_NULL && _this.state !== SimpleStatus.STATUS_COMPLETED) {
                _this.logger.warn("Rejecting incoming call. Simple only supports 1 call at a time");
                session.reject();
                return;
            }
            _this.session = session;
            _this.setupSession();
            _this.emit("ringing", _this.session);
        });
        _this.ua.on("message", function (message) {
            _this.emit("message", message);
        });
        return _this;
    }
    Simple.prototype.call = function (destination) {
        if (!this.ua || !this.checkRegistration()) {
            this.logger.warn("A registered UA is required for calling");
            return;
        }
        if (this.state !== SimpleStatus.STATUS_NULL && this.state !== SimpleStatus.STATUS_COMPLETED) {
            this.logger.warn("Cannot make more than a single call with Simple");
            return;
        }
        // Safari hack, because you cannot call .play() from a non user action
        if (this.options.media.remote.audio) {
            this.options.media.remote.audio.autoplay = true;
        }
        if (this.options.media.remote.video) {
            this.options.media.remote.video.autoplay = true;
        }
        if (this.options.media.local && this.options.media.local.video) {
            this.options.media.local.video.autoplay = true;
            this.options.media.local.video.volume = 0;
        }
        this.session = this.ua.invite(destination, {
            sessionDescriptionHandlerOptions: {
                constraints: {
                    audio: this.audio,
                    video: this.video
                }
            }
        });
        this.setupSession();
        return this.session;
    };
    Simple.prototype.answer = function () {
        if (this.state !== SimpleStatus.STATUS_NEW && this.state !== SimpleStatus.STATUS_CONNECTING) {
            this.logger.warn("No call to answer");
            return;
        }
        // Safari hack, because you cannot call .play() from a non user action
        if (this.options.media.remote.audio) {
            this.options.media.remote.audio.autoplay = true;
        }
        if (this.options.media.remote.video) {
            this.options.media.remote.video.autoplay = true;
        }
        return this.session.accept({
            sessionDescriptionHandlerOptions: {
                constraints: {
                    audio: this.audio,
                    video: this.video
                }
            }
        });
        // emit call is active
    };
    Simple.prototype.reject = function () {
        if (this.state !== SimpleStatus.STATUS_NEW && this.state !== SimpleStatus.STATUS_CONNECTING) {
            this.logger.warn("Call is already answered");
            return;
        }
        return this.session.reject();
    };
    Simple.prototype.hangup = function () {
        if (this.state !== SimpleStatus.STATUS_CONNECTED &&
            this.state !== SimpleStatus.STATUS_CONNECTING &&
            this.state !== SimpleStatus.STATUS_NEW) {
            this.logger.warn("No active call to hang up on");
            return;
        }
        if (this.state !== SimpleStatus.STATUS_CONNECTED) {
            return this.session.cancel();
        }
        else if (this.session) {
            return this.session.bye();
        }
    };
    Simple.prototype.hold = function () {
        if (this.state !== SimpleStatus.STATUS_CONNECTED || !this.session || this.session.localHold) {
            this.logger.warn("Cannot put call on hold");
            return;
        }
        this.mute();
        this.logger.log("Placing session on hold");
        return this.session.hold();
    };
    Simple.prototype.unhold = function () {
        if (this.state !== SimpleStatus.STATUS_CONNECTED || !this.session || !this.session.localHold) {
            this.logger.warn("Cannot unhold a call that is not on hold");
            return;
        }
        this.unmute();
        this.logger.log("Placing call off hold");
        return this.session.unhold();
    };
    Simple.prototype.mute = function () {
        if (this.state !== SimpleStatus.STATUS_CONNECTED) {
            this.logger.warn("An acitve call is required to mute audio");
            return;
        }
        this.logger.log("Muting Audio");
        this.toggleMute(true);
        this.emit("mute", this);
    };
    Simple.prototype.unmute = function () {
        if (this.state !== SimpleStatus.STATUS_CONNECTED) {
            this.logger.warn("An active call is required to unmute audio");
            return;
        }
        this.logger.log("Unmuting Audio");
        this.toggleMute(false);
        this.emit("unmute", this);
    };
    Simple.prototype.sendDTMF = function (tone) {
        if (this.state !== SimpleStatus.STATUS_CONNECTED || !this.session) {
            this.logger.warn("An active call is required to send a DTMF tone");
            return;
        }
        this.logger.log("Sending DTMF tone: " + tone);
        this.session.dtmf(tone);
    };
    Simple.prototype.message = function (destination, message) {
        if (!this.ua || !this.checkRegistration()) {
            this.logger.warn("A registered UA is required to send a message");
            return;
        }
        if (!destination || !message) {
            this.logger.warn("A destination and message are required to send a message");
            return;
        }
        this.ua.message(destination, message);
    };
    // Private Helpers
    Simple.prototype.checkRegistration = function () {
        return (this.anonymous || (this.ua && this.ua.isRegistered()));
    };
    Simple.prototype.setupRemoteMedia = function () {
        var _this = this;
        if (!this.session) {
            this.logger.warn("No session to set remote media on");
            return;
        }
        // If there is a video track, it will attach the video and audio to the same element
        var pc = this.session.sessionDescriptionHandler.peerConnection;
        var remoteStream;
        if (pc.getReceivers) {
            remoteStream = new global.window.MediaStream();
            pc.getReceivers().forEach(function (receiver) {
                var track = receiver.track;
                if (track) {
                    remoteStream.addTrack(track);
                }
            });
        }
        else {
            remoteStream = pc.getRemoteStreams()[0];
        }
        if (this.video) {
            this.options.media.remote.video.srcObject = remoteStream;
            this.options.media.remote.video.play().catch(function () {
                _this.logger.log("play was rejected");
            });
        }
        else if (this.audio) {
            this.options.media.remote.audio.srcObject = remoteStream;
            this.options.media.remote.audio.play().catch(function () {
                _this.logger.log("play was rejected");
            });
        }
    };
    Simple.prototype.setupLocalMedia = function () {
        if (!this.session) {
            this.logger.warn("No session to set local media on");
            return;
        }
        if (this.video && this.options.media.local && this.options.media.local.video) {
            var pc = this.session.sessionDescriptionHandler.peerConnection;
            var localStream_1;
            if (pc.getSenders) {
                localStream_1 = new global.window.MediaStream();
                pc.getSenders().forEach(function (sender) {
                    var track = sender.track;
                    if (track && track.kind === "video") {
                        localStream_1.addTrack(track);
                    }
                });
            }
            else {
                localStream_1 = pc.getLocalStreams()[0];
            }
            this.options.media.local.video.srcObject = localStream_1;
            this.options.media.local.video.volume = 0;
            this.options.media.local.video.play();
        }
    };
    Simple.prototype.cleanupMedia = function () {
        if (this.video) {
            this.options.media.remote.video.srcObject = null;
            this.options.media.remote.video.pause();
            if (this.options.media.local && this.options.media.local.video) {
                this.options.media.local.video.srcObject = null;
                this.options.media.local.video.pause();
            }
        }
        if (this.audio) {
            this.options.media.remote.audio.srcObject = null;
            this.options.media.remote.audio.pause();
        }
    };
    Simple.prototype.setupSession = function () {
        var _this = this;
        if (!this.session) {
            this.logger.warn("No session to set up");
            return;
        }
        this.state = SimpleStatus.STATUS_NEW;
        this.emit("new", this.session);
        this.session.on("progress", function () { return _this.onProgress(); });
        this.session.on("accepted", function () { return _this.onAccepted(); });
        this.session.on("rejected", function () { return _this.onEnded(); });
        this.session.on("failed", function () { return _this.onFailed(); });
        this.session.on("terminated", function () { return _this.onEnded(); });
    };
    Simple.prototype.destroyMedia = function () {
        if (this.session && this.session.sessionDescriptionHandler) {
            this.session.sessionDescriptionHandler.close();
        }
    };
    Simple.prototype.toggleMute = function (mute) {
        if (!this.session) {
            this.logger.warn("No session to toggle mute");
            return;
        }
        var pc = this.session.sessionDescriptionHandler.peerConnection;
        if (pc.getSenders) {
            pc.getSenders().forEach(function (sender) {
                if (sender.track) {
                    sender.track.enabled = !mute;
                }
            });
        }
        else {
            pc.getLocalStreams().forEach(function (stream) {
                stream.getAudioTracks().forEach(function (track) {
                    track.enabled = !mute;
                });
                stream.getVideoTracks().forEach(function (track) {
                    track.enabled = !mute;
                });
            });
        }
    };
    Simple.prototype.onAccepted = function () {
        var _this = this;
        if (!this.session) {
            this.logger.warn("No session for accepting");
            return;
        }
        this.state = SimpleStatus.STATUS_CONNECTED;
        this.emit("connected", this.session);
        this.setupLocalMedia();
        this.setupRemoteMedia();
        if (this.session.sessionDescriptionHandler) {
            this.session.sessionDescriptionHandler.on("addTrack", function () {
                _this.logger.log("A track has been added, triggering new remoteMedia setup");
                _this.setupRemoteMedia();
            });
            this.session.sessionDescriptionHandler.on("addStream", function () {
                _this.logger.log("A stream has been added, trigger new remoteMedia setup");
                _this.setupRemoteMedia();
            });
        }
        this.session.on("dtmf", function (request, dtmf) {
            _this.emit("dtmf", dtmf.tone);
        });
        this.session.on("bye", function () { return _this.onEnded(); });
    };
    Simple.prototype.onProgress = function () {
        this.state = SimpleStatus.STATUS_CONNECTING;
        this.emit("connecting", this.session);
    };
    Simple.prototype.onFailed = function () {
        this.onEnded();
    };
    Simple.prototype.onEnded = function () {
        this.state = SimpleStatus.STATUS_COMPLETED;
        this.emit("ended", this.session);
        this.cleanupMedia();
    };
    Simple.C = SimpleStatus;
    return Simple;
}(events_1.EventEmitter));
exports.Simple = Simple;

/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(31)))

/***/ })
/******/ ]);
});