/**
 *  Copyright (C) 2021  Double Bastion LLC
 *
 *  This file is part of Roundpin, which is licensed under the
 *  GNU Affero General Public License Version 3.0. The license terms
 *  are detailed in the "LICENSE.txt" file located in the root directory.
 *
 *  The file content from below is identical with that of the
 *  original file "sip-0.11.6.js". The copyright notice for
 *  the original content follows:

/*!
 * 
 *  SIP version 0.11.6
 *  Copyright (c) 2014-2018 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";

module.exports = __webpack_require__(1)(__webpack_require__(40));


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

"use strict";
/**
 * @name SIP
 * @namespace
 */

module.exports = function (environment) {
    var pkg = __webpack_require__(2), version = pkg.version, title = pkg.title;
    var SIP = Object.defineProperties({}, {
        version: {
            get: function () { return version; }
        },
        name: {
            get: function () { return title; }
        }
    });
    __webpack_require__(3)(SIP, environment);
    SIP.LoggerFactory = __webpack_require__(4)(environment.console);
    SIP.EventEmitter = __webpack_require__(5)();
    SIP.C = __webpack_require__(7)(SIP.name, SIP.version);
    SIP.Exceptions = __webpack_require__(8);
    SIP.Timers = __webpack_require__(9)(environment.timers);
    SIP.Transport = __webpack_require__(10)(SIP);
    __webpack_require__(11)(SIP);
    __webpack_require__(12)(SIP);
    __webpack_require__(13)(SIP);
    __webpack_require__(14)(SIP);
    __webpack_require__(15)(SIP);
    __webpack_require__(16)(SIP);
    __webpack_require__(18)(SIP);
    __webpack_require__(19)(SIP);
    SIP.SessionDescriptionHandler = __webpack_require__(20)(SIP.EventEmitter);
    __webpack_require__(21)(SIP);
    __webpack_require__(22)(SIP);
    __webpack_require__(23)(SIP);
    __webpack_require__(25)(SIP);
    __webpack_require__(26)(SIP);
    __webpack_require__(27)(SIP, environment);
    __webpack_require__(32)(SIP);
    SIP.DigestAuthentication = __webpack_require__(33)(SIP.Utils);
    SIP.Grammar = __webpack_require__(36)(SIP);
    SIP.Web = {
        Modifiers: __webpack_require__(38)(SIP),
        Simple: __webpack_require__(39)(SIP)
    };
    return SIP;
};


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

module.exports = {"name":"sip.js","title":"SIP.js","description":"A simple, intuitive, and powerful JavaScript signaling library","version":"0.11.6","main":"dist/sip.js","browser":{"./src/environment.js":"./src/environment_browser.js"},"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","websocket","webrtc","library","javascript"],"devDependencies":{"awesome-typescript-loader":"^5.2.1","eslint":"^5.4.0","jasmine-core":"^3.2.1","karma":"^3.0.0","karma-chrome-launcher":"^2.2.0","karma-cli":"^1.0.1","karma-jasmine":"^1.1.0","karma-jasmine-html-reporter":"^1.3.1","karma-mocha-reporter":"^2.2.5","karma-webpack":"^3.0.0","pegjs":"^0.10.0","pegjs-loader":"^0.5.4","typescript":"^3.0.3","webpack":"^4.19.0","webpack-cli":"^3.0.8"},"engines":{"node":">=6.0"},"license":"MIT","scripts":{"prebuild":"eslint src/*.js src/**/*.js","build-dev":"webpack --progress --env.buildType dev","build-prod":"webpack --progress --env.buildType prod","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 build-dev && npm run build-prod && npm run copy-dist-files","browserTest":"sleep 2 && open http://0.0.0.0:9876/debug.html & karma start --reporters kjhtml --no-single-run","commandLineTest":"karma start --reporters mocha --browsers ChromeHeadless --single-run","buildAndTest":"npm run build && npm run commandLineTest","buildAndBrowserTest":"npm run build && npm run browserTest"},"dependencies":{"crypto-js":"^3.1.9-1"},"optionalDependencies":{"promiscuous":"^0.6.0"}};

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

"use strict";

/**
 * @fileoverview Utils
 */
module.exports = function (SIP, environment) {
    var Utils;
    Utils = {
        Promise: environment.Promise,
        defer: function defer() {
            var deferred = {};
            deferred.promise = new Utils.Promise(function (resolve, reject) {
                deferred.resolve = resolve;
                deferred.reject = reject;
            });
            return deferred;
        },
        reducePromises: function reducePromises(arr, val) {
            return arr.reduce(function (acc, fn) {
                acc = acc.then(fn);
                return acc;
            }, SIP.Utils.Promise.resolve(val));
        },
        augment: function (object, constructor, args, override) {
            var idx, proto;
            // Add public properties from constructor's prototype onto object
            proto = constructor.prototype;
            for (idx in proto) {
                if (override || object[idx] === undefined) {
                    object[idx] = proto[idx];
                }
            }
            // Construct the object as though it were just created by constructor
            constructor.apply(object, args);
        },
        defaultOptions: function (defaultOptions, overridingOptions) {
            defaultOptions = defaultOptions || {};
            overridingOptions = overridingOptions || {};
            return Object.assign({}, defaultOptions, overridingOptions);
        },
        optionsOverride: function (options, winner, loser, isDeprecated, logger, defaultValue) {
            if (isDeprecated && options[loser]) {
                logger.warn(loser + ' is deprecated, please use ' + winner + ' instead');
            }
            if (options[winner] && options[loser]) {
                logger.warn(winner + ' overriding ' + loser);
            }
            options[winner] = options[winner] || options[loser] || defaultValue;
        },
        str_utf8_length: function (string) {
            return encodeURIComponent(string).replace(/%[A-F\d]{2}/g, 'U').length;
        },
        generateFakeSDP: function (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';
        },
        isFunction: function (fn) {
            if (fn !== undefined) {
                return Object.prototype.toString.call(fn) === '[object Function]';
            }
            else {
                return false;
            }
        },
        isDecimal: function (num) {
            return !isNaN(num) && (parseFloat(num) === parseInt(num, 10));
        },
        createRandomToken: function (size, base) {
            var i, r, token = '';
            base = base || 32;
            for (i = 0; i < size; i++) {
                r = Math.random() * base | 0;
                token += r.toString(base);
            }
            return token;
        },
        newTag: function () {
            return SIP.Utils.createRandomToken(SIP.UA.C.TAG_LENGTH);
        },
        // http://stackoverflow.com/users/109538/broofa
        newUUID: function () {
            var UUID = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
                var r = Math.random() * 16 | 0, v = c === 'x' ? r : (r & 0x3 | 0x8);
                return v.toString(16);
            });
            return UUID;
        },
        hostType: function (host) {
            if (!host) {
                return;
            }
            else {
                host = SIP.Grammar.parse(host, 'host');
                if (host !== -1) {
                    return host.host_type;
                }
            }
        },
        /**
        * 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]
        */
        normalizeTarget: function (target, domain) {
            var uri, target_array, target_user, 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 instanceof SIP.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') {
                target_array = target.split('@');
                switch (target_array.length) {
                    case 1:
                        if (!domain) {
                            return;
                        }
                        target_user = target;
                        target_domain = domain;
                        break;
                    case 2:
                        target_user = target_array[0];
                        target_domain = target_array[1];
                        break;
                    default:
                        target_user = target_array.slice(0, target_array.length - 1).join('@');
                        target_domain = target_array[target_array.length - 1];
                }
                // Remove the URI scheme (if present).
                target_user = target_user.replace(/^(sips?|tel):/i, '');
                // Remove 'tel' visual separators if the user portion just contains 'tel' number symbols.
                if (/^[\-\.\(\)]*\+?[0-9\-\.\(\)]+$/.test(target_user)) {
                    target_user = target_user.replace(/[\-\.\(\)]/g, '');
                }
                // Build the complete SIP URI.
                target = SIP.C.SIP + ':' + SIP.Utils.escapeUser(target_user) + '@' + target_domain;
                // Finally parse the resulting URI.
                uri = SIP.URI.parse(target);
                return uri;
            }
            else {
                return;
            }
        },
        /**
        * Hex-escape a SIP URI user.
        * @private
        * @param {String} user
        */
        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, '/');
        },
        headerize: function (string) {
            var exceptions = {
                'Call-Id': 'Call-ID',
                'Cseq': 'CSeq',
                'Min-Se': 'Min-SE',
                'Rack': 'RAck',
                'Rseq': 'RSeq',
                'Www-Authenticate': 'WWW-Authenticate'
            }, name = string.toLowerCase().replace(/_/g, '-').split('-'), hname = '', parts = name.length, part;
            for (part = 0; part < parts; part++) {
                if (part !== 0) {
                    hname += '-';
                }
                hname += name[part].charAt(0).toUpperCase() + name[part].substring(1);
            }
            if (exceptions[hname]) {
                hname = exceptions[hname];
            }
            return hname;
        },
        sipErrorCause: function (status_code) {
            var cause;
            for (cause in SIP.C.SIP_ERROR_CAUSES) {
                if (SIP.C.SIP_ERROR_CAUSES[cause].indexOf(status_code) !== -1) {
                    return SIP.C.causes[cause];
                }
            }
            return SIP.C.causes.SIP_FAILURE_CODE;
        },
        getReasonPhrase: function getReasonPhrase(code, specific) {
            return specific || SIP.C.REASON_PHRASE[code] || '';
        },
        getReasonHeaderValue: function getReasonHeaderValue(code, reason) {
            reason = SIP.Utils.getReasonPhrase(code, reason);
            return 'SIP;cause=' + code + ';text="' + reason + '"';
        },
        getCancelReason: function getCancelReason(code, reason) {
            if (code && code < 200 || code > 699) {
                throw new TypeError('Invalid status_code: ' + code);
            }
            else if (code) {
                return SIP.Utils.getReasonHeaderValue(code, reason);
            }
        },
        buildStatusLine: function buildStatusLine(code, reason) {
            code = code || null;
            reason = reason || null;
            // Validate code and reason values
            if (!code || (code < 100 || code > 699)) {
                throw new TypeError('Invalid status_code: ' + code);
            }
            else if (reason && typeof reason !== 'string' && !(reason instanceof String)) {
                throw new TypeError('Invalid reason_phrase: ' + reason);
            }
            reason = Utils.getReasonPhrase(code, reason);
            return 'SIP/2.0 ' + code + ' ' + reason + '\r\n';
        },
        /**
        * Generate a random Test-Net IP (http://tools.ietf.org/html/rfc5735)
        * @private
        */
        getRandomTestNetIP: function () {
            function getOctet(from, to) {
                return Math.floor(Math.random() * (to - from + 1) + from);
            }
            return '192.0.2.' + getOctet(1, 254);
        }
    };
    SIP.Utils = Utils;
};


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

"use strict";

var levels = {
    'error': 0,
    'warn': 1,
    'log': 2,
    'debug': 3
};
module.exports = function (console) {
    var LoggerFactory = function () {
        var logger, level = 2, builtinEnabled = true, connector = null;
        this.loggers = {};
        logger = this.getLogger('sip.loggerfactory');
        Object.defineProperties(this, {
            builtinEnabled: {
                get: function () { return builtinEnabled; },
                set: function (value) {
                    if (typeof value === 'boolean') {
                        builtinEnabled = value;
                    }
                    else {
                        logger.error('invalid "builtinEnabled" parameter value: ' + JSON.stringify(value));
                    }
                }
            },
            level: {
                get: function () { return level; },
                set: function (value) {
                    if (value >= 0 && value <= 3) {
                        level = value;
                    }
                    else if (value > 3) {
                        level = 3;
                    }
                    else if (levels.hasOwnProperty(value)) {
                        level = levels[value];
                    }
                    else {
                        logger.error('invalid "level" parameter value: ' + JSON.stringify(value));
                    }
                }
            },
            connector: {
                get: function () { return connector; },
                set: function (value) {
                    if (value === null || value === "" || value === undefined) {
                        connector = null;
                    }
                    else if (typeof value === 'function') {
                        connector = value;
                    }
                    else {
                        logger.error('invalid "connector" parameter value: ' + JSON.stringify(value));
                    }
                }
            }
        });
    };
    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);
    };
    function Logger(logger, category, label) {
        this.logger = logger;
        this.category = category;
        this.label = label;
    }
    Object.keys(levels).forEach(function (targetName) {
        Logger.prototype[targetName] = function (content) {
            this.logger[targetName](this.category, this.label, content);
        };
        LoggerFactory.prototype[targetName] = function (category, label, content) {
            if (this.level >= levels[targetName]) {
                if (this.builtinEnabled) {
                    this.print(console[targetName], category, label, content);
                }
                if (this.connector) {
                    this.connector(targetName, category, label, content);
                }
            }
        };
    });
    LoggerFactory.prototype.getLogger = function (category, label) {
        var logger;
        if (label && this.level === 3) {
            return new Logger(this, category, label);
        }
        else if (this.loggers[category]) {
            return this.loggers[category];
        }
        else {
            logger = new Logger(this, category);
            this.loggers[category] = logger;
            return logger;
        }
    };
    return LoggerFactory;
};


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

"use strict";

var NodeEventEmitter = __webpack_require__(6).EventEmitter;
module.exports = function () {
    // Don't use `new SIP.EventEmitter()` for inheriting.
    // Use Object.create(SIP.EventEmitter.prototoype);
    function EventEmitter() {
        NodeEventEmitter.call(this);
    }
    EventEmitter.prototype = Object.create(NodeEventEmitter.prototype, {
        constructor: {
            value: EventEmitter,
            enumerable: false,
            writable: true,
            configurable: true
        }
    });
    return EventEmitter;
};


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

// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.

function EventEmitter() {
  this._events = this._events || {};
  this._maxListeners = this._maxListeners || undefined;
}
module.exports = EventEmitter;

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

EventEmitter.prototype._events = undefined;
EventEmitter.prototype._maxListeners = undefined;

// By default EventEmitters will print a warning if more than 10 listeners are
// added to it. This is a useful default which helps finding memory leaks.
EventEmitter.defaultMaxListeners = 10;

// Obviously not all Emitters should be limited to 10. This function allows
// that to be increased. Set to zero for unlimited.
EventEmitter.prototype.setMaxListeners = function(n) {
  if (!isNumber(n) || n < 0 || isNaN(n))
    throw TypeError('n must be a positive number');
  this._maxListeners = n;
  return this;
};

EventEmitter.prototype.emit = function(type) {
  var er, handler, len, args, i, listeners;

  if (!this._events)
    this._events = {};

  // If there is no 'error' event listener then throw.
  if (type === 'error') {
    if (!this._events.error ||
        (isObject(this._events.error) && !this._events.error.length)) {
      er = arguments[1];
      if (er instanceof Error) {
        throw er; // Unhandled 'error' event
      } else {
        // At least give some kind of context to the user
        var err = new Error('Uncaught, unspecified "error" event. (' + er + ')');
        err.context = er;
        throw err;
      }
    }
  }

  handler = this._events[type];

  if (isUndefined(handler))
    return false;

  if (isFunction(handler)) {
    switch (arguments.length) {
      // fast cases
      case 1:
        handler.call(this);
        break;
      case 2:
        handler.call(this, arguments[1]);
        break;
      case 3:
        handler.call(this, arguments[1], arguments[2]);
        break;
      // slower
      default:
        args = Array.prototype.slice.call(arguments, 1);
        handler.apply(this, args);
    }
  } else if (isObject(handler)) {
    args = Array.prototype.slice.call(arguments, 1);
    listeners = handler.slice();
    len = listeners.length;
    for (i = 0; i < len; i++)
      listeners[i].apply(this, args);
  }

  return true;
};

EventEmitter.prototype.addListener = function(type, listener) {
  var m;

  if (!isFunction(listener))
    throw TypeError('listener must be a function');

  if (!this._events)
    this._events = {};

  // To avoid recursion in the case that type === "newListener"! Before
  // adding it to the listeners, first emit "newListener".
  if (this._events.newListener)
    this.emit('newListener', type,
              isFunction(listener.listener) ?
              listener.listener : listener);

  if (!this._events[type])
    // Optimize the case of one listener. Don't need the extra array object.
    this._events[type] = listener;
  else if (isObject(this._events[type]))
    // If we've already got an array, just append.
    this._events[type].push(listener);
  else
    // Adding the second element, need to change to array.
    this._events[type] = [this._events[type], listener];

  // Check for listener leak
  if (isObject(this._events[type]) && !this._events[type].warned) {
    if (!isUndefined(this._maxListeners)) {
      m = this._maxListeners;
    } else {
      m = EventEmitter.defaultMaxListeners;
    }

    if (m && m > 0 && this._events[type].length > m) {
      this._events[type].warned = true;
      console.error('(node) warning: possible EventEmitter memory ' +
                    'leak detected. %d listeners added. ' +
                    'Use emitter.setMaxListeners() to increase limit.',
                    this._events[type].length);
      if (typeof console.trace === 'function') {
        // not supported in IE 10
        console.trace();
      }
    }
  }

  return this;
};

EventEmitter.prototype.on = EventEmitter.prototype.addListener;

EventEmitter.prototype.once = function(type, listener) {
  if (!isFunction(listener))
    throw TypeError('listener must be a function');

  var fired = false;

  function g() {
    this.removeListener(type, g);

    if (!fired) {
      fired = true;
      listener.apply(this, arguments);
    }
  }

  g.listener = listener;
  this.on(type, g);

  return this;
};

// emits a 'removeListener' event iff the listener was removed
EventEmitter.prototype.removeListener = function(type, listener) {
  var list, position, length, i;

  if (!isFunction(listener))
    throw TypeError('listener must be a function');

  if (!this._events || !this._events[type])
    return this;

  list = this._events[type];
  length = list.length;
  position = -1;

  if (list === listener ||
      (isFunction(list.listener) && list.listener === listener)) {
    delete this._events[type];
    if (this._events.removeListener)
      this.emit('removeListener', type, listener);

  } else if (isObject(list)) {
    for (i = length; i-- > 0;) {
      if (list[i] === listener ||
          (list[i].listener && list[i].listener === listener)) {
        position = i;
        break;
      }
    }

    if (position < 0)
      return this;

    if (list.length === 1) {
      list.length = 0;
      delete this._events[type];
    } else {
      list.splice(position, 1);
    }

    if (this._events.removeListener)
      this.emit('removeListener', type, listener);
  }

  return this;
};

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

  if (!this._events)
    return this;

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

  // emit removeListener for all listeners on all events
  if (arguments.length === 0) {
    for (key in this._events) {
      if (key === 'removeListener') continue;
      this.removeAllListeners(key);
    }
    this.removeAllListeners('removeListener');
    this._events = {};
    return this;
  }

  listeners = this._events[type];

  if (isFunction(listeners)) {
    this.removeListener(type, listeners);
  } else if (listeners) {
    // LIFO order
    while (listeners.length)
      this.removeListener(type, listeners[listeners.length - 1]);
  }
  delete this._events[type];

  return this;
};

EventEmitter.prototype.listeners = function(type) {
  var ret;
  if (!this._events || !this._events[type])
    ret = [];
  else if (isFunction(this._events[type]))
    ret = [this._events[type]];
  else
    ret = this._events[type].slice();
  return ret;
};

EventEmitter.prototype.listenerCount = function(type) {
  if (this._events) {
    var evlistener = this._events[type];

    if (isFunction(evlistener))
      return 1;
    else if (evlistener)
      return evlistener.length;
  }
  return 0;
};

EventEmitter.listenerCount = function(emitter, type) {
  return emitter.listenerCount(type);
};

function isFunction(arg) {
  return typeof arg === 'function';
}

function isNumber(arg) {
  return typeof arg === 'number';
}

function isObject(arg) {
  return typeof arg === 'object' && arg !== null;
}

function isUndefined(arg) {
  return arg === void 0;
}


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

"use strict";

/**
 * @fileoverview SIP Constants
 */
/**
 * SIP Constants.
 * @augments SIP
 */
module.exports = function (name, version) {
    return {
        USER_AGENT: name + '/' + version,
        // SIP scheme
        SIP: 'sip',
        SIPS: 'sips',
        // End and Failure causes
        causes: {
            // Generic error causes
            CONNECTION_ERROR: 'Connection Error',
            REQUEST_TIMEOUT: 'Request Timeout',
            SIP_FAILURE_CODE: 'SIP Failure Code',
            INTERNAL_ERROR: 'Internal Error',
            // SIP error causes
            BUSY: 'Busy',
            REJECTED: 'Rejected',
            REDIRECTED: 'Redirected',
            UNAVAILABLE: 'Unavailable',
            NOT_FOUND: 'Not Found',
            ADDRESS_INCOMPLETE: 'Address Incomplete',
            INCOMPATIBLE_SDP: 'Incompatible SDP',
            AUTHENTICATION_ERROR: 'Authentication Error',
            DIALOG_ERROR: 'Dialog Error',
            // Session error causes
            WEBRTC_NOT_SUPPORTED: 'WebRTC Not Supported',
            WEBRTC_ERROR: 'WebRTC Error',
            CANCELED: 'Canceled',
            NO_ANSWER: 'No Answer',
            EXPIRES: 'Expires',
            NO_ACK: 'No ACK',
            NO_PRACK: 'No PRACK',
            USER_DENIED_MEDIA_ACCESS: 'User Denied Media Access',
            BAD_MEDIA_DESCRIPTION: 'Bad Media Description',
            RTP_TIMEOUT: 'RTP Timeout'
        },
        supported: {
            UNSUPPORTED: 'none',
            SUPPORTED: 'supported',
            REQUIRED: 'required'
        },
        SIP_ERROR_CAUSES: {
            REDIRECTED: [300, 301, 302, 305, 380],
            BUSY: [486, 600],
            REJECTED: [403, 603],
            NOT_FOUND: [404, 604],
            UNAVAILABLE: [480, 410, 408, 430],
            ADDRESS_INCOMPLETE: [484],
            INCOMPATIBLE_SDP: [488, 606],
            AUTHENTICATION_ERROR: [401, 407]
        },
        // SIP Methods
        ACK: 'ACK',
        BYE: 'BYE',
        CANCEL: 'CANCEL',
        INFO: 'INFO',
        INVITE: 'INVITE',
        MESSAGE: 'MESSAGE',
        NOTIFY: 'NOTIFY',
        OPTIONS: 'OPTIONS',
        REGISTER: 'REGISTER',
        UPDATE: 'UPDATE',
        SUBSCRIBE: 'SUBSCRIBE',
        PUBLISH: 'PUBLISH',
        REFER: 'REFER',
        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
         */
        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
         */
        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': true,
            'sec-agree': true,
            tdialog: true,
            timer: true,
            uui: true // RFC 7433
        },
        dtmfType: {
            INFO: 'info',
            RTP: 'rtp'
        }
    };
};


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

"use strict";

/**
 * @fileoverview Exceptions
 */
/**
 * SIP Exceptions.
 * @augments SIP
 */
module.exports = {
    ConfigurationError: (function () {
        var exception = function (parameter, value) {
            this.code = 1;
            this.name = 'CONFIGURATION_ERROR';
            this.parameter = parameter;
            this.value = value;
            this.message = (!this.value) ? 'Missing parameter: ' + this.parameter : 'Invalid value ' + JSON.stringify(this.value) + ' for parameter "' + this.parameter + '"';
        };
        exception.prototype = new Error();
        return exception;
    }()),
    InvalidStateError: (function () {
        var exception = function (status) {
            this.code = 2;
            this.name = 'INVALID_STATE_ERROR';
            this.status = status;
            this.message = 'Invalid status: ' + status;
        };
        exception.prototype = new Error();
        return exception;
    }()),
    NotSupportedError: (function () {
        var exception = function (message) {
            this.code = 3;
            this.name = 'NOT_SUPPORTED_ERROR';
            this.message = message;
        };
        exception.prototype = new Error();
        return exception;
    }()),
    // Deprecated
    GetDescriptionError: (function () {
        var exception = function (message) {
            this.code = 4;
            this.name = 'GET_DESCRIPTION_ERROR';
            this.message = message;
        };
        exception.prototype = new Error();
        return exception;
    }()),
    RenegotiationError: (function () {
        var exception = function (message) {
            this.code = 5;
            this.name = 'RENEGOTIATION_ERROR';
            this.message = message;
        };
        exception.prototype = new Error();
        return exception;
    }()),
    MethodParameterError: (function () {
        var exception = function (method, parameter, value) {
            this.code = 6;
            this.name = 'METHOD_PARAMETER_ERROR';
            this.method = method;
            this.parameter = parameter;
            this.value = value;
            this.message = (!this.value) ? 'Missing parameter: ' + this.parameter : 'Invalid value ' + JSON.stringify(this.value) + ' for parameter "' + this.parameter + '"';
        };
        exception.prototype = new Error();
        return exception;
    }()),
    TransportError: (function () {
        var exception = function (message) {
            this.code = 7;
            this.name = 'TRANSPORT_ERROR';
            this.message = message;
        };
        exception.prototype = new Error();
        return exception;
    }()),
    SessionDescriptionHandlerError: (function () {
        var exception = function (method, error, message) {
            this.code = 8;
            this.name = 'SESSION_DESCRIPTION_HANDLER_ERROR';
            this.method = method;
            this.error = error;
            this.message = message || 'Error with Session Description Handler';
        };
        exception.prototype = new Error();
        return exception;
    }()),
};


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

"use strict";

/**
 * @fileoverview SIP TIMERS
 */
/**
 * @augments SIP
 */
var T1 = 500, T2 = 4000, T4 = 5000;
module.exports = function (timers) {
    var 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 * T1,
        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
    };
    ['setTimeout', 'clearTimeout', 'setInterval', 'clearInterval']
        .forEach(function (name) {
        // can't just use timers[name].bind(timers) since it bypasses jasmine's
        // clock-mocking
        Timers[name] = function () {
            return timers[name].apply(timers, arguments);
        };
    });
    return Timers;
};


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

"use strict";

/* eslint-disable */
/**
 * @fileoverview Transport
 */
/* Transport
 * @class Abstract transport layer parent class
 * @param {Logger} logger
 * @param {Object} [options]
 */
module.exports = function (SIP) {
    var Transport = function (logger, options) { };
    Transport.prototype = Object.create(SIP.EventEmitter.prototype, {
        /**
        * 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}
        */
        connect: { writable: true, value: function connect(options) {
                options = options || {};
                return this.connectPromise(options).then(function (data) { !data.overrideEvent && this.emit('connected'); }.bind(this));
            } },
        /**
        * Called by connect, must return a promise
        * promise must resolve to an object. object supports 1 parameter: overrideEvent - Boolean
        * @abstract
        * @private
        * @param {Object} [options]
        * @returns {Promise}
        */
        connectPromise: { writable: true, value: function connectPromise(options) { } },
        /**
        * Returns true if the transport is connected
        * @abstract
        * @returns {Boolean}
        */
        isConnected: { writable: true, value: function isConnected() { } },
        /**
        * 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 {SIP.OutgoingRequest|String} msg
        * @param {Object} options
        * @returns {Promise}
        */
        send: { writable: true, value: function send(msg, options) {
                options = options || {};
                return this.sendPromise(msg).then(function (data) { !data.overrideEvent && this.emit('messageSent', data.msg); }.bind(this));
            } },
        /**
        * Called by send, must return a promise
        * promise must resolve to an object. object supports 2 parameters: msg - string (mandatory) and overrideEvent - Boolean (optional)
        * @abstract
        * @private
        * @param {SIP.OutgoingRequest|String} msg
        * @param {Object} [options]
        * @returns {Promise}
        */
        sendPromise: { writable: true, value: function sendPromise(msg, options) { } },
        /**
        * To be called when a message is received
        * @abstract
        * @param {Event} e
        */
        onMessage: { writable: true, value: function onMessage(e) { } },
        /**
        * 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}
        */
        disconnect: { writable: true, value: function disconnect(options) {
                options = options || {};
                return this.disconnectPromise(options).then(function (data) { !data.overrideEvent && this.emit('disconnected'); }.bind(this));
            } },
        /**
        * Called by disconnect, must return a promise
        * promise must resolve to an object. object supports 1 parameter: overrideEvent - Boolean
        * @abstract
        * @private
        * @param {Object} [options]
        * @returns {Promise}
        */
        disconnectPromise: { writable: true, value: function disconnectPromise(options) { } },
        afterConnected: { writable: true, value: function afterConnected(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}
         */
        waitForConnected: { writable: true, value: function waitForConnected() {
                console.warn("DEPRECATION WARNING Transport.waitForConnected(): use afterConnected() instead");
                return new SIP.Utils.Promise(function (resolve) {
                    this.afterConnected(resolve);
                }.bind(this));
            } },
    });
    return Transport;
};


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

"use strict";

/**
 * @fileoverview SIP Message Parser
 */
/**
 * Extract and parse every header of a SIP message.
 * @augments SIP
 * @namespace
 */
module.exports = function (SIP) {
    var Parser;
    function getHeader(data, headerStart) {
        var 
        // 'start' position of the header.
        start = headerStart, 
        // 'end' position of the header.
        end = 0, 
        // 'partial end' position of the header.
        partialEnd = 0;
        //End of message.
        if (data.substring(start, start + 2).match(/(^\r\n)/)) {
            return -2;
        }
        while (end === 0) {
            // Partial End of Header.
            partialEnd = data.indexOf('\r\n', start);
            // 'indexOf' returns -1 if the value to be found never occurs.
            if (partialEnd === -1) {
                return partialEnd;
            }
            if (!data.substring(partialEnd + 2, partialEnd + 4).match(/(^\r\n)/) && data.charAt(partialEnd + 2).match(/(^\s+)/)) {
                // Not the end of the message. Continue from the next position.
                start = partialEnd + 2;
            }
            else {
                end = partialEnd;
            }
        }
        return end;
    }
    function parseHeader(message, data, headerStart, headerEnd) {
        var header, idx, length, parsed, hcolonIndex = data.indexOf(':', headerStart), headerName = data.substring(headerStart, hcolonIndex).trim(), headerValue = data.substring(hcolonIndex + 1, headerEnd).trim();
        // If header-field is well-known, parse it.
        switch (headerName.toLowerCase()) {
            case 'via':
            case 'v':
                message.addHeader('via', headerValue);
                if (message.getHeaders('via').length === 1) {
                    parsed = message.parseHeader('Via');
                    if (parsed) {
                        message.via = parsed;
                        message.via_branch = parsed.branch;
                    }
                }
                else {
                    parsed = 0;
                }
                break;
            case 'from':
            case 'f':
                message.setHeader('from', headerValue);
                parsed = message.parseHeader('from');
                if (parsed) {
                    message.from = parsed;
                    message.from_tag = parsed.getParam('tag');
                }
                break;
            case 'to':
            case 't':
                message.setHeader('to', headerValue);
                parsed = message.parseHeader('to');
                if (parsed) {
                    message.to = parsed;
                    message.to_tag = parsed.getParam('tag');
                }
                break;
            case 'record-route':
                parsed = SIP.Grammar.parse(headerValue, 'Record_Route');
                if (parsed === -1) {
                    parsed = undefined;
                    break;
                }
                length = parsed.length;
                for (idx = 0; idx < length; idx++) {
                    header = parsed[idx];
                    message.addHeader('record-route', headerValue.substring(header.position, header.offset));
                    message.headers['Record-Route'][message.getHeaders('record-route').length - 1].parsed = header.parsed;
                }
                break;
            case 'call-id':
            case 'i':
                message.setHeader('call-id', headerValue);
                parsed = message.parseHeader('call-id');
                if (parsed) {
                    message.call_id = headerValue;
                }
                break;
            case 'contact':
            case 'm':
                parsed = SIP.Grammar.parse(headerValue, 'Contact');
                if (parsed === -1) {
                    parsed = undefined;
                    break;
                }
                length = parsed.length;
                for (idx = 0; idx < length; idx++) {
                    header = parsed[idx];
                    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 instanceof SIP.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.refer_to = 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;
        }
    }
    /** Parse SIP Message
     * @function
     * @param {String} message SIP message.
     * @param {Object} logger object.
     * @returns {SIP.IncomingRequest|SIP.IncomingResponse|undefined}
     */
    Parser = {};
    Parser.parseMessage = function (data, ua) {
        var message, firstLine, contentLength, bodyStart, parsed, headerStart = 0, headerEnd = data.indexOf('\r\n'), 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.
        firstLine = data.substring(0, headerEnd);
        parsed = SIP.Grammar.parse(firstLine, 'Request_Response');
        if (parsed === -1) {
            logger.warn('error parsing first line of SIP message: "' + firstLine + '"');
            return;
        }
        else if (!parsed.status_code) {
            message = new SIP.IncomingRequest(ua);
            message.method = parsed.method;
            message.ruri = parsed.uri;
        }
        else {
            message = new SIP.IncomingResponse(ua);
            message.status_code = parsed.status_code;
            message.reason_phrase = 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.
        */
        while (true) {
            headerEnd = getHeader(data, headerStart);
            // The SIP message has normally finished.
            if (headerEnd === -2) {
                bodyStart = headerStart + 2;
                break;
            }
            // data.indexOf returned -1 due to a malformed message.
            else if (headerEnd === -1) {
                logger.error('malformed message');
                return;
            }
            parsed = parseHeader(message, data, headerStart, headerEnd);
            if (parsed !== 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')) {
            contentLength = message.getHeader('content-length');
            message.body = data.substr(bodyStart, contentLength);
        }
        else {
            message.body = data.substring(bodyStart);
        }
        return message;
    };
    SIP.Parser = Parser;
};


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

"use strict";

/**
 * @fileoverview SIP Message
 */
module.exports = function (SIP) {
    var OutgoingRequest, IncomingMessage, IncomingRequest, IncomingResponse;
    function getSupportedHeader(request) {
        var allowUnregistered = request.ua.configuration.hackAllowUnregisteredOptionTags;
        var optionTags = [];
        var optionTagSet = {};
        if (request.method === SIP.C.REGISTER) {
            optionTags.push('path', 'gruu');
        }
        else if (request.method === SIP.C.INVITE &&
            (request.ua.contact.pub_gruu || request.ua.contact.temp_gruu)) {
            optionTags.push('gruu');
        }
        if (request.ua.configuration.rel100 === SIP.C.supported.SUPPORTED) {
            optionTags.push('100rel');
        }
        if (request.ua.configuration.replaces === SIP.C.supported.SUPPORTED) {
            optionTags.push('replaces');
        }
        optionTags.push('outbound');
        optionTags = optionTags.concat(request.ua.configuration.extraSupported);
        optionTags = optionTags.filter(function (optionTag) {
            var registered = SIP.C.OPTION_TAGS[optionTag];
            var unique = !optionTagSet[optionTag];
            optionTagSet[optionTag] = true;
            return (registered || allowUnregistered) && unique;
        });
        return 'Supported: ' + optionTags.join(', ') + '\r\n';
    }
    /**
     * @augments SIP
     * @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, call_id, from_tag, from_uri, from_displayName, to_uri, to_tag, route_set
     * @param {Object} [headers] extra headers
     * @param {String} [body]
     */
    OutgoingRequest = function (method, ruri, ua, params, extraHeaders, body) {
        var to, from, call_id, cseq, to_uri, from_uri;
        params = params || {};
        // Mandatory parameters check
        if (!method || !ruri || !ua) {
            return null;
        }
        this.logger = ua.getLogger('sip.sipmessage');
        this.ua = ua;
        this.headers = {};
        this.method = method;
        this.ruri = ruri;
        this.body = body;
        this.extraHeaders = (extraHeaders || []).slice();
        this.statusCode = params.status_code;
        this.reasonPhrase = params.reason_phrase;
        // Fill the Common SIP Request Headers
        // Route
        if (params.route_set) {
            this.setHeader('route', params.route_set);
        }
        else if (ua.configuration.usePreloadedRoute) {
            this.setHeader('route', ua.transport.server.sip_uri);
        }
        // Via
        // Empty Via header. Will be filled by the client transaction.
        this.setHeader('via', '');
        // Max-Forwards
        this.setHeader('max-forwards', SIP.UA.C.MAX_FORWARDS);
        // To
        to_uri = params.to_uri || ruri;
        to = (params.to_displayName || params.to_displayName === 0) ? '"' + params.to_displayName + '" ' : '';
        to += '<' + (to_uri && to_uri.toRaw ? to_uri.toRaw() : to_uri) + '>';
        to += params.to_tag ? ';tag=' + params.to_tag : '';
        this.to = new SIP.NameAddrHeader.parse(to);
        this.setHeader('to', to);
        // From
        from_uri = params.from_uri || ua.configuration.uri;
        if (params.from_displayName || params.from_displayName === 0) {
            from = '"' + params.from_displayName + '" ';
        }
        else if (ua.configuration.displayName) {
            from = '"' + ua.configuration.displayName + '" ';
        }
        else {
            from = '';
        }
        from += '<' + (from_uri && from_uri.toRaw ? from_uri.toRaw() : from_uri) + '>;tag=';
        from += params.from_tag || SIP.Utils.newTag();
        this.from = new SIP.NameAddrHeader.parse(from);
        this.setHeader('from', from);
        // Call-ID
        call_id = params.call_id || (ua.configuration.sipjsId + SIP.Utils.createRandomToken(15));
        this.call_id = call_id;
        this.setHeader('call-id', call_id);
        // CSeq
        cseq = params.cseq || Math.floor(Math.random() * 10000);
        this.cseq = cseq;
        this.setHeader('cseq', cseq + ' ' + method);
    };
    OutgoingRequest.prototype = {
        /**
         * Replace the the given header by the given value.
         * @param {String} name header name
         * @param {String | Array} value header value
         */
        setHeader: function (name, value) {
            this.headers[SIP.Utils.headerize(name)] = (value instanceof Array) ? value : [value];
        },
        /**
         * Get the value of the given header name at the given position.
         * @param {String} name header name
         * @returns {String|undefined} Returns the specified header, undefined if header doesn't exist.
         */
        getHeader: function (name) {
            var regexp, idx, length = this.extraHeaders.length, header = this.headers[SIP.Utils.headerize(name)];
            if (header) {
                if (header[0]) {
                    return header[0];
                }
            }
            else {
                regexp = new RegExp('^\\s*' + name + '\\s*:', 'i');
                for (idx = 0; idx < length; idx++) {
                    header = this.extraHeaders[idx];
                    if (regexp.test(header)) {
                        return header.substring(header.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.
         */
        getHeaders: function (name) {
            var idx, length, regexp, header = this.headers[SIP.Utils.headerize(name)], result = [];
            if (header) {
                length = header.length;
                for (idx = 0; idx < length; idx++) {
                    result.push(header[idx]);
                }
                return result;
            }
            else {
                length = this.extraHeaders.length;
                regexp = new RegExp('^\\s*' + name + '\\s*:', 'i');
                for (idx = 0; idx < length; idx++) {
                    header = this.extraHeaders[idx];
                    if (regexp.test(header)) {
                        result.push(header.substring(header.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
         */
        hasHeader: function (name) {
            var regexp, idx, length = this.extraHeaders.length;
            if (this.headers[SIP.Utils.headerize(name)]) {
                return true;
            }
            else {
                regexp = new RegExp('^\\s*' + name + '\\s*:', 'i');
                for (idx = 0; idx < length; idx++) {
                    if (regexp.test(this.extraHeaders[idx])) {
                        return true;
                    }
                }
            }
            return false;
        },
        toString: function () {
            var msg = '', header, length, idx;
            msg += this.method + ' ' + (this.ruri.toRaw ? this.ruri.toRaw() : this.ruri) + ' SIP/2.0\r\n';
            for (header in this.headers) {
                length = this.headers[header].length;
                for (idx = 0; idx < length; idx++) {
                    msg += header + ': ' + this.headers[header][idx] + '\r\n';
                }
            }
            length = this.extraHeaders.length;
            for (idx = 0; idx < length; idx++) {
                msg += this.extraHeaders[idx].trim() + '\r\n';
            }
            msg += getSupportedHeader(this);
            msg += 'User-Agent: ' + this.ua.configuration.userAgentString + '\r\n';
            if (this.body) {
                if (typeof this.body === 'string') {
                    length = SIP.Utils.str_utf8_length(this.body);
                    msg += 'Content-Length: ' + length + '\r\n\r\n';
                    msg += this.body;
                }
                else {
                    if (this.body.body && this.body.contentType) {
                        length = SIP.Utils.str_utf8_length(this.body.body);
                        msg += 'Content-Type: ' + this.body.contentType + '\r\n';
                        msg += 'Content-Length: ' + length + '\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;
        }
    };
    /**
     * @augments SIP
     * @class Class for incoming SIP message.
     */
    IncomingMessage = function () {
        this.data = null;
        this.headers = null;
        this.method = null;
        this.via = null;
        this.via_branch = null;
        this.call_id = null;
        this.cseq = null;
        this.from = null;
        this.from_tag = null;
        this.to = null;
        this.to_tag = null;
        this.body = null;
    };
    IncomingMessage.prototype = {
        /**
        * 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
        */
        addHeader: function (name, value) {
            var header = { raw: value };
            name = SIP.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, null if header doesn't exist.
         */
        getHeader: function (name) {
            var header = this.headers[SIP.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.
         */
        getHeaders: function (name) {
            var idx, length, header = this.headers[SIP.Utils.headerize(name)], result = [];
            if (!header) {
                return [];
            }
            length = header.length;
            for (idx = 0; idx < length; idx++) {
                result.push(header[idx].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
         */
        hasHeader: function (name) {
            return (this.headers[SIP.Utils.headerize(name)]) ? true : false;
        },
        /**
        * Parse the given header on the given index.
        * @param {String} name header name
        * @param {Number} [idx=0] header index
        * @returns {Object|undefined} Parsed header object, undefined if the header is not present or in case of a parsing error.
        */
        parseHeader: function (name, idx) {
            var header, value, parsed;
            name = SIP.Utils.headerize(name);
            idx = idx || 0;
            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;
            }
            header = this.headers[name][idx];
            value = header.raw;
            if (header.parsed) {
                return header.parsed;
            }
            //substitute '-' by '_' for grammar rule matching.
            parsed = SIP.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
         */
        s: function (name, idx) {
            return this.parseHeader(name, idx);
        },
        /**
        * Replace the value of the given header by the value.
        * @param {String} name header name
        * @param {String} value header value
        */
        setHeader: function (name, value) {
            var header = { raw: value };
            this.headers[SIP.Utils.headerize(name)] = [header];
        },
        toString: function () {
            return this.data;
        }
    };
    /**
     * @augments IncomingMessage
     * @class Class for incoming SIP request.
     */
    IncomingRequest = function (ua) {
        this.logger = ua.getLogger('sip.sipmessage');
        this.ua = ua;
        this.headers = {};
        this.ruri = null;
        this.transport = null;
        this.server_transaction = null;
    };
    IncomingRequest.prototype = new IncomingMessage();
    /**
    * Stateful reply.
    * @param {Number} code status code
    * @param {String} reason reason phrase
    * @param {Object} headers extra headers
    * @param {String} body body
    * @param {Function} [onSuccess] onSuccess callback
    * @param {Function} [onFailure] onFailure callback
    */
    // TODO: Get rid of callbacks and make promise based
    IncomingRequest.prototype.reply = function (code, reason, extraHeaders, body, onSuccess, onFailure) {
        var rr, vias, length, idx, response, to = this.getHeader('To'), r = 0, v = 0;
        response = SIP.Utils.buildStatusLine(code, reason);
        extraHeaders = (extraHeaders || []).slice();
        if (this.method === SIP.C.INVITE && code > 100 && code <= 200) {
            rr = this.getHeaders('record-route');
            length = rr.length;
            for (r; r < length; r++) {
                response += 'Record-Route: ' + rr[r] + '\r\n';
            }
        }
        vias = this.getHeaders('via');
        length = vias.length;
        for (v; v < length; v++) {
            response += 'Via: ' + vias[v] + '\r\n';
        }
        if (!this.to_tag && code > 100) {
            to += ';tag=' + SIP.Utils.newTag();
        }
        else if (this.to_tag && !this.s('to').hasParam('tag')) {
            to += ';tag=' + this.to_tag;
        }
        response += 'To: ' + to + '\r\n';
        response += 'From: ' + this.getHeader('From') + '\r\n';
        response += 'Call-ID: ' + this.call_id + '\r\n';
        response += 'CSeq: ' + this.cseq + ' ' + this.method + '\r\n';
        length = extraHeaders.length;
        for (idx = 0; idx < length; idx++) {
            response += extraHeaders[idx].trim() + '\r\n';
        }
        response += getSupportedHeader(this);
        response += 'User-Agent: ' + this.ua.configuration.userAgentString + '\r\n';
        if (body) {
            if (typeof body === 'string') {
                length = SIP.Utils.str_utf8_length(body);
                response += 'Content-Type: application/sdp\r\n';
                response += 'Content-Length: ' + length + '\r\n\r\n';
                response += body;
            }
            else {
                if (body.body && body.contentType) {
                    length = SIP.Utils.str_utf8_length(body.body);
                    response += 'Content-Type: ' + body.contentType + '\r\n';
                    response += 'Content-Length: ' + length + '\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.server_transaction.receiveResponse(code, response).then(onSuccess, onFailure);
        return response;
    };
    /**
    * Stateless reply.
    * @param {Number} code status code
    * @param {String} reason reason phrase
    */
    IncomingRequest.prototype.reply_sl = function (code, reason) {
        var to, response, v = 0, vias = this.getHeaders('via'), length = vias.length;
        response = SIP.Utils.buildStatusLine(code, reason);
        for (v; v < length; v++) {
            response += 'Via: ' + vias[v] + '\r\n';
        }
        to = this.getHeader('To');
        if (!this.to_tag && code > 100) {
            to += ';tag=' + SIP.Utils.newTag();
        }
        else if (this.to_tag && !this.s('to').hasParam('tag')) {
            to += ';tag=' + this.to_tag;
        }
        response += 'To: ' + to + '\r\n';
        response += 'From: ' + this.getHeader('From') + '\r\n';
        response += 'Call-ID: ' + this.call_id + '\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);
    };
    /**
     * @augments IncomingMessage
     * @class Class for incoming SIP response.
     */
    IncomingResponse = function (ua) {
        this.logger = ua.getLogger('sip.sipmessage');
        this.headers = {};
        this.status_code = null;
        this.reason_phrase = null;
    };
    IncomingResponse.prototype = new IncomingMessage();
    SIP.OutgoingRequest = OutgoingRequest;
    SIP.IncomingRequest = IncomingRequest;
    SIP.IncomingResponse = IncomingResponse;
};


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

"use strict";

/**
 * @fileoverview SIP URI
 */
/**
 * @augments SIP
 * @class Class creating a SIP URI.
 *
 * @param {String} [scheme]
 * @param {String} [user]
 * @param {String} host
 * @param {String} [port]
 * @param {Object} [parameters]
 * @param {Object} [headers]
 *
 */
module.exports = function (SIP) {
    var URI;
    URI = function (scheme, user, host, port, parameters, headers) {
        var param, header, raw, normal;
        // Checks
        if (!host) {
            throw new TypeError('missing or invalid "host" parameter');
        }
        // Initialize parameters
        scheme = scheme || SIP.C.SIP;
        this.parameters = {};
        this.headers = {};
        for (param in parameters) {
            this.setParam(param, parameters[param]);
        }
        for (header in headers) {
            this.setHeader(header, headers[header]);
        }
        // Raw URI
        raw = {
            scheme: scheme,
            user: user,
            host: host,
            port: port
        };
        // Normalized URI
        normal = {
            scheme: scheme.toLowerCase(),
            user: user,
            host: host.toLowerCase(),
            port: port
        };
        Object.defineProperties(this, {
            _normal: {
                get: function () { return normal; }
            },
            _raw: {
                get: function () { return raw; }
            },
            scheme: {
                get: function () { return normal.scheme; },
                set: function (value) {
                    raw.scheme = value;
                    normal.scheme = value.toLowerCase();
                }
            },
            user: {
                get: function () { return normal.user; },
                set: function (value) {
                    normal.user = raw.user = value;
                }
            },
            host: {
                get: function () { return normal.host; },
                set: function (value) {
                    raw.host = value;
                    normal.host = value.toLowerCase();
                }
            },
            aor: {
                get: function () { return normal.user + '@' + normal.host; }
            },
            port: {
                get: function () { return normal.port; },
                set: function (value) {
                    normal.port = raw.port = value === 0 ? value : (parseInt(value, 10) || null);
                }
            }
        });
    };
    URI.prototype = {
        setParam: function (key, value) {
            if (key) {
                this.parameters[key.toLowerCase()] = (typeof value === 'undefined' || value === null) ? null : value.toString();
            }
        },
        getParam: function (key) {
            if (key) {
                return this.parameters[key.toLowerCase()];
            }
        },
        hasParam: function (key) {
            if (key) {
                return (this.parameters.hasOwnProperty(key.toLowerCase()) && true) || false;
            }
        },
        deleteParam: function (parameter) {
            var value;
            parameter = parameter.toLowerCase();
            if (this.parameters.hasOwnProperty(parameter)) {
                value = this.parameters[parameter];
                delete this.parameters[parameter];
                return value;
            }
        },
        clearParams: function () {
            this.parameters = {};
        },
        setHeader: function (name, value) {
            this.headers[SIP.Utils.headerize(name)] = (value instanceof Array) ? value : [value];
        },
        getHeader: function (name) {
            if (name) {
                return this.headers[SIP.Utils.headerize(name)];
            }
        },
        hasHeader: function (name) {
            if (name) {
                return (this.headers.hasOwnProperty(SIP.Utils.headerize(name)) && true) || false;
            }
        },
        deleteHeader: function (header) {
            var value;
            header = SIP.Utils.headerize(header);
            if (this.headers.hasOwnProperty(header)) {
                value = this.headers[header];
                delete this.headers[header];
                return value;
            }
        },
        clearHeaders: function () {
            this.headers = {};
        },
        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)));
        },
        toRaw: function () {
            return this._toString(this._raw);
        },
        toString: function () {
            return this._toString(this._normal);
        },
        _toString: function (uri) {
            var header, parameter, idx, uriString, headers = [];
            uriString = uri.scheme + ':';
            // add slashes if it's not a sip(s) URI
            if (!uri.scheme.toLowerCase().match("^sips?$")) {
                uriString += "//";
            }
            if (uri.user) {
                uriString += SIP.Utils.escapeUser(uri.user) + '@';
            }
            uriString += uri.host;
            if (uri.port || uri.port === 0) {
                uriString += ':' + uri.port;
            }
            for (parameter in this.parameters) {
                uriString += ';' + parameter;
                if (this.parameters[parameter] !== null) {
                    uriString += '=' + this.parameters[parameter];
                }
            }
            for (header in this.headers) {
                for (idx in this.headers[header]) {
                    headers.push(header + '=' + this.headers[header][idx]);
                }
            }
            if (headers.length > 0) {
                uriString += '?' + headers.join('&');
            }
            return uriString;
        }
    };
    /**
      * Parse the given string and returns a SIP.URI instance or undefined if
      * it is an invalid URI.
      * @public
      * @param {String} uri
      */
    URI.parse = function (uri) {
        uri = SIP.Grammar.parse(uri, 'SIP_URI');
        if (uri !== -1) {
            return uri;
        }
        else {
            return undefined;
        }
    };
    SIP.URI = URI;
};


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

"use strict";

/**
 * @fileoverview SIP NameAddrHeader
 */
/**
 * @augments SIP
 * @class Class creating a Name Address SIP header.
 *
 * @param {SIP.URI} uri
 * @param {String} [displayName]
 * @param {Object} [parameters]
 *
 */
module.exports = function (SIP) {
    var NameAddrHeader;
    NameAddrHeader = function (uri, displayName, parameters) {
        var param;
        // Checks
        if (!uri || !(uri instanceof SIP.URI)) {
            throw new TypeError('missing or invalid "uri" parameter');
        }
        // Initialize parameters
        this.uri = uri;
        this.parameters = {};
        for (param in parameters) {
            this.setParam(param, parameters[param]);
        }
        Object.defineProperties(this, {
            friendlyName: {
                get: function () { return this.displayName || uri.aor; }
            },
            displayName: {
                get: function () { return displayName; },
                set: function (value) {
                    displayName = (value === 0) ? '0' : value;
                }
            }
        });
    };
    NameAddrHeader.prototype = {
        setParam: function (key, value) {
            if (key) {
                this.parameters[key.toLowerCase()] = (typeof value === 'undefined' || value === null) ? null : value.toString();
            }
        },
        getParam: SIP.URI.prototype.getParam,
        hasParam: SIP.URI.prototype.hasParam,
        deleteParam: SIP.URI.prototype.deleteParam,
        clearParams: SIP.URI.prototype.clearParams,
        clone: function () {
            return new NameAddrHeader(this.uri.clone(), this.displayName, JSON.parse(JSON.stringify(this.parameters)));
        },
        toString: function () {
            var body, parameter;
            body = (this.displayName || this.displayName === 0) ? '"' + this.displayName + '" ' : '';
            body += '<' + this.uri.toString() + '>';
            for (parameter in this.parameters) {
                body += ';' + parameter;
                if (this.parameters[parameter] !== null) {
                    body += '=' + this.parameters[parameter];
                }
            }
            return body;
        }
    };
    /**
      * Parse the given string and returns a SIP.NameAddrHeader instance or undefined if
      * it is an invalid NameAddrHeader.
      * @public
      * @param {String} name_addr_header
      */
    NameAddrHeader.parse = function (name_addr_header) {
        name_addr_header = SIP.Grammar.parse(name_addr_header, 'Name_Addr_Header');
        if (name_addr_header !== -1) {
            return name_addr_header;
        }
        else {
            return undefined;
        }
    };
    SIP.NameAddrHeader = NameAddrHeader;
};


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

"use strict";

/**
 * @fileoverview SIP Transactions
 */
/**
 * SIP Transactions module.
 * @augments SIP
 */
module.exports = function (SIP) {
    var C = {
        // Transaction states
        STATUS_TRYING: 1,
        STATUS_PROCEEDING: 2,
        STATUS_CALLING: 3,
        STATUS_ACCEPTED: 4,
        STATUS_COMPLETED: 5,
        STATUS_TERMINATED: 6,
        STATUS_CONFIRMED: 7,
        // Transaction types
        NON_INVITE_CLIENT: 'nict',
        NON_INVITE_SERVER: 'nist',
        INVITE_CLIENT: 'ict',
        INVITE_SERVER: 'ist'
    };
    function buildViaHeader(request_sender, transport, id) {
        var via;
        via = 'SIP/2.0/' + (request_sender.ua.configuration.hackViaTcp ? 'TCP' : transport.server.scheme);
        via += ' ' + request_sender.ua.configuration.viaHost + ';branch=' + id;
        if (request_sender.ua.configuration.forceRport) {
            via += ';rport';
        }
        return via;
    }
    /**
    * @augments SIP.Transactions
    * @class Non Invite Client Transaction
    * @param {SIP.RequestSender} request_sender
    * @param {SIP.OutgoingRequest} request
    * @param {SIP.Transport} transport
    */
    var NonInviteClientTransaction = function (request_sender, request, transport) {
        var via;
        this.type = C.NON_INVITE_CLIENT;
        this.transport = transport;
        this.id = 'z9hG4bK' + Math.floor(Math.random() * 10000000);
        this.request_sender = request_sender;
        this.request = request;
        this.logger = request_sender.ua.getLogger('sip.transaction.nict', this.id);
        via = buildViaHeader(request_sender, transport, this.id);
        this.request.setHeader('via', via);
        this.request_sender.ua.newTransaction(this);
    };
    NonInviteClientTransaction.prototype = Object.create(SIP.EventEmitter.prototype);
    NonInviteClientTransaction.prototype.stateChanged = function (state) {
        this.state = state;
        this.emit('stateChanged');
    };
    NonInviteClientTransaction.prototype.send = function () {
        var tr = this;
        this.stateChanged(C.STATUS_TRYING);
        this.F = SIP.Timers.setTimeout(tr.timer_F.bind(tr), SIP.Timers.TIMER_F);
        this.transport.send(this.request).catch(function () {
            this.onTransportError();
        }.bind(this));
    };
    NonInviteClientTransaction.prototype.onTransportError = function () {
        this.logger.log('transport error occurred, deleting non-INVITE client transaction ' + this.id);
        SIP.Timers.clearTimeout(this.F);
        SIP.Timers.clearTimeout(this.K);
        this.stateChanged(C.STATUS_TERMINATED);
        this.request_sender.ua.destroyTransaction(this);
        this.request_sender.onTransportError();
    };
    NonInviteClientTransaction.prototype.timer_F = function () {
        this.logger.debug('Timer F expired for non-INVITE client transaction ' + this.id);
        this.stateChanged(C.STATUS_TERMINATED);
        this.request_sender.ua.destroyTransaction(this);
        this.request_sender.onRequestTimeout();
    };
    NonInviteClientTransaction.prototype.timer_K = function () {
        this.stateChanged(C.STATUS_TERMINATED);
        this.request_sender.ua.destroyTransaction(this);
    };
    NonInviteClientTransaction.prototype.receiveResponse = function (response) {
        var tr = this, status_code = response.status_code;
        if (status_code < 200) {
            switch (this.state) {
                case C.STATUS_TRYING:
                case C.STATUS_PROCEEDING:
                    this.stateChanged(C.STATUS_PROCEEDING);
                    this.request_sender.receiveResponse(response);
                    break;
            }
        }
        else {
            switch (this.state) {
                case C.STATUS_TRYING:
                case C.STATUS_PROCEEDING:
                    this.stateChanged(C.STATUS_COMPLETED);
                    SIP.Timers.clearTimeout(this.F);
                    if (status_code === 408) {
                        this.request_sender.onRequestTimeout();
                    }
                    else {
                        this.request_sender.receiveResponse(response);
                    }
                    this.K = SIP.Timers.setTimeout(tr.timer_K.bind(tr), SIP.Timers.TIMER_K);
                    break;
                case C.STATUS_COMPLETED:
                    break;
            }
        }
    };
    /**
    * @augments SIP.Transactions
    * @class Invite Client Transaction
    * @param {SIP.RequestSender} request_sender
    * @param {SIP.OutgoingRequest} request
    * @param {SIP.Transport} transport
    */
    var InviteClientTransaction = function (request_sender, request, transport) {
        var via, tr = this;
        this.type = C.INVITE_CLIENT;
        this.transport = transport;
        this.id = 'z9hG4bK' + Math.floor(Math.random() * 10000000);
        this.request_sender = request_sender;
        this.request = request;
        this.logger = request_sender.ua.getLogger('sip.transaction.ict', this.id);
        via = buildViaHeader(request_sender, transport, this.id);
        this.request.setHeader('via', via);
        this.request_sender.ua.newTransaction(this);
        // Add the cancel property to the request.
        //Will be called from the request instance, not the transaction itself.
        this.request.cancel = function (reason, extraHeaders) {
            extraHeaders = (extraHeaders || []).slice();
            var length = extraHeaders.length;
            var extraHeadersString = null;
            for (var idx = 0; idx < length; idx++) {
                extraHeadersString = (extraHeadersString || '') + extraHeaders[idx].trim() + '\r\n';
            }
            tr.cancel_request(tr, reason, extraHeadersString);
        };
    };
    InviteClientTransaction.prototype = Object.create(SIP.EventEmitter.prototype);
    InviteClientTransaction.prototype.stateChanged = function (state) {
        this.state = state;
        this.emit('stateChanged');
    };
    InviteClientTransaction.prototype.send = function () {
        var tr = this;
        this.stateChanged(C.STATUS_CALLING);
        this.B = SIP.Timers.setTimeout(tr.timer_B.bind(tr), SIP.Timers.TIMER_B);
        this.transport.send(this.request).catch(function () {
            this.onTransportError();
        }.bind(this));
    };
    InviteClientTransaction.prototype.onTransportError = function () {
        this.logger.log('transport error occurred, deleting INVITE client transaction ' + this.id);
        SIP.Timers.clearTimeout(this.B);
        SIP.Timers.clearTimeout(this.D);
        SIP.Timers.clearTimeout(this.M);
        this.stateChanged(C.STATUS_TERMINATED);
        this.request_sender.ua.destroyTransaction(this);
        if (this.state !== C.STATUS_ACCEPTED) {
            this.request_sender.onTransportError();
        }
    };
    // RFC 6026 7.2
    InviteClientTransaction.prototype.timer_M = function () {
        this.logger.debug('Timer M expired for INVITE client transaction ' + this.id);
        if (this.state === C.STATUS_ACCEPTED) {
            SIP.Timers.clearTimeout(this.B);
            this.stateChanged(C.STATUS_TERMINATED);
            this.request_sender.ua.destroyTransaction(this);
        }
    };
    // RFC 3261 17.1.1
    InviteClientTransaction.prototype.timer_B = function () {
        this.logger.debug('Timer B expired for INVITE client transaction ' + this.id);
        if (this.state === C.STATUS_CALLING) {
            this.stateChanged(C.STATUS_TERMINATED);
            this.request_sender.ua.destroyTransaction(this);
            this.request_sender.onRequestTimeout();
        }
    };
    InviteClientTransaction.prototype.timer_D = function () {
        this.logger.debug('Timer D expired for INVITE client transaction ' + this.id);
        SIP.Timers.clearTimeout(this.B);
        this.stateChanged(C.STATUS_TERMINATED);
        this.request_sender.ua.destroyTransaction(this);
    };
    InviteClientTransaction.prototype.sendACK = function (options) {
        // TODO: Move PRACK stuff into the transaction layer. That is really where it should be
        var self = this, ruri;
        options = options || {};
        if (this.response.getHeader('contact')) {
            ruri = this.response.parseHeader('contact').uri;
        }
        else {
            ruri = this.request.ruri;
        }
        var ack = new SIP.OutgoingRequest("ACK", ruri, this.request.ua, {
            cseq: this.response.cseq,
            call_id: this.response.call_id,
            from_uri: this.response.from.uri,
            from_tag: this.response.from_tag,
            to_uri: this.response.to.uri,
            to_tag: this.response.to_tag,
            route_set: this.response.getHeaders('record-route').reverse()
        }, options.extraHeaders || [], options.body);
        this.ackSender = new SIP.RequestSender({
            request: ack,
            onRequestTimeout: this.request_sender.applicant.applicant ? this.request_sender.applicant.applicant.onRequestTimeout : function () {
                self.logger.warn("ACK Request timed out");
            },
            onTransportError: this.request_sender.applicant.applicant ? this.request_sender.applicant.applicant.onRequestTransportError : function () {
                self.logger.warn("ACK Request had a transport error");
            },
            receiveResponse: options.receiveResponse || function () {
                self.logger.warn("Received a response to an ACK which was unexpected. Dropping Response.");
            }
        }, this.request.ua).send();
        return ack;
    };
    InviteClientTransaction.prototype.cancel_request = function (tr, reason, extraHeaders) {
        var request = tr.request;
        this.cancel = SIP.C.CANCEL + ' ' + request.ruri + ' SIP/2.0\r\n';
        this.cancel += 'Via: ' + request.headers['Via'].toString() + '\r\n';
        if (this.request.headers['Route']) {
            this.cancel += 'Route: ' + request.headers['Route'].toString() + '\r\n';
        }
        this.cancel += 'To: ' + request.headers['To'].toString() + '\r\n';
        this.cancel += 'From: ' + request.headers['From'].toString() + '\r\n';
        this.cancel += 'Call-ID: ' + request.headers['Call-ID'].toString() + '\r\n';
        this.cancel += 'Max-Forwards: ' + SIP.UA.C.MAX_FORWARDS + '\r\n';
        this.cancel += 'CSeq: ' + request.headers['CSeq'].toString().split(' ')[0] +
            ' CANCEL\r\n';
        if (reason) {
            this.cancel += 'Reason: ' + reason + '\r\n';
        }
        if (extraHeaders) {
            this.cancel += extraHeaders;
        }
        this.cancel += 'Content-Length: 0\r\n\r\n';
        // Send only if a provisional response (>100) has been received.
        if (this.state === C.STATUS_PROCEEDING) {
            this.transport.send(this.cancel);
        }
    };
    InviteClientTransaction.prototype.receiveResponse = function (response) {
        var tr = this, status_code = response.status_code;
        // This may create a circular dependency...
        response.transaction = this;
        if (this.response &&
            this.response.status_code === response.status_code &&
            this.response.cseq === response.cseq) {
            this.logger.debug("ICT Received a retransmission for cseq: " + response.cseq);
            if (this.ackSender) {
                this.ackSender.send();
            }
            return;
        }
        this.response = response;
        if (status_code >= 100 && status_code <= 199) {
            switch (this.state) {
                case C.STATUS_CALLING:
                    this.stateChanged(C.STATUS_PROCEEDING);
                    this.request_sender.receiveResponse(response);
                    if (this.cancel) {
                        this.transport.send(this.cancel);
                    }
                    break;
                case C.STATUS_PROCEEDING:
                    this.request_sender.receiveResponse(response);
                    break;
            }
        }
        else if (status_code >= 200 && status_code <= 299) {
            switch (this.state) {
                case C.STATUS_CALLING:
                case C.STATUS_PROCEEDING:
                    this.stateChanged(C.STATUS_ACCEPTED);
                    this.M = SIP.Timers.setTimeout(tr.timer_M.bind(tr), SIP.Timers.TIMER_M);
                    this.request_sender.receiveResponse(response);
                    break;
                case C.STATUS_ACCEPTED:
                    this.request_sender.receiveResponse(response);
                    break;
            }
        }
        else if (status_code >= 300 && status_code <= 699) {
            switch (this.state) {
                case C.STATUS_CALLING:
                case C.STATUS_PROCEEDING:
                    this.stateChanged(C.STATUS_COMPLETED);
                    this.sendACK();
                    this.request_sender.receiveResponse(response);
                    break;
                case C.STATUS_COMPLETED:
                    this.sendACK();
                    break;
            }
        }
    };
    /**
     * @augments SIP.Transactions
     * @class ACK Client Transaction
     * @param {SIP.RequestSender} request_sender
     * @param {SIP.OutgoingRequest} request
     * @param {SIP.Transport} transport
     */
    var AckClientTransaction = function (request_sender, request, transport) {
        var via;
        this.transport = transport;
        this.id = 'z9hG4bK' + Math.floor(Math.random() * 10000000);
        this.request_sender = request_sender;
        this.request = request;
        this.logger = request_sender.ua.getLogger('sip.transaction.nict', this.id);
        via = buildViaHeader(request_sender, transport, this.id);
        this.request.setHeader('via', via);
    };
    AckClientTransaction.prototype = Object.create(SIP.EventEmitter.prototype);
    AckClientTransaction.prototype.send = function () {
        this.transport.send(this.request).catch(function () {
            this.onTransportError();
        }.bind(this));
    };
    AckClientTransaction.prototype.onTransportError = function () {
        this.logger.log('transport error occurred, for an ACK client transaction ' + this.id);
        this.request_sender.onTransportError();
    };
    /**
    * @augments SIP.Transactions
    * @class Non Invite Server Transaction
    * @param {SIP.IncomingRequest} request
    * @param {SIP.UA} ua
    */
    var NonInviteServerTransaction = function (request, ua) {
        this.type = C.NON_INVITE_SERVER;
        this.id = request.via_branch;
        this.request = request;
        this.transport = ua.transport;
        this.ua = ua;
        this.last_response = '';
        request.server_transaction = this;
        this.logger = ua.getLogger('sip.transaction.nist', this.id);
        this.state = C.STATUS_TRYING;
        ua.newTransaction(this);
    };
    NonInviteServerTransaction.prototype = Object.create(SIP.EventEmitter.prototype);
    NonInviteServerTransaction.prototype.stateChanged = function (state) {
        this.state = state;
        this.emit('stateChanged');
    };
    NonInviteServerTransaction.prototype.timer_J = function () {
        this.logger.debug('Timer J expired for non-INVITE server transaction ' + this.id);
        this.stateChanged(C.STATUS_TERMINATED);
        this.ua.destroyTransaction(this);
    };
    NonInviteServerTransaction.prototype.onTransportError = function () {
        if (!this.transportError) {
            this.transportError = true;
            this.logger.log('transport error occurred, deleting non-INVITE server transaction ' + this.id);
            SIP.Timers.clearTimeout(this.J);
            this.stateChanged(C.STATUS_TERMINATED);
            this.ua.destroyTransaction(this);
        }
    };
    NonInviteServerTransaction.prototype.receiveResponse = function (status_code, response) {
        var tr = this;
        var deferred = SIP.Utils.defer();
        if (status_code === 100) {
            /* RFC 4320 4.1
             * 'A SIP element MUST NOT
             * send any provisional response with a
             * Status-Code other than 100 to a non-INVITE request.'
             */
            switch (this.state) {
                case C.STATUS_TRYING:
                    this.stateChanged(C.STATUS_PROCEEDING);
                    this.transport.send(response).catch(function () {
                        this.onTransportError();
                    }.bind(this));
                    break;
                case C.STATUS_PROCEEDING:
                    this.last_response = response;
                    this.transport.send(response).then(function () {
                        deferred.resolve();
                    }).catch(function () {
                        this.onTransportError();
                        deferred.reject();
                    }.bind(this));
                    break;
            }
        }
        else if (status_code >= 200 && status_code <= 699) {
            switch (this.state) {
                case C.STATUS_TRYING:
                case C.STATUS_PROCEEDING:
                    this.stateChanged(C.STATUS_COMPLETED);
                    this.last_response = response;
                    this.J = SIP.Timers.setTimeout(tr.timer_J.bind(tr), SIP.Timers.TIMER_J);
                    this.transport.send(response).then(function () {
                        deferred.resolve();
                    }).catch(function () {
                        this.onTransportError();
                        deferred.reject();
                    }.bind(this));
                    break;
                case C.STATUS_COMPLETED:
                    break;
            }
        }
        return deferred.promise;
    };
    /**
    * @augments SIP.Transactions
    * @class Invite Server Transaction
    * @param {SIP.IncomingRequest} request
    * @param {SIP.UA} ua
    */
    var InviteServerTransaction = function (request, ua) {
        this.type = C.INVITE_SERVER;
        this.id = request.via_branch;
        this.request = request;
        this.transport = ua.transport;
        this.ua = ua;
        this.last_response = '';
        request.server_transaction = this;
        this.logger = ua.getLogger('sip.transaction.ist', this.id);
        this.state = C.STATUS_PROCEEDING;
        ua.newTransaction(this);
        this.resendProvisionalTimer = null;
        request.reply(100);
    };
    InviteServerTransaction.prototype = Object.create(SIP.EventEmitter.prototype);
    InviteServerTransaction.prototype.stateChanged = function (state) {
        this.state = state;
        this.emit('stateChanged');
    };
    InviteServerTransaction.prototype.timer_H = function () {
        this.logger.debug('Timer H expired for INVITE server transaction ' + this.id);
        if (this.state === C.STATUS_COMPLETED) {
            this.logger.warn('transactions', 'ACK for INVITE server transaction was never received, call will be terminated');
        }
        this.stateChanged(C.STATUS_TERMINATED);
        this.ua.destroyTransaction(this);
    };
    InviteServerTransaction.prototype.timer_I = function () {
        this.stateChanged(C.STATUS_TERMINATED);
        this.ua.destroyTransaction(this);
    };
    // RFC 6026 7.1
    InviteServerTransaction.prototype.timer_L = function () {
        this.logger.debug('Timer L expired for INVITE server transaction ' + this.id);
        if (this.state === C.STATUS_ACCEPTED) {
            this.stateChanged(C.STATUS_TERMINATED);
            this.ua.destroyTransaction(this);
        }
    };
    InviteServerTransaction.prototype.onTransportError = function () {
        if (!this.transportError) {
            this.transportError = true;
            this.logger.log('transport error occurred, deleting INVITE server transaction ' + this.id);
            if (this.resendProvisionalTimer !== null) {
                SIP.Timers.clearInterval(this.resendProvisionalTimer);
                this.resendProvisionalTimer = null;
            }
            SIP.Timers.clearTimeout(this.L);
            SIP.Timers.clearTimeout(this.H);
            SIP.Timers.clearTimeout(this.I);
            this.stateChanged(C.STATUS_TERMINATED);
            this.ua.destroyTransaction(this);
        }
    };
    InviteServerTransaction.prototype.resend_provisional = function () {
        this.transport.send(this.request).catch(function () {
            this.onTransportError();
        }.bind(this));
    };
    // INVITE Server Transaction RFC 3261 17.2.1
    InviteServerTransaction.prototype.receiveResponse = function (status_code, response) {
        var tr = this;
        var deferred = SIP.Utils.defer();
        if (status_code >= 100 && status_code <= 199) {
            switch (this.state) {
                case C.STATUS_PROCEEDING:
                    this.transport.send(response).catch(function () {
                        this.onTransportError();
                    }.bind(this));
                    this.last_response = response;
                    break;
            }
        }
        if (status_code > 100 && status_code <= 199 && this.state === C.STATUS_PROCEEDING) {
            // Trigger the resendProvisionalTimer only for the first non 100 provisional response.
            if (this.resendProvisionalTimer === null) {
                this.resendProvisionalTimer = SIP.Timers.setInterval(tr.resend_provisional.bind(tr), SIP.Timers.PROVISIONAL_RESPONSE_INTERVAL);
            }
        }
        else if (status_code >= 200 && status_code <= 299) {
            switch (this.state) {
                case C.STATUS_PROCEEDING:
                    this.stateChanged(C.STATUS_ACCEPTED);
                    this.last_response = response;
                    this.L = SIP.Timers.setTimeout(tr.timer_L.bind(tr), SIP.Timers.TIMER_L);
                    if (this.resendProvisionalTimer !== null) {
                        SIP.Timers.clearInterval(this.resendProvisionalTimer);
                        this.resendProvisionalTimer = null;
                    }
                /* falls through */
                case C.STATUS_ACCEPTED:
                    // Note that this point will be reached for proceeding tr.state also.
                    this.transport.send(response).then(function () {
                        deferred.resolve();
                    }).catch(function (error) {
                        this.logger.error(error);
                        this.onTransportError();
                        deferred.reject();
                    }.bind(this));
                    break;
            }
        }
        else if (status_code >= 300 && status_code <= 699) {
            switch (this.state) {
                case C.STATUS_PROCEEDING:
                    if (this.resendProvisionalTimer !== null) {
                        SIP.Timers.clearInterval(this.resendProvisionalTimer);
                        this.resendProvisionalTimer = null;
                    }
                    this.transport.send(response).then(function () {
                        this.stateChanged(C.STATUS_COMPLETED);
                        this.H = SIP.Timers.setTimeout(tr.timer_H.bind(tr), SIP.Timers.TIMER_H);
                        deferred.resolve();
                    }.bind(this)).catch(function (error) {
                        this.logger.error(error);
                        this.onTransportError();
                        deferred.reject();
                    }.bind(this));
                    break;
            }
        }
        return deferred.promise;
    };
    /**
     * @function
     * @param {SIP.UA} ua
     * @param {SIP.IncomingRequest} request
     *
     * @return {boolean}
     * INVITE:
     *  _true_ if retransmission
     *  _false_ new request
     *
     * ACK:
     *  _true_  ACK to non2xx response
     *  _false_ ACK must be passed to TU (accepted state)
     *          ACK to 2xx response
     *
     * CANCEL:
     *  _true_  no matching invite transaction
     *  _false_ matching invite transaction and no final response sent
     *
     * OTHER:
     *  _true_  retransmission
     *  _false_ new request
     */
    var checkTransaction = function (ua, request) {
        var tr;
        switch (request.method) {
            case SIP.C.INVITE:
                tr = ua.transactions.ist[request.via_branch];
                if (tr) {
                    switch (tr.state) {
                        case C.STATUS_PROCEEDING:
                            tr.transport.send(tr.last_response);
                            break;
                        // RFC 6026 7.1 Invite retransmission
                        //received while in C.STATUS_ACCEPTED state. Absorb it.
                        case C.STATUS_ACCEPTED:
                            break;
                    }
                    return true;
                }
                break;
            case SIP.C.ACK:
                tr = ua.transactions.ist[request.via_branch];
                // RFC 6026 7.1
                if (tr) {
                    if (tr.state === C.STATUS_ACCEPTED) {
                        return false;
                    }
                    else if (tr.state === C.STATUS_COMPLETED) {
                        tr.stateChanged(C.STATUS_CONFIRMED);
                        tr.I = SIP.Timers.setTimeout(tr.timer_I.bind(tr), SIP.Timers.TIMER_I);
                        return true;
                    }
                }
                // ACK to 2XX Response.
                else {
                    return false;
                }
                break;
            case SIP.C.CANCEL:
                tr = ua.transactions.ist[request.via_branch];
                if (tr) {
                    request.reply_sl(200);
                    if (tr.state === C.STATUS_PROCEEDING) {
                        return false;
                    }
                    else {
                        return true;
                    }
                }
                else {
                    request.reply_sl(481);
                    return true;
                }
            default:
                // Non-INVITE Server Transaction RFC 3261 17.2.2
                tr = ua.transactions.nist[request.via_branch];
                if (tr) {
                    switch (tr.state) {
                        case C.STATUS_TRYING:
                            break;
                        case C.STATUS_PROCEEDING:
                        case C.STATUS_COMPLETED:
                            tr.transport.send(tr.last_response);
                            break;
                    }
                    return true;
                }
                break;
        }
    };
    SIP.Transactions = {
        C: C,
        checkTransaction: checkTransaction,
        NonInviteClientTransaction: NonInviteClientTransaction,
        InviteClientTransaction: InviteClientTransaction,
        AckClientTransaction: AckClientTransaction,
        NonInviteServerTransaction: NonInviteServerTransaction,
        InviteServerTransaction: InviteServerTransaction
    };
};


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

"use strict";

/**
 * @fileoverview SIP Dialog
 */
/**
 * @augments SIP
 * @class Class creating a SIP dialog.
 * @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
 */
module.exports = function (SIP) {
    var RequestSender = __webpack_require__(17)(SIP);
    var Dialog, C = {
        // Dialog states
        STATUS_EARLY: 1,
        STATUS_CONFIRMED: 2
    };
    // RFC 3261 12.1
    Dialog = function (owner, message, type, state) {
        var contact;
        this.uac_pending_reply = false;
        this.uas_pending_reply = false;
        if (!message.hasHeader('contact')) {
            return {
                error: 'unable to create a Dialog without Contact header field'
            };
        }
        if (message instanceof SIP.IncomingResponse) {
            state = (message.status_code < 200) ? C.STATUS_EARLY : C.STATUS_CONFIRMED;
        }
        else {
            // Create confirmed dialog if state is not defined
            state = state || C.STATUS_CONFIRMED;
        }
        contact = message.parseHeader('contact');
        // RFC 3261 12.1.1
        if (type === 'UAS') {
            this.id = {
                call_id: message.call_id,
                local_tag: message.to_tag,
                remote_tag: message.from_tag,
                toString: function () {
                    return this.call_id + this.local_tag + this.remote_tag;
                }
            };
            this.state = state;
            this.remote_seqnum = message.cseq;
            this.local_uri = message.parseHeader('to').uri;
            this.remote_uri = message.parseHeader('from').uri;
            this.remote_target = contact.uri;
            this.route_set = message.getHeaders('record-route');
            this.invite_seqnum = message.cseq;
            this.local_seqnum = message.cseq;
        }
        // RFC 3261 12.1.2
        else if (type === 'UAC') {
            this.id = {
                call_id: message.call_id,
                local_tag: message.from_tag,
                remote_tag: message.to_tag,
                toString: function () {
                    return this.call_id + this.local_tag + this.remote_tag;
                }
            };
            this.state = state;
            this.invite_seqnum = message.cseq;
            this.local_seqnum = message.cseq;
            this.local_uri = message.parseHeader('from').uri;
            this.pracked = [];
            this.remote_uri = message.parseHeader('to').uri;
            this.remote_target = contact.uri;
            this.route_set = 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 === C.STATUS_EARLY ? 'EARLY' : 'CONFIRMED'));
        owner.emit('dialog', this);
    };
    Dialog.prototype = {
        /**
         * @param {SIP.IncomingMessage} message
         * @param {Enum} UAC/UAS
         */
        update: function (message, type) {
            this.state = C.STATUS_CONFIRMED;
            this.logger.log('dialog ' + this.id.toString() + '  changed to CONFIRMED state');
            if (type === 'UAC') {
                // RFC 3261 13.2.2.4
                this.route_set = message.getHeaders('record-route').reverse();
            }
        },
        terminate: function () {
            this.logger.log('dialog ' + this.id.toString() + ' deleted');
            if (this.sessionDescriptionHandler && this.state !== C.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
        createRequest: function (method, extraHeaders, body) {
            var cseq, request;
            extraHeaders = (extraHeaders || []).slice();
            if (!this.local_seqnum) {
                this.local_seqnum = Math.floor(Math.random() * 10000);
            }
            cseq = (method === SIP.C.CANCEL || method === SIP.C.ACK) ? this.invite_seqnum : this.local_seqnum += 1;
            request = new SIP.OutgoingRequest(method, this.remote_target, this.owner.ua, {
                'cseq': cseq,
                'call_id': this.id.call_id,
                'from_uri': this.local_uri,
                'from_tag': this.id.local_tag,
                'to_uri': this.remote_uri,
                'to_tag': this.id.remote_tag,
                'route_set': this.route_set
            }, extraHeaders, body);
            request.dialog = this;
            return request;
        },
        /**
        * @param {SIP.IncomingRequest} request
        * @returns {Boolean}
        */
        // RFC 3261 12.2.2
        checkInDialogRequest: function (request) {
            var self = this;
            if (!this.remote_seqnum) {
                this.remote_seqnum = request.cseq;
            }
            else if (request.cseq < this.remote_seqnum) {
                //Do not try to reply to an ACK request.
                if (request.method !== SIP.C.ACK) {
                    request.reply(500);
                }
                if (request.cseq === this.invite_seqnum) {
                    return true;
                }
                return false;
            }
            switch (request.method) {
                // RFC3261 14.2 Modifying an Existing Session -UAS BEHAVIOR-
                case SIP.C.INVITE:
                    if (this.uac_pending_reply === true) {
                        request.reply(491);
                    }
                    else if (this.uas_pending_reply === true && request.cseq > this.remote_seqnum) {
                        var retryAfter = (Math.random() * 10 | 0) + 1;
                        request.reply(500, null, ['Retry-After:' + retryAfter]);
                        this.remote_seqnum = request.cseq;
                        return false;
                    }
                    else {
                        this.uas_pending_reply = true;
                        request.server_transaction.on('stateChanged', function stateChanged() {
                            if (this.state === SIP.Transactions.C.STATUS_ACCEPTED ||
                                this.state === SIP.Transactions.C.STATUS_COMPLETED ||
                                this.state === SIP.Transactions.C.STATUS_TERMINATED) {
                                this.removeListener('stateChanged', stateChanged);
                                self.uas_pending_reply = false;
                            }
                        });
                    }
                    // RFC3261 12.2.2 Replace the dialog`s remote target URI if the request is accepted
                    if (request.hasHeader('contact')) {
                        request.server_transaction.on('stateChanged', function () {
                            if (this.state === SIP.Transactions.C.STATUS_ACCEPTED) {
                                self.remote_target = request.parseHeader('contact').uri;
                            }
                        });
                    }
                    break;
                case SIP.C.NOTIFY:
                    // RFC6665 3.2 Replace the dialog`s remote target URI if the request is accepted
                    if (request.hasHeader('contact')) {
                        request.server_transaction.on('stateChanged', function () {
                            if (this.state === SIP.Transactions.C.STATUS_COMPLETED) {
                                self.remote_target = request.parseHeader('contact').uri;
                            }
                        });
                    }
                    break;
            }
            if (request.cseq > this.remote_seqnum) {
                this.remote_seqnum = request.cseq;
            }
            return true;
        },
        sendRequest: function (applicant, method, options) {
            options = options || {};
            var extraHeaders = (options.extraHeaders || []).slice();
            var body = null;
            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), request_sender = new RequestSender(this, applicant, request);
            request_sender.send();
            return request;
        },
        /**
        * @param {SIP.IncomingRequest} request
        */
        receiveRequest: function (request) {
            //Check in-dialog request
            if (!this.checkInDialogRequest(request)) {
                return;
            }
            this.owner.receiveRequest(request);
        }
    };
    Dialog.C = C;
    SIP.Dialog = Dialog;
};


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

"use strict";

/**
 * @fileoverview In-Dialog Request Sender
 */
/**
 * @augments SIP.Dialog
 * @class Class creating an In-dialog request sender.
 * @param {SIP.Dialog} dialog
 * @param {Object} applicant
 * @param {SIP.OutgoingRequest} request
 */
/**
 * @fileoverview in-Dialog Request Sender
 */
module.exports = function (SIP) {
    var RequestSender;
    RequestSender = function (dialog, applicant, request) {
        this.dialog = dialog;
        this.applicant = applicant;
        this.request = request;
        // RFC3261 14.1 Modifying an Existing Session. UAC Behavior.
        this.reattempt = false;
        this.reattemptTimer = null;
    };
    RequestSender.prototype = {
        send: function () {
            var self = this, request_sender = new SIP.RequestSender(this, this.dialog.owner.ua);
            request_sender.send();
            // RFC3261 14.2 Modifying an Existing Session -UAC BEHAVIOR-
            if (this.request.method === SIP.C.INVITE && request_sender.clientTransaction.state !== SIP.Transactions.C.STATUS_TERMINATED) {
                this.dialog.uac_pending_reply = true;
                request_sender.clientTransaction.on('stateChanged', function stateChanged() {
                    if (this.state === SIP.Transactions.C.STATUS_ACCEPTED ||
                        this.state === SIP.Transactions.C.STATUS_COMPLETED ||
                        this.state === SIP.Transactions.C.STATUS_TERMINATED) {
                        this.removeListener('stateChanged', stateChanged);
                        self.dialog.uac_pending_reply = false;
                    }
                });
            }
        },
        onRequestTimeout: function () {
            this.applicant.onRequestTimeout();
        },
        onTransportError: function () {
            this.applicant.onTransportError();
        },
        receiveResponse: function (response) {
            var self = this;
            // RFC3261 12.2.1.2 408 or 481 is received for a request within a dialog.
            if (response.status_code === 408 || response.status_code === 481) {
                this.applicant.onDialogError(response);
            }
            else if (response.method === SIP.C.INVITE && response.status_code === 491) {
                if (this.reattempt) {
                    this.applicant.receiveResponse(response);
                }
                else {
                    this.request.cseq.value = this.dialog.local_seqnum += 1;
                    this.reattemptTimer = SIP.Timers.setTimeout(function () {
                        if (self.applicant.owner.status !== SIP.Session.C.STATUS_TERMINATED) {
                            self.reattempt = true;
                            self.request_sender.send();
                        }
                    }, this.getReattemptTimeout());
                }
            }
            else {
                this.applicant.receiveResponse(response);
            }
        }
    };
    return RequestSender;
};


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

"use strict";

/**
 * @fileoverview Request Sender
 */
/**
 * @augments SIP
 * @class Class creating a request sender.
 * @param {Object} applicant
 * @param {SIP.UA} ua
 */
module.exports = function (SIP) {
    var RequestSender;
    RequestSender = function (applicant, ua) {
        this.logger = ua.getLogger('sip.requestsender');
        this.ua = ua;
        this.applicant = applicant;
        this.method = applicant.request.method;
        this.request = applicant.request;
        this.credentials = null;
        this.challenged = false;
        this.staled = false;
        // If ua is in closing process or even closed just allow sending Bye and ACK
        if (ua.status === SIP.UA.C.STATUS_USER_CLOSED && (this.method !== SIP.C.BYE || this.method !== SIP.C.ACK)) {
            this.onTransportError();
        }
    };
    /**
    * Create the client transaction and send the message.
    */
    RequestSender.prototype = {
        send: function () {
            switch (this.method) {
                case "INVITE":
                    this.clientTransaction = new SIP.Transactions.InviteClientTransaction(this, this.request, this.ua.transport);
                    break;
                case "ACK":
                    this.clientTransaction = new SIP.Transactions.AckClientTransaction(this, this.request, this.ua.transport);
                    break;
                default:
                    this.clientTransaction = new SIP.Transactions.NonInviteClientTransaction(this, this.request, this.ua.transport);
            }
            this.clientTransaction.send();
            return this.clientTransaction;
        },
        /**
        * Callback fired when receiving a request timeout error from the client transaction.
        * To be re-defined by the applicant.
        * @event
        */
        onRequestTimeout: function () {
            this.applicant.onRequestTimeout();
        },
        /**
        * Callback fired when receiving a transport error from the client transaction.
        * To be re-defined by the applicant.
        * @event
        */
        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
        */
        receiveResponse: function (response) {
            var cseq, challenge, authorization_header_name, status_code = response.status_code;
            /*
            * Authentication
            * Authenticate once. _challenged_ flag used to avoid infinite authentications.
            */
            if (status_code === 401 || status_code === 407) {
                // Get and parse the appropriate WWW-Authenticate or Proxy-Authenticate header.
                if (response.status_code === 401) {
                    challenge = response.parseHeader('www-authenticate');
                    authorization_header_name = 'authorization';
                }
                else {
                    challenge = response.parseHeader('proxy-authenticate');
                    authorization_header_name = 'proxy-authorization';
                }
                // Verify it seems a valid challenge.
                if (!challenge) {
                    this.logger.warn(response.status_code + ' with wrong or missing challenge, cannot authenticate');
                    this.applicant.receiveResponse(response);
                    return;
                }
                if (!this.challenged || (!this.staled && challenge.stale === true)) {
                    if (!this.credentials) {
                        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;
                    }
                    if (response.method === SIP.C.REGISTER) {
                        cseq = this.applicant.cseq += 1;
                    }
                    else if (this.request.dialog) {
                        cseq = this.request.dialog.local_seqnum += 1;
                    }
                    else {
                        cseq = this.request.cseq + 1;
                        this.request.cseq = cseq;
                    }
                    this.request.setHeader('cseq', cseq + ' ' + this.method);
                    this.request.setHeader(authorization_header_name, this.credentials.toString());
                    this.send();
                }
                else {
                    this.applicant.receiveResponse(response);
                }
            }
            else {
                this.applicant.receiveResponse(response);
            }
        }
    };
    SIP.RequestSender = RequestSender;
};


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

"use strict";

module.exports = function (SIP) {
    var RegisterContext;
    RegisterContext = function (ua) {
        var params = {}, regId = 1;
        this.registrar = ua.configuration.registrarServer;
        this.expires = ua.configuration.registerExpires;
        // Contact header
        this.contact = ua.contact.toString();
        if (regId) {
            this.contact += ';reg-id=' + regId;
            this.contact += ';+sip.instance="<urn:uuid:' + ua.configuration.instanceId + '>"';
        }
        // Call-ID and CSeq values RFC3261 10.2
        this.call_id = SIP.Utils.createRandomToken(22);
        this.cseq = Math.floor(Math.random() * 10000);
        this.to_uri = ua.configuration.uri;
        params.to_uri = this.to_uri;
        params.to_displayName = ua.configuration.displayName;
        params.call_id = this.call_id;
        params.cseq = this.cseq;
        // Extends ClientContext
        SIP.Utils.augment(this, SIP.ClientContext, [ua, 'REGISTER', this.registrar, { params: params }]);
        this.registrationTimer = null;
        this.registrationExpiredTimer = null;
        // Set status
        this.registered = false;
        this.logger = ua.getLogger('sip.registercontext');
        ua.on('transportCreated', function (transport) {
            transport.on('disconnected', this.onTransportDisconnected.bind(this));
        }.bind(this));
    };
    RegisterContext.prototype = Object.create({}, {
        register: { writable: true, value: function register(options) {
                var self = this, extraHeaders;
                // Handle Options
                this.options = options || {};
                extraHeaders = (this.options.extraHeaders || []).slice();
                extraHeaders.push('Contact: ' + this.contact + ';expires=' + this.expires);
                extraHeaders.push('Allow: ' + SIP.UA.C.ALLOWED_METHODS.toString());
                // Save original extraHeaders to be used in .close
                this.closeHeaders = this.options.closeWithHeaders ?
                    (this.options.extraHeaders || []).slice() : [];
                this.receiveResponse = function (response) {
                    var contact, expires, contacts = response.getHeaders('contact').length, cause;
                    // Discard responses to older REGISTER/un-REGISTER requests.
                    if (response.cseq !== this.cseq) {
                        return;
                    }
                    // Clear registration timer
                    if (this.registrationTimer !== null) {
                        SIP.Timers.clearTimeout(this.registrationTimer);
                        this.registrationTimer = null;
                    }
                    switch (true) {
                        case /^1[0-9]{2}$/.test(response.status_code):
                            this.emit('progress', response);
                            break;
                        case /^2[0-9]{2}$/.test(response.status_code):
                            this.emit('accepted', response);
                            if (response.hasHeader('expires')) {
                                expires = response.getHeader('expires');
                            }
                            if (this.registrationExpiredTimer !== null) {
                                SIP.Timers.clearTimeout(this.registrationExpiredTimer);
                                this.registrationExpiredTimer = null;
                            }
                            // Search the Contact pointing to us and update the expires value accordingly.
                            if (!contacts) {
                                this.logger.warn('no Contact header in response to REGISTER, response ignored');
                                break;
                            }
                            while (contacts--) {
                                contact = response.parseHeader('contact', contacts);
                                if (contact.uri.user === this.ua.contact.uri.user) {
                                    expires = contact.getParam('expires');
                                    break;
                                }
                                else {
                                    contact = null;
                                }
                            }
                            if (!contact) {
                                this.logger.warn('no Contact header pointing to us, response ignored');
                                break;
                            }
                            if (!expires) {
                                expires = this.expires;
                            }
                            // Re-Register before the expiration interval has elapsed.
                            // For that, decrease the expires value. ie: 3 seconds
                            this.registrationTimer = SIP.Timers.setTimeout(function () {
                                self.registrationTimer = null;
                                self.register(self.options);
                            }, (expires * 1000) - 3000);
                            this.registrationExpiredTimer = SIP.Timers.setTimeout(function () {
                                self.logger.warn('registration expired');
                                if (self.registered) {
                                    self.unregistered(null, SIP.C.causes.EXPIRES);
                                }
                            }, expires * 1000);
                            //Save gruu values
                            if (contact.hasParam('temp-gruu')) {
                                this.ua.contact.temp_gruu = SIP.URI.parse(contact.getParam('temp-gruu').replace(/"/g, ''));
                            }
                            if (contact.hasParam('pub-gruu')) {
                                this.ua.contact.pub_gruu = SIP.URI.parse(contact.getParam('pub-gruu').replace(/"/g, ''));
                            }
                            this.registered = true;
                            this.emit('registered', response || null);
                            break;
                        // Interval too brief RFC3261 10.2.8
                        case /^423$/.test(response.status_code):
                            if (response.hasHeader('min-expires')) {
                                // Increase our registration interval to the suggested minimum
                                this.expires = 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, SIP.C.causes.SIP_FAILURE_CODE);
                            }
                            break;
                        default:
                            cause = SIP.Utils.sipErrorCause(response.status_code);
                            this.registrationFailure(response, cause);
                    }
                };
                this.onRequestTimeout = function () {
                    this.registrationFailure(null, SIP.C.causes.REQUEST_TIMEOUT);
                };
                this.onTransportError = function () {
                    this.registrationFailure(null, SIP.C.causes.CONNECTION_ERROR);
                };
                this.cseq++;
                this.request.cseq = this.cseq;
                this.request.setHeader('cseq', this.cseq + ' REGISTER');
                this.request.extraHeaders = extraHeaders;
                this.send();
            } },
        registrationFailure: { writable: true, value: function registrationFailure(response, cause) {
                this.emit('failed', response || null, cause || null);
            } },
        onTransportDisconnected: { writable: true, value: function onTransportDisconnected() {
                this.registered_before = this.registered;
                if (this.registrationTimer !== null) {
                    SIP.Timers.clearTimeout(this.registrationTimer);
                    this.registrationTimer = null;
                }
                if (this.registrationExpiredTimer !== null) {
                    SIP.Timers.clearTimeout(this.registrationExpiredTimer);
                    this.registrationExpiredTimer = null;
                }
                if (this.registered) {
                    this.unregistered(null, SIP.C.causes.CONNECTION_ERROR);
                }
            } },
        onTransportConnected: { writable: true, value: function onTransportConnected() {
                this.register(this.options);
            } },
        close: { writable: true, value: function close() {
                var options = {
                    all: false,
                    extraHeaders: this.closeHeaders
                };
                this.registered_before = this.registered;
                if (this.registered) {
                    this.unregister(options);
                }
            } },
        unregister: { writable: true, value: function unregister(options) {
                var extraHeaders;
                options = options || {};
                if (!this.registered && !options.all) {
                    this.logger.warn('Already unregistered, but sending an unregister anyways.');
                }
                extraHeaders = (options.extraHeaders || []).slice();
                this.registered = false;
                // Clear the registration timer.
                if (this.registrationTimer !== null) {
                    SIP.Timers.clearTimeout(this.registrationTimer);
                    this.registrationTimer = null;
                }
                if (options.all) {
                    extraHeaders.push('Contact: *');
                    extraHeaders.push('Expires: 0');
                }
                else {
                    extraHeaders.push('Contact: ' + this.contact + ';expires=0');
                }
                this.receiveResponse = function (response) {
                    var cause;
                    switch (true) {
                        case /^1[0-9]{2}$/.test(response.status_code):
                            this.emit('progress', response);
                            break;
                        case /^2[0-9]{2}$/.test(response.status_code):
                            this.emit('accepted', response);
                            if (this.registrationExpiredTimer !== null) {
                                SIP.Timers.clearTimeout(this.registrationExpiredTimer);
                                this.registrationExpiredTimer = null;
                            }
                            this.unregistered(response);
                            break;
                        default:
                            cause = SIP.Utils.sipErrorCause(response.status_code);
                            this.unregistered(response, cause);
                    }
                };
                this.onRequestTimeout = function () {
                    // Not actually unregistered...
                    //this.unregistered(null, SIP.C.causes.REQUEST_TIMEOUT);
                };
                this.cseq++;
                this.request.cseq = this.cseq;
                this.request.setHeader('cseq', this.cseq + ' REGISTER');
                this.request.extraHeaders = extraHeaders;
                this.send();
            } },
        unregistered: { writable: true, value: function unregistered(response, cause) {
                this.registered = false;
                this.emit('unregistered', response || null, cause || null);
            } }
    });
    SIP.RegisterContext = RegisterContext;
};


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

"use strict";

/* eslint-disable */
/**
 * @fileoverview SessionDescriptionHandler
 */
/* SessionDescriptionHandler
 * @class PeerConnection helper Class.
 * @param {SIP.Session} session
 * @param {Object} [options]
 */
module.exports = function (EventEmitter) {
    var SessionDescriptionHandler = function () { };
    SessionDescriptionHandler.prototype = Object.create(EventEmitter.prototype, {
        /**
         * Destructor
         */
        close: { value: function close() { } },
        /**
         * Gets the local description from the underlying media implementation
         * @param {Object} [options] Options object to be used by getDescription
         * @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
         */
        getDescription: { value: function getDescription(options, modifiers) { } },
        /**
         * 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}
         */
        hasDescription: { value: function hasSessionDescription(contentType) { } },
        /**
         * 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
         */
        holdModifier: { value: function holdModifier(sdp) { } },
        /**
         * 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 setDescription
         * @param {Array} [modifiers] Array with one time use description modifiers
         * @returns {Promise} Promise that resolves once the description is set
         */
        setDescription: { value: function setDescription(sessionDescription, options, modifiers) { } },
        /**
         * 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
         */
        sendDtmf: { value: function sendDtmf(tones, options) { } },
        /**
        * Get the direction of the session description
        * @returns {String} direction of the description
        */
        getDirection: { value: function getDirection() { } },
    });
    return SessionDescriptionHandler;
};


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

"use strict";

module.exports = function (SIP) {
    var ClientContext;
    ClientContext = function (ua, method, target, options) {
        var originalTarget = target;
        // Validate arguments
        if (target === undefined) {
            throw new TypeError('Not enough arguments');
        }
        this.ua = ua;
        this.logger = ua.getLogger('sip.clientcontext');
        this.method = method;
        target = ua.normalizeTarget(target);
        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
        this.request = new SIP.OutgoingRequest(this.method, target, this.ua, options.params, options.extraHeaders);
        if (options.body) {
            this.body = {};
            this.body.body = options.body;
            if (options.contentType) {
                this.body.contentType = options.contentType;
            }
            this.request.body = this.body;
        }
        /* Set other properties from the request */
        this.localIdentity = this.request.from;
        this.remoteIdentity = this.request.to;
        this.data = {};
    };
    ClientContext.prototype = Object.create(SIP.EventEmitter.prototype);
    ClientContext.prototype.send = function () {
        (new SIP.RequestSender(this, this.ua)).send();
        return this;
    };
    ClientContext.prototype.cancel = function (options) {
        options = options || {};
        options.extraHeaders = (options.extraHeaders || []).slice();
        var cancel_reason = SIP.Utils.getCancelReason(options.status_code, options.reason_phrase);
        this.request.cancel(cancel_reason, options.extraHeaders);
        this.emit('cancel');
    };
    ClientContext.prototype.receiveResponse = function (response) {
        var cause = SIP.Utils.getReasonPhrase(response.status_code);
        switch (true) {
            case /^1[0-9]{2}$/.test(response.status_code):
                this.emit('progress', response, cause);
                break;
            case /^2[0-9]{2}$/.test(response.status_code):
                if (this.ua.applicants[this]) {
                    delete this.ua.applicants[this];
                }
                this.emit('accepted', response, cause);
                break;
            default:
                if (this.ua.applicants[this]) {
                    delete this.ua.applicants[this];
                }
                this.emit('rejected', response, cause);
                this.emit('failed', response, cause);
                break;
        }
    };
    ClientContext.prototype.onRequestTimeout = function () {
        this.emit('failed', null, SIP.C.causes.REQUEST_TIMEOUT);
    };
    ClientContext.prototype.onTransportError = function () {
        this.emit('failed', null, SIP.C.causes.CONNECTION_ERROR);
    };
    SIP.ClientContext = ClientContext;
};


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

"use strict";

module.exports = function (SIP) {
    var ServerContext;
    ServerContext = function (ua, request) {
        this.ua = ua;
        this.logger = ua.getLogger('sip.servercontext');
        this.request = request;
        if (request.method === SIP.C.INVITE) {
            this.transaction = new SIP.Transactions.InviteServerTransaction(request, ua);
        }
        else {
            this.transaction = new SIP.Transactions.NonInviteServerTransaction(request, ua);
        }
        if (request.body) {
            this.body = request.body;
        }
        if (request.hasHeader('Content-Type')) {
            this.contentType = request.getHeader('Content-Type');
        }
        this.method = request.method;
        this.data = {};
        this.localIdentity = request.to;
        this.remoteIdentity = request.from;
        if (request.hasHeader('P-Asserted-Identity')) {
            this.assertedIdentity = new SIP.NameAddrHeader.parse(request.getHeader('P-Asserted-Identity'));
        }
    };
    ServerContext.prototype = Object.create(SIP.EventEmitter.prototype);
    ServerContext.prototype.progress = function (options) {
        options = Object.create(options || Object.prototype);
        options.statusCode || (options.statusCode = 180);
        options.minCode = 100;
        options.maxCode = 199;
        options.events = ['progress'];
        return this.reply(options);
    };
    ServerContext.prototype.accept = function (options) {
        options = Object.create(options || Object.prototype);
        options.statusCode || (options.statusCode = 200);
        options.minCode = 200;
        options.maxCode = 299;
        options.events = ['accepted'];
        return this.reply(options);
    };
    ServerContext.prototype.reject = function (options) {
        options = Object.create(options || Object.prototype);
        options.statusCode || (options.statusCode = 480);
        options.minCode = 300;
        options.maxCode = 699;
        options.events = ['rejected', 'failed'];
        return this.reply(options);
    };
    ServerContext.prototype.reply = function (options) {
        options = options || {}; // This is okay, so long as we treat options as read-only in this method
        var statusCode = options.statusCode || 100, minCode = options.minCode || 100, maxCode = options.maxCode || 699, reasonPhrase = SIP.Utils.getReasonPhrase(statusCode, options.reasonPhrase), extraHeaders = options.extraHeaders || [], body = options.body, events = options.events || [], response;
        if (statusCode < minCode || statusCode > maxCode) {
            throw new TypeError('Invalid statusCode: ' + statusCode);
        }
        response = this.request.reply(statusCode, reasonPhrase, extraHeaders, body);
        events.forEach(function (event) {
            this.emit(event, response, reasonPhrase);
        }, this);
        return this;
    };
    ServerContext.prototype.onRequestTimeout = function () {
        this.emit('failed', null, SIP.C.causes.REQUEST_TIMEOUT);
    };
    ServerContext.prototype.onTransportError = function () {
        this.emit('failed', null, SIP.C.causes.CONNECTION_ERROR);
    };
    SIP.ServerContext = ServerContext;
};


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

"use strict";

module.exports = function (SIP) {
    var DTMF = __webpack_require__(24)(SIP);
    var Session, InviteServerContext, InviteClientContext, ReferServerContext, ReferClientContext, C = {
        //Session states
        STATUS_NULL: 0,
        STATUS_INVITE_SENT: 1,
        STATUS_1XX_RECEIVED: 2,
        STATUS_INVITE_RECEIVED: 3,
        STATUS_WAITING_FOR_ANSWER: 4,
        STATUS_ANSWERED: 5,
        STATUS_WAITING_FOR_PRACK: 6,
        STATUS_WAITING_FOR_ACK: 7,
        STATUS_CANCELED: 8,
        STATUS_TERMINATED: 9,
        STATUS_ANSWERED_WAITING_FOR_PRACK: 10,
        STATUS_EARLY_MEDIA: 11,
        STATUS_CONFIRMED: 12
    };
    /*
     * @param {function returning SIP.sessionDescriptionHandler} [sessionDescriptionHandlerFactory]
     *        (See the documentation for the sessionDescriptionHandlerFactory argument of the UA constructor.)
     */
    Session = function (sessionDescriptionHandlerFactory) {
        this.status = C.STATUS_NULL;
        this.dialog = null;
        this.pendingReinvite = false;
        this.earlyDialogs = {};
        if (!sessionDescriptionHandlerFactory) {
            throw new SIP.Exceptions.SessionDescriptionHandlerMissing('A session description handler is required for the session to function');
        }
        this.sessionDescriptionHandlerFactory = sessionDescriptionHandlerFactory;
        this.hasOffer = false;
        this.hasAnswer = false;
        // Session Timers
        this.timers = {
            ackTimer: null,
            expiresTimer: null,
            invite2xxTimer: null,
            userNoAnswerTimer: null,
            rel1xxTimer: null,
            prackTimer: null
        };
        // Session info
        this.startTime = null;
        this.endTime = null;
        this.tones = null;
        // Hold state
        this.local_hold = false;
        this.early_sdp = null;
        this.rel100 = SIP.C.supported.UNSUPPORTED;
    };
    Session.prototype = {
        dtmf: function (tones, options) {
            var tone, dtmfs = [], self = this, dtmfType = this.ua.configuration.dtmfType;
            options = options || {};
            if (tones === undefined) {
                throw new TypeError('Not enough arguments');
            }
            // Check Session Status
            if (this.status !== C.STATUS_CONFIRMED && this.status !== C.STATUS_WAITING_FOR_ACK) {
                throw new SIP.Exceptions.InvalidStateError(this.status);
            }
            // Check tones
            if ((typeof tones !== 'string' && typeof tones !== 'number') || !tones.toString().match(/^[0-9A-D#*,]+$/i)) {
                throw new TypeError('Invalid tones: ' + tones);
            }
            var sendDTMF = function () {
                var dtmf, timeout;
                if (self.status === C.STATUS_TERMINATED || !self.tones || self.tones.length === 0) {
                    // Stop sending DTMF
                    self.tones = null;
                    return this;
                }
                dtmf = self.tones.shift();
                if (tone === ',') {
                    timeout = 2000;
                }
                else {
                    dtmf.on('failed', function () { self.tones = null; });
                    dtmf.send(options);
                    timeout = dtmf.duration + dtmf.interToneGap;
                }
                // Set timeout for the next tone
                SIP.Timers.setTimeout(sendDTMF, timeout);
            };
            tones = tones.toString();
            if (dtmfType === SIP.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 = SIP.C.dtmfType.INFO;
                }
            }
            if (dtmfType === SIP.C.dtmfType.INFO) {
                tones = tones.split('');
                while (tones.length > 0) {
                    dtmfs.push(new DTMF(this, tones.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;
        },
        bye: function (options) {
            options = Object.create(options || Object.prototype);
            var statusCode = options.statusCode;
            // Check Session Status
            if (this.status === C.STATUS_TERMINATED) {
                this.logger.error('Error: Attempted to send BYE in a terminated session.');
                return this;
            }
            this.logger.log('terminating Session');
            if (statusCode && (statusCode < 200 || statusCode >= 700)) {
                throw new TypeError('Invalid statusCode: ' + statusCode);
            }
            options.receiveResponse = function () { };
            return this.
                sendRequest(SIP.C.BYE, options).
                terminated();
        },
        refer: function (target, options) {
            options = options || {};
            // Check Session Status
            if (this.status !== C.STATUS_CONFIRMED) {
                throw new SIP.Exceptions.InvalidStateError(this.status);
            }
            this.referContext = new SIP.ReferClientContext(this.ua, this, target, options);
            this.emit('referRequested', this.referContext);
            this.referContext.refer(options);
        },
        sendRequest: function (method, options) {
            options = options || {};
            var self = this;
            var request = new SIP.OutgoingRequest(method, this.dialog.remote_target, this.ua, {
                cseq: options.cseq || (this.dialog.local_seqnum += 1),
                call_id: this.dialog.id.call_id,
                from_uri: this.dialog.local_uri,
                from_tag: this.dialog.id.local_tag,
                to_uri: this.dialog.remote_uri,
                to_tag: this.dialog.id.remote_tag,
                route_set: this.dialog.route_set,
                statusCode: options.statusCode,
                reasonPhrase: options.reasonPhrase
            }, options.extraHeaders || [], options.body);
            new SIP.RequestSender({
                request: request,
                onRequestTimeout: function () {
                    self.onRequestTimeout();
                },
                onTransportError: function () {
                    self.onTransportError();
                },
                receiveResponse: options.receiveResponse || function (response) {
                    self.receiveNonInviteResponse(response);
                }
            }, this.ua).send();
            // Emit the request event
            this.emit(method.toLowerCase(), request);
            return this;
        },
        close: function () {
            var idx;
            if (this.status === C.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 (idx in this.timers) {
                SIP.Timers.clearTimeout(this.timers[idx]);
            }
            // Terminate dialogs
            // Terminate confirmed dialog
            if (this.dialog) {
                this.dialog.terminate();
                delete this.dialog;
            }
            // Terminate early dialogs
            for (idx in this.earlyDialogs) {
                this.earlyDialogs[idx].terminate();
                delete this.earlyDialogs[idx];
            }
            this.status = C.STATUS_TERMINATED;
            this.ua.transport.removeListener("transportError", this.errorListener);
            delete this.ua.sessions[this.id];
            return this;
        },
        createDialog: function (message, type, early) {
            var dialog, early_dialog, local_tag = message[(type === 'UAS') ? 'to_tag' : 'from_tag'], remote_tag = message[(type === 'UAS') ? 'from_tag' : 'to_tag'], id = message.call_id + local_tag + remote_tag;
            early_dialog = this.earlyDialogs[id];
            // Early Dialog
            if (early) {
                if (early_dialog) {
                    return true;
                }
                else {
                    early_dialog = new SIP.Dialog(this, message, type, SIP.Dialog.C.STATUS_EARLY);
                    // Dialog has been successfully created.
                    if (early_dialog.error) {
                        this.logger.error(early_dialog.error);
                        this.failed(message, SIP.C.causes.INTERNAL_ERROR);
                        return false;
                    }
                    else {
                        this.earlyDialogs[id] = early_dialog;
                        return true;
                    }
                }
            }
            // Confirmed Dialog
            else {
                // In case the dialog is in _early_ state, update it
                if (early_dialog) {
                    early_dialog.update(message, type);
                    this.dialog = early_dialog;
                    delete this.earlyDialogs[id];
                    for (var dia in this.earlyDialogs) {
                        this.earlyDialogs[dia].terminate();
                        delete this.earlyDialogs[dia];
                    }
                    return true;
                }
                // Otherwise, create a _confirmed_ dialog
                dialog = new SIP.Dialog(this, message, type);
                if (dialog.error) {
                    this.logger.error(dialog.error);
                    this.failed(message, SIP.C.causes.INTERNAL_ERROR);
                    return false;
                }
                else {
                    this.to_tag = message.to_tag;
                    this.dialog = dialog;
                    return true;
                }
            }
        },
        /**
         * Hold
         */
        hold: function (options, modifiers) {
            if (this.status !== C.STATUS_WAITING_FOR_ACK && this.status !== C.STATUS_CONFIRMED) {
                throw new SIP.Exceptions.InvalidStateError(this.status);
            }
            if (this.local_hold) {
                this.logger.log('Session is already on hold, cannot put it on hold again');
                return;
            }
            options = options || {};
            options.modifiers = modifiers || [];
            options.modifiers.push(this.sessionDescriptionHandler.holdModifier);
            this.local_hold = true;
            this.sendReinvite(options);
        },
        /**
         * Unhold
         */
        unhold: function (options, modifiers) {
            if (this.status !== C.STATUS_WAITING_FOR_ACK && this.status !== C.STATUS_CONFIRMED) {
                throw new SIP.Exceptions.InvalidStateError(this.status);
            }
            if (!this.local_hold) {
                this.logger.log('Session is not on hold, cannot unhold it');
                return;
            }
            options = options || {};
            if (modifiers) {
                options.modifiers = modifiers;
            }
            this.local_hold = false;
            this.sendReinvite(options);
        },
        reinvite: function (options, modifiers) {
            options = options || {};
            if (modifiers) {
                options.modifiers = modifiers;
            }
            return this.sendReinvite(options);
        },
        /**
         * In dialog INVITE Reception
         * @private
         */
        receiveReinvite: function (request) {
            var self = this, promise;
            // TODO: Should probably check state of the session
            self.emit('reinvite', this);
            if (request.hasHeader('P-Asserted-Identity')) {
                this.assertedIdentity = new SIP.NameAddrHeader.parse(request.getHeader('P-Asserted-Identity'));
            }
            // Invite w/o SDP
            if (request.getHeader('Content-Length') === '0' && !request.getHeader('Content-Type')) {
                promise = this.sessionDescriptionHandler.getDescription(this.sessionDescriptionHandlerOptions, this.modifiers);
                // Invite w/ SDP
            }
            else if (this.sessionDescriptionHandler.hasDescription(request.getHeader('Content-Type'))) {
                promise = this.sessionDescriptionHandler.setDescription(request.body, this.sessionDescriptionHandlerOptions, this.modifiers)
                    .then(this.sessionDescriptionHandler.getDescription.bind(this.sessionDescriptionHandler, this.sessionDescriptionHandlerOptions, this.modifiers));
                // Bad Packet (should never get hit)
            }
            else {
                request.reply(415);
                this.emit('reinviteFailed', self);
                return;
            }
            this.receiveRequest = function (request) {
                if (request.method === SIP.C.ACK && this.status === C.STATUS_WAITING_FOR_ACK) {
                    if (this.sessionDescriptionHandler.hasDescription(request.getHeader('Content-Type'))) {
                        this.hasAnswer = true;
                        this.sessionDescriptionHandler.setDescription(request.body, this.sessionDescriptionHandlerOptions, this.modifiers)
                            .then(function () {
                            SIP.Timers.clearTimeout(this.timers.ackTimer);
                            SIP.Timers.clearTimeout(this.timers.invite2xxTimer);
                            this.status = C.STATUS_CONFIRMED;
                            this.emit('confirmed', request);
                        }.bind(this));
                    }
                    else {
                        SIP.Timers.clearTimeout(this.timers.ackTimer);
                        SIP.Timers.clearTimeout(this.timers.invite2xxTimer);
                        this.status = C.STATUS_CONFIRMED;
                        this.emit('confirmed', request);
                    }
                }
                else {
                    SIP.Session.prototype.receiveRequest.apply(this, [request]);
                }
            }.bind(this);
            promise.catch(function onFailure(e) {
                var statusCode;
                if (e instanceof SIP.Exceptions.SessionDescriptionHandlerError) {
                    statusCode = 500;
                }
                else if (e instanceof SIP.Exceptions.RenegotiationError) {
                    self.emit('renegotiationError', e);
                    self.logger.warn(e);
                    statusCode = 488;
                }
                else {
                    self.logger.error(e);
                    statusCode = 488;
                }
                request.reply(statusCode);
                self.emit('reinviteFailed', self);
                // TODO: This could be better
                throw e;
            })
                .then(function (description) {
                var extraHeaders = ['Contact: ' + self.contact];
                request.reply(200, null, extraHeaders, description, function () {
                    self.status = C.STATUS_WAITING_FOR_ACK;
                    self.setACKTimer();
                    self.emit('reinviteAccepted', self);
                });
            });
        },
        sendReinvite: function (options) {
            if (this.pendingReinvite) {
                this.logger.warn('Reinvite in progress. Please wait until complete, then try again.');
                return;
            }
            this.pendingReinvite = true;
            options = options || {};
            options.modifiers = options.modifiers || [];
            var self = this, extraHeaders = (options.extraHeaders || []).slice();
            extraHeaders.push('Contact: ' + this.contact);
            extraHeaders.push('Allow: ' + SIP.UA.C.ALLOWED_METHODS.toString());
            this.sessionDescriptionHandler.getDescription(options.sessionDescriptionHandlerOptions, options.modifiers)
                .then(function (description) {
                self.sendRequest(SIP.C.INVITE, {
                    extraHeaders: extraHeaders,
                    body: description,
                    receiveResponse: self.receiveReinviteResponse.bind(self)
                });
            }).catch(function onFailure(e) {
                if (e instanceof SIP.Exceptions.RenegotiationError) {
                    self.pendingReinvite = false;
                    self.emit('renegotiationError', e);
                    self.logger.warn('Renegotiation Error');
                    self.logger.warn(e);
                    return;
                }
                self.logger.error('sessionDescriptionHandler error');
                self.logger.error(e);
            });
        },
        receiveRequest: function (request) {
            switch (request.method) {
                case SIP.C.BYE:
                    request.reply(200);
                    if (this.status === C.STATUS_CONFIRMED) {
                        this.emit('bye', request);
                        this.terminated(request, SIP.C.causes.BYE);
                    }
                    break;
                case SIP.C.INVITE:
                    if (this.status === C.STATUS_CONFIRMED) {
                        this.logger.log('re-INVITE received');
                        this.receiveReinvite(request);
                    }
                    break;
                case SIP.C.INFO:
                    if (this.status === C.STATUS_CONFIRMED || this.status === C.STATUS_WAITING_FOR_ACK) {
                        if (this.onInfo) {
                            return this.onInfo(request);
                        }
                        var body, tone, duration, contentType = request.getHeader('content-type'), reg_tone = /^(Signal\s*?=\s*?)([0-9A-D#*]{1})(\s)?.*/, reg_duration = /^(Duration\s?=\s?)([0-9]{1,4})(\s)?.*/;
                        if (contentType) {
                            if (contentType.match(/^application\/dtmf-relay/i)) {
                                if (request.body) {
                                    body = request.body.split('\r\n', 2);
                                    if (body.length === 2) {
                                        if (reg_tone.test(body[0])) {
                                            tone = body[0].replace(reg_tone, "$2");
                                        }
                                        if (reg_duration.test(body[1])) {
                                            duration = parseInt(body[1].replace(reg_duration, "$2"), 10);
                                        }
                                    }
                                }
                                new DTMF(this, tone, { duration: duration }).init_incoming(request);
                            }
                            else {
                                request.reply(415, null, ["Accept: application/dtmf-relay"]);
                            }
                        }
                    }
                    break;
                case SIP.C.REFER:
                    if (this.status === C.STATUS_CONFIRMED) {
                        this.logger.log('REFER received');
                        this.referContext = new SIP.ReferServerContext(this.ua, request);
                        var hasReferListener = this.listeners('referRequested').length;
                        if (hasReferListener) {
                            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 SIP.C.NOTIFY:
                    if ((this.referContext && this.referContext instanceof SIP.ReferClientContext) && request.hasHeader('event') && /^refer(;.*)?$/.test(request.getHeader('event'))) {
                        this.referContext.receiveNotify(request);
                        return;
                    }
                    request.reply(200, 'OK');
                    this.emit('notify', request);
                    break;
            }
        },
        /**
         * Reception of Response for in-dialog INVITE
         * @private
         */
        receiveReinviteResponse: function (response) {
            var self = this;
            if (this.status === C.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;
            }
            switch (true) {
                case /^1[0-9]{2}$/.test(response.status_code):
                    break;
                case /^2[0-9]{2}$/.test(response.status_code):
                    this.status = C.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.transaction.sendACK());
                    this.pendingReinvite = false;
                    // TODO: All of these timers should move into the Transaction layer
                    SIP.Timers.clearTimeout(self.timers.invite2xxTimer);
                    if (!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', self);
                        this.emit('renegotiationError', new SIP.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 onFailure(e) {
                        self.logger.error('Could not set the description in 2XX response');
                        self.logger.error(e);
                        self.emit('reinviteFailed', self);
                        self.emit('renegotiationError', e);
                        self.sendRequest(SIP.C.BYE, {
                            extraHeaders: ['Reason: ' + SIP.Utils.getReasonHeaderValue(488, 'Not Acceptable Here')]
                        });
                        self.terminated(null, SIP.C.causes.INCOMPATIBLE_SDP);
                    }).then(function () {
                        self.emit('reinviteAccepted', self);
                    });
                    break;
                default:
                    this.pendingReinvite = false;
                    this.logger.log('Received a non 1XX or 2XX response to a re-invite');
                    this.emit('reinviteFailed', self);
                    this.emit('renegotiationError', new SIP.Exceptions.RenegotiationError('Invalid response to a re-invite'));
            }
        },
        acceptAndTerminate: function (response, status_code, reason_phrase) {
            var extraHeaders = [];
            if (status_code) {
                extraHeaders.push('Reason: ' + SIP.Utils.getReasonHeaderValue(status_code, reason_phrase));
            }
            // An error on dialog creation will fire 'failed' event
            if (this.dialog || this.createDialog(response, 'UAC')) {
                this.emit("ack", response.transaction.sendACK());
                this.sendRequest(SIP.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
         */
        setInvite2xxTimer: function (request, description) {
            var self = this, timeout = SIP.Timers.T1;
            this.timers.invite2xxTimer = SIP.Timers.setTimeout(function invite2xxRetransmission() {
                if (self.status !== C.STATUS_WAITING_FOR_ACK) {
                    return;
                }
                self.logger.log('no ACK received, attempting to retransmit OK');
                var extraHeaders = ['Contact: ' + self.contact];
                request.reply(200, null, extraHeaders, description);
                timeout = Math.min(timeout * 2, SIP.Timers.T2);
                self.timers.invite2xxTimer = SIP.Timers.setTimeout(invite2xxRetransmission, timeout);
            }, 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.
         */
        setACKTimer: function () {
            var self = this;
            this.timers.ackTimer = SIP.Timers.setTimeout(function () {
                if (self.status === C.STATUS_WAITING_FOR_ACK) {
                    self.logger.log('no ACK received for an extended period of time, terminating the call');
                    SIP.Timers.clearTimeout(self.timers.invite2xxTimer);
                    self.sendRequest(SIP.C.BYE);
                    self.terminated(null, SIP.C.causes.NO_ACK);
                }
            }, SIP.Timers.TIMER_H);
        },
        /*
         * @private
         */
        onTransportError: function () {
            if (this.status !== C.STATUS_CONFIRMED && this.status !== C.STATUS_TERMINATED) {
                this.failed(null, SIP.C.causes.CONNECTION_ERROR);
            }
        },
        onRequestTimeout: function () {
            if (this.status === C.STATUS_CONFIRMED) {
                this.terminated(null, SIP.C.causes.REQUEST_TIMEOUT);
            }
            else if (this.status !== C.STATUS_TERMINATED) {
                this.failed(null, SIP.C.causes.REQUEST_TIMEOUT);
                this.terminated(null, SIP.C.causes.REQUEST_TIMEOUT);
            }
        },
        onDialogError: function (response) {
            if (this.status === C.STATUS_CONFIRMED) {
                this.terminated(response, SIP.C.causes.DIALOG_ERROR);
            }
            else if (this.status !== C.STATUS_TERMINATED) {
                this.failed(response, SIP.C.causes.DIALOG_ERROR);
                this.terminated(response, SIP.C.causes.DIALOG_ERROR);
            }
        },
        /**
         * @private
         */
        failed: function (response, cause) {
            if (this.status === C.STATUS_TERMINATED) {
                return this;
            }
            this.emit('failed', response || null, cause || null);
            return this;
        },
        rejected: function (response, cause) {
            this.emit('rejected', response || null, cause || null);
            return this;
        },
        canceled: function () {
            if (this.sessionDescriptionHandler) {
                this.sessionDescriptionHandler.close();
            }
            this.emit('cancel');
            return this;
        },
        accepted: function (response, cause) {
            cause = SIP.Utils.getReasonPhrase(response && response.status_code, cause);
            this.startTime = new Date();
            if (this.replacee) {
                this.replacee.emit('replaced', this);
                this.replacee.terminate();
            }
            this.emit('accepted', response, cause);
            return this;
        },
        terminated: function (message, cause) {
            if (this.status === C.STATUS_TERMINATED) {
                return this;
            }
            this.endTime = new Date();
            this.close();
            this.emit('terminated', message || null, cause || null);
            return this;
        },
        connecting: function (request) {
            this.emit('connecting', { request: request });
            return this;
        }
    };
    Session.C = C;
    SIP.Session = Session;
    InviteServerContext = function (ua, request) {
        var expires, self = this, contentType = request.getHeader('Content-Type'), contentDisp = request.parseHeader('Content-Disposition');
        SIP.Utils.augment(this, SIP.ServerContext, [ua, request]);
        SIP.Utils.augment(this, SIP.Session, [ua.configuration.sessionDescriptionHandlerFactory]);
        if (contentDisp && contentDisp.type === 'render') {
            this.renderbody = request.body;
            this.rendertype = contentType;
        }
        this.status = C.STATUS_INVITE_RECEIVED;
        this.from_tag = request.from_tag;
        this.id = request.call_id + this.from_tag;
        this.request = request;
        this.contact = this.ua.contact.toString();
        this.receiveNonInviteResponse = function () { }; // intentional no-op
        this.logger = ua.getLogger('sip.inviteservercontext', this.id);
        //Save the session into the ua sessions collection.
        this.ua.sessions[this.id] = this;
        //Get the Expires header value if exists
        if (request.hasHeader('expires')) {
            expires = request.getHeader('expires') * 1000;
        }
        //Set 100rel if necessary
        function set100rel(h, c) {
            if (request.hasHeader(h) && request.getHeader(h).toLowerCase().indexOf('100rel') >= 0) {
                self.rel100 = c;
            }
        }
        set100rel('require', SIP.C.supported.REQUIRED);
        set100rel('supported', SIP.C.supported.SUPPORTED);
        /* Set the to_tag before
         * replying a response code that will create a dialog.
         */
        request.to_tag = SIP.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: ' + self.contact] };
        if (self.rel100 !== SIP.C.supported.REQUIRED) {
            self.progress(options);
        }
        self.status = C.STATUS_WAITING_FOR_ANSWER;
        // Set userNoAnswerTimer
        self.timers.userNoAnswerTimer = SIP.Timers.setTimeout(function () {
            request.reply(408);
            self.failed(request, SIP.C.causes.NO_ANSWER);
            self.terminated(request, SIP.C.causes.NO_ANSWER);
        }, self.ua.configuration.noAnswerTimeout);
        /* Set expiresTimer
         * RFC3261 13.3.1
         */
        if (expires) {
            self.timers.expiresTimer = SIP.Timers.setTimeout(function () {
                if (self.status === C.STATUS_WAITING_FOR_ANSWER) {
                    request.reply(487);
                    self.failed(request, SIP.C.causes.EXPIRES);
                    self.terminated(request, SIP.C.causes.EXPIRES);
                }
            }, expires);
        }
        this.errorListener = this.onTransportError.bind(this);
        ua.transport.on('transportError', this.errorListener);
    };
    InviteServerContext.prototype = Object.create({}, {
        reject: { writable: true, value: function (options) {
                // Check Session Status
                if (this.status === C.STATUS_TERMINATED) {
                    throw new SIP.Exceptions.InvalidStateError(this.status);
                }
                this.logger.log('rejecting RTCSession');
                SIP.ServerContext.prototype.reject.call(this, options);
                return this.terminated();
            } },
        terminate: { writable: true, value: function (options) {
                options = options || {};
                var extraHeaders = (options.extraHeaders || []).slice(), body = options.body, dialog, self = this;
                if (this.status === C.STATUS_WAITING_FOR_ACK &&
                    this.request.server_transaction.state !== SIP.Transactions.C.STATUS_TERMINATED) {
                    dialog = this.dialog;
                    this.receiveRequest = function (request) {
                        if (request.method === SIP.C.ACK) {
                            this.sendRequest(SIP.C.BYE, {
                                extraHeaders: extraHeaders,
                                body: body
                            });
                            dialog.terminate();
                        }
                    };
                    this.request.server_transaction.on('stateChanged', function () {
                        if (this.state === SIP.Transactions.C.STATUS_TERMINATED && this.dialog) {
                            this.request = new SIP.OutgoingRequest(SIP.C.BYE, this.dialog.remote_target, this.ua, {
                                'cseq': this.dialog.local_seqnum += 1,
                                'call_id': this.dialog.id.call_id,
                                'from_uri': this.dialog.local_uri,
                                'from_tag': this.dialog.id.local_tag,
                                'to_uri': this.dialog.remote_uri,
                                'to_tag': this.dialog.id.remote_tag,
                                'route_set': this.dialog.route_set
                            }, extraHeaders, body);
                            new SIP.RequestSender({
                                request: this.request,
                                onRequestTimeout: function () {
                                    self.onRequestTimeout();
                                },
                                onTransportError: function () {
                                    self.onTransportError();
                                },
                                receiveResponse: function () {
                                    return;
                                }
                            }, this.ua).send();
                            dialog.terminate();
                        }
                    });
                    this.emit('bye', this.request);
                    this.terminated();
                    // Restore the dialog into 'this' in order to be able to send the in-dialog BYE :-)
                    this.dialog = dialog;
                    // Restore the dialog into 'ua' so the ACK can reach 'this' session
                    this.ua.dialogs[dialog.id.toString()] = dialog;
                }
                else if (this.status === C.STATUS_CONFIRMED) {
                    this.bye(options);
                }
                else {
                    this.reject(options);
                }
                return this;
            } },
        /*
         * @param {Object} [options.sessionDescriptionHandlerOptions] gets passed to SIP.SessionDescriptionHandler.getDescription as options
         */
        progress: { writable: true, value: function (options) {
                options = options || {};
                var statusCode = options.statusCode || 180, reasonPhrase = options.reasonPhrase, extraHeaders = (options.extraHeaders || []).slice(), body = options.body, response;
                if (statusCode < 100 || statusCode > 199) {
                    throw new TypeError('Invalid statusCode: ' + statusCode);
                }
                if (this.isCanceled || this.status === C.STATUS_TERMINATED) {
                    return this;
                }
                function do100rel() {
                    /* jshint validthis: true */
                    statusCode = options.statusCode || 183;
                    // Set status and add extra headers
                    this.status = C.STATUS_WAITING_FOR_PRACK;
                    extraHeaders.push('Contact: ' + this.contact);
                    extraHeaders.push('Require: 100rel');
                    extraHeaders.push('RSeq: ' + Math.floor(Math.random() * 10000));
                    // Get the session description to add to preaccept with
                    this.sessionDescriptionHandler.getDescription(options.sessionDescriptionHandlerOptions, options.modifiers)
                        .then(function onSuccess(description) {
                        if (this.isCanceled || this.status === C.STATUS_TERMINATED) {
                            return;
                        }
                        this.early_sdp = description.body;
                        this[this.hasOffer ? 'hasAnswer' : 'hasOffer'] = true;
                        // Retransmit until we get a response or we time out (see prackTimer below)
                        var timeout = SIP.Timers.T1;
                        this.timers.rel1xxTimer = SIP.Timers.setTimeout(function rel1xxRetransmission() {
                            this.request.reply(statusCode, null, extraHeaders, description);
                            timeout *= 2;
                            this.timers.rel1xxTimer = SIP.Timers.setTimeout(rel1xxRetransmission.bind(this), timeout);
                        }.bind(this), timeout);
                        // Timeout and reject INVITE if no response
                        this.timers.prackTimer = SIP.Timers.setTimeout(function () {
                            if (this.status !== C.STATUS_WAITING_FOR_PRACK) {
                                return;
                            }
                            this.logger.log('no PRACK received, rejecting the call');
                            SIP.Timers.clearTimeout(this.timers.rel1xxTimer);
                            this.request.reply(504);
                            this.terminated(null, SIP.C.causes.NO_PRACK);
                        }.bind(this), SIP.Timers.T1 * 64);
                        // Send the initial response
                        response = this.request.reply(statusCode, reasonPhrase, extraHeaders, description);
                        this.emit('progress', response, reasonPhrase);
                    }.bind(this), function onFailure() {
                        this.request.reply(480);
                        this.failed(null, SIP.C.causes.WEBRTC_ERROR);
                        this.terminated(null, SIP.C.causes.WEBRTC_ERROR);
                    }.bind(this));
                } // end do100rel
                function normalReply() {
                    /* jshint validthis:true */
                    response = this.request.reply(statusCode, reasonPhrase, extraHeaders, body);
                    this.emit('progress', response, reasonPhrase);
                }
                if (options.statusCode !== 100 &&
                    (this.rel100 === SIP.C.supported.REQUIRED ||
                        (this.rel100 === SIP.C.supported.SUPPORTED && options.rel100) ||
                        (this.rel100 === SIP.C.supported.SUPPORTED && (this.ua.configuration.rel100 === SIP.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.apply(this))
                            .catch(function onFailure(e) {
                            this.logger.warn('invalid description');
                            this.logger.warn(e);
                            this.failed(null, SIP.C.causes.WEBRTC_ERROR);
                            this.terminated(null, SIP.C.causes.WEBRTC_ERROR);
                        }.bind(this));
                    }
                    else {
                        do100rel.apply(this);
                    }
                }
                else {
                    normalReply.apply(this);
                }
                return this;
            } },
        /*
         * @param {Object} [options.sessionDescriptionHandlerOptions] gets passed to SIP.SessionDescriptionHandler.getDescription as options
         */
        accept: { writable: true, value: function (options) {
                options = options || {};
                this.onInfo = options.onInfo;
                var self = this, request = this.request, extraHeaders = (options.extraHeaders || []).slice(), descriptionCreationSucceeded = function (description) {
                    var response, 
                    // run for reply success callback
                    replySucceeded = function () {
                        self.status = C.STATUS_WAITING_FOR_ACK;
                        self.setInvite2xxTimer(request, description);
                        self.setACKTimer();
                    }, 
                    // run for reply failure callback
                    replyFailed = function () {
                        self.failed(null, SIP.C.causes.CONNECTION_ERROR);
                        self.terminated(null, SIP.C.causes.CONNECTION_ERROR);
                    };
                    extraHeaders.push('Contact: ' + self.contact);
                    extraHeaders.push('Allow: ' + SIP.UA.C.ALLOWED_METHODS.toString());
                    if (!self.hasOffer) {
                        self.hasOffer = true;
                    }
                    else {
                        self.hasAnswer = true;
                    }
                    response = request.reply(200, null, extraHeaders, description, replySucceeded, replyFailed);
                    if (self.status !== C.STATUS_TERMINATED) { // Didn't fail
                        self.accepted(response, SIP.Utils.getReasonPhrase(200));
                    }
                }, descriptionCreationFailed = function (err) {
                    if (err instanceof SIP.Exceptions.SessionDescriptionHandlerError) {
                        self.logger.log(err.message);
                        self.logger.log(err.error);
                    }
                    // TODO: This should check the actual error and make sure it is an
                    //        "expected" error. Otherwise it should throw.
                    if (self.status === C.STATUS_TERMINATED) {
                        return;
                    }
                    self.request.reply(480);
                    self.failed(null, SIP.C.causes.WEBRTC_ERROR);
                    self.terminated(null, SIP.C.causes.WEBRTC_ERROR);
                };
                // Check Session Status
                if (this.status === C.STATUS_WAITING_FOR_PRACK) {
                    this.status = C.STATUS_ANSWERED_WAITING_FOR_PRACK;
                    return this;
                }
                else if (this.status === C.STATUS_WAITING_FOR_ANSWER) {
                    this.status = C.STATUS_ANSWERED;
                }
                else if (this.status !== C.STATUS_EARLY_MEDIA) {
                    throw new SIP.Exceptions.InvalidStateError(this.status);
                }
                // An error on dialog creation will fire 'failed' event
                if (!this.createDialog(request, 'UAS')) {
                    request.reply(500, 'Missing Contact header field');
                    return this;
                }
                SIP.Timers.clearTimeout(this.timers.userNoAnswerTimer);
                if (this.status === C.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 () {
                            return this.sessionDescriptionHandler.getDescription(options.sessionDescriptionHandlerOptions, options.modifiers);
                        }.bind(this))
                            .catch(descriptionCreationFailed)
                            .then(descriptionCreationSucceeded);
                    }
                    else {
                        this.request.reply(415);
                        // TODO: Events
                        return;
                    }
                }
                return this;
            } },
        receiveRequest: { writable: true, value: function (request) {
                // ISC RECEIVE REQUEST
                function confirmSession() {
                    /* jshint validthis:true */
                    var contentType, contentDisp;
                    SIP.Timers.clearTimeout(this.timers.ackTimer);
                    SIP.Timers.clearTimeout(this.timers.invite2xxTimer);
                    this.status = C.STATUS_CONFIRMED;
                    contentType = request.getHeader('Content-Type');
                    contentDisp = request.getHeader('Content-Disposition');
                    if (contentDisp && contentDisp.type === 'render') {
                        this.renderbody = request.body;
                        this.rendertype = contentType;
                    }
                    this.emit('confirmed', request);
                }
                switch (request.method) {
                    case SIP.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 === C.STATUS_WAITING_FOR_ANSWER ||
                            this.status === C.STATUS_WAITING_FOR_PRACK ||
                            this.status === C.STATUS_ANSWERED_WAITING_FOR_PRACK ||
                            this.status === C.STATUS_EARLY_MEDIA ||
                            this.status === C.STATUS_ANSWERED) {
                            this.status = C.STATUS_CANCELED;
                            this.request.reply(487);
                            this.canceled(request);
                            this.rejected(request, SIP.C.causes.CANCELED);
                            this.failed(request, SIP.C.causes.CANCELED);
                            this.terminated(request, SIP.C.causes.CANCELED);
                        }
                        break;
                    case SIP.C.ACK:
                        if (this.status === C.STATUS_WAITING_FOR_ACK) {
                            if (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)
                                    .then(
                                // TODO: Catch then .then
                                confirmSession.bind(this), function onFailure(e) {
                                    this.logger.warn(e);
                                    this.terminate({
                                        statusCode: '488',
                                        reasonPhrase: 'Bad Media Description'
                                    });
                                    this.failed(request, SIP.C.causes.BAD_MEDIA_DESCRIPTION);
                                    this.terminated(request, SIP.C.causes.BAD_MEDIA_DESCRIPTION);
                                }.bind(this));
                            }
                            else {
                                confirmSession.apply(this);
                            }
                        }
                        break;
                    case SIP.C.PRACK:
                        if (this.status === C.STATUS_WAITING_FOR_PRACK || this.status === C.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 onSuccess() {
                                        SIP.Timers.clearTimeout(this.timers.rel1xxTimer);
                                        SIP.Timers.clearTimeout(this.timers.prackTimer);
                                        request.reply(200);
                                        if (this.status === C.STATUS_ANSWERED_WAITING_FOR_PRACK) {
                                            this.status = C.STATUS_EARLY_MEDIA;
                                            this.accept();
                                        }
                                        this.status = C.STATUS_EARLY_MEDIA;
                                    }.bind(this), function onFailure(e) {
                                        this.logger.warn(e);
                                        this.terminate({
                                            statusCode: '488',
                                            reasonPhrase: 'Bad Media Description'
                                        });
                                        this.failed(request, SIP.C.causes.BAD_MEDIA_DESCRIPTION);
                                        this.terminated(request, SIP.C.causes.BAD_MEDIA_DESCRIPTION);
                                    }.bind(this));
                                }
                                else {
                                    this.terminate({
                                        statusCode: '488',
                                        reasonPhrase: 'Bad Media Description'
                                    });
                                    this.failed(request, SIP.C.causes.BAD_MEDIA_DESCRIPTION);
                                    this.terminated(request, SIP.C.causes.BAD_MEDIA_DESCRIPTION);
                                }
                            }
                            else {
                                SIP.Timers.clearTimeout(this.timers.rel1xxTimer);
                                SIP.Timers.clearTimeout(this.timers.prackTimer);
                                request.reply(200);
                                if (this.status === C.STATUS_ANSWERED_WAITING_FOR_PRACK) {
                                    this.status = C.STATUS_EARLY_MEDIA;
                                    this.accept();
                                }
                                this.status = C.STATUS_EARLY_MEDIA;
                            }
                        }
                        else if (this.status === C.STATUS_EARLY_MEDIA) {
                            request.reply(200);
                        }
                        break;
                    default:
                        Session.prototype.receiveRequest.apply(this, [request]);
                        break;
                }
            } },
        // Internal Function to setup the handler consistently
        setupSessionDescriptionHandler: { writable: true, value: function () {
                if (this.sessionDescriptionHandler) {
                    return this.sessionDescriptionHandler;
                }
                return this.sessionDescriptionHandlerFactory(this, this.ua.configuration.sessionDescriptionHandlerFactoryOptions);
            } },
        onTransportError: { writable: true, value: function () {
                if (this.status !== C.STATUS_CONFIRMED && this.status !== C.STATUS_TERMINATED) {
                    this.failed(null, SIP.C.causes.CONNECTION_ERROR);
                }
            } },
        onRequestTimeout: { writable: true, value: function () {
                if (this.status === C.STATUS_CONFIRMED) {
                    this.terminated(null, SIP.C.causes.REQUEST_TIMEOUT);
                }
                else if (this.status !== C.STATUS_TERMINATED) {
                    this.failed(null, SIP.C.causes.REQUEST_TIMEOUT);
                    this.terminated(null, SIP.C.causes.REQUEST_TIMEOUT);
                }
            } }
    });
    SIP.InviteServerContext = InviteServerContext;
    InviteClientContext = function (ua, target, options, modifiers) {
        options = options || {};
        this.passedOptions = options; // Save for later to use with refer
        options.params = Object.create(options.params || Object.prototype);
        var extraHeaders = (options.extraHeaders || []).slice(), sessionDescriptionHandlerFactory = ua.configuration.sessionDescriptionHandlerFactory;
        this.sessionDescriptionHandlerFactoryOptions = ua.configuration.sessionDescriptionHandlerFactoryOptions || {};
        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 || null;
        this.rendertype = options.rendertype || 'text/plain';
        // Session parameter initialization
        this.from_tag = SIP.Utils.newTag();
        options.params.from_tag = this.from_tag;
        /* Do not add ;ob in initial forming dialog requests if the registration over
         *  the current connection got a GRUU URI.
         */
        this.contact = ua.contact.toString({
            anonymous: this.anonymous,
            outbound: this.anonymous ? !ua.contact.temp_gruu : !ua.contact.pub_gruu
        });
        if (this.anonymous) {
            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: ' + this.contact);
        extraHeaders.push('Allow: ' + SIP.UA.C.ALLOWED_METHODS.toString());
        if (this.inviteWithoutSdp && this.renderbody) {
            extraHeaders.push('Content-Type: ' + this.rendertype);
            extraHeaders.push('Content-Disposition: render;handling=optional');
        }
        if (ua.configuration.rel100 === SIP.C.supported.REQUIRED) {
            extraHeaders.push('Require: 100rel');
        }
        if (ua.configuration.replaces === SIP.C.supported.REQUIRED) {
            extraHeaders.push('Require: replaces');
        }
        options.extraHeaders = extraHeaders;
        SIP.Utils.augment(this, SIP.ClientContext, [ua, SIP.C.INVITE, target, options]);
        SIP.Utils.augment(this, SIP.Session, [sessionDescriptionHandlerFactory]);
        // Check Session Status
        if (this.status !== C.STATUS_NULL) {
            throw new SIP.Exceptions.InvalidStateError(this.status);
        }
        // OutgoingSession specific parameters
        this.isCanceled = false;
        this.received_100 = false;
        this.method = SIP.C.INVITE;
        this.receiveNonInviteResponse = this.receiveResponse;
        this.receiveResponse = this.receiveInviteResponse;
        this.logger = ua.getLogger('sip.inviteclientcontext');
        ua.applicants[this] = this;
        this.id = this.request.call_id + this.from_tag;
        this.onInfo = options.onInfo;
        this.errorListener = this.onTransportError.bind(this);
        ua.transport.on('transportError', this.errorListener);
    };
    InviteClientContext.prototype = Object.create({}, {
        invite: { writable: true, value: function () {
                var self = 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
                SIP.Utils.Promise.resolve().then(function () {
                    if (this.inviteWithoutSdp) {
                        //just send an invite with no sdp...
                        this.request.body = self.renderbody;
                        this.status = C.STATUS_INVITE_SENT;
                        this.send();
                    }
                    else {
                        //Initialize Media Session
                        this.sessionDescriptionHandler = this.sessionDescriptionHandlerFactory(this, this.sessionDescriptionHandlerFactoryOptions);
                        this.emit('SessionDescriptionHandler-created', this.sessionDescriptionHandler);
                        this.sessionDescriptionHandler.getDescription(this.sessionDescriptionHandlerOptions, this.modifiers)
                            .then(function onSuccess(description) {
                            if (self.isCanceled || self.status === C.STATUS_TERMINATED) {
                                return;
                            }
                            self.hasOffer = true;
                            self.request.body = description;
                            self.status = C.STATUS_INVITE_SENT;
                            self.send();
                        }, function onFailure(err) {
                            if (err instanceof SIP.Exceptions.SessionDescriptionHandlerError) {
                                self.logger.log(err.message);
                                self.logger.log(err.error);
                            }
                            if (self.status === C.STATUS_TERMINATED) {
                                return;
                            }
                            self.failed(null, SIP.C.causes.WEBRTC_ERROR);
                            self.terminated(null, SIP.C.causes.WEBRTC_ERROR);
                        });
                    }
                }.bind(this));
                return this;
            } },
        receiveInviteResponse: { writable: true, value: function (response) {
                var cause, session = this, id = response.call_id + response.from_tag + response.to_tag, extraHeaders = [], options = {};
                if (this.status === C.STATUS_TERMINATED || response.method !== SIP.C.INVITE) {
                    return;
                }
                if (this.dialog && (response.status_code >= 200 && response.status_code <= 299)) {
                    if (id !== this.dialog.id.toString()) {
                        if (!this.createDialog(response, 'UAC', true)) {
                            return;
                        }
                        this.emit("ack", response.transaction.sendACK({ body: SIP.Utils.generateFakeSDP(response.body) }));
                        this.earlyDialogs[id].sendRequest(this, SIP.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 !== C.STATUS_CONFIRMED) {
                            this.failed(response, SIP.C.causes.WEBRTC_ERROR);
                            this.terminated(response, SIP.C.causes.WEBRTC_ERROR);
                        }
                        return;
                    }
                    else if (this.status === C.STATUS_CONFIRMED) {
                        this.emit("ack", response.transaction.sendACK());
                        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;
                    }
                }
                if (this.dialog && response.status_code < 200) {
                    /*
                      Early media has been set up with at least one other different branch,
                      but a final 2xx response hasn't been received
                    */
                    if (this.dialog.pracked.indexOf(response.getHeader('rseq')) !== -1 ||
                        (this.dialog.pracked[this.dialog.pracked.length - 1] >= response.getHeader('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] >= response.getHeader('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, SIP.C.PRACK, {
                        extraHeaders: extraHeaders,
                        body: SIP.Utils.generateFakeSDP(response.body)
                    });
                    return;
                }
                // Proceed to cancellation if the user requested.
                if (this.isCanceled) {
                    if (response.status_code >= 100 && response.status_code < 200) {
                        this.request.cancel(this.cancelReason, extraHeaders);
                        this.canceled(null);
                    }
                    else if (response.status_code >= 200 && response.status_code < 299) {
                        this.acceptAndTerminate(response);
                        this.emit('bye', this.request);
                    }
                    else if (response.status_code >= 300) {
                        cause = SIP.C.REASON_PHRASE[response.status_code] || SIP.C.causes.CANCELED;
                        this.rejected(response, cause);
                        this.failed(response, cause);
                        this.terminated(response, cause);
                    }
                    return;
                }
                switch (true) {
                    case /^100$/.test(response.status_code):
                        this.received_100 = true;
                        this.emit('progress', response);
                        break;
                    case (/^1[0-9]{2}$/.test(response.status_code)):
                        // Do nothing with 1xx responses without To tag.
                        if (!response.to_tag) {
                            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 = C.STATUS_1XX_RECEIVED;
                        if (response.hasHeader('P-Asserted-Identity')) {
                            this.assertedIdentity = new SIP.NameAddrHeader.parse(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;
                            }
                            if (this.earlyDialogs[id].pracked.indexOf(response.getHeader('rseq')) !== -1 ||
                                (this.earlyDialogs[id].pracked[this.earlyDialogs[id].pracked.length - 1] >= response.getHeader('rseq') && 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.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, SIP.C.PRACK, {
                                    extraHeaders: extraHeaders
                                });
                                this.emit('progress', response);
                            }
                            else if (this.hasOffer) {
                                if (!this.createDialog(response, 'UAC')) {
                                    break;
                                }
                                this.hasAnswer = true;
                                this.dialog.pracked.push(response.getHeader('rseq'));
                                this.sessionDescriptionHandler.setDescription(response.body, this.sessionDescriptionHandlerOptions, this.modifiers)
                                    .then(function onSuccess() {
                                    extraHeaders.push('RAck: ' + response.getHeader('rseq') + ' ' + response.getHeader('cseq'));
                                    session.sendRequest(SIP.C.PRACK, {
                                        extraHeaders: extraHeaders,
                                        receiveResponse: function () { }
                                    });
                                    session.status = C.STATUS_EARLY_MEDIA;
                                    session.emit('progress', response);
                                }, function onFailure(e) {
                                    session.logger.warn(e);
                                    session.acceptAndTerminate(response, 488, 'Not Acceptable Here');
                                    session.failed(response, SIP.C.causes.BAD_MEDIA_DESCRIPTION);
                                });
                            }
                            else {
                                var earlyDialog = this.earlyDialogs[id];
                                var earlyMedia = earlyDialog.sessionDescriptionHandler = this.sessionDescriptionHandlerFactory(this, this.sessionDescriptionHandlerFactoryOptions);
                                this.emit('SessionDescriptionHandler-created', earlyMedia);
                                earlyDialog.pracked.push(response.getHeader('rseq'));
                                earlyMedia.setDescription(response.body, session.sessionDescriptionHandlerOptions, session.modifers)
                                    .then(earlyMedia.getDescription.bind(earlyMedia, session.sessionDescriptionHandlerOptions, session.modifiers))
                                    .then(function onSuccess(description) {
                                    extraHeaders.push('RAck: ' + response.getHeader('rseq') + ' ' + response.getHeader('cseq'));
                                    earlyDialog.sendRequest(session, SIP.C.PRACK, {
                                        extraHeaders: extraHeaders,
                                        body: description
                                    });
                                    session.status = C.STATUS_EARLY_MEDIA;
                                    session.emit('progress', response);
                                })
                                    .catch(function onFailure(e) {
                                    // TODO: This is a bit wonky
                                    if (e instanceof SIP.Exceptions.SessionDescriptionHandlerError) {
                                        earlyDialog.pracked.push(response.getHeader('rseq'));
                                        if (session.status === C.STATUS_TERMINATED) {
                                            return;
                                        }
                                        session.failed(null, SIP.C.causes.WEBRTC_ERROR);
                                        session.terminated(null, SIP.C.causes.WEBRTC_ERROR);
                                    }
                                    else {
                                        earlyDialog.pracked.splice(earlyDialog.pracked.indexOf(response.getHeader('rseq')), 1);
                                        // Could not set remote description
                                        session.logger.warn('invalid description');
                                        session.logger.warn(e);
                                    }
                                });
                            }
                        }
                        else {
                            this.emit('progress', response);
                        }
                        break;
                    case /^2[0-9]{2}$/.test(response.status_code):
                        var cseq = this.request.cseq + ' ' + this.request.method;
                        if (cseq !== response.getHeader('cseq')) {
                            break;
                        }
                        if (response.hasHeader('P-Asserted-Identity')) {
                            this.assertedIdentity = new SIP.NameAddrHeader.parse(response.getHeader('P-Asserted-Identity'));
                        }
                        if (this.status === C.STATUS_EARLY_MEDIA && this.dialog) {
                            this.status = C.STATUS_CONFIRMED;
                            options = {};
                            if (this.renderbody) {
                                extraHeaders.push('Content-Type: ' + this.rendertype);
                                options.extraHeaders = extraHeaders;
                                options.body = this.renderbody;
                            }
                            this.emit("ack", response.transaction.sendACK(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 = C.STATUS_CONFIRMED;
                                this.emit("ack", response.transaction.sendACK());
                                this.accepted(response);
                            }
                            else {
                                this.sessionDescriptionHandler = this.sessionDescriptionHandlerFactory(this, this.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, SIP.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(this.sessionDescriptionHandler.getDescription.bind(this.sessionDescriptionHandler, this.sessionDescriptionHandlerOptions, this.modifiers))
                                    .then(function onSuccess(description) {
                                    //var localMedia;
                                    if (session.isCanceled || session.status === C.STATUS_TERMINATED) {
                                        return;
                                    }
                                    session.status = C.STATUS_CONFIRMED;
                                    session.hasAnswer = true;
                                    session.emit("ack", response.transaction.sendACK({ body: description }));
                                    session.accepted(response);
                                })
                                    .catch(function onFailure(e) {
                                    if (e instanceof SIP.Exceptions.SessionDescriptionHandlerError) {
                                        session.logger.warn('invalid description');
                                        session.logger.warn(e);
                                        // TODO: This message is inconsistent
                                        session.acceptAndTerminate(response, 488, 'Invalid session description');
                                        session.failed(response, SIP.C.causes.BAD_MEDIA_DESCRIPTION);
                                    }
                                });
                            }
                        }
                        else if (this.hasAnswer) {
                            if (this.renderbody) {
                                extraHeaders.push('Content-Type: ' + session.rendertype);
                                options.extraHeaders = extraHeaders;
                                options.body = this.renderbody;
                            }
                            this.emit("ack", response.transaction.sendACK(options));
                        }
                        else {
                            if (!this.sessionDescriptionHandler.hasDescription(response.getHeader('Content-Type'))) {
                                this.acceptAndTerminate(response, 400, 'Missing session description');
                                this.failed(response, SIP.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 onSuccess() {
                                var options = {};
                                session.status = C.STATUS_CONFIRMED;
                                if (session.renderbody) {
                                    extraHeaders.push('Content-Type: ' + session.rendertype);
                                    options.extraHeaders = extraHeaders;
                                    options.body = session.renderbody;
                                }
                                session.emit("ack", response.transaction.sendACK(options));
                                session.accepted(response);
                            }, function onFailure(e) {
                                session.logger.warn(e);
                                session.acceptAndTerminate(response, 488, 'Not Acceptable Here');
                                session.failed(response, SIP.C.causes.BAD_MEDIA_DESCRIPTION);
                            });
                        }
                        break;
                    default:
                        cause = SIP.Utils.sipErrorCause(response.status_code);
                        this.rejected(response, cause);
                        this.failed(response, cause);
                        this.terminated(response, cause);
                }
            } },
        cancel: { writable: true, value: function (options) {
                options = options || {};
                options.extraHeaders = (options.extraHeaders || []).slice();
                if (this.isCanceled) {
                    throw new SIP.Exceptions.InvalidStateError('CANCELED');
                }
                // Check Session Status
                if (this.status === C.STATUS_TERMINATED || this.status === C.STATUS_CONFIRMED) {
                    throw new SIP.Exceptions.InvalidStateError(this.status);
                }
                this.logger.log('canceling RTCSession');
                this.isCanceled = true;
                var cancel_reason = SIP.Utils.getCancelReason(options.status_code, options.reason_phrase);
                // Check Session Status
                if (this.status === C.STATUS_NULL ||
                    (this.status === C.STATUS_INVITE_SENT && !this.received_100)) {
                    this.cancelReason = cancel_reason;
                }
                else if (this.status === C.STATUS_INVITE_SENT ||
                    this.status === C.STATUS_1XX_RECEIVED ||
                    this.status === C.STATUS_EARLY_MEDIA) {
                    this.request.cancel(cancel_reason, options.extraHeaders);
                }
                return this.canceled();
            } },
        terminate: { writable: true, value: function (options) {
                if (this.status === C.STATUS_TERMINATED) {
                    return this;
                }
                if (this.status === C.STATUS_WAITING_FOR_ACK || this.status === C.STATUS_CONFIRMED) {
                    this.bye(options);
                }
                else {
                    this.cancel(options);
                }
                return this;
            } },
        receiveRequest: { writable: true, value: function (request) {
                // ICC RECEIVE REQUEST
                // Reject CANCELs
                if (request.method === SIP.C.CANCEL) {
                    // TODO; make this a switch when it gets added
                }
                if (request.method === SIP.C.ACK && this.status === C.STATUS_WAITING_FOR_ACK) {
                    SIP.Timers.clearTimeout(this.timers.ackTimer);
                    SIP.Timers.clearTimeout(this.timers.invite2xxTimer);
                    this.status = C.STATUS_CONFIRMED;
                    this.accepted();
                }
                return Session.prototype.receiveRequest.apply(this, [request]);
            } },
        onTransportError: { writable: true, value: function () {
                if (this.status !== C.STATUS_CONFIRMED && this.status !== C.STATUS_TERMINATED) {
                    this.failed(null, SIP.C.causes.CONNECTION_ERROR);
                }
            } },
        onRequestTimeout: { writable: true, value: function () {
                if (this.status === C.STATUS_CONFIRMED) {
                    this.terminated(null, SIP.C.causes.REQUEST_TIMEOUT);
                }
                else if (this.status !== C.STATUS_TERMINATED) {
                    this.failed(null, SIP.C.causes.REQUEST_TIMEOUT);
                    this.terminated(null, SIP.C.causes.REQUEST_TIMEOUT);
                }
            } }
    });
    SIP.InviteClientContext = InviteClientContext;
    ReferClientContext = function (ua, applicant, target, options) {
        this.options = options || {};
        this.extraHeaders = (this.options.extraHeaders || []).slice();
        if (ua === undefined || applicant === undefined || target === undefined) {
            throw new TypeError('Not enough arguments');
        }
        SIP.Utils.augment(this, SIP.ClientContext, [ua, SIP.C.REFER, applicant.remoteIdentity.uri.toString(), options]);
        this.applicant = applicant;
        var withReplaces = target instanceof SIP.InviteServerContext ||
            target instanceof SIP.InviteClientContext;
        if (withReplaces) {
            // Attended Transfer
            // All of these fields should be defined based on the check above
            this.target = '"' + target.remoteIdentity.friendlyName + '" ' +
                '<' + target.dialog.remote_target.toString() +
                '?Replaces=' + target.dialog.id.call_id +
                '%3Bto-tag%3D' + target.dialog.id.remote_tag +
                '%3Bfrom-tag%3D' + target.dialog.id.local_tag + '>';
        }
        else {
            // Blind Transfer
            // Refer-To: <sip:bob@example.com>
            try {
                this.target = SIP.Grammar.parse(target, 'Refer_To').uri || target;
            }
            catch (e) {
                this.logger.debug(".refer() cannot parse Refer_To from", target);
                this.logger.debug("...falling through to normalizeTarget()");
            }
            // Check target validity
            this.target = this.ua.normalizeTarget(this.target);
            if (!this.target) {
                throw new TypeError('Invalid target: ' + target);
            }
        }
        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.extraHeaders.push('Allow: ' + SIP.UA.C.ALLOWED_METHODS.toString());
        this.extraHeaders.push('Refer-To: ' + this.target);
        this.errorListener = this.onTransportError.bind(this);
        ua.transport.on('transportError', this.errorListener);
    };
    ReferClientContext.prototype = Object.create({}, {
        refer: { writable: true, value: function (options) {
                options = options || {};
                var extraHeaders = (this.extraHeaders || []).slice();
                if (options.extraHeaders) {
                    extraHeaders.concat(options.extraHeaders);
                }
                this.applicant.sendRequest(SIP.C.REFER, {
                    extraHeaders: this.extraHeaders,
                    receiveResponse: function (response) {
                        if (/^1[0-9]{2}$/.test(response.status_code)) {
                            this.emit('referRequestProgress', this);
                        }
                        else if (/^2[0-9]{2}$/.test(response.status_code)) {
                            this.emit('referRequestAccepted', this);
                        }
                        else if (/^[4-6][0-9]{2}$/.test(response.status_code)) {
                            this.emit('referRequestRejected', this);
                        }
                        if (options.receiveResponse) {
                            options.receiveResponse(response);
                        }
                    }.bind(this)
                });
                return this;
            } },
        receiveNotify: { writable: true, value: function (request) {
                // If we can correctly handle this, then we need to send a 200 OK!
                if (request.hasHeader('Content-Type') && request.getHeader('Content-Type').search(/^message\/sipfrag/) !== -1) {
                    var messageBody = SIP.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');
            } }
    });
    SIP.ReferClientContext = ReferClientContext;
    ReferServerContext = function (ua, request) {
        SIP.Utils.augment(this, SIP.ServerContext, [ua, request]);
        this.ua = ua;
        this.status = C.STATUS_INVITE_RECEIVED;
        this.from_tag = request.from_tag;
        this.id = request.call_id + this.from_tag;
        this.request = request;
        this.contact = this.ua.contact.toString();
        this.logger = ua.getLogger('sip.referservercontext', this.id);
        // 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.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);
        // Needed to send the NOTIFY's
        this.cseq = Math.floor(Math.random() * 10000);
        this.call_id = this.request.call_id;
        this.from_uri = this.request.to.uri;
        this.from_tag = this.request.to.parameters.tag;
        this.remote_target = this.request.headers.Contact[0].parsed.uri;
        this.to_uri = this.request.from.uri;
        this.to_tag = this.request.from_tag;
        this.route_set = this.request.getHeaders('record-route');
        this.receiveNonInviteResponse = function () { };
        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);
        ua.transport.on('transportError', this.errorListener);
        this.status = C.STATUS_WAITING_FOR_ANSWER;
    };
    ReferServerContext.prototype = Object.create({}, {
        progress: { writable: true, value: function () {
                if (this.status !== C.STATUS_WAITING_FOR_ANSWER) {
                    throw new SIP.Exceptions.InvalidStateError(this.status);
                }
                this.request.reply(100);
            } },
        reject: { writable: true, value: function (options) {
                if (this.status === C.STATUS_TERMINATED) {
                    throw new SIP.Exceptions.InvalidStateError(this.status);
                }
                this.logger.log('Rejecting refer');
                this.status = C.STATUS_TERMINATED;
                SIP.ServerContext.prototype.reject.call(this, options);
                this.emit('referRequestRejected', this);
            } },
        accept: { writable: true, value: function (options, modifiers) {
                options = options || {};
                if (this.status === C.STATUS_WAITING_FOR_ANSWER) {
                    this.status = C.STATUS_ANSWERED;
                }
                else {
                    throw new SIP.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.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, inviteOptions, modifiers);
                    this.emit('referInviteSent', this);
                    this.targetSession.once('progress', function () {
                        this.sendNotify('SIP/2.0 100 Trying');
                        this.emit('referProgress', this);
                        if (this.referredSession) {
                            this.referredSession.emit('referProgress', this);
                        }
                    }.bind(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);
                        }
                    }.bind(this));
                    var referFailed = function (response) {
                        if (this.status === C.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.status_code === 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 = C.STATUS_TERMINATED;
                        this.emit('referRejected', this);
                        if (this.referredSession) {
                            this.referredSession.emit('referRejected');
                        }
                    };
                    this.targetSession.once('rejected', referFailed.bind(this));
                    this.targetSession.once('failed', referFailed.bind(this));
                }
                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);
                    }
                }
            } },
        sendNotify: { writable: true, value: function (body) {
                if (this.status !== C.STATUS_ANSWERED) {
                    throw new SIP.Exceptions.InvalidStateError(this.status);
                }
                if (SIP.Grammar.parse(body, 'sipfrag') === -1) {
                    throw new Error('sipfrag body is required to send notify for refer');
                }
                var request = new SIP.OutgoingRequest(SIP.C.NOTIFY, this.remote_target, this.ua, {
                    cseq: this.cseq += 1,
                    call_id: this.call_id,
                    from_uri: this.from_uri,
                    from_tag: this.from_tag,
                    to_uri: this.to_uri,
                    to_tag: this.to_tag,
                    route_set: this.route_set
                }, [
                    'Event: refer',
                    'Subscription-State: terminated',
                    'Content-Type: message/sipfrag'
                ], body);
                new SIP.RequestSender({
                    request: request,
                    onRequestTimeout: function () {
                        return;
                    },
                    onTransportError: function () {
                        return;
                    },
                    receiveResponse: function () {
                        return;
                    }
                }, this.ua).send();
            } }
    });
    SIP.ReferServerContext = ReferServerContext;
};


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

"use strict";

/**
 * @fileoverview DTMF
 */
/**
 * @class DTMF
 * @param {SIP.Session} session
 */
module.exports = function (SIP) {
    var DTMF, C = {
        MIN_DURATION: 70,
        MAX_DURATION: 6000,
        DEFAULT_DURATION: 100,
        MIN_INTER_TONE_GAP: 50,
        DEFAULT_INTER_TONE_GAP: 500
    };
    DTMF = function (session, tone, options) {
        var duration, interToneGap;
        if (tone === undefined) {
            throw new TypeError('Not enough arguments');
        }
        this.logger = session.ua.getLogger('sip.invitecontext.dtmf', session.id);
        this.owner = session;
        this.direction = null;
        options = options || {};
        duration = options.duration || null;
        interToneGap = options.interToneGap || null;
        // 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;
        }
        // Check duration
        if (duration && !SIP.Utils.isDecimal(duration)) {
            throw new TypeError('Invalid tone duration: ' + duration);
        }
        else if (!duration) {
            duration = DTMF.C.DEFAULT_DURATION;
        }
        else if (duration < DTMF.C.MIN_DURATION) {
            this.logger.warn('"duration" value is lower than the minimum allowed, setting it to ' + DTMF.C.MIN_DURATION + ' milliseconds');
            duration = DTMF.C.MIN_DURATION;
        }
        else if (duration > DTMF.C.MAX_DURATION) {
            this.logger.warn('"duration" value is greater than the maximum allowed, setting it to ' + DTMF.C.MAX_DURATION + ' milliseconds');
            duration = DTMF.C.MAX_DURATION;
        }
        else {
            duration = Math.abs(duration);
        }
        this.duration = duration;
        // Check interToneGap
        if (interToneGap && !SIP.Utils.isDecimal(interToneGap)) {
            throw new TypeError('Invalid interToneGap: ' + interToneGap);
        }
        else if (!interToneGap) {
            interToneGap = DTMF.C.DEFAULT_INTER_TONE_GAP;
        }
        else if (interToneGap < DTMF.C.MIN_INTER_TONE_GAP) {
            this.logger.warn('"interToneGap" value is lower than the minimum allowed, setting it to ' + DTMF.C.MIN_INTER_TONE_GAP + ' milliseconds');
            interToneGap = DTMF.C.MIN_INTER_TONE_GAP;
        }
        else {
            interToneGap = Math.abs(interToneGap);
        }
        this.interToneGap = interToneGap;
    };
    DTMF.prototype = Object.create(SIP.EventEmitter.prototype);
    DTMF.prototype.send = function (options) {
        var extraHeaders, body = {};
        this.direction = 'outgoing';
        // Check RTCSession Status
        if (this.owner.status !== SIP.Session.C.STATUS_CONFIRMED &&
            this.owner.status !== SIP.Session.C.STATUS_WAITING_FOR_ACK) {
            throw new SIP.Exceptions.InvalidStateError(this.owner.status);
        }
        // Get DTMF options
        options = options || {};
        extraHeaders = options.extraHeaders ? options.extraHeaders.slice() : [];
        body.contentType = 'application/dtmf-relay';
        body.body = "Signal= " + this.tone + "\r\n";
        body.body += "Duration= " + this.duration;
        this.request = this.owner.dialog.sendRequest(this, SIP.C.INFO, {
            extraHeaders: extraHeaders,
            body: body
        });
        this.owner.emit('dtmf', this.request, this);
    };
    /**
     * @private
     */
    DTMF.prototype.receiveResponse = function (response) {
        var cause;
        switch (true) {
            case /^1[0-9]{2}$/.test(response.status_code):
                // Ignore provisional responses.
                break;
            case /^2[0-9]{2}$/.test(response.status_code):
                this.emit('succeeded', {
                    originator: 'remote',
                    response: response
                });
                break;
            default:
                cause = SIP.Utils.sipErrorCause(response.status_code);
                this.emit('failed', response, cause);
                break;
        }
    };
    /**
     * @private
     */
    DTMF.prototype.onRequestTimeout = function () {
        this.emit('failed', null, SIP.C.causes.REQUEST_TIMEOUT);
        this.owner.onRequestTimeout();
    };
    /**
     * @private
     */
    DTMF.prototype.onTransportError = function () {
        this.emit('failed', null, SIP.C.causes.CONNECTION_ERROR);
        this.owner.onTransportError();
    };
    /**
     * @private
     */
    DTMF.prototype.onDialogError = function (response) {
        this.emit('failed', response, SIP.C.causes.DIALOG_ERROR);
        this.owner.onDialogError(response);
    };
    /**
     * @private
     */
    DTMF.prototype.init_incoming = function (request) {
        this.direction = 'incoming';
        this.request = 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.C = C;
    return DTMF;
};


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

"use strict";

/**
 * @fileoverview SIP Subscriber (SIP-Specific Event Notifications RFC6665)
 */
/**
 * @augments SIP
 * @class Class creating a SIP Subscription.
 */
module.exports = function (SIP) {
    SIP.Subscription = function (ua, target, event, options) {
        options = Object.create(options || Object.prototype);
        this.extraHeaders = options.extraHeaders = (options.extraHeaders || []).slice();
        this.id = null;
        this.state = 'init';
        if (!event) {
            throw new TypeError('Event necessary to create a subscription.');
        }
        else {
            //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;
        }
        if (typeof options.expires !== 'number') {
            ua.logger.warn('expires must be a number. Using default of 3600.');
            this.expires = 3600;
        }
        else {
            this.expires = options.expires;
        }
        this.requestedExpires = this.expires;
        options.extraHeaders.push('Event: ' + this.event);
        options.extraHeaders.push('Expires: ' + this.expires);
        if (options.body) {
            this.body = options.body;
        }
        this.contact = ua.contact.toString();
        options.extraHeaders.push('Contact: ' + this.contact);
        options.extraHeaders.push('Allow: ' + SIP.UA.C.ALLOWED_METHODS.toString());
        SIP.Utils.augment(this, SIP.ClientContext, [ua, SIP.C.SUBSCRIBE, target, options]);
        this.logger = ua.getLogger('sip.subscription');
        this.dialog = null;
        this.timers = { N: null, sub_duration: null };
        this.errorCodes = [404, 405, 410, 416, 480, 481, 482, 483, 484, 485, 489, 501, 604];
    };
    SIP.Subscription.prototype = {
        subscribe: function () {
            var sub = 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;
            }
            SIP.Timers.clearTimeout(this.timers.sub_duration);
            SIP.Timers.clearTimeout(this.timers.N);
            this.timers.N = SIP.Timers.setTimeout(sub.timer_fire.bind(sub), SIP.Timers.TIMER_N);
            this.ua.earlySubscriptions[this.request.call_id + this.request.from.parameters.tag + this.event] = this;
            this.send();
            this.state = 'notify_wait';
            return this;
        },
        refresh: function () {
            if (this.state === 'terminated' || this.state === 'pending' || this.state === 'notify_wait') {
                return;
            }
            this.dialog.sendRequest(this, SIP.C.SUBSCRIBE, {
                extraHeaders: this.extraHeaders,
                body: this.body
            });
        },
        receiveResponse: function (response) {
            var expires, sub = this, cause = SIP.Utils.getReasonPhrase(response.status_code);
            if ((this.state === 'notify_wait' && response.status_code >= 300) ||
                (this.state !== 'notify_wait' && this.errorCodes.indexOf(response.status_code) !== -1)) {
                this.failed(response, null);
            }
            else if (/^2[0-9]{2}$/.test(response.status_code)) {
                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
                //SIP.Timers.clearTimeout(this.timers.N);
                expires = response.getHeader('Expires');
                if (expires && expires <= this.requestedExpires) {
                    // Preserve new expires value for subsequent requests
                    this.expires = expires;
                    this.timers.sub_duration = SIP.Timers.setTimeout(sub.refresh.bind(sub), expires * 900);
                }
                else {
                    if (!expires) {
                        this.logger.warn('Expires header missing in a 200-class response to SUBSCRIBE');
                        this.failed(response, SIP.C.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, SIP.C.INVALID_EXPIRES_HEADER);
                    }
                }
            }
            else if (response.statusCode > 300) {
                this.emit('failed', response, cause);
                this.emit('rejected', response, cause);
            }
        },
        unsubscribe: function () {
            var extraHeaders = [], sub = this;
            this.state = 'terminated';
            extraHeaders.push('Event: ' + this.event);
            extraHeaders.push('Expires: 0');
            extraHeaders.push('Contact: ' + this.contact);
            extraHeaders.push('Allow: ' + SIP.UA.C.ALLOWED_METHODS.toString());
            //makes sure expires isn't set, and other typical resubscribe behavior
            this.receiveResponse = function () { };
            this.dialog.sendRequest(this, this.method, {
                extraHeaders: extraHeaders,
                body: this.body
            });
            SIP.Timers.clearTimeout(this.timers.sub_duration);
            SIP.Timers.clearTimeout(this.timers.N);
            this.timers.N = SIP.Timers.setTimeout(sub.timer_fire.bind(sub), SIP.Timers.TIMER_N);
        },
        /**
        * @private
        */
        timer_fire: function () {
            if (this.state === 'terminated') {
                this.terminateDialog();
                SIP.Timers.clearTimeout(this.timers.N);
                SIP.Timers.clearTimeout(this.timers.sub_duration);
                delete this.ua.subscriptions[this.id];
            }
            else if (this.state === 'notify_wait' || this.state === 'pending') {
                this.close();
            }
            else {
                this.refresh();
            }
        },
        /**
        * @private
        */
        close: function () {
            if (this.state === 'notify_wait') {
                this.state = 'terminated';
                SIP.Timers.clearTimeout(this.timers.N);
                SIP.Timers.clearTimeout(this.timers.sub_duration);
                this.receiveResponse = function () { };
                delete this.ua.earlySubscriptions[this.request.call_id + this.request.from.parameters.tag + this.event];
            }
            else if (this.state !== 'terminated') {
                this.unsubscribe();
            }
        },
        /**
        * @private
        */
        createConfirmedDialog: function (message, type) {
            var dialog;
            this.terminateDialog();
            dialog = new SIP.Dialog(this, message, type);
            dialog.invite_seqnum = this.request.cseq;
            dialog.local_seqnum = this.request.cseq;
            if (!dialog.error) {
                this.dialog = dialog;
                return true;
            }
            // Dialog not created due to an error
            else {
                return false;
            }
        },
        /**
        * @private
        */
        terminateDialog: function () {
            if (this.dialog) {
                delete this.ua.subscriptions[this.id];
                this.dialog.terminate();
                delete this.dialog;
            }
        },
        /**
        * @private
        */
        receiveRequest: function (request) {
            var sub_state, sub = this;
            function setExpiresTimeout() {
                if (sub_state.expires) {
                    SIP.Timers.clearTimeout(sub.timers.sub_duration);
                    sub_state.expires = Math.min(sub.expires, Math.max(sub_state.expires, 0));
                    sub.timers.sub_duration = SIP.Timers.setTimeout(sub.refresh.bind(sub), sub_state.expires * 900);
                }
            }
            if (!this.matchEvent(request)) { //checks event and subscription_state headers
                request.reply(489);
                return;
            }
            if (!this.dialog) {
                if (this.createConfirmedDialog(request, 'UAS')) {
                    this.id = this.dialog.id.toString();
                    delete this.ua.earlySubscriptions[this.request.call_id + this.request.from.parameters.tag + this.event];
                    this.ua.subscriptions[this.id] = this;
                    // UPDATE ROUTE SET TO BE BACKWARDS COMPATIBLE?
                }
            }
            sub_state = request.parseHeader('Subscription-State');
            request.reply(200, SIP.C.REASON_200);
            SIP.Timers.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 (sub_state.state === 'terminated') {
                    this.terminateDialog();
                    SIP.Timers.clearTimeout(this.timers.N);
                    SIP.Timers.clearTimeout(this.timers.sub_duration);
                    delete this.ua.subscriptions[this.id];
                }
                return;
            }
            switch (sub_state.state) {
                case 'active':
                    this.state = 'active';
                    setExpiresTimeout();
                    break;
                case 'pending':
                    if (this.state === 'notify_wait') {
                        setExpiresTimeout();
                    }
                    this.state = 'pending';
                    break;
                case 'terminated':
                    SIP.Timers.clearTimeout(this.timers.sub_duration);
                    if (sub_state.reason) {
                        this.logger.log('terminating subscription with reason ' + sub_state.reason);
                        switch (sub_state.reason) {
                            case 'deactivated':
                            case 'timeout':
                                this.subscribe();
                                return;
                            case 'probation':
                            case 'giveup':
                                if (sub_state.params && sub_state.params['retry-after']) {
                                    this.timers.sub_duration = SIP.Timers.setTimeout(sub.subscribe.bind(sub), sub_state.params['retry-after']);
                                }
                                else {
                                    this.subscribe();
                                }
                                return;
                            case 'rejected':
                            case 'noresource':
                            case 'invariant':
                                break;
                        }
                    }
                    this.close();
                    break;
            }
        },
        failed: function (response, cause) {
            this.close();
            this.emit('failed', response, cause);
            this.emit('rejected', response, cause);
            return this;
        },
        onDialogError: function (response) {
            this.failed(response, SIP.C.causes.DIALOG_ERROR);
        },
        /**
        * @private
        */
        matchEvent: function (request) {
            var event;
            // 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
            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;
            }
        }
    };
};


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

"use strict";

/**
 * @fileoverview SIP Publish (SIP Extension for Event State Publication RFC3903)
 */
/**
 * @augments SIP
 * @class Class creating a SIP PublishContext.
 */
module.exports = function (SIP) {
    var PublishContext;
    PublishContext = function (ua, target, event, options) {
        this.options = options = (options || {});
        this.options.extraHeaders = (options.extraHeaders || []).slice();
        this.options.contentType = (options.contentType || 'text/plain');
        if (typeof options.expires !== 'number' || (options.expires % 1) !== 0) {
            this.options.expires = 3600;
        }
        else {
            this.options.expires = Number(options.expires);
        }
        if (typeof (options.unpublishOnClose) !== "boolean") {
            this.options.unpublishOnClose = true;
        }
        else {
            this.options.unpublishOnClose = options.unpublishOnClose;
        }
        if (target === undefined || target === null || target === '') {
            throw new SIP.Exceptions.MethodParameterError('Publish', 'Target', target);
        }
        else {
            this.target = ua.normalizeTarget(target);
        }
        if (event === undefined || event === null || event === '') {
            throw new SIP.Exceptions.MethodParameterError('Publish', 'Event', event);
        }
        else {
            this.event = event;
        }
        // Call parent constructor
        SIP.ClientContext.call(this, ua, SIP.C.PUBLISH, this.target, this.options);
        this.logger = this.ua.getLogger('sip.publish');
        this.pubRequestBody = null;
        this.pubRequestExpires = this.options.expires;
        this.pubRequestEtag = null;
        this.publish_refresh_timer = null;
        ua.on('transportCreated', function (transport) {
            transport.on('transportError', this.onTransportError.bind(this));
        }.bind(this));
    };
    // Extend ClientContext
    PublishContext.prototype = Object.create(SIP.ClientContext.prototype);
    // Restore the class constructor
    PublishContext.prototype.constructor = PublishContext;
    /**
     * Publish
     *
     * @param {string} Event body to publish, optional
     *
     */
    PublishContext.prototype.publish = function (body) {
        // Clean up before the run
        this.request = null;
        SIP.Timers.clearTimeout(this.publish_refresh_timer);
        if (body !== undefined && body !== null && body !== '') {
            // 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 = null;
            }
            if (!(this.ua.publishers[this.target.toString() + ':' + this.event])) {
                this.ua.publishers[this.target.toString() + ':' + this.event] = this;
            }
        }
        else {
            // This is Refresh request
            this.pubRequestBody = null;
            if (this.pubRequestEtag === null) {
                //Request not valid
                throw new SIP.Exceptions.MethodParameterError('Publish', 'Body', body);
            }
            if (this.pubRequestExpires === 0) {
                //Request not valid
                throw new SIP.Exceptions.MethodParameterError('Publish', 'Expire', this.pubRequestExpires);
            }
        }
        this.sendPublishRequest();
    };
    /**
     * Unpublish
     *
     */
    PublishContext.prototype.unpublish = function () {
        // Clean up before the run
        this.request = null;
        SIP.Timers.clearTimeout(this.publish_refresh_timer);
        this.pubRequestBody = null;
        this.pubRequestExpires = 0;
        if (this.pubRequestEtag !== null) {
            this.sendPublishRequest();
        }
    };
    /**
     * Close
     *
     */
    PublishContext.prototype.close = function () {
        // Send unpublish, if requested
        if (this.options.unpublishOnClose) {
            this.unpublish();
        }
        else {
            this.request = null;
            SIP.Timers.clearTimeout(this.publish_refresh_timer);
            this.pubRequestBody = null;
            this.pubRequestExpires = 0;
            this.pubRequestEtag = null;
        }
        if (this.ua.publishers[this.target.toString() + ':' + this.event]) {
            delete this.ua.publishers[this.target.toString() + ':' + this.event];
        }
    };
    /**
     * @private
     *
     */
    PublishContext.prototype.sendPublishRequest = function () {
        var reqOptions;
        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 !== null) {
            reqOptions.extraHeaders.push('SIP-If-Match: ' + this.pubRequestEtag);
        }
        this.request = new SIP.OutgoingRequest(SIP.C.PUBLISH, this.target, this.ua, this.options.params, reqOptions.extraHeaders);
        if (this.pubRequestBody !== null) {
            this.request.body = {};
            this.request.body.body = this.pubRequestBody;
            this.request.body.contentType = this.options.contentType;
        }
        this.send();
    };
    /**
     * @private
     *
     */
    PublishContext.prototype.receiveResponse = function (response) {
        var expires, minExpires, cause = SIP.Utils.getReasonPhrase(response.status_code);
        switch (true) {
            case /^1[0-9]{2}$/.test(response.status_code):
                this.emit('progress', response, cause);
                break;
            case /^2[0-9]{2}$/.test(response.status_code):
                // 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')) {
                    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.publish_refresh_timer = SIP.Timers.setTimeout(this.publish.bind(this), this.pubRequestExpires * 900);
                    this.emit('published', response, cause);
                }
                else {
                    this.emit('unpublished', response, cause);
                }
                break;
            case /^412$/.test(response.status_code):
                // 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 !== null && this.pubRequestExpires !== 0) {
                    this.logger.warn('412 response to PUBLISH, recovering');
                    this.pubRequestEtag = null;
                    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(response.status_code):
                // 423 code means we need to adjust the Expires interval up
                if (this.pubRequestExpires !== 0 && response.hasHeader('Min-Expires')) {
                    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) {
            SIP.Timers.clearTimeout(this.publish_refresh_timer);
            this.pubRequestBody = null;
            this.pubRequestEtag = null;
        }
    };
    PublishContext.prototype.onRequestTimeout = function () {
        SIP.ClientContext.prototype.onRequestTimeout.call(this);
        this.emit('unpublished', null, SIP.C.causes.REQUEST_TIMEOUT);
    };
    PublishContext.prototype.onTransportError = function () {
        SIP.ClientContext.prototype.onTransportError.call(this);
        this.emit('unpublished', null, SIP.C.causes.CONNECTION_ERROR);
    };
    SIP.PublishContext = PublishContext;
};


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

"use strict";
/* WEBPACK VAR INJECTION */(function(global) {
/**
 * @augments SIP
 * @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.
 *
 * @param {Object} [configuration.media] gets passed to SIP.sessionDescriptionHandler.getDescription as mediaHint
 */
module.exports = function (SIP, environment) {
    var 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
    };
    UA = function (configuration) {
        var self = this;
        // Helper function for forwarding events
        function selfEmit(type) {
            //registrationFailed handler is invoked with two arguments. Allow event handlers to be invoked with a variable no. of arguments
            return self.emit.bind(self, type);
        }
        // Set Accepted Body Types
        C.ACCEPTED_BODY_TYPES = C.ACCEPTED_BODY_TYPES.toString();
        this.log = new SIP.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.transport = null;
        this.contact = null;
        this.status = C.STATUS_INIT;
        this.error = null;
        this.transactions = {
            nist: {},
            nict: {},
            ist: {},
            ict: {}
        };
        Object.defineProperties(this, {
            transactionsCount: {
                get: function () {
                    var type, transactions = ['nist', 'nict', 'ist', 'ict'], count = 0;
                    for (type in transactions) {
                        count += Object.keys(this.transactions[transactions[type]]).length;
                    }
                    return count;
                }
            },
            nictTransactionsCount: {
                get: function () {
                    return Object.keys(this.transactions['nict']).length;
                }
            },
            nistTransactionsCount: {
                get: function () {
                    return Object.keys(this.transactions['nist']).length;
                }
            },
            ictTransactionsCount: {
                get: function () {
                    return Object.keys(this.transactions['ict']).length;
                }
            },
            istTransactionsCount: {
                get: function () {
                    return Object.keys(this.transactions['ist']).length;
                }
            }
        });
        /**
         * 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('level')) {
                this.log.level = configuration.log.level;
            }
            if (configuration.log.hasOwnProperty('connector')) {
                this.log.connector = configuration.log.connector;
            }
        }
        try {
            this.loadConfig(configuration);
        }
        catch (e) {
            this.status = C.STATUS_NOT_READY;
            this.error = C.CONFIGURATION_ERROR;
            throw e;
        }
        // Initialize registerContext
        this.registerContext = new SIP.RegisterContext(this);
        this.registerContext.on('failed', selfEmit('registrationFailed'));
        this.registerContext.on('registered', selfEmit('registered'));
        this.registerContext.on('unregistered', selfEmit('unregistered'));
        if (this.configuration.autostart) {
            this.start();
        }
    };
    UA.prototype = Object.create(SIP.EventEmitter.prototype);
    //=================
    //  High Level API
    //=================
    UA.prototype.register = function (options) {
        this.configuration.register = true;
        this.registerContext.register(options);
        return this;
    };
    /**
     * Unregister.
     *
     * @param {Boolean} [all] unregister all user bindings.
     *
     */
    UA.prototype.unregister = function (options) {
        this.configuration.register = false;
        var context = this.registerContext;
        this.transport.afterConnected(context.unregister.bind(context, 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 context = new SIP.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.
        this.transport.afterConnected(function () {
            context.invite();
            this.emit('inviteSent', context);
        }.bind(this));
        return context;
    };
    UA.prototype.subscribe = function (target, event, options) {
        var sub = new SIP.Subscription(this, target, event, options);
        this.transport.afterConnected(sub.subscribe.bind(sub));
        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 SIP.PublishContext(this, target, event, options);
        this.transport.afterConnected(pub.publish.bind(pub, 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 (body === undefined) {
            throw new TypeError('Not enough arguments');
        }
        // There is no Message module, so it is okay that the UA handles defaults here.
        options = Object.create(options || Object.prototype);
        options.contentType || (options.contentType = 'text/plain');
        options.body = body;
        return this.request(SIP.C.MESSAGE, target, options);
    };
    UA.prototype.request = function (method, target, options) {
        var req = new SIP.ClientContext(this, method, target, options);
        this.transport.afterConnected(req.send.bind(req));
        return req;
    };
    /**
     * Gracefully close.
     *
     */
    UA.prototype.stop = function () {
        var session, subscription, applicant, publisher, ua = this;
        function transactionsListener() {
            if (ua.nistTransactionsCount === 0 && ua.nictTransactionsCount === 0) {
                ua.removeListener('transactionDestroyed', transactionsListener);
                ua.transport.disconnect();
            }
        }
        this.logger.log('user requested closure...');
        if (this.status === C.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 (session in this.sessions) {
            this.logger.log('closing session ' + session);
            this.sessions[session].terminate();
        }
        //Run _close_ on every confirmed Subscription
        for (subscription in this.subscriptions) {
            this.logger.log('unsubscribing from subscription ' + subscription);
            this.subscriptions[subscription].close();
        }
        //Run _close_ on every early Subscription
        for (subscription in this.earlySubscriptions) {
            this.logger.log('unsubscribing from early subscription ' + subscription);
            this.earlySubscriptions[subscription].close();
        }
        //Run _close_ on every Publisher
        for (publisher in this.publishers) {
            this.logger.log('unpublish ' + publisher);
            this.publishers[publisher].close();
        }
        // Run  _close_ on every applicant
        for (applicant in this.applicants) {
            this.applicants[applicant].close();
        }
        this.status = C.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.disconnect();
        }
        else {
            this.on('transactionDestroyed', transactionsListener);
        }
        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 server;
        this.logger.log('user requested startup...');
        if (this.status === C.STATUS_INIT) {
            this.status = C.STATUS_STARTING;
            if (!this.configuration.transportConstructor) {
                throw new SIP.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 === C.STATUS_USER_CLOSED) {
            this.logger.log('resuming');
            this.status = C.STATUS_READY;
            this.transport.connect();
        }
        else if (this.status === C.STATUS_STARTING) {
            this.logger.log('UA is in STARTING status, not opening new connection');
        }
        else if (this.status === C.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.bind(this);
                environment.addEventListener('unload', 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 SIP.Utils.normalizeTarget(target, this.configuration.hostportParams);
    };
    //===============================
    //  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, credentials;
        realm = request.ruri.host;
        if (this.cache.credentials[realm] && this.cache.credentials[realm][request.ruri]) {
            credentials = this.cache.credentials[realm][request.ruri];
            credentials.method = request.method;
        }
        return credentials;
    };
    UA.prototype.getLogger = function (category, label) {
        return this.log.getLogger(category, label);
    };
    //==============================
    // Event Handlers
    //==============================
    UA.prototype.onTransportError = function () {
        if (this.status === C.STATUS_USER_CLOSED) {
            return;
        }
        if (!this.error || this.error !== C.NETWORK_ERROR) {
            this.status = C.STATUS_NOT_READY;
            this.error = C.NETWORK_ERROR;
        }
    };
    /**
     * Helper function. Sets transport listeners
     * @private
     */
    UA.prototype.setTransportListeners = function () {
        this.transport.on('connected', this.onTransportConnected.bind(this));
        this.transport.on('message', this.onTransportReceiveMsg.bind(this));
        this.transport.on('transportError', this.onTransportError.bind(this));
    };
    /**
     * Transport connection event.
     * @private
     * @event
     * @param {SIP.Transport} transport.
     */
    UA.prototype.onTransportConnected = function () {
        if (this.configuration.register) {
            this.configuration.authenticationFactory.initialize().then(function () {
                this.registerContext.onTransportConnected();
            }.bind(this));
        }
    };
    /**
     * Transport message receipt event.
     * @private
     * @event
     * @param {String} message
     */
    UA.prototype.onTransportReceiveMsg = function (message) {
        var transaction;
        message = SIP.Parser.parseMessage(message, this);
        if (this.status === SIP.UA.C.STATUS_USER_CLOSED && message instanceof SIP.IncomingRequest) {
            this.logger.warn('UA received message when status = USER_CLOSED - aborting');
            return;
        }
        // Do some sanity check
        if (SIP.sanityCheck(message, this, this.transport)) {
            if (message instanceof SIP.IncomingRequest) {
                message.transport = this.transport;
                this.receiveRequest(message);
            }
            else if (message instanceof SIP.IncomingResponse) {
                /* Unike stated in 18.1.2, if a response does not match
                * any transaction, it is discarded here and no passed to the core
                * in order to be discarded there.
                */
                switch (message.method) {
                    case SIP.C.INVITE:
                        transaction = this.transactions.ict[message.via_branch];
                        if (transaction) {
                            transaction.receiveResponse(message);
                        }
                        break;
                    case SIP.C.ACK:
                        // Just in case ;-)
                        break;
                    default:
                        transaction = this.transactions.nict[message.via_branch];
                        if (transaction) {
                            transaction.receiveResponse(message);
                        }
                        break;
                }
            }
        }
    };
    /**
     * new Transaction
     * @private
     * @param {SIP.Transaction} transaction.
     */
    UA.prototype.newTransaction = function (transaction) {
        this.transactions[transaction.type][transaction.id] = transaction;
        this.emit('newTransaction', { transaction: transaction });
    };
    /**
     * destroy Transaction
     * @private
     * @param {SIP.Transaction} transaction.
     */
    UA.prototype.destroyTransaction = function (transaction) {
        delete this.transactions[transaction.type][transaction.id];
        this.emit('transactionDestroyed', {
            transaction: transaction
        });
    };
    //=========================
    // receiveRequest
    //=========================
    /**
     * Request reception
     * @private
     * @param {SIP.IncomingRequest} request.
     */
    UA.prototype.receiveRequest = function (request) {
        var dialog, session, message, earlySubscription, method = request.method, replaces, replacedDialog, self = this;
        function ruriMatches(uri) {
            return uri && uri.user === request.ruri.user;
        }
        // Check that request URI points to us
        if (!(ruriMatches(this.configuration.uri) ||
            ruriMatches(this.contact.uri) ||
            ruriMatches(this.contact.pub_gruu) ||
            ruriMatches(this.contact.temp_gruu))) {
            this.logger.warn('Request-URI does not point to us');
            if (request.method !== SIP.C.ACK) {
                request.reply_sl(404);
            }
            return;
        }
        // Check request URI scheme
        if (request.ruri.scheme === SIP.C.SIPS) {
            request.reply_sl(416);
            return;
        }
        // Check transaction
        if (SIP.Transactions.checkTransaction(this, request)) {
            return;
        }
        /* RFC3261 12.2.2
         * Requests that do not change in any way the state of a dialog may be
         * received within a dialog (for example, an OPTIONS request).
         * They are processed as if they had been received outside the dialog.
         */
        if (method === SIP.C.OPTIONS) {
            new SIP.Transactions.NonInviteServerTransaction(request, this);
            request.reply(200, null, [
                'Allow: ' + SIP.UA.C.ALLOWED_METHODS.toString(),
                'Accept: ' + C.ACCEPTED_BODY_TYPES
            ]);
        }
        else if (method === SIP.C.MESSAGE) {
            message = new SIP.ServerContext(this, request);
            message.body = request.body;
            message.content_type = request.getHeader('Content-Type') || 'text/plain';
            request.reply(200, null);
            this.emit('message', message);
        }
        else if (method !== SIP.C.INVITE &&
            method !== SIP.C.ACK) {
            // Let those methods pass through to normal processing for now.
            new SIP.ServerContext(this, request);
        }
        // Initial Request
        if (!request.to_tag) {
            switch (method) {
                case SIP.C.INVITE:
                    replaces =
                        this.configuration.replaces !== SIP.C.supported.UNSUPPORTED &&
                            request.parseHeader('replaces');
                    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, null);
                            return;
                        }
                        else if (replacedDialog.owner.status === SIP.Session.C.STATUS_TERMINATED) {
                            request.reply_sl(603, null);
                            return;
                        }
                        else if (replacedDialog.state === SIP.Dialog.C.STATUS_CONFIRMED && replaces.early_only) {
                            request.reply_sl(486, null);
                            return;
                        }
                    }
                    session = new SIP.InviteServerContext(this, request);
                    session.replacee = replacedDialog && replacedDialog.owner;
                    self.emit('invite', session);
                    break;
                case SIP.C.BYE:
                    // Out of dialog BYE received
                    request.reply(481);
                    break;
                case SIP.C.CANCEL:
                    session = this.findSession(request);
                    if (session) {
                        session.receiveRequest(request);
                    }
                    else {
                        this.logger.warn('received CANCEL request for a non existent session');
                    }
                    break;
                case SIP.C.ACK:
                    /* Absorb it.
                     * ACK request without a corresponding Invite Transaction
                     * and without To tag.
                     */
                    break;
                case SIP.C.NOTIFY:
                    if (this.configuration.allowLegacyNotifications && this.listeners('notify').length > 0) {
                        request.reply(200, null);
                        self.emit('notify', { request: request });
                    }
                    else {
                        request.reply(481, 'Subscription does not exist');
                    }
                    break;
                case SIP.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 SIP.ReferServerContext(this, request);
                        var hasReferListener = this.listeners('outOfDialogReferRequested').length;
                        if (hasReferListener) {
                            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;
            }
        }
        // In-dialog request
        else {
            dialog = this.findDialog(request);
            if (dialog) {
                if (method === SIP.C.INVITE) {
                    new SIP.Transactions.InviteServerTransaction(request, this);
                }
                dialog.receiveRequest(request);
            }
            else if (method === SIP.C.NOTIFY) {
                session = this.findSession(request);
                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');
                }
            }
            /* RFC3261 12.2.2
             * Request with to tag, but no matching dialog found.
             * Exception: ACK for an Invite request for which a dialog has not
             * been created.
             */
            else {
                if (method !== SIP.C.ACK) {
                    request.reply(481);
                }
            }
        }
    };
    //=================
    // Utils
    //=================
    /**
     * Get the session to which the request belongs to, if any.
     * @private
     * @param {SIP.IncomingRequest} request.
     * @returns {SIP.OutgoingSession|SIP.IncomingSession|null}
     */
    UA.prototype.findSession = function (request) {
        return this.sessions[request.call_id + request.from_tag] ||
            this.sessions[request.call_id + request.to_tag] ||
            null;
    };
    /**
     * Get the dialog to which the request belongs to, if any.
     * @private
     * @param {SIP.IncomingRequest}
     * @returns {SIP.Dialog|null}
     */
    UA.prototype.findDialog = function (request) {
        return this.dialogs[request.call_id + request.from_tag + request.to_tag] ||
            this.dialogs[request.call_id + request.to_tag + request.from_tag] ||
            null;
    };
    /**
     * Get the subscription which has not been confirmed to which the request belongs to, if any
     * @private
     * @param {SIP.IncomingRequest}
     * @returns {SIP.Subscription|null}
     */
    UA.prototype.findEarlySubscription = function (request) {
        return this.earlySubscriptions[request.call_id + request.to_tag + request.getHeader('event')] || null;
    };
    function checkAuthenticationFactory(authenticationFactory) {
        if (!(authenticationFactory instanceof Function)) {
            return;
        }
        if (!authenticationFactory.initialize) {
            authenticationFactory.initialize = function initialize() {
                return SIP.Utils.Promise.resolve();
            };
        }
        return authenticationFactory;
    }
    /**
     * Configuration load.
     * @private
     * returns {Boolean}
     */
    UA.prototype.loadConfig = function (configuration) {
        // Settings and default values
        var parameter, value, checked_value, hostportParams, registrarServer, settings = {
            /* Host address
            * Value to be set in Via sent_by and host part of Contact FQDN
            */
            viaHost: SIP.Utils.createRandomToken(12) + '.invalid',
            uri: new SIP.URI('sip', 'anonymous.' + SIP.Utils.createRandomToken(6), 'anonymous.invalid', null, null),
            //Custom Configuration Settings
            custom: {},
            //Display name
            displayName: '',
            // Password
            password: null,
            // Registration parameters
            registerExpires: 600,
            register: true,
            registrarServer: null,
            // Transport related parameters
            transportConstructor: __webpack_require__(29)(SIP),
            transportOptions: {},
            //string to be inserted into User-Agent request header
            userAgentString: SIP.C.USER_AGENT,
            // Session parameters
            noAnswerTimeout: 60,
            // Hacks
            hackViaTcp: false,
            hackIpInContact: false,
            hackWssInTransport: false,
            hackAllowUnregisteredOptionTags: false,
            // Session Description Handler Options
            sessionDescriptionHandlerFactoryOptions: {
                constraints: {},
                peerConnectionOptions: {}
            },
            contactName: SIP.Utils.createRandomToken(8),
            contactTransport: 'ws',
            forceRport: false,
            //autostarting
            autostart: true,
            autostop: true,
            //Reliable Provisional Responses
            rel100: SIP.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: SIP.C.dtmfType.INFO,
            // Replaces header (RFC 3891)
            // http://tools.ietf.org/html/rfc3891
            replaces: SIP.C.supported.UNSUPPORTED,
            sessionDescriptionHandlerFactory: __webpack_require__(30)(SIP).defaultFactory,
            authenticationFactory: checkAuthenticationFactory(function authenticationFactory(ua) {
                return new SIP.DigestAuthentication(ua);
            }),
            allowLegacyNotifications: false,
            allowOutOfDialogRefers: false,
        };
        // Pre-Configuration
        function aliasUnderscored(parameter, logger) {
            var underscored = parameter.replace(/([a-z][A-Z])/g, function (m) {
                return m[0] + '_' + m[1].toLowerCase();
            });
            if (parameter === underscored) {
                return;
            }
            var hasParameter = configuration.hasOwnProperty(parameter);
            if (configuration.hasOwnProperty(underscored)) {
                logger.warn(underscored + ' is deprecated, please use ' + parameter);
                if (hasParameter) {
                    logger.warn(parameter + ' overriding ' + underscored);
                }
            }
            configuration[parameter] = hasParameter ? configuration[parameter] : configuration[underscored];
        }
        var configCheck = this.getConfigurationCheck();
        // Check Mandatory parameters
        for (parameter in configCheck.mandatory) {
            aliasUnderscored(parameter, this.logger);
            if (!configuration.hasOwnProperty(parameter)) {
                throw new SIP.Exceptions.ConfigurationError(parameter);
            }
            else {
                value = configuration[parameter];
                checked_value = configCheck.mandatory[parameter](value);
                if (checked_value !== undefined) {
                    settings[parameter] = checked_value;
                }
                else {
                    throw new SIP.Exceptions.ConfigurationError(parameter, value);
                }
            }
        }
        // Check Optional parameters
        for (parameter in configCheck.optional) {
            aliasUnderscored(parameter, this.logger);
            if (configuration.hasOwnProperty(parameter)) {
                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 (value === null || value === "" || value === undefined) {
                    continue;
                }
                // 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:
                else if (typeof (value) === 'number' && isNaN(value)) {
                    continue;
                }
                checked_value = configCheck.optional[parameter](value);
                if (checked_value !== undefined) {
                    settings[parameter] = checked_value;
                }
                else {
                    throw new SIP.Exceptions.ConfigurationError(parameter, value);
                }
            }
        }
        // Post Configuration Process
        // Allow passing 0 number as displayName.
        if (settings.displayName === 0) {
            settings.displayName = '0';
        }
        // Instance-id for GRUU
        if (!settings.instanceId) {
            settings.instanceId = SIP.Utils.newUUID();
        }
        // sipjsId instance parameter. Static random tag of length 5
        settings.sipjsId = SIP.Utils.createRandomToken(5);
        // String containing settings.uri without scheme and user.
        hostportParams = settings.uri.clone();
        hostportParams.user = null;
        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;
        }
        /* If no 'registrarServer' is set use the 'uri' value without user portion. */
        if (!settings.registrarServer) {
            registrarServer = settings.uri.clone();
            registrarServer.user = null;
            settings.registrarServer = registrarServer;
        }
        // User noAnswerTimeout
        settings.noAnswerTimeout = settings.noAnswerTimeout * 1000;
        // Via Host
        if (settings.hackIpInContact) {
            if (typeof settings.hackIpInContact === 'boolean') {
                settings.viaHost = SIP.Utils.getRandomTestNetIP();
            }
            else if (typeof settings.hackIpInContact === 'string') {
                settings.viaHost = settings.hackIpInContact;
            }
        }
        // Contact transport parameter
        if (settings.hackWssInTransport) {
            settings.contactTransport = 'wss';
        }
        this.contact = {
            pub_gruu: null,
            temp_gruu: null,
            uri: new SIP.URI('sip', settings.contactName, settings.viaHost, null, { transport: settings.contactTransport }),
            toString: function (options) {
                options = options || {};
                var anonymous = options.anonymous || null, outbound = options.outbound || null, contact = '<';
                if (anonymous) {
                    contact += (this.temp_gruu || ('sip:anonymous@anonymous.invalid;transport=' + settings.contactTransport)).toString();
                }
                else {
                    contact += (this.pub_gruu || this.uri).toString();
                }
                if (outbound) {
                    contact += ';ob';
                }
                contact += '>';
                return contact;
            }
        };
        var skeleton = {};
        // Fill the value of the configuration_skeleton
        for (parameter in settings) {
            skeleton[parameter] = settings[parameter];
        }
        Object.assign(this.configuration, skeleton);
        this.logger.log('configuration parameters after validation:');
        for (parameter in settings) {
            switch (parameter) {
                case 'uri':
                case 'registrarServer':
                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.
     * @private
     * @return {Boolean}
     */
    UA.prototype.getConfigurationCheck = function () {
        return {
            mandatory: {},
            optional: {
                uri: function (uri) {
                    var parsed;
                    if (!(/^sip:/i).test(uri)) {
                        uri = SIP.C.SIP + ':' + uri;
                    }
                    parsed = SIP.URI.parse(uri);
                    if (!parsed) {
                        return;
                    }
                    else if (!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 (SIP.Grammar.parse('"' + authorizationUser + '"', 'quoted_string') === -1) {
                        return;
                    }
                    else {
                        return authorizationUser;
                    }
                },
                displayName: function (displayName) {
                    if (SIP.Grammar.parse('"' + displayName + '"', 'displayName') === -1) {
                        return;
                    }
                    else {
                        return displayName;
                    }
                },
                dtmfType: function (dtmfType) {
                    switch (dtmfType) {
                        case SIP.C.dtmfType.RTP:
                            return SIP.C.dtmfType.RTP;
                        case SIP.C.dtmfType.INFO:
                        // Fall through
                        default:
                            return SIP.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' && SIP.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;
                    }
                },
                forceRport: function (forceRport) {
                    if (typeof forceRport === 'boolean') {
                        return forceRport;
                    }
                },
                instanceId: function (instanceId) {
                    if (typeof instanceId !== 'string') {
                        return;
                    }
                    if ((/^uuid:/i.test(instanceId))) {
                        instanceId = instanceId.substr(5);
                    }
                    if (SIP.Grammar.parse(instanceId, 'uuid') === -1) {
                        return;
                    }
                    else {
                        return instanceId;
                    }
                },
                noAnswerTimeout: function (noAnswerTimeout) {
                    var value;
                    if (SIP.Utils.isDecimal(noAnswerTimeout)) {
                        value = Number(noAnswerTimeout);
                        if (value > 0) {
                            return value;
                        }
                    }
                },
                password: function (password) {
                    return String(password);
                },
                rel100: function (rel100) {
                    if (rel100 === SIP.C.supported.REQUIRED) {
                        return SIP.C.supported.REQUIRED;
                    }
                    else if (rel100 === SIP.C.supported.SUPPORTED) {
                        return SIP.C.supported.SUPPORTED;
                    }
                    else {
                        return SIP.C.supported.UNSUPPORTED;
                    }
                },
                replaces: function (replaces) {
                    if (replaces === SIP.C.supported.REQUIRED) {
                        return SIP.C.supported.REQUIRED;
                    }
                    else if (replaces === SIP.C.supported.SUPPORTED) {
                        return SIP.C.supported.SUPPORTED;
                    }
                    else {
                        return SIP.C.supported.UNSUPPORTED;
                    }
                },
                register: function (register) {
                    if (typeof register === 'boolean') {
                        return register;
                    }
                },
                registerExpires: function (registerExpires) {
                    var value;
                    if (SIP.Utils.isDecimal(registerExpires)) {
                        value = Number(registerExpires);
                        if (value > 0) {
                            return value;
                        }
                    }
                },
                registrarServer: function (registrarServer) {
                    var parsed;
                    if (typeof registrarServer !== 'string') {
                        return;
                    }
                    if (!/^sip:/i.test(registrarServer)) {
                        registrarServer = SIP.C.SIP + ':' + registrarServer;
                    }
                    parsed = SIP.URI.parse(registrarServer);
                    if (!parsed) {
                        return;
                    }
                    else if (parsed.user) {
                        return;
                    }
                    else {
                        return parsed;
                    }
                },
                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: 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 = C;
    SIP.UA = UA;
};

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

/***/ }),
/* 28 */
/***/ (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 || Function("return this")() || (1, eval)("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;


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

"use strict";
/* WEBPACK VAR INJECTION */(function(global) {
/**
 * @fileoverview Transport
 */
/**
 * @augments SIP
 * @class Transport
 * @param {Object} options
 */
module.exports = function (SIP) {
    var Transport, C = {
        // Transport status codes
        STATUS_CONNECTING: 0,
        STATUS_OPEN: 1,
        STATUS_CLOSING: 2,
        STATUS_CLOSED: 3,
    };
    var WebSocket = (global.window || global).WebSocket;
    /**
     * Compute an amount of time in seconds to wait before sending another
     * keep-alive.
     * @returns {Number}
     */
    function computeKeepAliveTimeout(upperBound) {
        var lowerBound = upperBound * 0.8;
        return 1000 * (Math.random() * (upperBound - lowerBound) + lowerBound);
    }
    Transport = function (logger, options) {
        options = SIP.Utils.defaultOptions({}, options);
        this.logger = logger;
        this.ws = null;
        this.server = null;
        this.connectionPromise = null;
        this.connectDeferredResolve = null;
        this.connectionTimeout = null;
        this.disconnectionPromise = null;
        this.disconnectDeferredResolve = null;
        this.boundOnOpen = null;
        this.boundOnMessage = null;
        this.boundOnClose = null;
        this.boundOnError = null;
        this.reconnectionAttempts = 0;
        this.reconnectTimer = null;
        // Keep alive
        this.keepAliveInterval = null;
        this.keepAliveDebounceTimeout = null;
        this.status = C.STATUS_CONNECTING;
        this.configuration = {};
        this.loadConfig(options);
    };
    Transport.prototype = Object.create(SIP.Transport.prototype, {
        /**
        *
        * @returns {Boolean}
        */
        isConnected: { writable: true, value: function isConnected() {
                return this.status === C.STATUS_OPEN;
            } },
        /**
         * Send a message.
         * @param {SIP.OutgoingRequest|String} msg
         * @param {Object} [options]
         * @returns {Promise}
         */
        sendPromise: { writable: true, value: function sendPromise(msg, options) {
                options = options || {};
                if (!this.statusAssert(C.STATUS_OPEN, options.force)) {
                    this.onError('unable to send message - WebSocket not open');
                    return SIP.Utils.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 SIP.Utils.Promise.resolve({ msg: message });
                }
                else {
                    this.onError('unable to send message - WebSocket does not exist');
                    return SIP.Utils.Promise.reject();
                }
            } },
        /**
        * Disconnect socket.
        */
        disconnectPromise: { writable: true, value: function disconnectPromise(options) {
                if (this.disconnectionPromise) {
                    return this.disconnectionPromise;
                }
                options = options || {};
                if (!this.statusTransition(C.STATUS_CLOSING, options.force)) {
                    return SIP.Utils.Promise.reject('Failed status transition - attempted to disconnect a socket that was not open');
                }
                this.disconnectionPromise = new SIP.Utils.Promise(function (resolve, reject) {
                    this.disconnectDeferredResolve = resolve;
                    if (this.reconnectTimer) {
                        SIP.Timers.clearTimeout(this.reconnectTimer);
                        this.reconnectTimer = null;
                    }
                    if (this.ws) {
                        this.stopSendingKeepAlives();
                        this.logger.log('closing WebSocket ' + this.server.ws_uri);
                        this.ws.close(options.code, options.reason);
                    }
                    else {
                        reject('Attempted to disconnect but the websocket doesn\'t exist');
                    }
                }.bind(this));
                return this.disconnectionPromise;
            } },
        /**
        * Connect socket.
        */
        connectPromise: { writable: true, value: function connectPromise(options) {
                if (this.connectionPromise) {
                    return this.connectionPromise;
                }
                options = options || {};
                this.server = this.server || this.getNextWsServer(options.force);
                this.connectionPromise = new SIP.Utils.Promise(function (resolve, reject) {
                    if ((this.status === C.STATUS_OPEN || this.status === C.STATUS_CLOSING) && !options.force) {
                        this.logger.warn('WebSocket ' + this.server.ws_uri + ' is already connected');
                        reject('Failed status check - attempted to open a connection but already open/closing');
                        return;
                    }
                    this.connectDeferredResolve = resolve;
                    this.status = C.STATUS_CONNECTING;
                    this.logger.log('connecting to WebSocket ' + this.server.ws_uri);
                    this.disposeWs();
                    try {
                        this.ws = new WebSocket(this.server.ws_uri, 'sip');
                    }
                    catch (e) {
                        this.ws = null;
                        this.status = C.STATUS_CLOSED; // force status to closed in error case
                        this.onError('error connecting to WebSocket ' + this.server.ws_uri + ':' + e);
                        reject('Failed to create a websocket');
                        return;
                    }
                    if (!this.ws) {
                        reject('Unexpected instance websocket not set');
                        return;
                    }
                    this.connectionTimeout = SIP.Timers.setTimeout(function () {
                        this.onError('took too long to connect - exceeded time set in configuration.connectionTimeout: ' + this.configuration.connectionTimeout + 's');
                    }.bind(this), 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.onError.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);
                }.bind(this));
                return this.connectionPromise;
            } },
        // Transport Event Handlers
        /**
        * @event
        * @param {event} e
        */
        onOpen: { writable: true, value: function onOpen() {
                this.status = C.STATUS_OPEN; // quietly force status to open
                this.emit('connected');
                SIP.Timers.clearTimeout(this.connectionTimeout);
                this.logger.log('WebSocket ' + this.server.ws_uri + ' connected');
                // Clear reconnectTimer since we are not disconnected
                if (this.reconnectTimer !== null) {
                    SIP.Timers.clearTimeout(this.reconnectTimer);
                    this.reconnectTimer = null;
                }
                // Reset reconnectionAttempts
                this.reconnectionAttempts = 0;
                // Reset disconnection promise so we can disconnect from a fresh state
                this.disconnectionPromise = null;
                this.disconnectDeferredResolve = null;
                // 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
        */
        onClose: { writable: true, value: function onClose(e) {
                this.logger.log('WebSocket disconnected (code: ' + e.code + (e.reason ? '| reason: ' + e.reason : '') + ')');
                this.emit('disconnected', { code: e.code, reason: e.reason });
                if (this.status !== C.STATUS_CLOSING) {
                    this.logger.warn('WebSocket abrupt disconnection');
                    this.emit('transportError');
                }
                this.stopSendingKeepAlives();
                // Clean up connection variables so we can connect again from a fresh state
                SIP.Timers.clearTimeout(this.connectionTimeout);
                this.connectionTimeout = null;
                this.connectionPromise = null;
                this.connectDeferredResolve = null;
                // Check whether the user requested to close.
                if (this.disconnectDeferredResolve) {
                    this.disconnectDeferredResolve({ overrideEvent: true });
                    this.statusTransition(C.STATUS_CLOSED);
                    this.disconnectDeferredResolve = null;
                    return;
                }
                this.status = C.STATUS_CLOSED; // quietly force status to closed
                this.reconnect();
            } },
        /**
        * Removes event listeners and clears the instance ws
        * @private
        * @param {event} e
        */
        disposeWs: { writable: true, value: function disposeWs() {
                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.boundOnOpen = null;
                    this.boundOnMessage = null;
                    this.boundOnClose = null;
                    this.boundOnError = null;
                    this.ws = null;
                }
            } },
        /**
        * @event
        * @param {event} e
        */
        onMessage: { writable: true, value: function onMessage(e) {
                var data = e.data;
                // 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;
                }
                // WebSocket binary message.
                else if (typeof data !== 'string') {
                    try {
                        data = 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');
                    }
                }
                // WebSocket text message.
                else {
                    if (this.configuration.traceSip === true) {
                        this.logger.log('received WebSocket text message:\n\n' + data + '\n');
                    }
                }
                this.emit('message', data);
            } },
        /**
        * @event
        * @param {event} e
        */
        onError: { writable: true, value: function onError(e) {
                this.logger.warn('Transport error: ' + e);
                this.emit('transportError');
            } },
        /**
        * Reconnection attempt logic.
        * @private
        */
        reconnect: { writable: true, value: function reconnect() {
                if (this.reconnectionAttempts > 0) {
                    this.logger.log('Reconnection attempt ' + this.reconnectionAttempts + ' failed');
                }
                if (this.noAvailableServers()) {
                    this.logger.warn('no available ws servers left - going to closed state');
                    this.status = C.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.ws_uri);
                    this.logger.log('transport ' + this.server.ws_uri + ' failed | connection state set to \'error\'');
                    this.server.isError = true;
                    this.emit('transportError');
                    this.server = this.getNextWsServer();
                    this.reconnectionAttempts = 0;
                    this.reconnect();
                }
                else {
                    this.logger.log('trying to reconnect to WebSocket ' + this.server.ws_uri + ' (reconnection attempt ' + this.reconnectionAttempts + ')');
                    this.reconnectTimer = SIP.Timers.setTimeout(function () {
                        this.connect();
                        this.reconnectTimer = null;
                    }.bind(this), (this.reconnectionAttempts === 1) ? 0 : this.configuration.reconnectionTimeout * 1000);
                }
            } },
        /**
        * Resets the error state of all servers in the configuration
        */
        resetServerErrorStatus: { writable: true, value: function resetServerErrorStatus() {
                var idx, length = this.configuration.wsServers.length;
                for (idx = 0; idx < length; idx++) {
                    this.configuration.wsServers[idx].isError = false;
                }
            } },
        /**
        * Retrieve the next server to which connect.
        * @private
        * @param {Boolean} force allows bypass of server error status checking
        * @returns {Object} wsServer
        */
        getNextWsServer: { writable: true, value: function getNextWsServer(force) {
                if (this.noAvailableServers()) {
                    this.logger.warn('attempted to get next ws server but there are no available ws servers left');
                    return;
                }
                // Order servers by weight
                var idx, length, wsServer, candidates = [];
                length = this.configuration.wsServers.length;
                for (idx = 0; idx < length; idx++) {
                    wsServer = this.configuration.wsServers[idx];
                    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);
                    }
                }
                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
        * @private
        * @returns {Boolean}
        */
        noAvailableServers: { writable: true, value: function noAvailableServers() {
                var server;
                for (server in this.configuration.wsServers) {
                    if (!this.configuration.wsServers[server].isError) {
                        return false;
                    }
                }
                return true;
            } },
        //==============================
        // KeepAlive Stuff
        //==============================
        /**
         * Send a keep-alive (a double-CRLF sequence).
         * @private
         * @returns {Boolean}
         */
        sendKeepAlive: { writable: true, value: function sendKeepAlive() {
                if (this.keepAliveDebounceTimeout) {
                    // We already have an outstanding keep alive, do not send another.
                    return;
                }
                this.keepAliveDebounceTimeout = SIP.Timers.setTimeout(function () {
                    this.emit('keepAliveDebounceTimeout');
                    this.clearKeepAliveTimeout();
                }.bind(this), this.configuration.keepAliveDebounce * 1000);
                return this.send('\r\n\r\n');
            } },
        clearKeepAliveTimeout: { writable: true, value: function clearKeepAliveTimeout() {
                SIP.Timers.clearTimeout(this.keepAliveDebounceTimeout);
                this.keepAliveDebounceTimeout = null;
            } },
        /**
         * Start sending keep-alives.
         * @private
         */
        startSendingKeepAlives: { writable: true, value: function startSendingKeepAlives() {
                if (this.configuration.keepAliveInterval && !this.keepAliveInterval) {
                    this.keepAliveInterval = SIP.Timers.setInterval(function () {
                        this.sendKeepAlive();
                        this.startSendingKeepAlives();
                    }.bind(this), computeKeepAliveTimeout(this.configuration.keepAliveInterval));
                }
            } },
        /**
         * Stop sending keep-alives.
         * @private
         */
        stopSendingKeepAlives: { writable: true, value: function stopSendingKeepAlives() {
                SIP.Timers.clearInterval(this.keepAliveInterval);
                SIP.Timers.clearTimeout(this.keepAliveDebounceTimeout);
                this.keepAliveInterval = null;
                this.keepAliveDebounceTimeout = null;
            } },
        //==============================
        // Status Stuff
        //==============================
        /**
        * Checks given status against instance current status. Returns true if they match
        * @private
        * @param {Number} status
        * @param {Boolean} [force]
        * @returns {Boolean}
        */
        statusAssert: { writable: true, value: function statusAssert(status, force) {
                if (status === this.status) {
                    return true;
                }
                else {
                    if (force) {
                        this.logger.warn('Attempted to assert ' + Object.keys(C)[this.status] + ' as ' + Object.keys(C)[status] + '- continuing with option: \'force\'');
                        return true;
                    }
                    else {
                        this.logger.warn('Tried to assert ' + Object.keys(C)[status] + ' but is currently ' + Object.keys(C)[this.status]);
                        return false;
                    }
                }
            } },
        /**
        * Transitions the status. Checks for legal transition via assertion beforehand
        * @private
        * @param {Number} status
        * @param {Boolean} [force]
        * @returns {Boolean}
        */
        statusTransition: { writable: true, value: function statusTransition(status, force) {
                this.logger.log('Attempting to transition status from ' + Object.keys(C)[this.status] + ' to ' + Object.keys(C)[status]);
                if ((status === C.STATUS_OPEN && this.statusAssert(C.STATUS_CONNECTING, force)) ||
                    (status === C.STATUS_CLOSING && this.statusAssert(C.STATUS_OPEN, force)) ||
                    (status === C.STATUS_CLOSED && this.statusAssert(C.STATUS_CLOSING, force))) {
                    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.
         * @private
         * returns {Boolean}
         */
        loadConfig: { writable: true, value: function loadConfig(configuration) {
                var parameter, value, checked_value, settings = {
                    wsServers: [{
                            scheme: 'WSS',
                            sip_uri: '<sip:edge.sip.onsip.com;transport=ws;lr>',
                            weight: 0,
                            ws_uri: 'wss://edge.sip.onsip.com',
                            isError: false
                        }],
                    connectionTimeout: 5,
                    maxReconnectionAttempts: 3,
                    reconnectionTimeout: 4,
                    keepAliveInterval: 0,
                    keepAliveDebounce: 10,
                    // Logging
                    traceSip: false,
                };
                // Pre-Configuration
                function aliasUnderscored(parameter, logger) {
                    var underscored = parameter.replace(/([a-z][A-Z])/g, function (m) {
                        return m[0] + '_' + m[1].toLowerCase();
                    });
                    if (parameter === underscored) {
                        return;
                    }
                    var hasParameter = configuration.hasOwnProperty(parameter);
                    if (configuration.hasOwnProperty(underscored)) {
                        logger.warn(underscored + ' is deprecated, please use ' + parameter);
                        if (hasParameter) {
                            logger.warn(parameter + ' overriding ' + underscored);
                        }
                    }
                    configuration[parameter] = hasParameter ? configuration[parameter] : configuration[underscored];
                }
                var configCheck = this.getConfigurationCheck();
                // Check Mandatory parameters
                for (parameter in configCheck.mandatory) {
                    aliasUnderscored(parameter, this.logger);
                    if (!configuration.hasOwnProperty(parameter)) {
                        throw new SIP.Exceptions.ConfigurationError(parameter);
                    }
                    else {
                        value = configuration[parameter];
                        checked_value = configCheck.mandatory[parameter](value);
                        if (checked_value !== undefined) {
                            settings[parameter] = checked_value;
                        }
                        else {
                            throw new SIP.Exceptions.ConfigurationError(parameter, value);
                        }
                    }
                }
                // Check Optional parameters
                for (parameter in configCheck.optional) {
                    aliasUnderscored(parameter, this.logger);
                    if (configuration.hasOwnProperty(parameter)) {
                        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 (value === null || value === '' || value === undefined) {
                            continue;
                        }
                        // 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:
                        else if (typeof (value) === 'number' && isNaN(value)) {
                            continue;
                        }
                        checked_value = configCheck.optional[parameter](value);
                        if (checked_value !== undefined) {
                            settings[parameter] = checked_value;
                        }
                        else {
                            throw new SIP.Exceptions.ConfigurationError(parameter, value);
                        }
                    }
                }
                var skeleton = {};
                // Fill the value of the configuration_skeleton
                for (parameter in settings) {
                    skeleton[parameter] = {
                        value: settings[parameter],
                    };
                }
                Object.defineProperties(this.configuration, skeleton);
                this.logger.log('configuration parameters after validation:');
                for (parameter in settings) {
                    this.logger.log('· ' + parameter + ': ' + JSON.stringify(settings[parameter]));
                }
                return;
            } },
        /**
         * Configuration checker.
         * @private
         * @return {Boolean}
         */
        getConfigurationCheck: { writable: true, value: function getConfigurationCheck() {
                return {
                    mandatory: {},
                    optional: {
                        //Note: this function used to call 'this.logger.error' but calling 'this' with anything here is invalid
                        wsServers: function (wsServers) {
                            var idx, length, url;
                            /* Allow defining wsServers parameter as:
                             *  String: "host"
                             *  Array of Strings: ["host1", "host2"]
                             *  Array of Objects: [{ws_uri:"host1", weight:1}, {ws_uri:"host2", weight:0}]
                             *  Array of Objects and Strings: [{ws_uri:"host1"}, "host2"]
                             */
                            if (typeof wsServers === 'string') {
                                wsServers = [{ ws_uri: wsServers }];
                            }
                            else if (wsServers instanceof Array) {
                                length = wsServers.length;
                                for (idx = 0; idx < length; idx++) {
                                    if (typeof wsServers[idx] === 'string') {
                                        wsServers[idx] = { ws_uri: wsServers[idx] };
                                    }
                                }
                            }
                            else {
                                return;
                            }
                            if (wsServers.length === 0) {
                                return false;
                            }
                            length = wsServers.length;
                            for (idx = 0; idx < length; idx++) {
                                if (!wsServers[idx].ws_uri) {
                                    return;
                                }
                                if (wsServers[idx].weight && !Number(wsServers[idx].weight)) {
                                    return;
                                }
                                url = SIP.Grammar.parse(wsServers[idx].ws_uri, 'absoluteURI');
                                if (url === -1) {
                                    return;
                                }
                                else if (['wss', 'ws', 'udp'].indexOf(url.scheme) < 0) {
                                    return;
                                }
                                else {
                                    wsServers[idx].sip_uri = '<sip:' + url.host + (url.port ? ':' + url.port : '') + ';transport=' + url.scheme.replace(/^wss$/i, 'ws') + ';lr>';
                                    if (!wsServers[idx].weight) {
                                        wsServers[idx].weight = 0;
                                    }
                                    wsServers[idx].isError = false;
                                    wsServers[idx].scheme = url.scheme.toUpperCase();
                                }
                            }
                            return wsServers;
                        },
                        keepAliveInterval: function (keepAliveInterval) {
                            var value;
                            if (SIP.Utils.isDecimal(keepAliveInterval)) {
                                value = Number(keepAliveInterval);
                                if (value > 0) {
                                    return value;
                                }
                            }
                        },
                        keepAliveDebounce: function (keepAliveDebounce) {
                            var value;
                            if (SIP.Utils.isDecimal(keepAliveDebounce)) {
                                value = Number(keepAliveDebounce);
                                if (value > 0) {
                                    return value;
                                }
                            }
                        },
                        traceSip: function (traceSip) {
                            if (typeof traceSip === 'boolean') {
                                return traceSip;
                            }
                        },
                        connectionTimeout: function (connectionTimeout) {
                            var value;
                            if (SIP.Utils.isDecimal(connectionTimeout)) {
                                value = Number(connectionTimeout);
                                if (value > 0) {
                                    return value;
                                }
                            }
                        },
                        maxReconnectionAttempts: function (maxReconnectionAttempts) {
                            var value;
                            if (SIP.Utils.isDecimal(maxReconnectionAttempts)) {
                                value = Number(maxReconnectionAttempts);
                                if (value >= 0) {
                                    return value;
                                }
                            }
                        },
                        reconnectionTimeout: function (reconnectionTimeout) {
                            var value;
                            if (SIP.Utils.isDecimal(reconnectionTimeout)) {
                                value = Number(reconnectionTimeout);
                                if (value > 0) {
                                    return value;
                                }
                            }
                        }
                    }
                };
            } }
    });
    Transport.C = C;
    SIP.Web.Transport = Transport;
    return Transport;
};

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

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

"use strict";
/* WEBPACK VAR INJECTION */(function(global) {
/**
 * @fileoverview SessionDescriptionHandler
 */
/* SessionDescriptionHandler
 * @class PeerConnection helper Class.
 * @param {SIP.Session} session
 * @param {Object} [options]
 */
module.exports = function (SIP) {
    // Constructor
    var SessionDescriptionHandler = function (logger, observer, options) {
        // TODO: Validate the options
        this.options = options || {};
        this.logger = logger;
        this.observer = observer;
        this.dtmfSender = null;
        this.shouldAcquireMedia = true;
        this.CONTENT_TYPE = 'application/sdp';
        this.C = {};
        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.iceGatheringDeferred = null;
        this.iceGatheringTimeout = false;
        this.iceGatheringTimer = null;
        this.initPeerConnection(this.options.peerConnectionOptions);
        this.constraints = this.checkAndDefaultConstraints(this.options.constraints);
    };
    /**
     * @param {SIP.Session} session
     * @param {Object} [options]
     */
    SessionDescriptionHandler.defaultFactory = function defaultFactory(session, options) {
        var logger = session.ua.getLogger('sip.invitecontext.sessionDescriptionHandler', session.id);
        var SessionDescriptionHandlerObserver = __webpack_require__(31);
        var observer = new SessionDescriptionHandlerObserver(session, options);
        return new SessionDescriptionHandler(logger, observer, options);
    };
    SessionDescriptionHandler.prototype = Object.create(SIP.SessionDescriptionHandler.prototype, {
        // Functions the sesssion can use
        /**
         * Destructor
         */
        close: { writable: true, value: 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
         */
        getDescription: { writable: true, value: function (options, modifiers) {
                options = options || {};
                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;
                }
                modifiers = modifiers || [];
                if (!Array.isArray(modifiers)) {
                    modifiers = [modifiers];
                }
                modifiers = modifiers.concat(this.modifiers);
                return SIP.Utils.Promise.resolve()
                    .then(function () {
                    if (this.shouldAcquireMedia) {
                        return this.acquire(this.constraints).then(function () {
                            this.shouldAcquireMedia = false;
                        }.bind(this));
                    }
                }.bind(this))
                    .then(function () {
                    return this.createOfferOrAnswer(options.RTCOfferOptions, modifiers);
                }.bind(this))
                    .then(function (description) {
                    this.emit('getDescription', description);
                    return {
                        body: description.sdp,
                        contentType: this.CONTENT_TYPE
                    };
                }.bind(this));
            } },
        /**
         * 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}
         */
        hasDescription: { writable: true, value: function hasDescription(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
         */
        holdModifier: { writable: true, value: function holdModifier(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 SIP.Utils.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
         */
        setDescription: { writable: true, value: function setDescription(sessionDescription, options, modifiers) {
                var _this = this;
                var self = this;
                options = options || {};
                if (options.peerConnectionOptions) {
                    this.initPeerConnection(options.peerConnectionOptions);
                }
                modifiers = modifiers || [];
                if (!Array.isArray(modifiers)) {
                    modifiers = [modifiers];
                }
                modifiers = modifiers.concat(this.modifiers);
                var description = {
                    type: this.hasOffer('local') ? 'answer' : 'offer',
                    sdp: sessionDescription
                };
                return SIP.Utils.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;
                        }.bind(this));
                    }
                }.bind(this))
                    .then(function () {
                    return SIP.Utils.reducePromises(modifiers, description);
                })
                    .catch(function (e) {
                    if (e instanceof SIP.Exceptions.SessionDescriptionHandlerError) {
                        throw e;
                    }
                    var error = new SIP.Exceptions.SessionDescriptionHandlerError("setDescription", e, "The modifiers did not resolve successfully");
                    _this.logger.error(error.message);
                    self.emit('peerConnection-setRemoteDescriptionFailed', error);
                    throw error;
                })
                    .then(function (modifiedDescription) {
                    self.emit('setDescription', modifiedDescription);
                    return self.peerConnection.setRemoteDescription(modifiedDescription);
                })
                    .catch(function (e) {
                    if (e instanceof SIP.Exceptions.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, [SIP.Web.Modifiers.stripVideo].concat(modifiers));
                    }
                    var error = new SIP.Exceptions.SessionDescriptionHandlerError("setDescription", e);
                    _this.logger.error(error.error);
                    _this.emit('peerConnection-setRemoteDescriptionFailed', error);
                    throw error;
                })
                    .then(function setRemoteDescriptionSuccess() {
                    if (self.peerConnection.getReceivers) {
                        self.emit('setRemoteDescription', self.peerConnection.getReceivers());
                    }
                    else {
                        self.emit('setRemoteDescription', self.peerConnection.getRemoteStreams());
                    }
                    self.emit('confirmed', self);
                });
            } },
        /**
         * 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
         */
        sendDtmf: { writable: true, value: function sendDtmf(tones, 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;
            } },
        getDirection: { writable: true, value: function getDirection() {
                return this.direction;
            } },
        // Internal functions
        createOfferOrAnswer: { writable: true, value: function createOfferOrAnswer(RTCOfferOptions, modifiers) {
                var _this = this;
                var self = this;
                var methodName;
                var pc = this.peerConnection;
                RTCOfferOptions = RTCOfferOptions || {};
                methodName = self.hasOffer('remote') ? 'createAnswer' : 'createOffer';
                return pc[methodName](RTCOfferOptions)
                    .catch(function (e) {
                    if (e instanceof SIP.Exceptions.SessionDescriptionHandlerError) {
                        throw e;
                    }
                    var error = new SIP.Exceptions.SessionDescriptionHandlerError("createOfferOrAnswer", e, 'peerConnection-' + methodName + 'Failed');
                    _this.emit('peerConnection-' + methodName + 'Failed', error);
                    throw error;
                })
                    .then(function (sdp) {
                    return SIP.Utils.reducePromises(modifiers, self.createRTCSessionDescriptionInit(sdp));
                })
                    .then(function (sdp) {
                    self.resetIceGatheringComplete();
                    return pc.setLocalDescription(sdp);
                })
                    .catch(function (e) {
                    if (e instanceof SIP.Exceptions.SessionDescriptionHandlerError) {
                        throw e;
                    }
                    var error = new SIP.Exceptions.SessionDescriptionHandlerError("createOfferOrAnswer", e, 'peerConnection-SetLocalDescriptionFailed');
                    _this.emit('peerConnection-SetLocalDescriptionFailed', error);
                    throw error;
                })
                    .then(function onSetLocalDescriptionSuccess() {
                    return self.waitForIceGatheringComplete();
                })
                    .then(function readySuccess() {
                    var localDescription = self.createRTCSessionDescriptionInit(self.peerConnection.localDescription);
                    return SIP.Utils.reducePromises(modifiers, localDescription);
                })
                    .then(function (localDescription) {
                    self.setDirection(localDescription.sdp);
                    return localDescription;
                })
                    .catch(function (e) {
                    if (e instanceof SIP.Exceptions.SessionDescriptionHandlerError) {
                        throw e;
                    }
                    var error = new SIP.Exceptions.SessionDescriptionHandlerError("createOfferOrAnswer", e);
                    _this.logger.error(error);
                    throw error;
                });
            } },
        // Creates an RTCSessionDescriptionInit from an RTCSessionDescription
        createRTCSessionDescriptionInit: { writable: true, value: function createRTCSessionDescriptionInit(RTCSessionDescription) {
                return {
                    type: RTCSessionDescription.type,
                    sdp: RTCSessionDescription.sdp
                };
            } },
        addDefaultIceCheckingTimeout: { writable: true, value: function addDefaultIceCheckingTimeout(peerConnectionOptions) {
                if (peerConnectionOptions.iceCheckingTimeout === undefined) {
                    peerConnectionOptions.iceCheckingTimeout = 5000;
                }
                return peerConnectionOptions;
            } },
        addDefaultIceServers: { writable: true, value: function addDefaultIceServers(rtcConfiguration) {
                if (!rtcConfiguration.iceServers) {
                    rtcConfiguration.iceServers = [{ urls: 'stun:stun.l.google.com:19302' }];
                }
                return rtcConfiguration;
            } },
        checkAndDefaultConstraints: { writable: true, value: function checkAndDefaultConstraints(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;
            } },
        hasBrowserTrackSupport: { writable: true, value: function hasBrowserTrackSupport() {
                return Boolean(this.peerConnection.addTrack);
            } },
        hasBrowserGetSenderSupport: { writable: true, value: function hasBrowserGetSenderSupport() {
                return Boolean(this.peerConnection.getSenders);
            } },
        initPeerConnection: { writable: true, value: function initPeerConnection(options) {
                var self = this;
                options = 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) {
                        self.logger.log('track added');
                        self.observer.trackAdded();
                        self.emit('addTrack', e);
                    });
                }
                else {
                    this.logger.warn('Using onaddstream which is deprecated');
                    this.peerConnection.onaddstream = function (e) {
                        self.logger.log('stream added');
                        self.emit('addStream', e);
                    };
                }
                this.peerConnection.onicecandidate = function (e) {
                    self.emit('iceCandidate', e);
                    if (e.candidate) {
                        self.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
                        self.logger.log('ICE candidate gathering complete');
                        self.triggerIceGatheringComplete();
                    }
                };
                this.peerConnection.onicegatheringstatechange = function () {
                    self.logger.log('RTCIceGatheringState changed: ' + this.iceGatheringState);
                    switch (this.iceGatheringState) {
                        case 'gathering':
                            self.emit('iceGathering', this);
                            if (!self.iceGatheringTimer && options.iceCheckingTimeout) {
                                self.iceGatheringTimeout = false;
                                self.iceGatheringTimer = SIP.Timers.setTimeout(function () {
                                    self.logger.log('RTCIceChecking Timeout Triggered after ' + options.iceCheckingTimeout + ' milliseconds');
                                    self.iceGatheringTimeout = true;
                                    self.triggerIceGatheringComplete();
                                }, options.iceCheckingTimeout);
                            }
                            break;
                        case 'complete':
                            self.triggerIceGatheringComplete();
                            break;
                    }
                };
                this.peerConnection.oniceconnectionstatechange = function () {
                    var stateEvent;
                    switch (this.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:
                            self.logger.warn('Unknown iceConnection state:', this.iceConnectionState);
                            return;
                    }
                    self.emit(stateEvent, this);
                };
            } },
        acquire: { writable: true, value: function acquire(constraints) {
                var _this = this;
                // Default audio & video to true
                constraints = this.checkAndDefaultConstraints(constraints);
                return new SIP.Utils.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 (constraints.audio || constraints.video) {
                        this.WebRTC.getUserMedia(constraints)
                            .then(function (streams) {
                            this.observer.trackAdded();
                            this.emit('userMedia', streams);
                            resolve(streams);
                        }.bind(this)).catch(function (e) {
                            this.emit('userMediaFailed', e);
                            reject(e);
                        }.bind(this));
                    }
                    else {
                        // Local streams were explicitly excluded.
                        resolve([]);
                    }
                }.bind(this))
                    .catch(function (e) {
                    // TODO: This propogates downwards
                    if (e instanceof SIP.Exceptions.SessionDescriptionHandlerError) {
                        throw e;
                    }
                    var error = new SIP.Exceptions.SessionDescriptionHandlerError("acquire", e, "unable to acquire streams");
                    _this.logger.error(error.message);
                    _this.logger.error(error.error);
                    throw error;
                })
                    .then(function acquireSucceeded(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);
                            }, this);
                        }
                        return streams;
                    }
                    catch (e) {
                        return SIP.Utils.Promise.reject(e);
                    }
                }.bind(this))
                    .catch(function (e) {
                    if (e instanceof SIP.Exceptions.SessionDescriptionHandlerError) {
                        throw e;
                    }
                    var error = new SIP.Exceptions.SessionDescriptionHandlerError("acquire", e, "error removing streams");
                    _this.logger.error(error.message);
                    _this.logger.error(error.error);
                    throw error;
                })
                    .then(function addStreams(streams) {
                    try {
                        streams = [].concat(streams);
                        streams.forEach(function (stream) {
                            if (this.peerConnection.addTrack) {
                                stream.getTracks().forEach(function (track) {
                                    this.peerConnection.addTrack(track, stream);
                                }, this);
                            }
                            else {
                                // Chrome 59 does not support addTrack
                                this.peerConnection.addStream(stream);
                            }
                        }, this);
                    }
                    catch (e) {
                        return SIP.Utils.Promise.reject(e);
                    }
                    return SIP.Utils.Promise.resolve();
                }.bind(this))
                    .catch(function (e) {
                    if (e instanceof SIP.Exceptions.SessionDescriptionHandlerError) {
                        throw e;
                    }
                    var error = new SIP.Exceptions.SessionDescriptionHandlerError("acquire", e, "error adding stream");
                    _this.logger.error(error.message);
                    _this.logger.error(error.error);
                    throw error;
                });
            } },
        hasOffer: { writable: true, value: function hasOffer(where) {
                var offerState = 'have-' + where + '-offer';
                return this.peerConnection.signalingState === offerState;
            } },
        // ICE gathering state handling
        isIceGatheringComplete: { writable: true, value: function isIceGatheringComplete() {
                return this.peerConnection.iceGatheringState === 'complete' || this.iceGatheringTimeout;
            } },
        resetIceGatheringComplete: { writable: true, value: function resetIceGatheringComplete() {
                this.iceGatheringTimeout = false;
                if (this.iceGatheringTimer) {
                    SIP.Timers.clearTimeout(this.iceGatheringTimer);
                    this.iceGatheringTimer = null;
                }
                if (this.iceGatheringDeferred) {
                    this.iceGatheringDeferred.reject();
                    this.iceGatheringDeferred = null;
                }
            } },
        setDirection: { writable: true, value: function setDirection(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();
            } },
        triggerIceGatheringComplete: { writable: true, value: function triggerIceGatheringComplete() {
                if (this.isIceGatheringComplete()) {
                    this.emit('iceGatheringComplete', this);
                    if (this.iceGatheringTimer) {
                        SIP.Timers.clearTimeout(this.iceGatheringTimer);
                        this.iceGatheringTimer = null;
                    }
                    if (this.iceGatheringDeferred) {
                        this.iceGatheringDeferred.resolve();
                        this.iceGatheringDeferred = null;
                    }
                }
            } },
        waitForIceGatheringComplete: { writable: true, value: function waitForIceGatheringComplete() {
                if (this.isIceGatheringComplete()) {
                    return SIP.Utils.Promise.resolve();
                }
                else if (!this.isIceGatheringDeferred) {
                    this.iceGatheringDeferred = SIP.Utils.defer();
                }
                return this.iceGatheringDeferred.promise;
            } }
    });
    return SessionDescriptionHandler;
};

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

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

"use strict";

/**
 * @fileoverview SessionDescriptionHandlerObserver
 */
/* SessionDescriptionHandlerObserver
 * @class SessionDescriptionHandler Observer Class.
 * @param {SIP.Session} session
 * @param {Object} [options]
 */
// Constructor
var SessionDescriptionHandlerObserver = function (session, options) {
    this.session = session || {};
    this.options = options || {};
};
SessionDescriptionHandlerObserver.prototype = {
    trackAdded: function () {
        this.session.emit('trackAdded');
    },
    directionChanged: function () {
        this.session.emit('directionChanged');
    },
};
module.exports = SessionDescriptionHandlerObserver;


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

"use strict";

/**
 * @fileoverview Incoming SIP Message Sanity Check
 */
/**
 * SIP message sanity check.
 * @augments SIP
 * @function
 * @param {SIP.IncomingMessage} message
 * @param {SIP.UA} ua
 * @param {SIP.Transport} transport
 * @returns {Boolean}
 */
module.exports = function (SIP) {
    var sanityCheck, requests = [], responses = [], all = [];
    // Reply
    function reply(status_code, message, transport) {
        var to, response = SIP.Utils.buildStatusLine(status_code), vias = message.getHeaders('via'), length = vias.length, idx = 0;
        for (idx; idx < length; idx++) {
            response += "Via: " + vias[idx] + "\r\n";
        }
        to = message.getHeader('To');
        if (!message.to_tag) {
            to += ';tag=' + SIP.Utils.newTag();
        }
        response += "To: " + to + "\r\n";
        response += "From: " + message.getHeader('From') + "\r\n";
        response += "Call-ID: " + message.call_id + "\r\n";
        response += "CSeq: " + message.cseq + " " + message.method + "\r\n";
        response += "\r\n";
        transport.send(response);
    }
    /*
     * 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;
        }
    }
    function rfc3261_16_3_4(message, ua, transport) {
        if (!message.to_tag) {
            if (message.call_id.substr(0, 5) === ua.configuration.sipjsId) {
                reply(482, message, transport);
                return false;
            }
        }
    }
    function rfc3261_18_3_request(message, ua, transport) {
        var len = SIP.Utils.str_utf8_length(message.body), contentLength = message.getHeader('content-length');
        if (len < contentLength) {
            reply(400, message, transport);
            return false;
        }
    }
    function rfc3261_8_2_2_2(message, ua, transport) {
        var tr, idx, fromTag = message.from_tag, call_id = message.call_id, cseq = message.cseq;
        if (!message.to_tag) {
            if (message.method === SIP.C.INVITE) {
                tr = ua.transactions.ist[message.via_branch];
                if (tr) {
                    return;
                }
                else {
                    for (idx in ua.transactions.ist) {
                        tr = ua.transactions.ist[idx];
                        if (tr.request.from_tag === fromTag && tr.request.call_id === call_id && tr.request.cseq === cseq) {
                            reply(482, message, transport);
                            return false;
                        }
                    }
                }
            }
            else {
                tr = ua.transactions.nist[message.via_branch];
                if (tr) {
                    return;
                }
                else {
                    for (idx in ua.transactions.nist) {
                        tr = ua.transactions.nist[idx];
                        if (tr.request.from_tag === fromTag && tr.request.call_id === call_id && tr.request.cseq === cseq) {
                            reply(482, message, transport);
                            return false;
                        }
                    }
                }
            }
        }
    }
    // 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;
        }
    }
    function rfc3261_18_1_2(message, ua) {
        var viaHost = ua.configuration.viaHost;
        if (message.via.host !== 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;
        }
    }
    function rfc3261_18_3_response(message, ua) {
        var len = SIP.Utils.str_utf8_length(message.body), contentLength = message.getHeader('content-length');
        if (len < contentLength) {
            ua.getLogger('sip.sanitycheck').warn('Message body length is lower than the value in Content-Length header field. Dropping the response');
            return false;
        }
    }
    // Sanity Check functions for requests and responses
    function minimumHeaders(message, ua) {
        var mandatoryHeaders = ['from', 'to', 'call_id', 'cseq', 'via'], idx = mandatoryHeaders.length;
        while (idx--) {
            if (!message.hasHeader(mandatoryHeaders[idx])) {
                ua.getLogger('sip.sanitycheck').warn('Missing mandatory header field : ' + mandatoryHeaders[idx] + '. Dropping the response');
                return false;
            }
        }
    }
    requests.push(rfc3261_8_2_2_1);
    requests.push(rfc3261_16_3_4);
    requests.push(rfc3261_18_3_request);
    requests.push(rfc3261_8_2_2_2);
    responses.push(rfc3261_8_1_3_3);
    responses.push(rfc3261_18_1_2);
    responses.push(rfc3261_18_3_response);
    all.push(minimumHeaders);
    sanityCheck = function (message, ua, transport) {
        var len, pass;
        len = all.length;
        while (len--) {
            pass = all[len](message, ua, transport);
            if (pass === false) {
                return false;
            }
        }
        if (message instanceof SIP.IncomingRequest) {
            len = requests.length;
            while (len--) {
                pass = requests[len](message, ua, transport);
                if (pass === false) {
                    return false;
                }
            }
        }
        else if (message instanceof SIP.IncomingResponse) {
            len = responses.length;
            while (len--) {
                pass = responses[len](message, ua, transport);
                if (pass === false) {
                    return false;
                }
            }
        }
        //Everything is OK
        return true;
    };
    SIP.sanityCheck = sanityCheck;
};


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

"use strict";

var md5 = __webpack_require__(34);
/**
 * @fileoverview SIP Digest Authentication
 */
/**
 * SIP Digest Authentication.
 * @augments SIP.
 * @function Digest Authentication
 * @param {SIP.UA} ua
 */
module.exports = function (Utils) {
    var DigestAuthentication;
    DigestAuthentication = function (ua) {
        this.logger = ua.getLogger('sipjs.digestauthentication');
        this.username = ua.configuration.authorizationUser;
        this.password = ua.configuration.password;
        this.cnonce = null;
        this.nc = 0;
        this.ncHex = '00000000';
        this.response = null;
    };
    /**
    * 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) {
        // 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 = null;
        }
        // Fill other attributes.
        this.method = request.method;
        this.uri = request.ruri;
        this.cnonce = 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();
        return true;
    };
    /**
    * Generate Digest 'response' value.
    * @private
    */
    DigestAuthentication.prototype.calculateResponse = function () {
        var ha1, ha2;
        // HA1 = MD5(A1) = MD5(username:realm:password)
        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(this.body ? this.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 === null) {
            // 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 the Proxy-Authorization or WWW-Authorization header value.
    */
    DigestAuthentication.prototype.toString = function () {
        var auth_params = [];
        if (!this.response) {
            throw new Error('response field does not exist, cannot generate Authorization header');
        }
        auth_params.push('algorithm=' + this.algorithm);
        auth_params.push('username="' + this.username + '"');
        auth_params.push('realm="' + this.realm + '"');
        auth_params.push('nonce="' + this.nonce + '"');
        auth_params.push('uri="' + this.uri + '"');
        auth_params.push('response="' + this.response + '"');
        if (this.opaque) {
            auth_params.push('opaque="' + this.opaque + '"');
        }
        if (this.qop) {
            auth_params.push('qop=' + this.qop);
            auth_params.push('cnonce="' + this.cnonce + '"');
            auth_params.push('nc=' + this.ncHex);
        }
        return 'Digest ' + auth_params.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;
    };
    return DigestAuthentication;
};


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

;(function (root, factory) {
	if (true) {
		// CommonJS
		module.exports = exports = factory(__webpack_require__(35));
	}
	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;

}));

/***/ }),
/* 35 */
/***/ (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;

}));

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

"use strict";

var Grammar = __webpack_require__(37);
module.exports = function (SIP) {
    return {
        parse: function parseCustom(input, startRule) {
            var options = { startRule: startRule, SIP: SIP };
            try {
                Grammar.parse(input, options);
            }
            catch (e) {
                options.data = -1;
            }
            return options.data;
        }
    };
};


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

"use strict";
/*
 * Generated by PEG.js 0.10.0.
 *
 * http://pegjs.org/
 */



function peg$subclass(child, parent) {
  function ctor() { this.constructor = child; }
  ctor.prototype = parent.prototype;
  child.prototype = new ctor();
}

function peg$SyntaxError(message, expected, found, location) {
  this.message  = message;
  this.expected = expected;
  this.found    = found;
  this.location = location;
  this.name     = "SyntaxError";

  if (typeof Error.captureStackTrace === "function") {
    Error.captureStackTrace(this, peg$SyntaxError);
  }
}

peg$subclass(peg$SyntaxError, Error);

peg$SyntaxError.buildMessage = function(expected, found) {
  var DESCRIBE_EXPECTATION_FNS = {
        literal: function(expectation) {
          return "\"" + literalEscape(expectation.text) + "\"";
        },

        "class": function(expectation) {
          var escapedParts = "",
              i;

          for (i = 0; i < expectation.parts.length; i++) {
            escapedParts += expectation.parts[i] instanceof Array
              ? classEscape(expectation.parts[i][0]) + "-" + classEscape(expectation.parts[i][1])
              : classEscape(expectation.parts[i]);
          }

          return "[" + (expectation.inverted ? "^" : "") + escapedParts + "]";
        },

        any: function(expectation) {
          return "any character";
        },

        end: function(expectation) {
          return "end of input";
        },

        other: function(expectation) {
          return expectation.description;
        }
      };

  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) {
    return DESCRIBE_EXPECTATION_FNS[expectation.type](expectation);
  }

  function describeExpected(expected) {
    var descriptions = new Array(expected.length),
        i, j;

    for (i = 0; i < expected.length; i++) {
      descriptions[i] = describeExpectation(expected[i]);
    }

    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(found) {
    return found ? "\"" + literalEscape(found) + "\"" : "end of input";
  }

  return "Expected " + describeExpected(expected) + " but " + describeFound(found) + " found.";
};

function peg$parse(input, options) {
  options = options !== void 0 ? options : {};

  var peg$FAILED = {},

      peg$startRuleIndices = { Contact: 119, Name_Addr_Header: 156, Record_Route: 176, Request_Response: 81, SIP_URI: 45, Subscription_State: 186, Supported: 191, Require: 182, Via: 194, absoluteURI: 84, Call_ID: 118, Content_Disposition: 130, Content_Length: 135, Content_Type: 136, CSeq: 146, displayName: 122, Event: 149, From: 151, host: 52, Max_Forwards: 154, Min_SE: 213, Proxy_Authenticate: 157, quoted_string: 40, Refer_To: 178, Replaces: 179, Session_Expires: 210, stun_URI: 217, To: 192, turn_URI: 223, uuid: 226, WWW_Authenticate: 209, challenge: 158, sipfrag: 230, Referred_By: 231 },
      peg$startRuleIndex   = 119,

      peg$consts = [
        "\r\n",
        peg$literalExpectation("\r\n", false),
        /^[0-9]/,
        peg$classExpectation([["0", "9"]], false, false),
        /^[a-zA-Z]/,
        peg$classExpectation([["a", "z"], ["A", "Z"]], false, false),
        /^[0-9a-fA-F]/,
        peg$classExpectation([["0", "9"], ["a", "f"], ["A", "F"]], false, false),
        /^[\0-\xFF]/,
        peg$classExpectation([["\0", "\xFF"]], false, false),
        /^["]/,
        peg$classExpectation(["\""], false, false),
        " ",
        peg$literalExpectation(" ", false),
        "\t",
        peg$literalExpectation("\t", false),
        /^[a-zA-Z0-9]/,
        peg$classExpectation([["a", "z"], ["A", "Z"], ["0", "9"]], false, false),
        ";",
        peg$literalExpectation(";", false),
        "/",
        peg$literalExpectation("/", false),
        "?",
        peg$literalExpectation("?", false),
        ":",
        peg$literalExpectation(":", false),
        "@",
        peg$literalExpectation("@", false),
        "&",
        peg$literalExpectation("&", false),
        "=",
        peg$literalExpectation("=", false),
        "+",
        peg$literalExpectation("+", false),
        "$",
        peg$literalExpectation("$", false),
        ",",
        peg$literalExpectation(",", false),
        "-",
        peg$literalExpectation("-", false),
        "_",
        peg$literalExpectation("_", false),
        ".",
        peg$literalExpectation(".", false),
        "!",
        peg$literalExpectation("!", false),
        "~",
        peg$literalExpectation("~", false),
        "*",
        peg$literalExpectation("*", false),
        "'",
        peg$literalExpectation("'", false),
        "(",
        peg$literalExpectation("(", false),
        ")",
        peg$literalExpectation(")", false),
        "%",
        peg$literalExpectation("%", false),
        function() {return " "; },
        function() {return ':'; },
        /^[!-~]/,
        peg$classExpectation([["!", "~"]], false, false),
        /^[\x80-\uFFFF]/,
        peg$classExpectation([["\x80", "\uFFFF"]], false, false),
        /^[\x80-\xBF]/,
        peg$classExpectation([["\x80", "\xBF"]], false, false),
        /^[a-f]/,
        peg$classExpectation([["a", "f"]], false, false),
        "`",
        peg$literalExpectation("`", false),
        "<",
        peg$literalExpectation("<", false),
        ">",
        peg$literalExpectation(">", false),
        "\\",
        peg$literalExpectation("\\", false),
        "[",
        peg$literalExpectation("[", false),
        "]",
        peg$literalExpectation("]", false),
        "{",
        peg$literalExpectation("{", false),
        "}",
        peg$literalExpectation("}", false),
        function() {return "*"; },
        function() {return "/"; },
        function() {return "="; },
        function() {return "("; },
        function() {return ")"; },
        function() {return ">"; },
        function() {return "<"; },
        function() {return ","; },
        function() {return ";"; },
        function() {return ":"; },
        function() {return "\""; },
        /^[!-']/,
        peg$classExpectation([["!", "'"]], false, false),
        /^[*-[]/,
        peg$classExpectation([["*", "["]], false, false),
        /^[\]-~]/,
        peg$classExpectation([["]", "~"]], false, false),
        function(contents) {
                                return contents; },
        /^[#-[]/,
        peg$classExpectation([["#", "["]], false, false),
        /^[\0-\t]/,
        peg$classExpectation([["\0", "\t"]], false, false),
        /^[\x0B-\f]/,
        peg$classExpectation([["\x0B", "\f"]], false, false),
        /^[\x0E-\x7F]/,
        peg$classExpectation([["\x0E", "\x7F"]], false, false),
        function() {
                                options.data.uri = new options.SIP.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;
                              },
        function() {
                                options.data.uri = new options.SIP.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;}
                              },
        "sips",
        peg$literalExpectation("sips", true),
        "sip",
        peg$literalExpectation("sip", true),
        function(uri_scheme) {
                            options.data.scheme = uri_scheme; },
        function() {
                            options.data.user = decodeURIComponent(text().slice(0, -1));},
        function() {
                            options.data.password = text(); },
        function() {
                            options.data.host = text();
                            return options.data.host; },
        function() {
                          options.data.host_type = 'domain';
                          return text(); },
        /^[a-zA-Z0-9_\-]/,
        peg$classExpectation([["a", "z"], ["A", "Z"], ["0", "9"], "_", "-"], false, false),
        /^[a-zA-Z0-9\-]/,
        peg$classExpectation([["a", "z"], ["A", "Z"], ["0", "9"], "-"], false, false),
        function() {
                            options.data.host_type = 'IPv6';
                            return text(); },
        "::",
        peg$literalExpectation("::", false),
        function() {
                          options.data.host_type = 'IPv6';
                          return text(); },
        function() {
                            options.data.host_type = 'IPv4';
                            return text(); },
        "25",
        peg$literalExpectation("25", false),
        /^[0-5]/,
        peg$classExpectation([["0", "5"]], false, false),
        "2",
        peg$literalExpectation("2", false),
        /^[0-4]/,
        peg$classExpectation([["0", "4"]], false, false),
        "1",
        peg$literalExpectation("1", false),
        /^[1-9]/,
        peg$classExpectation([["1", "9"]], false, false),
        function(port) {
                            port = parseInt(port.join(''));
                            options.data.port = port;
                            return port; },
        "transport=",
        peg$literalExpectation("transport=", true),
        "udp",
        peg$literalExpectation("udp", true),
        "tcp",
        peg$literalExpectation("tcp", true),
        "sctp",
        peg$literalExpectation("sctp", true),
        "tls",
        peg$literalExpectation("tls", true),
        function(transport) {
                              if(!options.data.uri_params) options.data.uri_params={};
                              options.data.uri_params['transport'] = transport.toLowerCase(); },
        "user=",
        peg$literalExpectation("user=", true),
        "phone",
        peg$literalExpectation("phone", true),
        "ip",
        peg$literalExpectation("ip", true),
        function(user) {
                              if(!options.data.uri_params) options.data.uri_params={};
                              options.data.uri_params['user'] = user.toLowerCase(); },
        "method=",
        peg$literalExpectation("method=", true),
        function(method) {
                              if(!options.data.uri_params) options.data.uri_params={};
                              options.data.uri_params['method'] = method; },
        "ttl=",
        peg$literalExpectation("ttl=", true),
        function(ttl) {
                              if(!options.data.params) options.data.params={};
                              options.data.params['ttl'] = ttl; },
        "maddr=",
        peg$literalExpectation("maddr=", true),
        function(maddr) {
                              if(!options.data.uri_params) options.data.uri_params={};
                              options.data.uri_params['maddr'] = maddr; },
        "lr",
        peg$literalExpectation("lr", true),
        function() {
                              if(!options.data.uri_params) options.data.uri_params={};
                              options.data.uri_params['lr'] = undefined; },
        function(param, value) {
                              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;},
        function(hname, hvalue) {
                              hname = hname.join('').toLowerCase();
                              hvalue = hvalue.join('');
                              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);
                              }},
        function() {
                              // lots of tests fail if this isn't guarded...
                              if (options.startRule === 'Refer_To') {
                                options.data.uri = new options.SIP.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;
                              }
                            },
        "//",
        peg$literalExpectation("//", false),
        function() {
                            options.data.scheme= text(); },
        peg$literalExpectation("SIP", true),
        function() {
                            options.data.sip_version = text(); },
        "INVITE",
        peg$literalExpectation("INVITE", false),
        "ACK",
        peg$literalExpectation("ACK", false),
        "VXACH",
        peg$literalExpectation("VXACH", false),
        "OPTIONS",
        peg$literalExpectation("OPTIONS", false),
        "BYE",
        peg$literalExpectation("BYE", false),
        "CANCEL",
        peg$literalExpectation("CANCEL", false),
        "REGISTER",
        peg$literalExpectation("REGISTER", false),
        "SUBSCRIBE",
        peg$literalExpectation("SUBSCRIBE", false),
        "NOTIFY",
        peg$literalExpectation("NOTIFY", false),
        "REFER",
        peg$literalExpectation("REFER", false),
        "PUBLISH",
        peg$literalExpectation("PUBLISH", false),
        function() {

                            options.data.method = text();
                            return options.data.method; },
        function(status_code) {
                          options.data.status_code = parseInt(status_code.join('')); },
        function() {
                          options.data.reason_phrase = text(); },
        function() {
                      options.data = text(); },
        function() {
                                var idx, length;
                                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;
                                }},
        function() {
                                var header;
                                if(!options.data.multi_header) options.data.multi_header = [];
                                try {
                                  header = new options.SIP.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
                                                        });},
        function(displayName) {
                                displayName = text().trim();
                                if (displayName[0] === '\"') {
                                  displayName = displayName.substring(1, displayName.length-1);
                                }
                                options.data.displayName = displayName; },
        "q",
        peg$literalExpectation("q", true),
        function(q) {
                                if(!options.data.params) options.data.params = {};
                                options.data.params['q'] = q; },
        "expires",
        peg$literalExpectation("expires", true),
        function(expires) {
                                if(!options.data.params) options.data.params = {};
                                options.data.params['expires'] = expires; },
        function(delta_seconds) {
                                return parseInt(delta_seconds.join('')); },
        "0",
        peg$literalExpectation("0", false),
        function() {
                                return parseFloat(text()); },
        function(param, value) {
                                if(!options.data.params) options.data.params = {};
                                if (value === null){
                                  value = undefined;
                                }
                                else {
                                  value = value[1];
                                }
                                options.data.params[param.toLowerCase()] = value;},
        "render",
        peg$literalExpectation("render", true),
        "session",
        peg$literalExpectation("session", true),
        "icon",
        peg$literalExpectation("icon", true),
        "alert",
        peg$literalExpectation("alert", true),
        function() {
                                    if (options.startRule === 'Content_Disposition') {
                                      options.data.type = text().toLowerCase();
                                    }
                                  },
        "handling",
        peg$literalExpectation("handling", true),
        "optional",
        peg$literalExpectation("optional", true),
        "required",
        peg$literalExpectation("required", true),
        function(length) {
                                options.data = parseInt(length.join('')); },
        function() {
                                options.data = text(); },
        "text",
        peg$literalExpectation("text", true),
        "image",
        peg$literalExpectation("image", true),
        "audio",
        peg$literalExpectation("audio", true),
        "video",
        peg$literalExpectation("video", true),
        "application",
        peg$literalExpectation("application", true),
        "message",
        peg$literalExpectation("message", true),
        "multipart",
        peg$literalExpectation("multipart", true),
        "x-",
        peg$literalExpectation("x-", true),
        function(cseq_value) {
                          options.data.value=parseInt(cseq_value.join('')); },
        function(expires) {options.data = expires; },
        function(event_type) {
                               options.data.event = event_type.toLowerCase(); },
        function() {
                        var tag = options.data.tag;
                          options.data = new options.SIP.NameAddrHeader(options.data.uri, options.data.displayName, options.data.params);
                          if (tag) {options.data.setParam('tag',tag)}
                        },
        "tag",
        peg$literalExpectation("tag", true),
        function(tag) {options.data.tag = tag; },
        function(forwards) {
                          options.data = parseInt(forwards.join('')); },
        function(min_expires) {options.data = min_expires; },
        function() {
                                options.data = new options.SIP.NameAddrHeader(options.data.uri, options.data.displayName, options.data.params);
                              },
        "digest",
        peg$literalExpectation("Digest", true),
        "realm",
        peg$literalExpectation("realm", true),
        function(realm) { options.data.realm = realm; },
        "domain",
        peg$literalExpectation("domain", true),
        "nonce",
        peg$literalExpectation("nonce", true),
        function(nonce) { options.data.nonce=nonce; },
        "opaque",
        peg$literalExpectation("opaque", true),
        function(opaque) { options.data.opaque=opaque; },
        "stale",
        peg$literalExpectation("stale", true),
        "true",
        peg$literalExpectation("true", true),
        function() { options.data.stale=true; },
        "false",
        peg$literalExpectation("false", true),
        function() { options.data.stale=false; },
        "algorithm",
        peg$literalExpectation("algorithm", true),
        "md5",
        peg$literalExpectation("MD5", true),
        "md5-sess",
        peg$literalExpectation("MD5-sess", true),
        function(algorithm) {
                              options.data.algorithm=algorithm.toUpperCase(); },
        "qop",
        peg$literalExpectation("qop", true),
        "auth-int",
        peg$literalExpectation("auth-int", true),
        "auth",
        peg$literalExpectation("auth", true),
        function(qop_value) {
                                options.data.qop || (options.data.qop=[]);
                                options.data.qop.push(qop_value.toLowerCase()); },
        function(rack_value) {
                          options.data.value=parseInt(rack_value.join('')); },
        function() {
                          var idx, length;
                          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;
                          }},
        function() {
                          var header;
                          if(!options.data.multi_header) options.data.multi_header = [];
                          try {
                            header = new options.SIP.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
                                                  });},
        function() {
                      options.data = new options.SIP.NameAddrHeader(options.data.uri, options.data.displayName, options.data.params);
                    },
        function() {
                              if (!(options.data.replaces_from_tag && options.data.replaces_to_tag)) {
                                options.data = -1;
                              }
                            },
        function() {
                              options.data = {
                                call_id: options.data
                              };
                            },
        "from-tag",
        peg$literalExpectation("from-tag", true),
        function(from_tag) {
                              options.data.replaces_from_tag = from_tag;
                            },
        "to-tag",
        peg$literalExpectation("to-tag", true),
        function(to_tag) {
                              options.data.replaces_to_tag = to_tag;
                            },
        "early-only",
        peg$literalExpectation("early-only", true),
        function() {
                              options.data.early_only = true;
                            },
        function(head, r) {return r;},
        function(head, tail) { return list(head, tail); },
        function(value) {
                        if (options.startRule === 'Require') {
                          options.data = value || [];
                        }
                      },
        function(rseq_value) {
                          options.data.value=parseInt(rseq_value.join('')); },
        "active",
        peg$literalExpectation("active", true),
        "pending",
        peg$literalExpectation("pending", true),
        "terminated",
        peg$literalExpectation("terminated", true),
        function() {
                                options.data.state = text(); },
        "reason",
        peg$literalExpectation("reason", true),
        function(reason) {
                                if (typeof reason !== 'undefined') options.data.reason = reason; },
        function(expires) {
                                if (typeof expires !== 'undefined') options.data.expires = expires; },
        "retry_after",
        peg$literalExpectation("retry_after", true),
        function(retry_after) {
                                if (typeof retry_after !== 'undefined') options.data.retry_after = retry_after; },
        "deactivated",
        peg$literalExpectation("deactivated", true),
        "probation",
        peg$literalExpectation("probation", true),
        "rejected",
        peg$literalExpectation("rejected", true),
        "timeout",
        peg$literalExpectation("timeout", true),
        "giveup",
        peg$literalExpectation("giveup", true),
        "noresource",
        peg$literalExpectation("noresource", true),
        "invariant",
        peg$literalExpectation("invariant", true),
        function(value) {
                        if (options.startRule === 'Supported') {
                          options.data = value || [];
                        }
                      },
        function() {
                      var tag = options.data.tag;
                        options.data = new options.SIP.NameAddrHeader(options.data.uri, options.data.displayName, options.data.params);
                        if (tag) {options.data.setParam('tag',tag)}
                      },
        "ttl",
        peg$literalExpectation("ttl", true),
        function(via_ttl_value) {
                              options.data.ttl = via_ttl_value; },
        "maddr",
        peg$literalExpectation("maddr", true),
        function(via_maddr) {
                              options.data.maddr = via_maddr; },
        "received",
        peg$literalExpectation("received", true),
        function(via_received) {
                              options.data.received = via_received; },
        "branch",
        peg$literalExpectation("branch", true),
        function(via_branch) {
                              options.data.branch = via_branch; },
        "rport",
        peg$literalExpectation("rport", true),
        function() {
                              if(typeof response_port !== 'undefined')
                                options.data.rport = response_port.join(''); },
        function(via_protocol) {
                              options.data.protocol = via_protocol; },
        peg$literalExpectation("UDP", true),
        peg$literalExpectation("TCP", true),
        peg$literalExpectation("TLS", true),
        peg$literalExpectation("SCTP", true),
        function(via_transport) {
                              options.data.transport = via_transport; },
        function() {
                              options.data.host = text(); },
        function(via_sent_by_port) {
                              options.data.port = parseInt(via_sent_by_port.join('')); },
        function(ttl) {
                              return parseInt(ttl.join('')); },
        function(deltaSeconds) {
                              if (options.startRule === 'Session_Expires') {
                                options.data.deltaSeconds = deltaSeconds;
                              }
                            },
        "refresher",
        peg$literalExpectation("refresher", false),
        "uas",
        peg$literalExpectation("uas", false),
        "uac",
        peg$literalExpectation("uac", false),
        function(endpoint) {
                              if (options.startRule === 'Session_Expires') {
                                options.data.refresher = endpoint;
                              }
                            },
        function(deltaSeconds) {
                              if (options.startRule === 'Min_SE') {
                                options.data = deltaSeconds;
                              }
                            },
        "stuns",
        peg$literalExpectation("stuns", true),
        "stun",
        peg$literalExpectation("stun", true),
        function(scheme) {
                              options.data.scheme = scheme; },
        function(host) {
                              options.data.host = host; },
        "?transport=",
        peg$literalExpectation("?transport=", false),
        "turns",
        peg$literalExpectation("turns", true),
        "turn",
        peg$literalExpectation("turn", true),
        function() {
                              options.data.transport = transport; },
        function() {
                          options.data = text(); },
        "Referred-By",
        peg$literalExpectation("Referred-By", false),
        "b",
        peg$literalExpectation("b", false),
        "cid",
        peg$literalExpectation("cid", false)
      ],

      peg$bytecode = [
        peg$decode("2 \"\"6 7!"),
        peg$decode("4\"\"\"5!7#"),
        peg$decode("4$\"\"5!7%"),
        peg$decode("4&\"\"5!7'"),
        peg$decode(";'.# &;("),
        peg$decode("4(\"\"5!7)"),
        peg$decode("4*\"\"5!7+"),
        peg$decode("2,\"\"6,7-"),
        peg$decode("2.\"\"6.7/"),
        peg$decode("40\"\"5!71"),
        peg$decode("22\"\"6273.\x89 &24\"\"6475.} &26\"\"6677.q &28\"\"6879.e &2:\"\"6:7;.Y &2<\"\"6<7=.M &2>\"\"6>7?.A &2@\"\"6@7A.5 &2B\"\"6B7C.) &2D\"\"6D7E"),
        peg$decode(";).# &;,"),
        peg$decode("2F\"\"6F7G.} &2H\"\"6H7I.q &2J\"\"6J7K.e &2L\"\"6L7M.Y &2N\"\"6N7O.M &2P\"\"6P7Q.A &2R\"\"6R7S.5 &2T\"\"6T7U.) &2V\"\"6V7W"),
        peg$decode("%%2X\"\"6X7Y/5#;#/,$;#/#$+#)(#'#(\"'#&'#/\"!&,)"),
        peg$decode("%%$;$0#*;$&/,#; /#$+\")(\"'#&'#.\" &\"/=#$;$/&#0#*;$&&&#/'$8\":Z\" )(\"'#&'#"),
        peg$decode(";..\" &\""),
        peg$decode("%$;'.# &;(0)*;'.# &;(&/?#28\"\"6879/0$;//'$8#:[# )(#'#(\"'#&'#"),
        peg$decode("%%$;2/&#0#*;2&&&#/g#$%$;.0#*;.&/,#;2/#$+\")(\"'#&'#0=*%$;.0#*;.&/,#;2/#$+\")(\"'#&'#&/#$+\")(\"'#&'#/\"!&,)"),
        peg$decode("4\\\"\"5!7].# &;3"),
        peg$decode("4^\"\"5!7_"),
        peg$decode("4`\"\"5!7a"),
        peg$decode(";!.) &4b\"\"5!7c"),
        peg$decode("%$;).\x95 &2F\"\"6F7G.\x89 &2J\"\"6J7K.} &2L\"\"6L7M.q &2X\"\"6X7Y.e &2P\"\"6P7Q.Y &2H\"\"6H7I.M &2@\"\"6@7A.A &2d\"\"6d7e.5 &2R\"\"6R7S.) &2N\"\"6N7O/\x9E#0\x9B*;).\x95 &2F\"\"6F7G.\x89 &2J\"\"6J7K.} &2L\"\"6L7M.q &2X\"\"6X7Y.e &2P\"\"6P7Q.Y &2H\"\"6H7I.M &2@\"\"6@7A.A &2d\"\"6d7e.5 &2R\"\"6R7S.) &2N\"\"6N7O&&&#/\"!&,)"),
        peg$decode("%$;).\x89 &2F\"\"6F7G.} &2L\"\"6L7M.q &2X\"\"6X7Y.e &2P\"\"6P7Q.Y &2H\"\"6H7I.M &2@\"\"6@7A.A &2d\"\"6d7e.5 &2R\"\"6R7S.) &2N\"\"6N7O/\x92#0\x8F*;).\x89 &2F\"\"6F7G.} &2L\"\"6L7M.q &2X\"\"6X7Y.e &2P\"\"6P7Q.Y &2H\"\"6H7I.M &2@\"\"6@7A.A &2d\"\"6d7e.5 &2R\"\"6R7S.) &2N\"\"6N7O&&&#/\"!&,)"),
        peg$decode("2T\"\"6T7U.\xE3 &2V\"\"6V7W.\xD7 &2f\"\"6f7g.\xCB &2h\"\"6h7i.\xBF &2:\"\"6:7;.\xB3 &2D\"\"6D7E.\xA7 &22\"\"6273.\x9B &28\"\"6879.\x8F &2j\"\"6j7k.\x83 &;&.} &24\"\"6475.q &2l\"\"6l7m.e &2n\"\"6n7o.Y &26\"\"6677.M &2>\"\"6>7?.A &2p\"\"6p7q.5 &2r\"\"6r7s.) &;'.# &;("),
        peg$decode("%$;).\u012B &2F\"\"6F7G.\u011F &2J\"\"6J7K.\u0113 &2L\"\"6L7M.\u0107 &2X\"\"6X7Y.\xFB &2P\"\"6P7Q.\xEF &2H\"\"6H7I.\xE3 &2@\"\"6@7A.\xD7 &2d\"\"6d7e.\xCB &2R\"\"6R7S.\xBF &2N\"\"6N7O.\xB3 &2T\"\"6T7U.\xA7 &2V\"\"6V7W.\x9B &2f\"\"6f7g.\x8F &2h\"\"6h7i.\x83 &28\"\"6879.w &2j\"\"6j7k.k &;&.e &24\"\"6475.Y &2l\"\"6l7m.M &2n\"\"6n7o.A &26\"\"6677.5 &2p\"\"6p7q.) &2r\"\"6r7s/\u0134#0\u0131*;).\u012B &2F\"\"6F7G.\u011F &2J\"\"6J7K.\u0113 &2L\"\"6L7M.\u0107 &2X\"\"6X7Y.\xFB &2P\"\"6P7Q.\xEF &2H\"\"6H7I.\xE3 &2@\"\"6@7A.\xD7 &2d\"\"6d7e.\xCB &2R\"\"6R7S.\xBF &2N\"\"6N7O.\xB3 &2T\"\"6T7U.\xA7 &2V\"\"6V7W.\x9B &2f\"\"6f7g.\x8F &2h\"\"6h7i.\x83 &28\"\"6879.w &2j\"\"6j7k.k &;&.e &24\"\"6475.Y &2l\"\"6l7m.M &2n\"\"6n7o.A &26\"\"6677.5 &2p\"\"6p7q.) &2r\"\"6r7s&&&#/\"!&,)"),
        peg$decode("%;//?#2P\"\"6P7Q/0$;//'$8#:t# )(#'#(\"'#&'#"),
        peg$decode("%;//?#24\"\"6475/0$;//'$8#:u# )(#'#(\"'#&'#"),
        peg$decode("%;//?#2>\"\"6>7?/0$;//'$8#:v# )(#'#(\"'#&'#"),
        peg$decode("%;//?#2T\"\"6T7U/0$;//'$8#:w# )(#'#(\"'#&'#"),
        peg$decode("%;//?#2V\"\"6V7W/0$;//'$8#:x# )(#'#(\"'#&'#"),
        peg$decode("%2h\"\"6h7i/0#;//'$8\":y\" )(\"'#&'#"),
        peg$decode("%;//6#2f\"\"6f7g/'$8\":z\" )(\"'#&'#"),
        peg$decode("%;//?#2D\"\"6D7E/0$;//'$8#:{# )(#'#(\"'#&'#"),
        peg$decode("%;//?#22\"\"6273/0$;//'$8#:|# )(#'#(\"'#&'#"),
        peg$decode("%;//?#28\"\"6879/0$;//'$8#:}# )(#'#(\"'#&'#"),
        peg$decode("%;//0#;&/'$8\":~\" )(\"'#&'#"),
        peg$decode("%;&/0#;//'$8\":~\" )(\"'#&'#"),
        peg$decode("%;=/T#$;G.) &;K.# &;F0/*;G.) &;K.# &;F&/,$;>/#$+#)(#'#(\"'#&'#"),
        peg$decode("4\x7F\"\"5!7\x80.A &4\x81\"\"5!7\x82.5 &4\x83\"\"5!7\x84.) &;3.# &;."),
        peg$decode("%%;//Q#;&/H$$;J.# &;K0)*;J.# &;K&/,$;&/#$+$)($'#(#'#(\"'#&'#/\"!&,)"),
        peg$decode("%;//]#;&/T$%$;J.# &;K0)*;J.# &;K&/\"!&,)/1$;&/($8$:\x85$!!)($'#(#'#(\"'#&'#"),
        peg$decode(";..G &2L\"\"6L7M.; &4\x86\"\"5!7\x87./ &4\x83\"\"5!7\x84.# &;3"),
        peg$decode("%2j\"\"6j7k/J#4\x88\"\"5!7\x89.5 &4\x8A\"\"5!7\x8B.) &4\x8C\"\"5!7\x8D/#$+\")(\"'#&'#"),
        peg$decode("%;N/M#28\"\"6879/>$;O.\" &\"/0$;S/'$8$:\x8E$ )($'#(#'#(\"'#&'#"),
        peg$decode("%;N/d#28\"\"6879/U$;O.\" &\"/G$;S/>$;_/5$;l.\" &\"/'$8&:\x8F& )(&'#(%'#($'#(#'#(\"'#&'#"),
        peg$decode("%3\x90\"\"5$7\x91.) &3\x92\"\"5#7\x93/' 8!:\x94!! )"),
        peg$decode("%;P/]#%28\"\"6879/,#;R/#$+\")(\"'#&'#.\" &\"/6$2:\"\"6:7;/'$8#:\x95# )(#'#(\"'#&'#"),
        peg$decode("$;+.) &;-.# &;Q/2#0/*;+.) &;-.# &;Q&&&#"),
        peg$decode("2<\"\"6<7=.q &2>\"\"6>7?.e &2@\"\"6@7A.Y &2B\"\"6B7C.M &2D\"\"6D7E.A &22\"\"6273.5 &26\"\"6677.) &24\"\"6475"),
        peg$decode("%$;+._ &;-.Y &2<\"\"6<7=.M &2>\"\"6>7?.A &2@\"\"6@7A.5 &2B\"\"6B7C.) &2D\"\"6D7E0e*;+._ &;-.Y &2<\"\"6<7=.M &2>\"\"6>7?.A &2@\"\"6@7A.5 &2B\"\"6B7C.) &2D\"\"6D7E&/& 8!:\x96! )"),
        peg$decode("%;T/J#%28\"\"6879/,#;^/#$+\")(\"'#&'#.\" &\"/#$+\")(\"'#&'#"),
        peg$decode("%;U.) &;\\.# &;X/& 8!:\x97! )"),
        peg$decode("%$%;V/2#2J\"\"6J7K/#$+\")(\"'#&'#0<*%;V/2#2J\"\"6J7K/#$+\")(\"'#&'#&/D#;W/;$2J\"\"6J7K.\" &\"/'$8#:\x98# )(#'#(\"'#&'#"),
        peg$decode("$4\x99\"\"5!7\x9A/,#0)*4\x99\"\"5!7\x9A&&&#"),
        peg$decode("%4$\"\"5!7%/?#$4\x9B\"\"5!7\x9C0)*4\x9B\"\"5!7\x9C&/#$+\")(\"'#&'#"),
        peg$decode("%2l\"\"6l7m/?#;Y/6$2n\"\"6n7o/'$8#:\x9D# )(#'#(\"'#&'#"),
        peg$decode("%%;Z/\xB3#28\"\"6879/\xA4$;Z/\x9B$28\"\"6879/\x8C$;Z/\x83$28\"\"6879/t$;Z/k$28\"\"6879/\\$;Z/S$28\"\"6879/D$;Z/;$28\"\"6879/,$;[/#$+-)(-'#(,'#(+'#(*'#()'#(('#(''#(&'#(%'#($'#(#'#(\"'#&'#.\u0790 &%2\x9E\"\"6\x9E7\x9F/\xA4#;Z/\x9B$28\"\"6879/\x8C$;Z/\x83$28\"\"6879/t$;Z/k$28\"\"6879/\\$;Z/S$28\"\"6879/D$;Z/;$28\"\"6879/,$;[/#$+,)(,'#(+'#(*'#()'#(('#(''#(&'#(%'#($'#(#'#(\"'#&'#.\u06F9 &%2\x9E\"\"6\x9E7\x9F/\x8C#;Z/\x83$28\"\"6879/t$;Z/k$28\"\"6879/\\$;Z/S$28\"\"6879/D$;Z/;$28\"\"6879/,$;[/#$+*)(*'#()'#(('#(''#(&'#(%'#($'#(#'#(\"'#&'#.\u067A &%2\x9E\"\"6\x9E7\x9F/t#;Z/k$28\"\"6879/\\$;Z/S$28\"\"6879/D$;Z/;$28\"\"6879/,$;[/#$+()(('#(''#(&'#(%'#($'#(#'#(\"'#&'#.\u0613 &%2\x9E\"\"6\x9E7\x9F/\\#;Z/S$28\"\"6879/D$;Z/;$28\"\"6879/,$;[/#$+&)(&'#(%'#($'#(#'#(\"'#&'#.\u05C4 &%2\x9E\"\"6\x9E7\x9F/D#;Z/;$28\"\"6879/,$;[/#$+$)($'#(#'#(\"'#&'#.\u058D &%2\x9E\"\"6\x9E7\x9F/,#;[/#$+\")(\"'#&'#.\u056E &%2\x9E\"\"6\x9E7\x9F/,#;Z/#$+\")(\"'#&'#.\u054F &%;Z/\x9B#2\x9E\"\"6\x9E7\x9F/\x8C$;Z/\x83$28\"\"6879/t$;Z/k$28\"\"6879/\\$;Z/S$28\"\"6879/D$;Z/;$28\"\"6879/,$;[/#$++)(+'#(*'#()'#(('#(''#(&'#(%'#($'#(#'#(\"'#&'#.\u04C7 &%;Z/\xAA#%28\"\"6879/,#;Z/#$+\")(\"'#&'#.\" &\"/\x83$2\x9E\"\"6\x9E7\x9F/t$;Z/k$28\"\"6879/\\$;Z/S$28\"\"6879/D$;Z/;$28\"\"6879/,$;[/#$+*)(*'#()'#(('#(''#(&'#(%'#($'#(#'#(\"'#&'#.\u0430 &%;Z/\xB9#%28\"\"6879/,#;Z/#$+\")(\"'#&'#.\" &\"/\x92$%28\"\"6879/,#;Z/#$+\")(\"'#&'#.\" &\"/k$2\x9E\"\"6\x9E7\x9F/\\$;Z/S$28\"\"6879/D$;Z/;$28\"\"6879/,$;[/#$+))()'#(('#(''#(&'#(%'#($'#(#'#(\"'#&'#.\u038A &%;Z/\xC8#%28\"\"6879/,#;Z/#$+\")(\"'#&'#.\" &\"/\xA1$%28\"\"6879/,#;Z/#$+\")(\"'#&'#.\" &\"/z$%28\"\"6879/,#;Z/#$+\")(\"'#&'#.\" &\"/S$2\x9E\"\"6\x9E7\x9F/D$;Z/;$28\"\"6879/,$;[/#$+()(('#(''#(&'#(%'#($'#(#'#(\"'#&'#.\u02D5 &%;Z/\xD7#%28\"\"6879/,#;Z/#$+\")(\"'#&'#.\" &\"/\xB0$%28\"\"6879/,#;Z/#$+\")(\"'#&'#.\" &\"/\x89$%28\"\"6879/,#;Z/#$+\")(\"'#&'#.\" &\"/b$%28\"\"6879/,#;Z/#$+\")(\"'#&'#.\" &\"/;$2\x9E\"\"6\x9E7\x9F/,$;[/#$+')(''#(&'#(%'#($'#(#'#(\"'#&'#.\u0211 &%;Z/\xFE#%28\"\"6879/,#;Z/#$+\")(\"'#&'#.\" &\"/\xD7$%28\"\"6879/,#;Z/#$+\")(\"'#&'#.\" &\"/\xB0$%28\"\"6879/,#;Z/#$+\")(\"'#&'#.\" &\"/\x89$%28\"\"6879/,#;Z/#$+\")(\"'#&'#.\" &\"/b$%28\"\"6879/,#;Z/#$+\")(\"'#&'#.\" &\"/;$2\x9E\"\"6\x9E7\x9F/,$;Z/#$+()(('#(''#(&'#(%'#($'#(#'#(\"'#&'#.\u0126 &%;Z/\u011C#%28\"\"6879/,#;Z/#$+\")(\"'#&'#.\" &\"/\xF5$%28\"\"6879/,#;Z/#$+\")(\"'#&'#.\" &\"/\xCE$%28\"\"6879/,#;Z/#$+\")(\"'#&'#.\" &\"/\xA7$%28\"\"6879/,#;Z/#$+\")(\"'#&'#.\" &\"/\x80$%28\"\"6879/,#;Z/#$+\")(\"'#&'#.\" &\"/Y$%28\"\"6879/,#;Z/#$+\")(\"'#&'#.\" &\"/2$2\x9E\"\"6\x9E7\x9F/#$+()(('#(''#(&'#(%'#($'#(#'#(\"'#&'#/& 8!:\xA0! )"),
        peg$decode("%;#/M#;#.\" &\"/?$;#.\" &\"/1$;#.\" &\"/#$+$)($'#(#'#(\"'#&'#"),
        peg$decode("%;Z/;#28\"\"6879/,$;Z/#$+#)(#'#(\"'#&'#.# &;\\"),
        peg$decode("%;]/o#2J\"\"6J7K/`$;]/W$2J\"\"6J7K/H$;]/?$2J\"\"6J7K/0$;]/'$8':\xA1' )(''#(&'#(%'#($'#(#'#(\"'#&'#"),
        peg$decode("%2\xA2\"\"6\xA27\xA3/2#4\xA4\"\"5!7\xA5/#$+\")(\"'#&'#.\x98 &%2\xA6\"\"6\xA67\xA7/;#4\xA8\"\"5!7\xA9/,$;!/#$+#)(#'#(\"'#&'#.j &%2\xAA\"\"6\xAA7\xAB/5#;!/,$;!/#$+#)(#'#(\"'#&'#.B &%4\xAC\"\"5!7\xAD/,#;!/#$+\")(\"'#&'#.# &;!"),
        peg$decode("%%;!.\" &\"/[#;!.\" &\"/M$;!.\" &\"/?$;!.\" &\"/1$;!.\" &\"/#$+%)(%'#($'#(#'#(\"'#&'#/' 8!:\xAE!! )"),
        peg$decode("$%22\"\"6273/,#;`/#$+\")(\"'#&'#0<*%22\"\"6273/,#;`/#$+\")(\"'#&'#&"),
        peg$decode(";a.A &;b.; &;c.5 &;d./ &;e.) &;f.# &;g"),
        peg$decode("%3\xAF\"\"5*7\xB0/a#3\xB1\"\"5#7\xB2.G &3\xB3\"\"5#7\xB4.; &3\xB5\"\"5$7\xB6./ &3\xB7\"\"5#7\xB8.# &;6/($8\":\xB9\"! )(\"'#&'#"),
        peg$decode("%3\xBA\"\"5%7\xBB/I#3\xBC\"\"5%7\xBD./ &3\xBE\"\"5\"7\xBF.# &;6/($8\":\xC0\"! )(\"'#&'#"),
        peg$decode("%3\xC1\"\"5'7\xC2/1#;\x90/($8\":\xC3\"! )(\"'#&'#"),
        peg$decode("%3\xC4\"\"5$7\xC5/1#;\xF0/($8\":\xC6\"! )(\"'#&'#"),
        peg$decode("%3\xC7\"\"5&7\xC8/1#;T/($8\":\xC9\"! )(\"'#&'#"),
        peg$decode("%3\xCA\"\"5\"7\xCB/N#%2>\"\"6>7?/,#;6/#$+\")(\"'#&'#.\" &\"/'$8\":\xCC\" )(\"'#&'#"),
        peg$decode("%;h/P#%2>\"\"6>7?/,#;i/#$+\")(\"'#&'#.\" &\"/)$8\":\xCD\"\"! )(\"'#&'#"),
        peg$decode("%$;j/&#0#*;j&&&#/\"!&,)"),
        peg$decode("%$;j/&#0#*;j&&&#/\"!&,)"),
        peg$decode(";k.) &;+.# &;-"),
        peg$decode("2l\"\"6l7m.e &2n\"\"6n7o.Y &24\"\"6475.M &28\"\"6879.A &2<\"\"6<7=.5 &2@\"\"6@7A.) &2B\"\"6B7C"),
        peg$decode("%26\"\"6677/n#;m/e$$%2<\"\"6<7=/,#;m/#$+\")(\"'#&'#0<*%2<\"\"6<7=/,#;m/#$+\")(\"'#&'#&/#$+#)(#'#(\"'#&'#"),
        peg$decode("%;n/A#2>\"\"6>7?/2$;o/)$8#:\xCE#\"\" )(#'#(\"'#&'#"),
        peg$decode("$;p.) &;+.# &;-/2#0/*;p.) &;+.# &;-&&&#"),
        peg$decode("$;p.) &;+.# &;-0/*;p.) &;+.# &;-&"),
        peg$decode("2l\"\"6l7m.e &2n\"\"6n7o.Y &24\"\"6475.M &26\"\"6677.A &28\"\"6879.5 &2@\"\"6@7A.) &2B\"\"6B7C"),
        peg$decode(";\x91.# &;r"),
        peg$decode("%;\x90/G#;'/>$;s/5$;'/,$;\x84/#$+%)(%'#($'#(#'#(\"'#&'#"),
        peg$decode(";M.# &;t"),
        peg$decode("%;\x7F/E#28\"\"6879/6$;u.# &;x/'$8#:\xCF# )(#'#(\"'#&'#"),
        peg$decode("%;v.# &;w/J#%26\"\"6677/,#;\x83/#$+\")(\"'#&'#.\" &\"/#$+\")(\"'#&'#"),
        peg$decode("%2\xD0\"\"6\xD07\xD1/:#;\x80/1$;w.\" &\"/#$+#)(#'#(\"'#&'#"),
        peg$decode("%24\"\"6475/,#;{/#$+\")(\"'#&'#"),
        peg$decode("%;z/3#$;y0#*;y&/#$+\")(\"'#&'#"),
        peg$decode(";*.) &;+.# &;-"),
        peg$decode(";+.\x8F &;-.\x89 &22\"\"6273.} &26\"\"6677.q &28\"\"6879.e &2:\"\"6:7;.Y &2<\"\"6<7=.M &2>\"\"6>7?.A &2@\"\"6@7A.5 &2B\"\"6B7C.) &2D\"\"6D7E"),
        peg$decode("%;|/e#$%24\"\"6475/,#;|/#$+\")(\"'#&'#0<*%24\"\"6475/,#;|/#$+\")(\"'#&'#&/#$+\")(\"'#&'#"),
        peg$decode("%$;~0#*;~&/e#$%22\"\"6273/,#;}/#$+\")(\"'#&'#0<*%22\"\"6273/,#;}/#$+\")(\"'#&'#&/#$+\")(\"'#&'#"),
        peg$decode("$;~0#*;~&"),
        peg$decode(";+.w &;-.q &28\"\"6879.e &2:\"\"6:7;.Y &2<\"\"6<7=.M &2>\"\"6>7?.A &2@\"\"6@7A.5 &2B\"\"6B7C.) &2D\"\"6D7E"),
        peg$decode("%%;\"/\x87#$;\".G &;!.A &2@\"\"6@7A.5 &2F\"\"6F7G.) &2J\"\"6J7K0M*;\".G &;!.A &2@\"\"6@7A.5 &2F\"\"6F7G.) &2J\"\"6J7K&/#$+\")(\"'#&'#/& 8!:\xD2! )"),
        peg$decode(";\x81.# &;\x82"),
        peg$decode("%%;O/2#2:\"\"6:7;/#$+\")(\"'#&'#.\" &\"/,#;S/#$+\")(\"'#&'#.\" &\""),
        peg$decode("$;+.\x83 &;-.} &2B\"\"6B7C.q &2D\"\"6D7E.e &22\"\"6273.Y &28\"\"6879.M &2:\"\"6:7;.A &2<\"\"6<7=.5 &2>\"\"6>7?.) &2@\"\"6@7A/\x8C#0\x89*;+.\x83 &;-.} &2B\"\"6B7C.q &2D\"\"6D7E.e &22\"\"6273.Y &28\"\"6879.M &2:\"\"6:7;.A &2<\"\"6<7=.5 &2>\"\"6>7?.) &2@\"\"6@7A&&&#"),
        peg$decode("$;y0#*;y&"),
        peg$decode("%3\x92\"\"5#7\xD3/q#24\"\"6475/b$$;!/&#0#*;!&&&#/L$2J\"\"6J7K/=$$;!/&#0#*;!&&&#/'$8%:\xD4% )(%'#($'#(#'#(\"'#&'#"),
        peg$decode("2\xD5\"\"6\xD57\xD6"),
        peg$decode("2\xD7\"\"6\xD77\xD8"),
        peg$decode("2\xD9\"\"6\xD97\xDA"),
        peg$decode("2\xDB\"\"6\xDB7\xDC"),
        peg$decode("2\xDD\"\"6\xDD7\xDE"),
        peg$decode("2\xDF\"\"6\xDF7\xE0"),
        peg$decode("2\xE1\"\"6\xE17\xE2"),
        peg$decode("2\xE3\"\"6\xE37\xE4"),
        peg$decode("2\xE5\"\"6\xE57\xE6"),
        peg$decode("2\xE7\"\"6\xE77\xE8"),
        peg$decode("2\xE9\"\"6\xE97\xEA"),
        peg$decode("%;\x85.Y &;\x86.S &;\x88.M &;\x89.G &;\x8A.A &;\x8B.; &;\x8C.5 &;\x8F./ &;\x8D.) &;\x8E.# &;6/& 8!:\xEB! )"),
        peg$decode("%;\x84/G#;'/>$;\x92/5$;'/,$;\x94/#$+%)(%'#($'#(#'#(\"'#&'#"),
        peg$decode("%;\x93/' 8!:\xEC!! )"),
        peg$decode("%;!/5#;!/,$;!/#$+#)(#'#(\"'#&'#"),
        peg$decode("%$;*.A &;+.; &;-.5 &;3./ &;4.) &;'.# &;(0G*;*.A &;+.; &;-.5 &;3./ &;4.) &;'.# &;(&/& 8!:\xED! )"),
        peg$decode("%;\xB6/Y#$%;A/,#;\xB6/#$+\")(\"'#&'#06*%;A/,#;\xB6/#$+\")(\"'#&'#&/#$+\")(\"'#&'#"),
        peg$decode("%;9/N#%2:\"\"6:7;/,#;9/#$+\")(\"'#&'#.\" &\"/'$8\":\xEE\" )(\"'#&'#"),
        peg$decode("%;:.c &%;\x98/Y#$%;A/,#;\x98/#$+\")(\"'#&'#06*%;A/,#;\x98/#$+\")(\"'#&'#&/#$+\")(\"'#&'#/& 8!:\xEF! )"),
        peg$decode("%;L.# &;\x99/]#$%;B/,#;\x9B/#$+\")(\"'#&'#06*%;B/,#;\x9B/#$+\")(\"'#&'#&/'$8\":\xF0\" )(\"'#&'#"),
        peg$decode("%;\x9A.\" &\"/>#;@/5$;M/,$;?/#$+$)($'#(#'#(\"'#&'#"),
        peg$decode("%%;6/Y#$%;./,#;6/#$+\")(\"'#&'#06*%;./,#;6/#$+\")(\"'#&'#&/#$+\")(\"'#&'#.# &;H/' 8!:\xF1!! )"),
        peg$decode(";\x9C.) &;\x9D.# &;\xA0"),
        peg$decode("%3\xF2\"\"5!7\xF3/:#;</1$;\x9F/($8#:\xF4#! )(#'#(\"'#&'#"),
        peg$decode("%3\xF5\"\"5'7\xF6/:#;</1$;\x9E/($8#:\xF7#! )(#'#(\"'#&'#"),
        peg$decode("%$;!/&#0#*;!&&&#/' 8!:\xF8!! )"),
        peg$decode("%2\xF9\"\"6\xF97\xFA/o#%2J\"\"6J7K/M#;!.\" &\"/?$;!.\" &\"/1$;!.\" &\"/#$+$)($'#(#'#(\"'#&'#.\" &\"/'$8\":\xFB\" )(\"'#&'#"),
        peg$decode("%;6/J#%;</,#;\xA1/#$+\")(\"'#&'#.\" &\"/)$8\":\xFC\"\"! )(\"'#&'#"),
        peg$decode(";6.) &;T.# &;H"),
        peg$decode("%;\xA3/Y#$%;B/,#;\xA4/#$+\")(\"'#&'#06*%;B/,#;\xA4/#$+\")(\"'#&'#&/#$+\")(\"'#&'#"),
        peg$decode("%3\xFD\"\"5&7\xFE.G &3\xFF\"\"5'7\u0100.; &3\u0101\"\"5$7\u0102./ &3\u0103\"\"5%7\u0104.# &;6/& 8!:\u0105! )"),
        peg$decode(";\xA5.# &;\xA0"),
        peg$decode("%3\u0106\"\"5(7\u0107/M#;</D$3\u0108\"\"5(7\u0109./ &3\u010A\"\"5(7\u010B.# &;6/#$+#)(#'#(\"'#&'#"),
        peg$decode("%;6/Y#$%;A/,#;6/#$+\")(\"'#&'#06*%;A/,#;6/#$+\")(\"'#&'#&/#$+\")(\"'#&'#"),
        peg$decode("%$;!/&#0#*;!&&&#/' 8!:\u010C!! )"),
        peg$decode("%;\xA9/& 8!:\u010D! )"),
        peg$decode("%;\xAA/k#;;/b$;\xAF/Y$$%;B/,#;\xB0/#$+\")(\"'#&'#06*%;B/,#;\xB0/#$+\")(\"'#&'#&/#$+$)($'#(#'#(\"'#&'#"),
        peg$decode(";\xAB.# &;\xAC"),
        peg$decode("3\u010E\"\"5$7\u010F.S &3\u0110\"\"5%7\u0111.G &3\u0112\"\"5%7\u0113.; &3\u0114\"\"5%7\u0115./ &3\u0116\"\"5+7\u0117.# &;\xAD"),
        peg$decode("3\u0118\"\"5'7\u0119./ &3\u011A\"\"5)7\u011B.# &;\xAD"),
        peg$decode(";6.# &;\xAE"),
        peg$decode("%3\u011C\"\"5\"7\u011D/,#;6/#$+\")(\"'#&'#"),
        peg$decode(";\xAD.# &;6"),
        peg$decode("%;6/5#;</,$;\xB1/#$+#)(#'#(\"'#&'#"),
        peg$decode(";6.# &;H"),
        peg$decode("%;\xB3/5#;./,$;\x90/#$+#)(#'#(\"'#&'#"),
        peg$decode("%$;!/&#0#*;!&&&#/' 8!:\u011E!! )"),
        peg$decode("%;\x9E/' 8!:\u011F!! )"),
        peg$decode("%;\xB6/^#$%;B/,#;\xA0/#$+\")(\"'#&'#06*%;B/,#;\xA0/#$+\")(\"'#&'#&/($8\":\u0120\"!!)(\"'#&'#"),
        peg$decode("%%;7/e#$%2J\"\"6J7K/,#;7/#$+\")(\"'#&'#0<*%2J\"\"6J7K/,#;7/#$+\")(\"'#&'#&/#$+\")(\"'#&'#/\"!&,)"),
        peg$decode("%;L.# &;\x99/]#$%;B/,#;\xB8/#$+\")(\"'#&'#06*%;B/,#;\xB8/#$+\")(\"'#&'#&/'$8\":\u0121\" )(\"'#&'#"),
        peg$decode(";\xB9.# &;\xA0"),
        peg$decode("%3\u0122\"\"5#7\u0123/:#;</1$;6/($8#:\u0124#! )(#'#(\"'#&'#"),
        peg$decode("%$;!/&#0#*;!&&&#/' 8!:\u0125!! )"),
        peg$decode("%;\x9E/' 8!:\u0126!! )"),
        peg$decode("%$;\x9A0#*;\x9A&/x#;@/o$;M/f$;?/]$$%;B/,#;\xA0/#$+\")(\"'#&'#06*%;B/,#;\xA0/#$+\")(\"'#&'#&/'$8%:\u0127% )(%'#($'#(#'#(\"'#&'#"),
        peg$decode(";\xBE"),
        peg$decode("%3\u0128\"\"5&7\u0129/k#;./b$;\xC1/Y$$%;A/,#;\xC1/#$+\")(\"'#&'#06*%;A/,#;\xC1/#$+\")(\"'#&'#&/#$+$)($'#(#'#(\"'#&'#.# &;\xBF"),
        peg$decode("%;6/k#;./b$;\xC0/Y$$%;A/,#;\xC0/#$+\")(\"'#&'#06*%;A/,#;\xC0/#$+\")(\"'#&'#&/#$+$)($'#(#'#(\"'#&'#"),
        peg$decode("%;6/;#;</2$;6.# &;H/#$+#)(#'#(\"'#&'#"),
        peg$decode(";\xC2.G &;\xC4.A &;\xC6.; &;\xC8.5 &;\xC9./ &;\xCA.) &;\xCB.# &;\xC0"),
        peg$decode("%3\u012A\"\"5%7\u012B/5#;</,$;\xC3/#$+#)(#'#(\"'#&'#"),
        peg$decode("%;I/' 8!:\u012C!! )"),
        peg$decode("%3\u012D\"\"5&7\u012E/\x97#;</\x8E$;D/\x85$;\xC5/|$$%$;'/&#0#*;'&&&#/,#;\xC5/#$+\")(\"'#&'#0C*%$;'/&#0#*;'&&&#/,#;\xC5/#$+\")(\"'#&'#&/,$;E/#$+&)(&'#(%'#($'#(#'#(\"'#&'#"),
        peg$decode(";t.# &;w"),
        peg$decode("%3\u012F\"\"5%7\u0130/5#;</,$;\xC7/#$+#)(#'#(\"'#&'#"),
        peg$decode("%;I/' 8!:\u0131!! )"),
        peg$decode("%3\u0132\"\"5&7\u0133/:#;</1$;I/($8#:\u0134#! )(#'#(\"'#&'#"),
        peg$decode("%3\u0135\"\"5%7\u0136/]#;</T$%3\u0137\"\"5$7\u0138/& 8!:\u0139! ).4 &%3\u013A\"\"5%7\u013B/& 8!:\u013C! )/#$+#)(#'#(\"'#&'#"),
        peg$decode("%3\u013D\"\"5)7\u013E/R#;</I$3\u013F\"\"5#7\u0140./ &3\u0141\"\"5(7\u0142.# &;6/($8#:\u0143#! )(#'#(\"'#&'#"),
        peg$decode("%3\u0144\"\"5#7\u0145/\x93#;</\x8A$;D/\x81$%;\xCC/e#$%2D\"\"6D7E/,#;\xCC/#$+\")(\"'#&'#0<*%2D\"\"6D7E/,#;\xCC/#$+\")(\"'#&'#&/#$+\")(\"'#&'#/,$;E/#$+%)(%'#($'#(#'#(\"'#&'#"),
        peg$decode("%3\u0146\"\"5(7\u0147./ &3\u0148\"\"5$7\u0149.# &;6/' 8!:\u014A!! )"),
        peg$decode("%;6/Y#$%;A/,#;6/#$+\")(\"'#&'#06*%;A/,#;6/#$+\")(\"'#&'#&/#$+\")(\"'#&'#"),
        peg$decode("%;\xCF/G#;./>$;\xCF/5$;./,$;\x90/#$+%)(%'#($'#(#'#(\"'#&'#"),
        peg$decode("%$;!/&#0#*;!&&&#/' 8!:\u014B!! )"),
        peg$decode("%;\xD1/]#$%;A/,#;\xD1/#$+\")(\"'#&'#06*%;A/,#;\xD1/#$+\")(\"'#&'#&/'$8\":\u014C\" )(\"'#&'#"),
        peg$decode("%;\x99/]#$%;B/,#;\xA0/#$+\")(\"'#&'#06*%;B/,#;\xA0/#$+\")(\"'#&'#&/'$8\":\u014D\" )(\"'#&'#"),
        peg$decode("%;L.O &;\x99.I &%;@.\" &\"/:#;t/1$;?.\" &\"/#$+#)(#'#(\"'#&'#/]#$%;B/,#;\xA0/#$+\")(\"'#&'#06*%;B/,#;\xA0/#$+\")(\"'#&'#&/'$8\":\u014E\" )(\"'#&'#"),
        peg$decode("%;\xD4/]#$%;B/,#;\xD5/#$+\")(\"'#&'#06*%;B/,#;\xD5/#$+\")(\"'#&'#&/'$8\":\u014F\" )(\"'#&'#"),
        peg$decode("%;\x96/& 8!:\u0150! )"),
        peg$decode("%3\u0151\"\"5(7\u0152/:#;</1$;6/($8#:\u0153#! )(#'#(\"'#&'#.g &%3\u0154\"\"5&7\u0155/:#;</1$;6/($8#:\u0156#! )(#'#(\"'#&'#.: &%3\u0157\"\"5*7\u0158/& 8!:\u0159! ).# &;\xA0"),
        peg$decode("%%;6/k#$%;A/2#;6/)$8\":\u015A\"\"$ )(\"'#&'#0<*%;A/2#;6/)$8\":\u015A\"\"$ )(\"'#&'#&/)$8\":\u015B\"\"! )(\"'#&'#.\" &\"/' 8!:\u015C!! )"),
        peg$decode("%;\xD8/Y#$%;A/,#;\xD8/#$+\")(\"'#&'#06*%;A/,#;\xD8/#$+\")(\"'#&'#&/#$+\")(\"'#&'#"),
        peg$decode("%;\x99/Y#$%;B/,#;\xA0/#$+\")(\"'#&'#06*%;B/,#;\xA0/#$+\")(\"'#&'#&/#$+\")(\"'#&'#"),
        peg$decode("%$;!/&#0#*;!&&&#/' 8!:\u015D!! )"),
        peg$decode("%;\xDB/Y#$%;B/,#;\xDC/#$+\")(\"'#&'#06*%;B/,#;\xDC/#$+\")(\"'#&'#&/#$+\")(\"'#&'#"),
        peg$decode("%3\u015E\"\"5&7\u015F.; &3\u0160\"\"5'7\u0161./ &3\u0162\"\"5*7\u0163.# &;6/& 8!:\u0164! )"),
        peg$decode("%3\u0165\"\"5&7\u0166/:#;</1$;\xDD/($8#:\u0167#! )(#'#(\"'#&'#.} &%3\xF5\"\"5'7\xF6/:#;</1$;\x9E/($8#:\u0168#! )(#'#(\"'#&'#.P &%3\u0169\"\"5+7\u016A/:#;</1$;\x9E/($8#:\u016B#! )(#'#(\"'#&'#.# &;\xA0"),
        peg$decode("3\u016C\"\"5+7\u016D.k &3\u016E\"\"5)7\u016F._ &3\u0170\"\"5(7\u0171.S &3\u0172\"\"5'7\u0173.G &3\u0174\"\"5&7\u0175.; &3\u0176\"\"5*7\u0177./ &3\u0178\"\"5)7\u0179.# &;6"),
        peg$decode(";1.\" &\""),
        peg$decode("%%;6/k#$%;A/2#;6/)$8\":\u015A\"\"$ )(\"'#&'#0<*%;A/2#;6/)$8\":\u015A\"\"$ )(\"'#&'#&/)$8\":\u015B\"\"! )(\"'#&'#.\" &\"/' 8!:\u017A!! )"),
        peg$decode("%;L.# &;\x99/]#$%;B/,#;\xE1/#$+\")(\"'#&'#06*%;B/,#;\xE1/#$+\")(\"'#&'#&/'$8\":\u017B\" )(\"'#&'#"),
        peg$decode(";\xB9.# &;\xA0"),
        peg$decode("%;\xE3/Y#$%;A/,#;\xE3/#$+\")(\"'#&'#06*%;A/,#;\xE3/#$+\")(\"'#&'#&/#$+\")(\"'#&'#"),
        peg$decode("%;\xEA/k#;./b$;\xED/Y$$%;B/,#;\xE4/#$+\")(\"'#&'#06*%;B/,#;\xE4/#$+\")(\"'#&'#&/#$+$)($'#(#'#(\"'#&'#"),
        peg$decode(";\xE5.; &;\xE6.5 &;\xE7./ &;\xE8.) &;\xE9.# &;\xA0"),
        peg$decode("%3\u017C\"\"5#7\u017D/:#;</1$;\xF0/($8#:\u017E#! )(#'#(\"'#&'#"),
        peg$decode("%3\u017F\"\"5%7\u0180/:#;</1$;T/($8#:\u0181#! )(#'#(\"'#&'#"),
        peg$decode("%3\u0182\"\"5(7\u0183/F#;</=$;\\.) &;Y.# &;X/($8#:\u0184#! )(#'#(\"'#&'#"),
        peg$decode("%3\u0185\"\"5&7\u0186/:#;</1$;6/($8#:\u0187#! )(#'#(\"'#&'#"),
        peg$decode("%3\u0188\"\"5%7\u0189/O#%;</3#$;!0#*;!&/#$+\")(\"'#&'#.\" &\"/'$8\":\u018A\" )(\"'#&'#"),
        peg$decode("%;\xEB/G#;;/>$;6/5$;;/,$;\xEC/#$+%)(%'#($'#(#'#(\"'#&'#"),
        peg$decode("%3\x92\"\"5#7\xD3.# &;6/' 8!:\u018B!! )"),
        peg$decode("%3\xB1\"\"5#7\u018C.G &3\xB3\"\"5#7\u018D.; &3\xB7\"\"5#7\u018E./ &3\xB5\"\"5$7\u018F.# &;6/' 8!:\u0190!! )"),
        peg$decode("%;\xEE/D#%;C/,#;\xEF/#$+\")(\"'#&'#.\" &\"/#$+\")(\"'#&'#"),
        peg$decode("%;U.) &;\\.# &;X/& 8!:\u0191! )"),
        peg$decode("%%;!.\" &\"/[#;!.\" &\"/M$;!.\" &\"/?$;!.\" &\"/1$;!.\" &\"/#$+%)(%'#($'#(#'#(\"'#&'#/' 8!:\u0192!! )"),
        peg$decode("%%;!/?#;!.\" &\"/1$;!.\" &\"/#$+#)(#'#(\"'#&'#/' 8!:\u0193!! )"),
        peg$decode(";\xBE"),
        peg$decode("%;\x9E/^#$%;B/,#;\xF3/#$+\")(\"'#&'#06*%;B/,#;\xF3/#$+\")(\"'#&'#&/($8\":\u0194\"!!)(\"'#&'#"),
        peg$decode(";\xF4.# &;\xA0"),
        peg$decode("%2\u0195\"\"6\u01957\u0196/L#;</C$2\u0197\"\"6\u01977\u0198.) &2\u0199\"\"6\u01997\u019A/($8#:\u019B#! )(#'#(\"'#&'#"),
        peg$decode("%;\x9E/^#$%;B/,#;\xA0/#$+\")(\"'#&'#06*%;B/,#;\xA0/#$+\")(\"'#&'#&/($8\":\u019C\"!!)(\"'#&'#"),
        peg$decode("%;6/5#;0/,$;\xF7/#$+#)(#'#(\"'#&'#"),
        peg$decode("$;2.) &;4.# &;.0/*;2.) &;4.# &;.&"),
        peg$decode("$;%0#*;%&"),
        peg$decode("%;\xFA/;#28\"\"6879/,$;\xFB/#$+#)(#'#(\"'#&'#"),
        peg$decode("%3\u019D\"\"5%7\u019E.) &3\u019F\"\"5$7\u01A0/' 8!:\u01A1!! )"),
        peg$decode("%;\xFC/J#%28\"\"6879/,#;^/#$+\")(\"'#&'#.\" &\"/#$+\")(\"'#&'#"),
        peg$decode("%;\\.) &;X.# &;\x82/' 8!:\u01A2!! )"),
        peg$decode(";\".S &;!.M &2F\"\"6F7G.A &2J\"\"6J7K.5 &2H\"\"6H7I.) &2N\"\"6N7O"),
        peg$decode("2L\"\"6L7M.\x95 &2B\"\"6B7C.\x89 &2<\"\"6<7=.} &2R\"\"6R7S.q &2T\"\"6T7U.e &2V\"\"6V7W.Y &2P\"\"6P7Q.M &2@\"\"6@7A.A &2D\"\"6D7E.5 &22\"\"6273.) &2>\"\"6>7?"),
        peg$decode("%;\u0100/b#28\"\"6879/S$;\xFB/J$%2\u01A3\"\"6\u01A37\u01A4/,#;\xEC/#$+\")(\"'#&'#.\" &\"/#$+$)($'#(#'#(\"'#&'#"),
        peg$decode("%3\u01A5\"\"5%7\u01A6.) &3\u01A7\"\"5$7\u01A8/' 8!:\u01A1!! )"),
        peg$decode("%;\xEC/O#3\xB1\"\"5#7\xB2.6 &3\xB3\"\"5#7\xB4.* &$;+0#*;+&/'$8\":\u01A9\" )(\"'#&'#"),
        peg$decode("%;\u0104/\x87#2F\"\"6F7G/x$;\u0103/o$2F\"\"6F7G/`$;\u0103/W$2F\"\"6F7G/H$;\u0103/?$2F\"\"6F7G/0$;\u0105/'$8):\u01AA) )()'#(('#(''#(&'#(%'#($'#(#'#(\"'#&'#"),
        peg$decode("%;#/>#;#/5$;#/,$;#/#$+$)($'#(#'#(\"'#&'#"),
        peg$decode("%;\u0103/,#;\u0103/#$+\")(\"'#&'#"),
        peg$decode("%;\u0103/5#;\u0103/,$;\u0103/#$+#)(#'#(\"'#&'#"),
        peg$decode("%;\x84/U#;'/L$;\x92/C$;'/:$;\x90/1$; .\" &\"/#$+&)(&'#(%'#($'#(#'#(\"'#&'#"),
        peg$decode("%2\u01AB\"\"6\u01AB7\u01AC.) &2\u01AD\"\"6\u01AD7\u01AE/w#;0/n$;\u0108/e$$%;B/2#;\u0109.# &;\xA0/#$+\")(\"'#&'#0<*%;B/2#;\u0109.# &;\xA0/#$+\")(\"'#&'#&/#$+$)($'#(#'#(\"'#&'#"),
        peg$decode(";\x99.# &;L"),
        peg$decode("%2\u01AF\"\"6\u01AF7\u01B0/5#;</,$;\u010A/#$+#)(#'#(\"'#&'#"),
        peg$decode("%;D/S#;,/J$2:\"\"6:7;/;$;,.# &;T/,$;E/#$+%)(%'#($'#(#'#(\"'#&'#")
      ],

      peg$currPos          = 0,
      peg$savedPos         = 0,
      peg$posDetailsCache  = [{ line: 1, column: 1 }],
      peg$maxFailPos       = 0,
      peg$maxFailExpected  = [],
      peg$silentFails      = 0,

      peg$result;

  if ("startRule" in options) {
    if (!(options.startRule in peg$startRuleIndices)) {
      throw new Error("Can't start parsing from rule \"" + options.startRule + "\".");
    }

    peg$startRuleIndex = peg$startRuleIndices[options.startRule];
  }

  function text() {
    return input.substring(peg$savedPos, peg$currPos);
  }

  function location() {
    return peg$computeLocation(peg$savedPos, peg$currPos);
  }

  function expected(description, location) {
    location = location !== void 0 ? location : peg$computeLocation(peg$savedPos, peg$currPos)

    throw peg$buildStructuredError(
      [peg$otherExpectation(description)],
      input.substring(peg$savedPos, peg$currPos),
      location
    );
  }

  function error(message, location) {
    location = location !== void 0 ? location : peg$computeLocation(peg$savedPos, peg$currPos)

    throw peg$buildSimpleError(message, location);
  }

  function peg$literalExpectation(text, ignoreCase) {
    return { type: "literal", text: text, 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], 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),
        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(expected) {
    if (peg$currPos < peg$maxFailPos) { return; }

    if (peg$currPos > peg$maxFailPos) {
      peg$maxFailPos = peg$currPos;
      peg$maxFailExpected = [];
    }

    peg$maxFailExpected.push(expected);
  }

  function peg$buildSimpleError(message, location) {
    return new peg$SyntaxError(message, null, null, location);
  }

  function peg$buildStructuredError(expected, found, location) {
    return new peg$SyntaxError(
      peg$SyntaxError.buildMessage(expected, found),
      expected,
      found,
      location
    );
  }

  function peg$decode(s) {
    var bc = new Array(s.length), i;

    for (i = 0; i < s.length; i++) {
      bc[i] = s.charCodeAt(i) - 32;
    }

    return bc;
  }

  function peg$parseRule(index) {
    var bc    = peg$bytecode[index],
        ip    = 0,
        ips   = [],
        end   = bc.length,
        ends  = [],
        stack = [],
        params, i;

    while (true) {
      while (ip < end) {
        switch (bc[ip]) {
          case 0:
            stack.push(peg$consts[bc[ip + 1]]);
            ip += 2;
            break;

          case 1:
            stack.push(void 0);
            ip++;
            break;

          case 2:
            stack.push(null);
            ip++;
            break;

          case 3:
            stack.push(peg$FAILED);
            ip++;
            break;

          case 4:
            stack.push([]);
            ip++;
            break;

          case 5:
            stack.push(peg$currPos);
            ip++;
            break;

          case 6:
            stack.pop();
            ip++;
            break;

          case 7:
            peg$currPos = stack.pop();
            ip++;
            break;

          case 8:
            stack.length -= bc[ip + 1];
            ip += 2;
            break;

          case 9:
            stack.splice(-2, 1);
            ip++;
            break;

          case 10:
            stack[stack.length - 2].push(stack.pop());
            ip++;
            break;

          case 11:
            stack.push(stack.splice(stack.length - bc[ip + 1], bc[ip + 1]));
            ip += 2;
            break;

          case 12:
            stack.push(input.substring(stack.pop(), peg$currPos));
            ip++;
            break;

          case 13:
            ends.push(end);
            ips.push(ip + 3 + bc[ip + 1] + bc[ip + 2]);

            if (stack[stack.length - 1]) {
              end = ip + 3 + bc[ip + 1];
              ip += 3;
            } else {
              end = ip + 3 + bc[ip + 1] + bc[ip + 2];
              ip += 3 + bc[ip + 1];
            }

            break;

          case 14:
            ends.push(end);
            ips.push(ip + 3 + bc[ip + 1] + bc[ip + 2]);

            if (stack[stack.length - 1] === peg$FAILED) {
              end = ip + 3 + bc[ip + 1];
              ip += 3;
            } else {
              end = ip + 3 + bc[ip + 1] + bc[ip + 2];
              ip += 3 + bc[ip + 1];
            }

            break;

          case 15:
            ends.push(end);
            ips.push(ip + 3 + bc[ip + 1] + bc[ip + 2]);

            if (stack[stack.length - 1] !== peg$FAILED) {
              end = ip + 3 + bc[ip + 1];
              ip += 3;
            } else {
              end = ip + 3 + bc[ip + 1] + bc[ip + 2];
              ip += 3 + bc[ip + 1];
            }

            break;

          case 16:
            if (stack[stack.length - 1] !== peg$FAILED) {
              ends.push(end);
              ips.push(ip);

              end = ip + 2 + bc[ip + 1];
              ip += 2;
            } else {
              ip += 2 + bc[ip + 1];
            }

            break;

          case 17:
            ends.push(end);
            ips.push(ip + 3 + bc[ip + 1] + bc[ip + 2]);

            if (input.length > peg$currPos) {
              end = ip + 3 + bc[ip + 1];
              ip += 3;
            } else {
              end = ip + 3 + bc[ip + 1] + bc[ip + 2];
              ip += 3 + bc[ip + 1];
            }

            break;

          case 18:
            ends.push(end);
            ips.push(ip + 4 + bc[ip + 2] + bc[ip + 3]);

            if (input.substr(peg$currPos, peg$consts[bc[ip + 1]].length) === peg$consts[bc[ip + 1]]) {
              end = ip + 4 + bc[ip + 2];
              ip += 4;
            } else {
              end = ip + 4 + bc[ip + 2] + bc[ip + 3];
              ip += 4 + bc[ip + 2];
            }

            break;

          case 19:
            ends.push(end);
            ips.push(ip + 4 + bc[ip + 2] + bc[ip + 3]);

            if (input.substr(peg$currPos, peg$consts[bc[ip + 1]].length).toLowerCase() === peg$consts[bc[ip + 1]]) {
              end = ip + 4 + bc[ip + 2];
              ip += 4;
            } else {
              end = ip + 4 + bc[ip + 2] + bc[ip + 3];
              ip += 4 + bc[ip + 2];
            }

            break;

          case 20:
            ends.push(end);
            ips.push(ip + 4 + bc[ip + 2] + bc[ip + 3]);

            if (peg$consts[bc[ip + 1]].test(input.charAt(peg$currPos))) {
              end = ip + 4 + bc[ip + 2];
              ip += 4;
            } else {
              end = ip + 4 + bc[ip + 2] + bc[ip + 3];
              ip += 4 + bc[ip + 2];
            }

            break;

          case 21:
            stack.push(input.substr(peg$currPos, bc[ip + 1]));
            peg$currPos += bc[ip + 1];
            ip += 2;
            break;

          case 22:
            stack.push(peg$consts[bc[ip + 1]]);
            peg$currPos += peg$consts[bc[ip + 1]].length;
            ip += 2;
            break;

          case 23:
            stack.push(peg$FAILED);
            if (peg$silentFails === 0) {
              peg$fail(peg$consts[bc[ip + 1]]);
            }
            ip += 2;
            break;

          case 24:
            peg$savedPos = stack[stack.length - 1 - bc[ip + 1]];
            ip += 2;
            break;

          case 25:
            peg$savedPos = peg$currPos;
            ip++;
            break;

          case 26:
            params = bc.slice(ip + 4, ip + 4 + bc[ip + 3]);
            for (i = 0; i < bc[ip + 3]; i++) {
              params[i] = stack[stack.length - 1 - params[i]];
            }

            stack.splice(
              stack.length - bc[ip + 2],
              bc[ip + 2],
              peg$consts[bc[ip + 1]].apply(null, params)
            );

            ip += 4 + bc[ip + 3];
            break;

          case 27:
            stack.push(peg$parseRule(bc[ip + 1]));
            ip += 2;
            break;

          case 28:
            peg$silentFails++;
            ip++;
            break;

          case 29:
            peg$silentFails--;
            ip++;
            break;

          default:
            throw new Error("Invalid opcode: " + bc[ip] + ".");
        }
      }

      if (ends.length > 0) {
        end = ends.pop();
        ip = ips.pop();
      } else {
        break;
      }
    }

    return stack[0];
  }


    options.data = {}; // Object to which header attributes will be assigned during parsing

    function list (head, tail) {
      return [head].concat(tail);
    }


  peg$result = peg$parseRule(peg$startRuleIndex);

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

module.exports = {
  SyntaxError: peg$SyntaxError,
  parse:       peg$parse
};


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

"use strict";
/**
 * @name SIP
 * @namespace
 */

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


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

"use strict";
/* WEBPACK VAR INJECTION */(function(global) {
/**
 * @fileoverview Simple
 */
/* Simple
 * @class Simple
 */
module.exports = function (SIP) {
    var C = {
        STATUS_NULL: 0,
        STATUS_NEW: 1,
        STATUS_CONNECTING: 2,
        STATUS_CONNECTED: 3,
        STATUS_COMPLETED: 4
    };
    /*
     * @param {Object} options
     */
    var Simple = function (options) {
        /*
         *  {
         *    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 = [SIP.Web.Modifiers.stripG722];
        }
        if (isFirefox) {
            sessionDescriptionHandlerFactoryOptions.alwaysAcquireMediaFirst = true;
        }
        if (!this.options.ua.uri) {
            this.anonymous = true;
        }
        this.ua = new SIP.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 = C.STATUS_NULL;
        this.logger = this.ua.getLogger('sip.simple');
        this.ua.on('registered', function () {
            this.emit('registered', this.ua);
        }.bind(this));
        this.ua.on('unregistered', function () {
            this.emit('unregistered', this.ua);
        }.bind(this));
        this.ua.on('failed', function () {
            this.emit('unregistered', this.ua);
        }.bind(this));
        this.ua.on('invite', function (session) {
            // If there is already an active session reject the incoming session
            if (this.state !== C.STATUS_NULL && this.state !== C.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);
        }.bind(this));
        this.ua.on('message', function (message) {
            this.emit('message', message);
        }.bind(this));
        return this;
    };
    Simple.prototype = Object.create(SIP.EventEmitter.prototype);
    Simple.C = C;
    // Public
    Simple.prototype.call = function (destination) {
        if (!this.ua || !this.checkRegistration()) {
            this.logger.warn('A registered UA is required for calling');
            return;
        }
        if (this.state !== C.STATUS_NULL && this.state !== C.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 !== C.STATUS_NEW && this.state !== C.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 !== C.STATUS_NEW && this.state !== C.STATUS_CONNECTING) {
            this.logger.warn('Call is already answered');
            return;
        }
        return this.session.reject();
    };
    Simple.prototype.hangup = function () {
        if (this.state !== C.STATUS_CONNECTED && this.state !== C.STATUS_CONNECTING && this.state !== C.STATUS_NEW) {
            this.logger.warn('No active call to hang up on');
            return;
        }
        if (this.state !== C.STATUS_CONNECTED) {
            return this.session.cancel();
        }
        else {
            return this.session.bye();
        }
    };
    Simple.prototype.hold = function () {
        if (this.state !== C.STATUS_CONNECTED || this.session.local_hold) {
            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 !== C.STATUS_CONNECTED || !this.session.local_hold) {
            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 !== C.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 !== C.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 !== C.STATUS_CONNECTED) {
            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 () {
        // 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');
            }.bind(this));
        }
        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');
            }.bind(this));
        }
    };
    Simple.prototype.setupLocalMedia = function () {
        if (this.video && this.options.media.local && this.options.media.local.video) {
            var pc = this.session.sessionDescriptionHandler.peerConnection;
            var localStream;
            if (pc.getSenders) {
                localStream = new global.window.MediaStream();
                pc.getSenders().forEach(function (sender) {
                    var track = sender.track;
                    if (track && track.kind === 'video') {
                        localStream.addTrack(track);
                    }
                });
            }
            else {
                localStream = pc.getLocalStreams()[0];
            }
            this.options.media.local.video.srcObject = localStream;
            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 () {
        this.state = C.STATUS_NEW;
        this.emit('new', this.session);
        this.session.on('progress', this.onProgress.bind(this));
        this.session.on('accepted', this.onAccepted.bind(this));
        this.session.on('rejected', this.onEnded.bind(this));
        this.session.on('failed', this.onFailed.bind(this));
        this.session.on('terminated', this.onEnded.bind(this));
    };
    Simple.prototype.destroyMedia = function () {
        this.session.sessionDescriptionHandler.close();
    };
    Simple.prototype.toggleMute = function (mute) {
        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 () {
        this.state = C.STATUS_CONNECTED;
        this.emit('connected', this.session);
        this.setupLocalMedia();
        this.setupRemoteMedia();
        this.session.sessionDescriptionHandler.on('addTrack', function () {
            this.logger.log('A track has been added, triggering new remoteMedia setup');
            this.setupRemoteMedia();
        }.bind(this));
        this.session.sessionDescriptionHandler.on('addStream', function () {
            this.logger.log('A stream has been added, trigger new remoteMedia setup');
            this.setupRemoteMedia();
        }.bind(this));
        this.session.on('hold', function () {
            this.emit('hold', this.session);
        }.bind(this));
        this.session.on('unhold', function () {
            this.emit('unhold', this.session);
        }.bind(this));
        this.session.on('dtmf', function (tone) {
            this.emit('dtmf', tone);
        }.bind(this));
        this.session.on('bye', this.onEnded.bind(this));
    };
    Simple.prototype.onProgress = function () {
        this.state = C.STATUS_CONNECTING;
        this.emit('connecting', this.session);
    };
    Simple.prototype.onFailed = function () {
        this.onEnded();
    };
    Simple.prototype.onEnded = function () {
        this.state = C.STATUS_COMPLETED;
        this.emit('ended', this.session);
        this.cleanupMedia();
    };
    return Simple;
};

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

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

"use strict";
/* WEBPACK VAR INJECTION */(function(global) {
var toplevel = global.window || global;
function getPrefixedProperty(object, name) {
    if (object == null) {
        return;
    }
    var capitalizedName = name.charAt(0).toUpperCase() + name.slice(1);
    var prefixedNames = [name, 'webkit' + capitalizedName, 'moz' + capitalizedName];
    for (var i in prefixedNames) {
        var property = object[prefixedNames[i]];
        if (property) {
            return property.bind(object);
        }
    }
}
module.exports = {
    WebSocket: toplevel.WebSocket,
    Transport: __webpack_require__(10),
    open: toplevel.open,
    Promise: toplevel.Promise,
    timers: toplevel,
    // Console is not defined in ECMAScript, so just in case...
    console: toplevel.console || {
        debug: function () { },
        log: function () { },
        warn: function () { },
        error: function () { }
    },
    addEventListener: getPrefixedProperty(toplevel, 'addEventListener'),
    removeEventListener: getPrefixedProperty(toplevel, 'removeEventListener')
};

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

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