Browse code

Created repository.

DoubleBastionAdmin authored on 26/01/2022 20:32:42
Showing 1 changed files
1 1
new file mode 100644
... ...
@@ -0,0 +1,12394 @@
1
+/**
2
+ *  Copyright (C) 2021  Double Bastion LLC
3
+ *
4
+ *  This file is part of Roundpin, which is licensed under the
5
+ *  GNU Affero General Public License Version 3.0. The license terms
6
+ *  are detailed in the "LICENSE.txt" file located in the root directory.
7
+ *
8
+ *  The file content from below is identical with that of the
9
+ *  original file "sip-0.11.6.js". The copyright notice for
10
+ *  the original content follows:
11
+
12
+/*!
13
+ * 
14
+ *  SIP version 0.11.6
15
+ *  Copyright (c) 2014-2018 Junction Networks, Inc <http://www.onsip.com>
16
+ *  Homepage: https://sipjs.com
17
+ *  License: https://sipjs.com/license/
18
+ * 
19
+ * 
20
+ *  ~~~SIP.js contains substantial portions of JsSIP under the following license~~~
21
+ *  Homepage: http://jssip.net
22
+ *  Copyright (c) 2012-2013 José Luis Millán - Versatica <http://www.versatica.com>
23
+ * 
24
+ *  Permission is hereby granted, free of charge, to any person obtaining
25
+ *  a copy of this software and associated documentation files (the
26
+ *  "Software"), to deal in the Software without restriction, including
27
+ *  without limitation the rights to use, copy, modify, merge, publish,
28
+ *  distribute, sublicense, and/or sell copies of the Software, and to
29
+ *  permit persons to whom the Software is furnished to do so, subject to
30
+ *  the following conditions:
31
+ * 
32
+ *  The above copyright notice and this permission notice shall be
33
+ *  included in all copies or substantial portions of the Software.
34
+ * 
35
+ *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
36
+ *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
37
+ *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
38
+ *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
39
+ *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
40
+ *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
41
+ *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
42
+ * 
43
+ *  ~~~ end JsSIP license ~~~
44
+ * 
45
+ * 
46
+ * 
47
+ * 
48
+ */
49
+(function webpackUniversalModuleDefinition(root, factory) {
50
+	if(typeof exports === 'object' && typeof module === 'object')
51
+		module.exports = factory();
52
+	else if(typeof define === 'function' && define.amd)
53
+		define([], factory);
54
+	else if(typeof exports === 'object')
55
+		exports["SIP"] = factory();
56
+	else
57
+		root["SIP"] = factory();
58
+})(this, function() {
59
+return /******/ (function(modules) { // webpackBootstrap
60
+/******/ 	// The module cache
61
+/******/ 	var installedModules = {};
62
+/******/
63
+/******/ 	// The require function
64
+/******/ 	function __webpack_require__(moduleId) {
65
+/******/
66
+/******/ 		// Check if module is in cache
67
+/******/ 		if(installedModules[moduleId]) {
68
+/******/ 			return installedModules[moduleId].exports;
69
+/******/ 		}
70
+/******/ 		// Create a new module (and put it into the cache)
71
+/******/ 		var module = installedModules[moduleId] = {
72
+/******/ 			i: moduleId,
73
+/******/ 			l: false,
74
+/******/ 			exports: {}
75
+/******/ 		};
76
+/******/
77
+/******/ 		// Execute the module function
78
+/******/ 		modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
79
+/******/
80
+/******/ 		// Flag the module as loaded
81
+/******/ 		module.l = true;
82
+/******/
83
+/******/ 		// Return the exports of the module
84
+/******/ 		return module.exports;
85
+/******/ 	}
86
+/******/
87
+/******/
88
+/******/ 	// expose the modules object (__webpack_modules__)
89
+/******/ 	__webpack_require__.m = modules;
90
+/******/
91
+/******/ 	// expose the module cache
92
+/******/ 	__webpack_require__.c = installedModules;
93
+/******/
94
+/******/ 	// define getter function for harmony exports
95
+/******/ 	__webpack_require__.d = function(exports, name, getter) {
96
+/******/ 		if(!__webpack_require__.o(exports, name)) {
97
+/******/ 			Object.defineProperty(exports, name, { enumerable: true, get: getter });
98
+/******/ 		}
99
+/******/ 	};
100
+/******/
101
+/******/ 	// define __esModule on exports
102
+/******/ 	__webpack_require__.r = function(exports) {
103
+/******/ 		if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
104
+/******/ 			Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
105
+/******/ 		}
106
+/******/ 		Object.defineProperty(exports, '__esModule', { value: true });
107
+/******/ 	};
108
+/******/
109
+/******/ 	// create a fake namespace object
110
+/******/ 	// mode & 1: value is a module id, require it
111
+/******/ 	// mode & 2: merge all properties of value into the ns
112
+/******/ 	// mode & 4: return value when already ns object
113
+/******/ 	// mode & 8|1: behave like require
114
+/******/ 	__webpack_require__.t = function(value, mode) {
115
+/******/ 		if(mode & 1) value = __webpack_require__(value);
116
+/******/ 		if(mode & 8) return value;
117
+/******/ 		if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
118
+/******/ 		var ns = Object.create(null);
119
+/******/ 		__webpack_require__.r(ns);
120
+/******/ 		Object.defineProperty(ns, 'default', { enumerable: true, value: value });
121
+/******/ 		if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
122
+/******/ 		return ns;
123
+/******/ 	};
124
+/******/
125
+/******/ 	// getDefaultExport function for compatibility with non-harmony modules
126
+/******/ 	__webpack_require__.n = function(module) {
127
+/******/ 		var getter = module && module.__esModule ?
128
+/******/ 			function getDefault() { return module['default']; } :
129
+/******/ 			function getModuleExports() { return module; };
130
+/******/ 		__webpack_require__.d(getter, 'a', getter);
131
+/******/ 		return getter;
132
+/******/ 	};
133
+/******/
134
+/******/ 	// Object.prototype.hasOwnProperty.call
135
+/******/ 	__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
136
+/******/
137
+/******/ 	// __webpack_public_path__
138
+/******/ 	__webpack_require__.p = "";
139
+/******/
140
+/******/
141
+/******/ 	// Load entry module and return exports
142
+/******/ 	return __webpack_require__(__webpack_require__.s = 0);
143
+/******/ })
144
+/************************************************************************/
145
+/******/ ([
146
+/* 0 */
147
+/***/ (function(module, exports, __webpack_require__) {
148
+
149
+"use strict";
150
+
151
+module.exports = __webpack_require__(1)(__webpack_require__(40));
152
+
153
+
154
+/***/ }),
155
+/* 1 */
156
+/***/ (function(module, exports, __webpack_require__) {
157
+
158
+"use strict";
159
+/**
160
+ * @name SIP
161
+ * @namespace
162
+ */
163
+
164
+module.exports = function (environment) {
165
+    var pkg = __webpack_require__(2), version = pkg.version, title = pkg.title;
166
+    var SIP = Object.defineProperties({}, {
167
+        version: {
168
+            get: function () { return version; }
169
+        },
170
+        name: {
171
+            get: function () { return title; }
172
+        }
173
+    });
174
+    __webpack_require__(3)(SIP, environment);
175
+    SIP.LoggerFactory = __webpack_require__(4)(environment.console);
176
+    SIP.EventEmitter = __webpack_require__(5)();
177
+    SIP.C = __webpack_require__(7)(SIP.name, SIP.version);
178
+    SIP.Exceptions = __webpack_require__(8);
179
+    SIP.Timers = __webpack_require__(9)(environment.timers);
180
+    SIP.Transport = __webpack_require__(10)(SIP);
181
+    __webpack_require__(11)(SIP);
182
+    __webpack_require__(12)(SIP);
183
+    __webpack_require__(13)(SIP);
184
+    __webpack_require__(14)(SIP);
185
+    __webpack_require__(15)(SIP);
186
+    __webpack_require__(16)(SIP);
187
+    __webpack_require__(18)(SIP);
188
+    __webpack_require__(19)(SIP);
189
+    SIP.SessionDescriptionHandler = __webpack_require__(20)(SIP.EventEmitter);
190
+    __webpack_require__(21)(SIP);
191
+    __webpack_require__(22)(SIP);
192
+    __webpack_require__(23)(SIP);
193
+    __webpack_require__(25)(SIP);
194
+    __webpack_require__(26)(SIP);
195
+    __webpack_require__(27)(SIP, environment);
196
+    __webpack_require__(32)(SIP);
197
+    SIP.DigestAuthentication = __webpack_require__(33)(SIP.Utils);
198
+    SIP.Grammar = __webpack_require__(36)(SIP);
199
+    SIP.Web = {
200
+        Modifiers: __webpack_require__(38)(SIP),
201
+        Simple: __webpack_require__(39)(SIP)
202
+    };
203
+    return SIP;
204
+};
205
+
206
+
207
+/***/ }),
208
+/* 2 */
209
+/***/ (function(module) {
210
+
211
+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"}};
212
+
213
+/***/ }),
214
+/* 3 */
215
+/***/ (function(module, exports, __webpack_require__) {
216
+
217
+"use strict";
218
+
219
+/**
220
+ * @fileoverview Utils
221
+ */
222
+module.exports = function (SIP, environment) {
223
+    var Utils;
224
+    Utils = {
225
+        Promise: environment.Promise,
226
+        defer: function defer() {
227
+            var deferred = {};
228
+            deferred.promise = new Utils.Promise(function (resolve, reject) {
229
+                deferred.resolve = resolve;
230
+                deferred.reject = reject;
231
+            });
232
+            return deferred;
233
+        },
234
+        reducePromises: function reducePromises(arr, val) {
235
+            return arr.reduce(function (acc, fn) {
236
+                acc = acc.then(fn);
237
+                return acc;
238
+            }, SIP.Utils.Promise.resolve(val));
239
+        },
240
+        augment: function (object, constructor, args, override) {
241
+            var idx, proto;
242
+            // Add public properties from constructor's prototype onto object
243
+            proto = constructor.prototype;
244
+            for (idx in proto) {
245
+                if (override || object[idx] === undefined) {
246
+                    object[idx] = proto[idx];
247
+                }
248
+            }
249
+            // Construct the object as though it were just created by constructor
250
+            constructor.apply(object, args);
251
+        },
252
+        defaultOptions: function (defaultOptions, overridingOptions) {
253
+            defaultOptions = defaultOptions || {};
254
+            overridingOptions = overridingOptions || {};
255
+            return Object.assign({}, defaultOptions, overridingOptions);
256
+        },
257
+        optionsOverride: function (options, winner, loser, isDeprecated, logger, defaultValue) {
258
+            if (isDeprecated && options[loser]) {
259
+                logger.warn(loser + ' is deprecated, please use ' + winner + ' instead');
260
+            }
261
+            if (options[winner] && options[loser]) {
262
+                logger.warn(winner + ' overriding ' + loser);
263
+            }
264
+            options[winner] = options[winner] || options[loser] || defaultValue;
265
+        },
266
+        str_utf8_length: function (string) {
267
+            return encodeURIComponent(string).replace(/%[A-F\d]{2}/g, 'U').length;
268
+        },
269
+        generateFakeSDP: function (body) {
270
+            if (!body) {
271
+                return;
272
+            }
273
+            var start = body.indexOf('o=');
274
+            var end = body.indexOf('\r\n', start);
275
+            return 'v=0\r\n' + body.slice(start, end) + '\r\ns=-\r\nt=0 0\r\nc=IN IP4 0.0.0.0';
276
+        },
277
+        isFunction: function (fn) {
278
+            if (fn !== undefined) {
279
+                return Object.prototype.toString.call(fn) === '[object Function]';
280
+            }
281
+            else {
282
+                return false;
283
+            }
284
+        },
285
+        isDecimal: function (num) {
286
+            return !isNaN(num) && (parseFloat(num) === parseInt(num, 10));
287
+        },
288
+        createRandomToken: function (size, base) {
289
+            var i, r, token = '';
290
+            base = base || 32;
291
+            for (i = 0; i < size; i++) {
292
+                r = Math.random() * base | 0;
293
+                token += r.toString(base);
294
+            }
295
+            return token;
296
+        },
297
+        newTag: function () {
298
+            return SIP.Utils.createRandomToken(SIP.UA.C.TAG_LENGTH);
299
+        },
300
+        // http://stackoverflow.com/users/109538/broofa
301
+        newUUID: function () {
302
+            var UUID = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
303
+                var r = Math.random() * 16 | 0, v = c === 'x' ? r : (r & 0x3 | 0x8);
304
+                return v.toString(16);
305
+            });
306
+            return UUID;
307
+        },
308
+        hostType: function (host) {
309
+            if (!host) {
310
+                return;
311
+            }
312
+            else {
313
+                host = SIP.Grammar.parse(host, 'host');
314
+                if (host !== -1) {
315
+                    return host.host_type;
316
+                }
317
+            }
318
+        },
319
+        /**
320
+        * Normalize SIP URI.
321
+        * NOTE: It does not allow a SIP URI without username.
322
+        * Accepts 'sip', 'sips' and 'tel' URIs and convert them into 'sip'.
323
+        * Detects the domain part (if given) and properly hex-escapes the user portion.
324
+        * If the user portion has only 'tel' number symbols the user portion is clean of 'tel' visual separators.
325
+        * @private
326
+        * @param {String} target
327
+        * @param {String} [domain]
328
+        */
329
+        normalizeTarget: function (target, domain) {
330
+            var uri, target_array, target_user, target_domain;
331
+            // If no target is given then raise an error.
332
+            if (!target) {
333
+                return;
334
+                // If a SIP.URI instance is given then return it.
335
+            }
336
+            else if (target instanceof SIP.URI) {
337
+                return target;
338
+                // If a string is given split it by '@':
339
+                // - Last fragment is the desired domain.
340
+                // - Otherwise append the given domain argument.
341
+            }
342
+            else if (typeof target === 'string') {
343
+                target_array = target.split('@');
344
+                switch (target_array.length) {
345
+                    case 1:
346
+                        if (!domain) {
347
+                            return;
348
+                        }
349
+                        target_user = target;
350
+                        target_domain = domain;
351
+                        break;
352
+                    case 2:
353
+                        target_user = target_array[0];
354
+                        target_domain = target_array[1];
355
+                        break;
356
+                    default:
357
+                        target_user = target_array.slice(0, target_array.length - 1).join('@');
358
+                        target_domain = target_array[target_array.length - 1];
359
+                }
360
+                // Remove the URI scheme (if present).
361
+                target_user = target_user.replace(/^(sips?|tel):/i, '');
362
+                // Remove 'tel' visual separators if the user portion just contains 'tel' number symbols.
363
+                if (/^[\-\.\(\)]*\+?[0-9\-\.\(\)]+$/.test(target_user)) {
364
+                    target_user = target_user.replace(/[\-\.\(\)]/g, '');
365
+                }
366
+                // Build the complete SIP URI.
367
+                target = SIP.C.SIP + ':' + SIP.Utils.escapeUser(target_user) + '@' + target_domain;
368
+                // Finally parse the resulting URI.
369
+                uri = SIP.URI.parse(target);
370
+                return uri;
371
+            }
372
+            else {
373
+                return;
374
+            }
375
+        },
376
+        /**
377
+        * Hex-escape a SIP URI user.
378
+        * @private
379
+        * @param {String} user
380
+        */
381
+        escapeUser: function (user) {
382
+            // Don't hex-escape ':' (%3A), '+' (%2B), '?' (%3F"), '/' (%2F).
383
+            return encodeURIComponent(decodeURIComponent(user)).replace(/%3A/ig, ':').replace(/%2B/ig, '+').replace(/%3F/ig, '?').replace(/%2F/ig, '/');
384
+        },
385
+        headerize: function (string) {
386
+            var exceptions = {
387
+                'Call-Id': 'Call-ID',
388
+                'Cseq': 'CSeq',
389
+                'Min-Se': 'Min-SE',
390
+                'Rack': 'RAck',
391
+                'Rseq': 'RSeq',
392
+                'Www-Authenticate': 'WWW-Authenticate'
393
+            }, name = string.toLowerCase().replace(/_/g, '-').split('-'), hname = '', parts = name.length, part;
394
+            for (part = 0; part < parts; part++) {
395
+                if (part !== 0) {
396
+                    hname += '-';
397
+                }
398
+                hname += name[part].charAt(0).toUpperCase() + name[part].substring(1);
399
+            }
400
+            if (exceptions[hname]) {
401
+                hname = exceptions[hname];
402
+            }
403
+            return hname;
404
+        },
405
+        sipErrorCause: function (status_code) {
406
+            var cause;
407
+            for (cause in SIP.C.SIP_ERROR_CAUSES) {
408
+                if (SIP.C.SIP_ERROR_CAUSES[cause].indexOf(status_code) !== -1) {
409
+                    return SIP.C.causes[cause];
410
+                }
411
+            }
412
+            return SIP.C.causes.SIP_FAILURE_CODE;
413
+        },
414
+        getReasonPhrase: function getReasonPhrase(code, specific) {
415
+            return specific || SIP.C.REASON_PHRASE[code] || '';
416
+        },
417
+        getReasonHeaderValue: function getReasonHeaderValue(code, reason) {
418
+            reason = SIP.Utils.getReasonPhrase(code, reason);
419
+            return 'SIP;cause=' + code + ';text="' + reason + '"';
420
+        },
421
+        getCancelReason: function getCancelReason(code, reason) {
422
+            if (code && code < 200 || code > 699) {
423
+                throw new TypeError('Invalid status_code: ' + code);
424
+            }
425
+            else if (code) {
426
+                return SIP.Utils.getReasonHeaderValue(code, reason);
427
+            }
428
+        },
429
+        buildStatusLine: function buildStatusLine(code, reason) {
430
+            code = code || null;
431
+            reason = reason || null;
432
+            // Validate code and reason values
433
+            if (!code || (code < 100 || code > 699)) {
434
+                throw new TypeError('Invalid status_code: ' + code);
435
+            }
436
+            else if (reason && typeof reason !== 'string' && !(reason instanceof String)) {
437
+                throw new TypeError('Invalid reason_phrase: ' + reason);
438
+            }
439
+            reason = Utils.getReasonPhrase(code, reason);
440
+            return 'SIP/2.0 ' + code + ' ' + reason + '\r\n';
441
+        },
442
+        /**
443
+        * Generate a random Test-Net IP (http://tools.ietf.org/html/rfc5735)
444
+        * @private
445
+        */
446
+        getRandomTestNetIP: function () {
447
+            function getOctet(from, to) {
448
+                return Math.floor(Math.random() * (to - from + 1) + from);
449
+            }
450
+            return '192.0.2.' + getOctet(1, 254);
451
+        }
452
+    };
453
+    SIP.Utils = Utils;
454
+};
455
+
456
+
457
+/***/ }),
458
+/* 4 */
459
+/***/ (function(module, exports, __webpack_require__) {
460
+
461
+"use strict";
462
+
463
+var levels = {
464
+    'error': 0,
465
+    'warn': 1,
466
+    'log': 2,
467
+    'debug': 3
468
+};
469
+module.exports = function (console) {
470
+    var LoggerFactory = function () {
471
+        var logger, level = 2, builtinEnabled = true, connector = null;
472
+        this.loggers = {};
473
+        logger = this.getLogger('sip.loggerfactory');
474
+        Object.defineProperties(this, {
475
+            builtinEnabled: {
476
+                get: function () { return builtinEnabled; },
477
+                set: function (value) {
478
+                    if (typeof value === 'boolean') {
479
+                        builtinEnabled = value;
480
+                    }
481
+                    else {
482
+                        logger.error('invalid "builtinEnabled" parameter value: ' + JSON.stringify(value));
483
+                    }
484
+                }
485
+            },
486
+            level: {
487
+                get: function () { return level; },
488
+                set: function (value) {
489
+                    if (value >= 0 && value <= 3) {
490
+                        level = value;
491
+                    }
492
+                    else if (value > 3) {
493
+                        level = 3;
494
+                    }
495
+                    else if (levels.hasOwnProperty(value)) {
496
+                        level = levels[value];
497
+                    }
498
+                    else {
499
+                        logger.error('invalid "level" parameter value: ' + JSON.stringify(value));
500
+                    }
501
+                }
502
+            },
503
+            connector: {
504
+                get: function () { return connector; },
505
+                set: function (value) {
506
+                    if (value === null || value === "" || value === undefined) {
507
+                        connector = null;
508
+                    }
509
+                    else if (typeof value === 'function') {
510
+                        connector = value;
511
+                    }
512
+                    else {
513
+                        logger.error('invalid "connector" parameter value: ' + JSON.stringify(value));
514
+                    }
515
+                }
516
+            }
517
+        });
518
+    };
519
+    LoggerFactory.prototype.print = function (target, category, label, content) {
520
+        if (typeof content === 'string') {
521
+            var prefix = [new Date(), category];
522
+            if (label) {
523
+                prefix.push(label);
524
+            }
525
+            content = prefix.concat(content).join(' | ');
526
+        }
527
+        target.call(console, content);
528
+    };
529
+    function Logger(logger, category, label) {
530
+        this.logger = logger;
531
+        this.category = category;
532
+        this.label = label;
533
+    }
534
+    Object.keys(levels).forEach(function (targetName) {
535
+        Logger.prototype[targetName] = function (content) {
536
+            this.logger[targetName](this.category, this.label, content);
537
+        };
538
+        LoggerFactory.prototype[targetName] = function (category, label, content) {
539
+            if (this.level >= levels[targetName]) {
540
+                if (this.builtinEnabled) {
541
+                    this.print(console[targetName], category, label, content);
542
+                }
543
+                if (this.connector) {
544
+                    this.connector(targetName, category, label, content);
545
+                }
546
+            }
547
+        };
548
+    });
549
+    LoggerFactory.prototype.getLogger = function (category, label) {
550
+        var logger;
551
+        if (label && this.level === 3) {
552
+            return new Logger(this, category, label);
553
+        }
554
+        else if (this.loggers[category]) {
555
+            return this.loggers[category];
556
+        }
557
+        else {
558
+            logger = new Logger(this, category);
559
+            this.loggers[category] = logger;
560
+            return logger;
561
+        }
562
+    };
563
+    return LoggerFactory;
564
+};
565
+
566
+
567
+/***/ }),
568
+/* 5 */
569
+/***/ (function(module, exports, __webpack_require__) {
570
+
571
+"use strict";
572
+
573
+var NodeEventEmitter = __webpack_require__(6).EventEmitter;
574
+module.exports = function () {
575
+    // Don't use `new SIP.EventEmitter()` for inheriting.
576
+    // Use Object.create(SIP.EventEmitter.prototoype);
577
+    function EventEmitter() {
578
+        NodeEventEmitter.call(this);
579
+    }
580
+    EventEmitter.prototype = Object.create(NodeEventEmitter.prototype, {
581
+        constructor: {
582
+            value: EventEmitter,
583
+            enumerable: false,
584
+            writable: true,
585
+            configurable: true
586
+        }
587
+    });
588
+    return EventEmitter;
589
+};
590
+
591
+
592
+/***/ }),
593
+/* 6 */
594
+/***/ (function(module, exports) {
595
+
596
+// Copyright Joyent, Inc. and other Node contributors.
597
+//
598
+// Permission is hereby granted, free of charge, to any person obtaining a
599
+// copy of this software and associated documentation files (the
600
+// "Software"), to deal in the Software without restriction, including
601
+// without limitation the rights to use, copy, modify, merge, publish,
602
+// distribute, sublicense, and/or sell copies of the Software, and to permit
603
+// persons to whom the Software is furnished to do so, subject to the
604
+// following conditions:
605
+//
606
+// The above copyright notice and this permission notice shall be included
607
+// in all copies or substantial portions of the Software.
608
+//
609
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
610
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
611
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
612
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
613
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
614
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
615
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
616
+
617
+function EventEmitter() {
618
+  this._events = this._events || {};
619
+  this._maxListeners = this._maxListeners || undefined;
620
+}
621
+module.exports = EventEmitter;
622
+
623
+// Backwards-compat with node 0.10.x
624
+EventEmitter.EventEmitter = EventEmitter;
625
+
626
+EventEmitter.prototype._events = undefined;
627
+EventEmitter.prototype._maxListeners = undefined;
628
+
629
+// By default EventEmitters will print a warning if more than 10 listeners are
630
+// added to it. This is a useful default which helps finding memory leaks.
631
+EventEmitter.defaultMaxListeners = 10;
632
+
633
+// Obviously not all Emitters should be limited to 10. This function allows
634
+// that to be increased. Set to zero for unlimited.
635
+EventEmitter.prototype.setMaxListeners = function(n) {
636
+  if (!isNumber(n) || n < 0 || isNaN(n))
637
+    throw TypeError('n must be a positive number');
638
+  this._maxListeners = n;
639
+  return this;
640
+};
641
+
642
+EventEmitter.prototype.emit = function(type) {
643
+  var er, handler, len, args, i, listeners;
644
+
645
+  if (!this._events)
646
+    this._events = {};
647
+
648
+  // If there is no 'error' event listener then throw.
649
+  if (type === 'error') {
650
+    if (!this._events.error ||
651
+        (isObject(this._events.error) && !this._events.error.length)) {
652
+      er = arguments[1];
653
+      if (er instanceof Error) {
654
+        throw er; // Unhandled 'error' event
655
+      } else {
656
+        // At least give some kind of context to the user
657
+        var err = new Error('Uncaught, unspecified "error" event. (' + er + ')');
658
+        err.context = er;
659
+        throw err;
660
+      }
661
+    }
662
+  }
663
+
664
+  handler = this._events[type];
665
+
666
+  if (isUndefined(handler))
667
+    return false;
668
+
669
+  if (isFunction(handler)) {
670
+    switch (arguments.length) {
671
+      // fast cases
672
+      case 1:
673
+        handler.call(this);
674
+        break;
675
+      case 2:
676
+        handler.call(this, arguments[1]);
677
+        break;
678
+      case 3:
679
+        handler.call(this, arguments[1], arguments[2]);
680
+        break;
681
+      // slower
682
+      default:
683
+        args = Array.prototype.slice.call(arguments, 1);
684
+        handler.apply(this, args);
685
+    }
686
+  } else if (isObject(handler)) {
687
+    args = Array.prototype.slice.call(arguments, 1);
688
+    listeners = handler.slice();
689
+    len = listeners.length;
690
+    for (i = 0; i < len; i++)
691
+      listeners[i].apply(this, args);
692
+  }
693
+
694
+  return true;
695
+};
696
+
697
+EventEmitter.prototype.addListener = function(type, listener) {
698
+  var m;
699
+
700
+  if (!isFunction(listener))
701
+    throw TypeError('listener must be a function');
702
+
703
+  if (!this._events)
704
+    this._events = {};
705
+
706
+  // To avoid recursion in the case that type === "newListener"! Before
707
+  // adding it to the listeners, first emit "newListener".
708
+  if (this._events.newListener)
709
+    this.emit('newListener', type,
710
+              isFunction(listener.listener) ?
711
+              listener.listener : listener);
712
+
713
+  if (!this._events[type])
714
+    // Optimize the case of one listener. Don't need the extra array object.
715
+    this._events[type] = listener;
716
+  else if (isObject(this._events[type]))
717
+    // If we've already got an array, just append.
718
+    this._events[type].push(listener);
719
+  else
720
+    // Adding the second element, need to change to array.
721
+    this._events[type] = [this._events[type], listener];
722
+
723
+  // Check for listener leak
724
+  if (isObject(this._events[type]) && !this._events[type].warned) {
725
+    if (!isUndefined(this._maxListeners)) {
726
+      m = this._maxListeners;
727
+    } else {
728
+      m = EventEmitter.defaultMaxListeners;
729
+    }
730
+
731
+    if (m && m > 0 && this._events[type].length > m) {
732
+      this._events[type].warned = true;
733
+      console.error('(node) warning: possible EventEmitter memory ' +
734
+                    'leak detected. %d listeners added. ' +
735
+                    'Use emitter.setMaxListeners() to increase limit.',
736
+                    this._events[type].length);
737
+      if (typeof console.trace === 'function') {
738
+        // not supported in IE 10
739
+        console.trace();
740
+      }
741
+    }
742
+  }
743
+
744
+  return this;
745
+};
746
+
747
+EventEmitter.prototype.on = EventEmitter.prototype.addListener;
748
+
749
+EventEmitter.prototype.once = function(type, listener) {
750
+  if (!isFunction(listener))
751
+    throw TypeError('listener must be a function');
752
+
753
+  var fired = false;
754
+
755
+  function g() {
756
+    this.removeListener(type, g);
757
+
758
+    if (!fired) {
759
+      fired = true;
760
+      listener.apply(this, arguments);
761
+    }
762
+  }
763
+
764
+  g.listener = listener;
765
+  this.on(type, g);
766
+
767
+  return this;
768
+};
769
+
770
+// emits a 'removeListener' event iff the listener was removed
771
+EventEmitter.prototype.removeListener = function(type, listener) {
772
+  var list, position, length, i;
773
+
774
+  if (!isFunction(listener))
775
+    throw TypeError('listener must be a function');
776
+
777
+  if (!this._events || !this._events[type])
778
+    return this;
779
+
780
+  list = this._events[type];
781
+  length = list.length;
782
+  position = -1;
783
+
784
+  if (list === listener ||
785
+      (isFunction(list.listener) && list.listener === listener)) {
786
+    delete this._events[type];
787
+    if (this._events.removeListener)
788
+      this.emit('removeListener', type, listener);
789
+
790
+  } else if (isObject(list)) {
791
+    for (i = length; i-- > 0;) {
792
+      if (list[i] === listener ||
793
+          (list[i].listener && list[i].listener === listener)) {
794
+        position = i;
795
+        break;
796
+      }
797
+    }
798
+
799
+    if (position < 0)
800
+      return this;
801
+
802
+    if (list.length === 1) {
803
+      list.length = 0;
804
+      delete this._events[type];
805
+    } else {
806
+      list.splice(position, 1);
807
+    }
808
+
809
+    if (this._events.removeListener)
810
+      this.emit('removeListener', type, listener);
811
+  }
812
+
813
+  return this;
814
+};
815
+
816
+EventEmitter.prototype.removeAllListeners = function(type) {
817
+  var key, listeners;
818
+
819
+  if (!this._events)
820
+    return this;
821
+
822
+  // not listening for removeListener, no need to emit
823
+  if (!this._events.removeListener) {
824
+    if (arguments.length === 0)
825
+      this._events = {};
826
+    else if (this._events[type])
827
+      delete this._events[type];
828
+    return this;
829
+  }
830
+
831
+  // emit removeListener for all listeners on all events
832
+  if (arguments.length === 0) {
833
+    for (key in this._events) {
834
+      if (key === 'removeListener') continue;
835
+      this.removeAllListeners(key);
836
+    }
837
+    this.removeAllListeners('removeListener');
838
+    this._events = {};
839
+    return this;
840
+  }
841
+
842
+  listeners = this._events[type];
843
+
844
+  if (isFunction(listeners)) {
845
+    this.removeListener(type, listeners);
846
+  } else if (listeners) {
847
+    // LIFO order
848
+    while (listeners.length)
849
+      this.removeListener(type, listeners[listeners.length - 1]);
850
+  }
851
+  delete this._events[type];
852
+
853
+  return this;
854
+};
855
+
856
+EventEmitter.prototype.listeners = function(type) {
857
+  var ret;
858
+  if (!this._events || !this._events[type])
859
+    ret = [];
860
+  else if (isFunction(this._events[type]))
861
+    ret = [this._events[type]];
862
+  else
863
+    ret = this._events[type].slice();
864
+  return ret;
865
+};
866
+
867
+EventEmitter.prototype.listenerCount = function(type) {
868
+  if (this._events) {
869
+    var evlistener = this._events[type];
870
+
871
+    if (isFunction(evlistener))
872
+      return 1;
873
+    else if (evlistener)
874
+      return evlistener.length;
875
+  }
876
+  return 0;
877
+};
878
+
879
+EventEmitter.listenerCount = function(emitter, type) {
880
+  return emitter.listenerCount(type);
881
+};
882
+
883
+function isFunction(arg) {
884
+  return typeof arg === 'function';
885
+}
886
+
887
+function isNumber(arg) {
888
+  return typeof arg === 'number';
889
+}
890
+
891
+function isObject(arg) {
892
+  return typeof arg === 'object' && arg !== null;
893
+}
894
+
895
+function isUndefined(arg) {
896
+  return arg === void 0;
897
+}
898
+
899
+
900
+/***/ }),
901
+/* 7 */
902
+/***/ (function(module, exports, __webpack_require__) {
903
+
904
+"use strict";
905
+
906
+/**
907
+ * @fileoverview SIP Constants
908
+ */
909
+/**
910
+ * SIP Constants.
911
+ * @augments SIP
912
+ */
913
+module.exports = function (name, version) {
914
+    return {
915
+        USER_AGENT: name + '/' + version,
916
+        // SIP scheme
917
+        SIP: 'sip',
918
+        SIPS: 'sips',
919
+        // End and Failure causes
920
+        causes: {
921
+            // Generic error causes
922
+            CONNECTION_ERROR: 'Connection Error',
923
+            REQUEST_TIMEOUT: 'Request Timeout',
924
+            SIP_FAILURE_CODE: 'SIP Failure Code',
925
+            INTERNAL_ERROR: 'Internal Error',
926
+            // SIP error causes
927
+            BUSY: 'Busy',
928
+            REJECTED: 'Rejected',
929
+            REDIRECTED: 'Redirected',
930
+            UNAVAILABLE: 'Unavailable',
931
+            NOT_FOUND: 'Not Found',
932
+            ADDRESS_INCOMPLETE: 'Address Incomplete',
933
+            INCOMPATIBLE_SDP: 'Incompatible SDP',
934
+            AUTHENTICATION_ERROR: 'Authentication Error',
935
+            DIALOG_ERROR: 'Dialog Error',
936
+            // Session error causes
937
+            WEBRTC_NOT_SUPPORTED: 'WebRTC Not Supported',
938
+            WEBRTC_ERROR: 'WebRTC Error',
939
+            CANCELED: 'Canceled',
940
+            NO_ANSWER: 'No Answer',
941
+            EXPIRES: 'Expires',
942
+            NO_ACK: 'No ACK',
943
+            NO_PRACK: 'No PRACK',
944
+            USER_DENIED_MEDIA_ACCESS: 'User Denied Media Access',
945
+            BAD_MEDIA_DESCRIPTION: 'Bad Media Description',
946
+            RTP_TIMEOUT: 'RTP Timeout'
947
+        },
948
+        supported: {
949
+            UNSUPPORTED: 'none',
950
+            SUPPORTED: 'supported',
951
+            REQUIRED: 'required'
952
+        },
953
+        SIP_ERROR_CAUSES: {
954
+            REDIRECTED: [300, 301, 302, 305, 380],
955
+            BUSY: [486, 600],
956
+            REJECTED: [403, 603],
957
+            NOT_FOUND: [404, 604],
958
+            UNAVAILABLE: [480, 410, 408, 430],
959
+            ADDRESS_INCOMPLETE: [484],
960
+            INCOMPATIBLE_SDP: [488, 606],
961
+            AUTHENTICATION_ERROR: [401, 407]
962
+        },
963
+        // SIP Methods
964
+        ACK: 'ACK',
965
+        BYE: 'BYE',
966
+        CANCEL: 'CANCEL',
967
+        INFO: 'INFO',
968
+        INVITE: 'INVITE',
969
+        MESSAGE: 'MESSAGE',
970
+        NOTIFY: 'NOTIFY',
971
+        OPTIONS: 'OPTIONS',
972
+        REGISTER: 'REGISTER',
973
+        UPDATE: 'UPDATE',
974
+        SUBSCRIBE: 'SUBSCRIBE',
975
+        PUBLISH: 'PUBLISH',
976
+        REFER: 'REFER',
977
+        PRACK: 'PRACK',
978
+        /* SIP Response Reasons
979
+         * DOC: http://www.iana.org/assignments/sip-parameters
980
+         * Copied from https://github.com/versatica/OverSIP/blob/master/lib/oversip/sip/constants.rb#L7
981
+         */
982
+        REASON_PHRASE: {
983
+            100: 'Trying',
984
+            180: 'Ringing',
985
+            181: 'Call Is Being Forwarded',
986
+            182: 'Queued',
987
+            183: 'Session Progress',
988
+            199: 'Early Dialog Terminated',
989
+            200: 'OK',
990
+            202: 'Accepted',
991
+            204: 'No Notification',
992
+            300: 'Multiple Choices',
993
+            301: 'Moved Permanently',
994
+            302: 'Moved Temporarily',
995
+            305: 'Use Proxy',
996
+            380: 'Alternative Service',
997
+            400: 'Bad Request',
998
+            401: 'Unauthorized',
999
+            402: 'Payment Required',
1000
+            403: 'Forbidden',
1001
+            404: 'Not Found',
1002
+            405: 'Method Not Allowed',
1003
+            406: 'Not Acceptable',
1004
+            407: 'Proxy Authentication Required',
1005
+            408: 'Request Timeout',
1006
+            410: 'Gone',
1007
+            412: 'Conditional Request Failed',
1008
+            413: 'Request Entity Too Large',
1009
+            414: 'Request-URI Too Long',
1010
+            415: 'Unsupported Media Type',
1011
+            416: 'Unsupported URI Scheme',
1012
+            417: 'Unknown Resource-Priority',
1013
+            420: 'Bad Extension',
1014
+            421: 'Extension Required',
1015
+            422: 'Session Interval Too Small',
1016
+            423: 'Interval Too Brief',
1017
+            428: 'Use Identity Header',
1018
+            429: 'Provide Referrer Identity',
1019
+            430: 'Flow Failed',
1020
+            433: 'Anonymity Disallowed',
1021
+            436: 'Bad Identity-Info',
1022
+            437: 'Unsupported Certificate',
1023
+            438: 'Invalid Identity Header',
1024
+            439: 'First Hop Lacks Outbound Support',
1025
+            440: 'Max-Breadth Exceeded',
1026
+            469: 'Bad Info Package',
1027
+            470: 'Consent Needed',
1028
+            478: 'Unresolvable Destination',
1029
+            480: 'Temporarily Unavailable',
1030
+            481: 'Call/Transaction Does Not Exist',
1031
+            482: 'Loop Detected',
1032
+            483: 'Too Many Hops',
1033
+            484: 'Address Incomplete',
1034
+            485: 'Ambiguous',
1035
+            486: 'Busy Here',
1036
+            487: 'Request Terminated',
1037
+            488: 'Not Acceptable Here',
1038
+            489: 'Bad Event',
1039
+            491: 'Request Pending',
1040
+            493: 'Undecipherable',
1041
+            494: 'Security Agreement Required',
1042
+            500: 'Internal Server Error',
1043
+            501: 'Not Implemented',
1044
+            502: 'Bad Gateway',
1045
+            503: 'Service Unavailable',
1046
+            504: 'Server Time-out',
1047
+            505: 'Version Not Supported',
1048
+            513: 'Message Too Large',
1049
+            580: 'Precondition Failure',
1050
+            600: 'Busy Everywhere',
1051
+            603: 'Decline',
1052
+            604: 'Does Not Exist Anywhere',
1053
+            606: 'Not Acceptable'
1054
+        },
1055
+        /* SIP Option Tags
1056
+         * DOC: http://www.iana.org/assignments/sip-parameters/sip-parameters.xhtml#sip-parameters-4
1057
+         */
1058
+        OPTION_TAGS: {
1059
+            '100rel': true,
1060
+            199: true,
1061
+            answermode: true,
1062
+            'early-session': true,
1063
+            eventlist: true,
1064
+            explicitsub: true,
1065
+            'from-change': true,
1066
+            'geolocation-http': true,
1067
+            'geolocation-sip': true,
1068
+            gin: true,
1069
+            gruu: true,
1070
+            histinfo: true,
1071
+            ice: true,
1072
+            join: true,
1073
+            'multiple-refer': true,
1074
+            norefersub: true,
1075
+            nosub: true,
1076
+            outbound: true,
1077
+            path: true,
1078
+            policy: true,
1079
+            precondition: true,
1080
+            pref: true,
1081
+            privacy: true,
1082
+            'recipient-list-invite': true,
1083
+            'recipient-list-message': true,
1084
+            'recipient-list-subscribe': true,
1085
+            replaces: true,
1086
+            'resource-priority': true,
1087
+            'sdp-anat': true,
1088
+            'sec-agree': true,
1089
+            tdialog: true,
1090
+            timer: true,
1091
+            uui: true // RFC 7433
1092
+        },
1093
+        dtmfType: {
1094
+            INFO: 'info',
1095
+            RTP: 'rtp'
1096
+        }
1097
+    };
1098
+};
1099
+
1100
+
1101
+/***/ }),
1102
+/* 8 */
1103
+/***/ (function(module, exports, __webpack_require__) {
1104
+
1105
+"use strict";
1106
+
1107
+/**
1108
+ * @fileoverview Exceptions
1109
+ */
1110
+/**
1111
+ * SIP Exceptions.
1112
+ * @augments SIP
1113
+ */
1114
+module.exports = {
1115
+    ConfigurationError: (function () {
1116
+        var exception = function (parameter, value) {
1117
+            this.code = 1;
1118
+            this.name = 'CONFIGURATION_ERROR';
1119
+            this.parameter = parameter;
1120
+            this.value = value;
1121
+            this.message = (!this.value) ? 'Missing parameter: ' + this.parameter : 'Invalid value ' + JSON.stringify(this.value) + ' for parameter "' + this.parameter + '"';
1122
+        };
1123
+        exception.prototype = new Error();
1124
+        return exception;
1125
+    }()),
1126
+    InvalidStateError: (function () {
1127
+        var exception = function (status) {
1128
+            this.code = 2;
1129
+            this.name = 'INVALID_STATE_ERROR';
1130
+            this.status = status;
1131
+            this.message = 'Invalid status: ' + status;
1132
+        };
1133
+        exception.prototype = new Error();
1134
+        return exception;
1135
+    }()),
1136
+    NotSupportedError: (function () {
1137
+        var exception = function (message) {
1138
+            this.code = 3;
1139
+            this.name = 'NOT_SUPPORTED_ERROR';
1140
+            this.message = message;
1141
+        };
1142
+        exception.prototype = new Error();
1143
+        return exception;
1144
+    }()),
1145
+    // Deprecated
1146
+    GetDescriptionError: (function () {
1147
+        var exception = function (message) {
1148
+            this.code = 4;
1149
+            this.name = 'GET_DESCRIPTION_ERROR';
1150
+            this.message = message;
1151
+        };
1152
+        exception.prototype = new Error();
1153
+        return exception;
1154
+    }()),
1155
+    RenegotiationError: (function () {
1156
+        var exception = function (message) {
1157
+            this.code = 5;
1158
+            this.name = 'RENEGOTIATION_ERROR';
1159
+            this.message = message;
1160
+        };
1161
+        exception.prototype = new Error();
1162
+        return exception;
1163
+    }()),
1164
+    MethodParameterError: (function () {
1165
+        var exception = function (method, parameter, value) {
1166
+            this.code = 6;
1167
+            this.name = 'METHOD_PARAMETER_ERROR';
1168
+            this.method = method;
1169
+            this.parameter = parameter;
1170
+            this.value = value;
1171
+            this.message = (!this.value) ? 'Missing parameter: ' + this.parameter : 'Invalid value ' + JSON.stringify(this.value) + ' for parameter "' + this.parameter + '"';
1172
+        };
1173
+        exception.prototype = new Error();
1174
+        return exception;
1175
+    }()),
1176
+    TransportError: (function () {
1177
+        var exception = function (message) {
1178
+            this.code = 7;
1179
+            this.name = 'TRANSPORT_ERROR';
1180
+            this.message = message;
1181
+        };
1182
+        exception.prototype = new Error();
1183
+        return exception;
1184
+    }()),
1185
+    SessionDescriptionHandlerError: (function () {
1186
+        var exception = function (method, error, message) {
1187
+            this.code = 8;
1188
+            this.name = 'SESSION_DESCRIPTION_HANDLER_ERROR';
1189
+            this.method = method;
1190
+            this.error = error;
1191
+            this.message = message || 'Error with Session Description Handler';
1192
+        };
1193
+        exception.prototype = new Error();
1194
+        return exception;
1195
+    }()),
1196
+};
1197
+
1198
+
1199
+/***/ }),
1200
+/* 9 */
1201
+/***/ (function(module, exports, __webpack_require__) {
1202
+
1203
+"use strict";
1204
+
1205
+/**
1206
+ * @fileoverview SIP TIMERS
1207
+ */
1208
+/**
1209
+ * @augments SIP
1210
+ */
1211
+var T1 = 500, T2 = 4000, T4 = 5000;
1212
+module.exports = function (timers) {
1213
+    var Timers = {
1214
+        T1: T1,
1215
+        T2: T2,
1216
+        T4: T4,
1217
+        TIMER_B: 64 * T1,
1218
+        TIMER_D: 0 * T1,
1219
+        TIMER_F: 64 * T1,
1220
+        TIMER_H: 64 * T1,
1221
+        TIMER_I: 0 * T1,
1222
+        TIMER_J: 0 * T1,
1223
+        TIMER_K: 0 * T4,
1224
+        TIMER_L: 64 * T1,
1225
+        TIMER_M: 64 * T1,
1226
+        TIMER_N: 64 * T1,
1227
+        PROVISIONAL_RESPONSE_INTERVAL: 60000 // See RFC 3261 Section 13.3.1.1
1228
+    };
1229
+    ['setTimeout', 'clearTimeout', 'setInterval', 'clearInterval']
1230
+        .forEach(function (name) {
1231
+        // can't just use timers[name].bind(timers) since it bypasses jasmine's
1232
+        // clock-mocking
1233
+        Timers[name] = function () {
1234
+            return timers[name].apply(timers, arguments);
1235
+        };
1236
+    });
1237
+    return Timers;
1238
+};
1239
+
1240
+
1241
+/***/ }),
1242
+/* 10 */
1243
+/***/ (function(module, exports, __webpack_require__) {
1244
+
1245
+"use strict";
1246
+
1247
+/* eslint-disable */
1248
+/**
1249
+ * @fileoverview Transport
1250
+ */
1251
+/* Transport
1252
+ * @class Abstract transport layer parent class
1253
+ * @param {Logger} logger
1254
+ * @param {Object} [options]
1255
+ */
1256
+module.exports = function (SIP) {
1257
+    var Transport = function (logger, options) { };
1258
+    Transport.prototype = Object.create(SIP.EventEmitter.prototype, {
1259
+        /**
1260
+        * 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
1261
+        * @param {Object} [options]
1262
+        * @returns {Promise}
1263
+        */
1264
+        connect: { writable: true, value: function connect(options) {
1265
+                options = options || {};
1266
+                return this.connectPromise(options).then(function (data) { !data.overrideEvent && this.emit('connected'); }.bind(this));
1267
+            } },
1268
+        /**
1269
+        * Called by connect, must return a promise
1270
+        * promise must resolve to an object. object supports 1 parameter: overrideEvent - Boolean
1271
+        * @abstract
1272
+        * @private
1273
+        * @param {Object} [options]
1274
+        * @returns {Promise}
1275
+        */
1276
+        connectPromise: { writable: true, value: function connectPromise(options) { } },
1277
+        /**
1278
+        * Returns true if the transport is connected
1279
+        * @abstract
1280
+        * @returns {Boolean}
1281
+        */
1282
+        isConnected: { writable: true, value: function isConnected() { } },
1283
+        /**
1284
+        * 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
1285
+        * @param {SIP.OutgoingRequest|String} msg
1286
+        * @param {Object} options
1287
+        * @returns {Promise}
1288
+        */
1289
+        send: { writable: true, value: function send(msg, options) {
1290
+                options = options || {};
1291
+                return this.sendPromise(msg).then(function (data) { !data.overrideEvent && this.emit('messageSent', data.msg); }.bind(this));
1292
+            } },
1293
+        /**
1294
+        * Called by send, must return a promise
1295
+        * promise must resolve to an object. object supports 2 parameters: msg - string (mandatory) and overrideEvent - Boolean (optional)
1296
+        * @abstract
1297
+        * @private
1298
+        * @param {SIP.OutgoingRequest|String} msg
1299
+        * @param {Object} [options]
1300
+        * @returns {Promise}
1301
+        */
1302
+        sendPromise: { writable: true, value: function sendPromise(msg, options) { } },
1303
+        /**
1304
+        * To be called when a message is received
1305
+        * @abstract
1306
+        * @param {Event} e
1307
+        */
1308
+        onMessage: { writable: true, value: function onMessage(e) { } },
1309
+        /**
1310
+        * 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
1311
+        * @param {Object} [options]
1312
+        * @returns {Promise}
1313
+        */
1314
+        disconnect: { writable: true, value: function disconnect(options) {
1315
+                options = options || {};
1316
+                return this.disconnectPromise(options).then(function (data) { !data.overrideEvent && this.emit('disconnected'); }.bind(this));
1317
+            } },
1318
+        /**
1319
+        * Called by disconnect, must return a promise
1320
+        * promise must resolve to an object. object supports 1 parameter: overrideEvent - Boolean
1321
+        * @abstract
1322
+        * @private
1323
+        * @param {Object} [options]
1324
+        * @returns {Promise}
1325
+        */
1326
+        disconnectPromise: { writable: true, value: function disconnectPromise(options) { } },
1327
+        afterConnected: { writable: true, value: function afterConnected(callback) {
1328
+                if (this.isConnected()) {
1329
+                    callback();
1330
+                }
1331
+                else {
1332
+                    this.once('connected', callback);
1333
+                }
1334
+            } },
1335
+        /**
1336
+         * Returns a promise which resolves once the UA is connected. DEPRECATION WARNING: just use afterConnected()
1337
+         * @returns {Promise}
1338
+         */
1339
+        waitForConnected: { writable: true, value: function waitForConnected() {
1340
+                console.warn("DEPRECATION WARNING Transport.waitForConnected(): use afterConnected() instead");
1341
+                return new SIP.Utils.Promise(function (resolve) {
1342
+                    this.afterConnected(resolve);
1343
+                }.bind(this));
1344
+            } },
1345
+    });
1346
+    return Transport;
1347
+};
1348
+
1349
+
1350
+/***/ }),
1351
+/* 11 */
1352
+/***/ (function(module, exports, __webpack_require__) {
1353
+
1354
+"use strict";
1355
+
1356
+/**
1357
+ * @fileoverview SIP Message Parser
1358
+ */
1359
+/**
1360
+ * Extract and parse every header of a SIP message.
1361
+ * @augments SIP
1362
+ * @namespace
1363
+ */
1364
+module.exports = function (SIP) {
1365
+    var Parser;
1366
+    function getHeader(data, headerStart) {
1367
+        var 
1368
+        // 'start' position of the header.
1369
+        start = headerStart, 
1370
+        // 'end' position of the header.
1371
+        end = 0, 
1372
+        // 'partial end' position of the header.
1373
+        partialEnd = 0;
1374
+        //End of message.
1375
+        if (data.substring(start, start + 2).match(/(^\r\n)/)) {
1376
+            return -2;
1377
+        }
1378
+        while (end === 0) {
1379
+            // Partial End of Header.
1380
+            partialEnd = data.indexOf('\r\n', start);
1381
+            // 'indexOf' returns -1 if the value to be found never occurs.
1382
+            if (partialEnd === -1) {
1383
+                return partialEnd;
1384
+            }
1385
+            if (!data.substring(partialEnd + 2, partialEnd + 4).match(/(^\r\n)/) && data.charAt(partialEnd + 2).match(/(^\s+)/)) {
1386
+                // Not the end of the message. Continue from the next position.
1387
+                start = partialEnd + 2;
1388
+            }
1389
+            else {
1390
+                end = partialEnd;
1391
+            }
1392
+        }
1393
+        return end;
1394
+    }
1395
+    function parseHeader(message, data, headerStart, headerEnd) {
1396
+        var header, idx, length, parsed, hcolonIndex = data.indexOf(':', headerStart), headerName = data.substring(headerStart, hcolonIndex).trim(), headerValue = data.substring(hcolonIndex + 1, headerEnd).trim();
1397
+        // If header-field is well-known, parse it.
1398
+        switch (headerName.toLowerCase()) {
1399
+            case 'via':
1400
+            case 'v':
1401
+                message.addHeader('via', headerValue);
1402
+                if (message.getHeaders('via').length === 1) {
1403
+                    parsed = message.parseHeader('Via');
1404
+                    if (parsed) {
1405
+                        message.via = parsed;
1406
+                        message.via_branch = parsed.branch;
1407
+                    }
1408
+                }
1409
+                else {
1410
+                    parsed = 0;
1411
+                }
1412
+                break;
1413
+            case 'from':
1414
+            case 'f':
1415
+                message.setHeader('from', headerValue);
1416
+                parsed = message.parseHeader('from');
1417
+                if (parsed) {
1418
+                    message.from = parsed;
1419
+                    message.from_tag = parsed.getParam('tag');
1420
+                }
1421
+                break;
1422
+            case 'to':
1423
+            case 't':
1424
+                message.setHeader('to', headerValue);
1425
+                parsed = message.parseHeader('to');
1426
+                if (parsed) {
1427
+                    message.to = parsed;
1428
+                    message.to_tag = parsed.getParam('tag');
1429
+                }
1430
+                break;
1431
+            case 'record-route':
1432
+                parsed = SIP.Grammar.parse(headerValue, 'Record_Route');
1433
+                if (parsed === -1) {
1434
+                    parsed = undefined;
1435
+                    break;
1436
+                }
1437
+                length = parsed.length;
1438
+                for (idx = 0; idx < length; idx++) {
1439
+                    header = parsed[idx];
1440
+                    message.addHeader('record-route', headerValue.substring(header.position, header.offset));
1441
+                    message.headers['Record-Route'][message.getHeaders('record-route').length - 1].parsed = header.parsed;
1442
+                }
1443
+                break;
1444
+            case 'call-id':
1445
+            case 'i':
1446
+                message.setHeader('call-id', headerValue);
1447
+                parsed = message.parseHeader('call-id');
1448
+                if (parsed) {
1449
+                    message.call_id = headerValue;
1450
+                }
1451
+                break;
1452
+            case 'contact':
1453
+            case 'm':
1454
+                parsed = SIP.Grammar.parse(headerValue, 'Contact');
1455
+                if (parsed === -1) {
1456
+                    parsed = undefined;
1457
+                    break;
1458
+                }
1459
+                length = parsed.length;
1460
+                for (idx = 0; idx < length; idx++) {
1461
+                    header = parsed[idx];
1462
+                    message.addHeader('contact', headerValue.substring(header.position, header.offset));
1463
+                    message.headers['Contact'][message.getHeaders('contact').length - 1].parsed = header.parsed;
1464
+                }
1465
+                break;
1466
+            case 'content-length':
1467
+            case 'l':
1468
+                message.setHeader('content-length', headerValue);
1469
+                parsed = message.parseHeader('content-length');
1470
+                break;
1471
+            case 'content-type':
1472
+            case 'c':
1473
+                message.setHeader('content-type', headerValue);
1474
+                parsed = message.parseHeader('content-type');
1475
+                break;
1476
+            case 'cseq':
1477
+                message.setHeader('cseq', headerValue);
1478
+                parsed = message.parseHeader('cseq');
1479
+                if (parsed) {
1480
+                    message.cseq = parsed.value;
1481
+                }
1482
+                if (message instanceof SIP.IncomingResponse) {
1483
+                    message.method = parsed.method;
1484
+                }
1485
+                break;
1486
+            case 'max-forwards':
1487
+                message.setHeader('max-forwards', headerValue);
1488
+                parsed = message.parseHeader('max-forwards');
1489
+                break;
1490
+            case 'www-authenticate':
1491
+                message.setHeader('www-authenticate', headerValue);
1492
+                parsed = message.parseHeader('www-authenticate');
1493
+                break;
1494
+            case 'proxy-authenticate':
1495
+                message.setHeader('proxy-authenticate', headerValue);
1496
+                parsed = message.parseHeader('proxy-authenticate');
1497
+                break;
1498
+            case 'refer-to':
1499
+            case 'r':
1500
+                message.setHeader('refer-to', headerValue);
1501
+                parsed = message.parseHeader('refer-to');
1502
+                if (parsed) {
1503
+                    message.refer_to = parsed;
1504
+                }
1505
+                break;
1506
+            default:
1507
+                // Do not parse this header.
1508
+                message.setHeader(headerName, headerValue);
1509
+                parsed = 0;
1510
+        }
1511
+        if (parsed === undefined) {
1512
+            return {
1513
+                error: 'error parsing header "' + headerName + '"'
1514
+            };
1515
+        }
1516
+        else {
1517
+            return true;
1518
+        }
1519
+    }
1520
+    /** Parse SIP Message
1521
+     * @function
1522
+     * @param {String} message SIP message.
1523
+     * @param {Object} logger object.
1524
+     * @returns {SIP.IncomingRequest|SIP.IncomingResponse|undefined}
1525
+     */
1526
+    Parser = {};
1527
+    Parser.parseMessage = function (data, ua) {
1528
+        var message, firstLine, contentLength, bodyStart, parsed, headerStart = 0, headerEnd = data.indexOf('\r\n'), logger = ua.getLogger('sip.parser');
1529
+        if (headerEnd === -1) {
1530
+            logger.warn('no CRLF found, not a SIP message, discarded');
1531
+            return;
1532
+        }
1533
+        // Parse first line. Check if it is a Request or a Reply.
1534
+        firstLine = data.substring(0, headerEnd);
1535
+        parsed = SIP.Grammar.parse(firstLine, 'Request_Response');
1536
+        if (parsed === -1) {
1537
+            logger.warn('error parsing first line of SIP message: "' + firstLine + '"');
1538
+            return;
1539
+        }
1540
+        else if (!parsed.status_code) {
1541
+            message = new SIP.IncomingRequest(ua);
1542
+            message.method = parsed.method;
1543
+            message.ruri = parsed.uri;
1544
+        }
1545
+        else {
1546
+            message = new SIP.IncomingResponse(ua);
1547
+            message.status_code = parsed.status_code;
1548
+            message.reason_phrase = parsed.reason_phrase;
1549
+        }
1550
+        message.data = data;
1551
+        headerStart = headerEnd + 2;
1552
+        /* Loop over every line in data. Detect the end of each header and parse
1553
+        * it or simply add to the headers collection.
1554
+        */
1555
+        while (true) {
1556
+            headerEnd = getHeader(data, headerStart);
1557
+            // The SIP message has normally finished.
1558
+            if (headerEnd === -2) {
1559
+                bodyStart = headerStart + 2;
1560
+                break;
1561
+            }
1562
+            // data.indexOf returned -1 due to a malformed message.
1563
+            else if (headerEnd === -1) {
1564
+                logger.error('malformed message');
1565
+                return;
1566
+            }
1567
+            parsed = parseHeader(message, data, headerStart, headerEnd);
1568
+            if (parsed !== true) {
1569
+                logger.error(parsed.error);
1570
+                return;
1571
+            }
1572
+            headerStart = headerEnd + 2;
1573
+        }
1574
+        /* RFC3261 18.3.
1575
+         * If there are additional bytes in the transport packet
1576
+         * beyond the end of the body, they MUST be discarded.
1577
+         */
1578
+        if (message.hasHeader('content-length')) {
1579
+            contentLength = message.getHeader('content-length');
1580
+            message.body = data.substr(bodyStart, contentLength);
1581
+        }
1582
+        else {
1583
+            message.body = data.substring(bodyStart);
1584
+        }
1585
+        return message;
1586
+    };
1587
+    SIP.Parser = Parser;
1588
+};
1589
+
1590
+
1591
+/***/ }),
1592
+/* 12 */
1593
+/***/ (function(module, exports, __webpack_require__) {
1594
+
1595
+"use strict";
1596
+
1597
+/**
1598
+ * @fileoverview SIP Message
1599
+ */
1600
+module.exports = function (SIP) {
1601
+    var OutgoingRequest, IncomingMessage, IncomingRequest, IncomingResponse;
1602
+    function getSupportedHeader(request) {
1603
+        var allowUnregistered = request.ua.configuration.hackAllowUnregisteredOptionTags;
1604
+        var optionTags = [];
1605
+        var optionTagSet = {};
1606
+        if (request.method === SIP.C.REGISTER) {
1607
+            optionTags.push('path', 'gruu');
1608
+        }
1609
+        else if (request.method === SIP.C.INVITE &&
1610
+            (request.ua.contact.pub_gruu || request.ua.contact.temp_gruu)) {
1611
+            optionTags.push('gruu');
1612
+        }
1613
+        if (request.ua.configuration.rel100 === SIP.C.supported.SUPPORTED) {
1614
+            optionTags.push('100rel');
1615
+        }
1616
+        if (request.ua.configuration.replaces === SIP.C.supported.SUPPORTED) {
1617
+            optionTags.push('replaces');
1618
+        }
1619
+        optionTags.push('outbound');
1620
+        optionTags = optionTags.concat(request.ua.configuration.extraSupported);
1621
+        optionTags = optionTags.filter(function (optionTag) {
1622
+            var registered = SIP.C.OPTION_TAGS[optionTag];
1623
+            var unique = !optionTagSet[optionTag];
1624
+            optionTagSet[optionTag] = true;
1625
+            return (registered || allowUnregistered) && unique;
1626
+        });
1627
+        return 'Supported: ' + optionTags.join(', ') + '\r\n';
1628
+    }
1629
+    /**
1630
+     * @augments SIP
1631
+     * @class Class for outgoing SIP request.
1632
+     * @param {String} method request method
1633
+     * @param {String} ruri request uri
1634
+     * @param {SIP.UA} ua
1635
+     * @param {Object} params parameters that will have priority over ua.configuration parameters:
1636
+     * <br>
1637
+     *  - cseq, call_id, from_tag, from_uri, from_displayName, to_uri, to_tag, route_set
1638
+     * @param {Object} [headers] extra headers
1639
+     * @param {String} [body]
1640
+     */
1641
+    OutgoingRequest = function (method, ruri, ua, params, extraHeaders, body) {
1642
+        var to, from, call_id, cseq, to_uri, from_uri;
1643
+        params = params || {};
1644
+        // Mandatory parameters check
1645
+        if (!method || !ruri || !ua) {
1646
+            return null;
1647
+        }
1648
+        this.logger = ua.getLogger('sip.sipmessage');
1649
+        this.ua = ua;
1650
+        this.headers = {};
1651
+        this.method = method;
1652
+        this.ruri = ruri;
1653
+        this.body = body;
1654
+        this.extraHeaders = (extraHeaders || []).slice();
1655
+        this.statusCode = params.status_code;
1656
+        this.reasonPhrase = params.reason_phrase;
1657
+        // Fill the Common SIP Request Headers
1658
+        // Route
1659
+        if (params.route_set) {
1660
+            this.setHeader('route', params.route_set);
1661
+        }
1662
+        else if (ua.configuration.usePreloadedRoute) {
1663
+            this.setHeader('route', ua.transport.server.sip_uri);
1664
+        }
1665
+        // Via
1666
+        // Empty Via header. Will be filled by the client transaction.
1667
+        this.setHeader('via', '');
1668
+        // Max-Forwards
1669
+        this.setHeader('max-forwards', SIP.UA.C.MAX_FORWARDS);
1670
+        // To
1671
+        to_uri = params.to_uri || ruri;
1672
+        to = (params.to_displayName || params.to_displayName === 0) ? '"' + params.to_displayName + '" ' : '';
1673
+        to += '<' + (to_uri && to_uri.toRaw ? to_uri.toRaw() : to_uri) + '>';
1674
+        to += params.to_tag ? ';tag=' + params.to_tag : '';
1675
+        this.to = new SIP.NameAddrHeader.parse(to);
1676
+        this.setHeader('to', to);
1677
+        // From
1678
+        from_uri = params.from_uri || ua.configuration.uri;
1679
+        if (params.from_displayName || params.from_displayName === 0) {
1680
+            from = '"' + params.from_displayName + '" ';
1681
+        }
1682
+        else if (ua.configuration.displayName) {
1683
+            from = '"' + ua.configuration.displayName + '" ';
1684
+        }
1685
+        else {
1686
+            from = '';
1687
+        }
1688
+        from += '<' + (from_uri && from_uri.toRaw ? from_uri.toRaw() : from_uri) + '>;tag=';
1689
+        from += params.from_tag || SIP.Utils.newTag();
1690
+        this.from = new SIP.NameAddrHeader.parse(from);
1691
+        this.setHeader('from', from);
1692
+        // Call-ID
1693
+        call_id = params.call_id || (ua.configuration.sipjsId + SIP.Utils.createRandomToken(15));
1694
+        this.call_id = call_id;
1695
+        this.setHeader('call-id', call_id);
1696
+        // CSeq
1697
+        cseq = params.cseq || Math.floor(Math.random() * 10000);
1698
+        this.cseq = cseq;
1699
+        this.setHeader('cseq', cseq + ' ' + method);
1700
+    };
1701
+    OutgoingRequest.prototype = {
1702
+        /**
1703
+         * Replace the the given header by the given value.
1704
+         * @param {String} name header name
1705
+         * @param {String | Array} value header value
1706
+         */
1707
+        setHeader: function (name, value) {
1708
+            this.headers[SIP.Utils.headerize(name)] = (value instanceof Array) ? value : [value];
1709
+        },
1710
+        /**
1711
+         * Get the value of the given header name at the given position.
1712
+         * @param {String} name header name
1713
+         * @returns {String|undefined} Returns the specified header, undefined if header doesn't exist.
1714
+         */
1715
+        getHeader: function (name) {
1716
+            var regexp, idx, length = this.extraHeaders.length, header = this.headers[SIP.Utils.headerize(name)];
1717
+            if (header) {
1718
+                if (header[0]) {
1719
+                    return header[0];
1720
+                }
1721
+            }
1722
+            else {
1723
+                regexp = new RegExp('^\\s*' + name + '\\s*:', 'i');
1724
+                for (idx = 0; idx < length; idx++) {
1725
+                    header = this.extraHeaders[idx];
1726
+                    if (regexp.test(header)) {
1727
+                        return header.substring(header.indexOf(':') + 1).trim();
1728
+                    }
1729
+                }
1730
+            }
1731
+            return;
1732
+        },
1733
+        /**
1734
+         * Get the header/s of the given name.
1735
+         * @param {String} name header name
1736
+         * @returns {Array} Array with all the headers of the specified name.
1737
+         */
1738
+        getHeaders: function (name) {
1739
+            var idx, length, regexp, header = this.headers[SIP.Utils.headerize(name)], result = [];
1740
+            if (header) {
1741
+                length = header.length;
1742
+                for (idx = 0; idx < length; idx++) {
1743
+                    result.push(header[idx]);
1744
+                }
1745
+                return result;
1746
+            }
1747
+            else {
1748
+                length = this.extraHeaders.length;
1749
+                regexp = new RegExp('^\\s*' + name + '\\s*:', 'i');
1750
+                for (idx = 0; idx < length; idx++) {
1751
+                    header = this.extraHeaders[idx];
1752
+                    if (regexp.test(header)) {
1753
+                        result.push(header.substring(header.indexOf(':') + 1).trim());
1754
+                    }
1755
+                }
1756
+                return result;
1757
+            }
1758
+        },
1759
+        /**
1760
+         * Verify the existence of the given header.
1761
+         * @param {String} name header name
1762
+         * @returns {boolean} true if header with given name exists, false otherwise
1763
+         */
1764
+        hasHeader: function (name) {
1765
+            var regexp, idx, length = this.extraHeaders.length;
1766
+            if (this.headers[SIP.Utils.headerize(name)]) {
1767
+                return true;
1768
+            }
1769
+            else {
1770
+                regexp = new RegExp('^\\s*' + name + '\\s*:', 'i');
1771
+                for (idx = 0; idx < length; idx++) {
1772
+                    if (regexp.test(this.extraHeaders[idx])) {
1773
+                        return true;
1774
+                    }
1775
+                }
1776
+            }
1777
+            return false;
1778
+        },
1779
+        toString: function () {
1780
+            var msg = '', header, length, idx;
1781
+            msg += this.method + ' ' + (this.ruri.toRaw ? this.ruri.toRaw() : this.ruri) + ' SIP/2.0\r\n';
1782
+            for (header in this.headers) {
1783
+                length = this.headers[header].length;
1784
+                for (idx = 0; idx < length; idx++) {
1785
+                    msg += header + ': ' + this.headers[header][idx] + '\r\n';
1786
+                }
1787
+            }
1788
+            length = this.extraHeaders.length;
1789
+            for (idx = 0; idx < length; idx++) {
1790
+                msg += this.extraHeaders[idx].trim() + '\r\n';
1791
+            }
1792
+            msg += getSupportedHeader(this);
1793
+            msg += 'User-Agent: ' + this.ua.configuration.userAgentString + '\r\n';
1794
+            if (this.body) {
1795
+                if (typeof this.body === 'string') {
1796
+                    length = SIP.Utils.str_utf8_length(this.body);
1797
+                    msg += 'Content-Length: ' + length + '\r\n\r\n';
1798
+                    msg += this.body;
1799
+                }
1800
+                else {
1801
+                    if (this.body.body && this.body.contentType) {
1802
+                        length = SIP.Utils.str_utf8_length(this.body.body);
1803
+                        msg += 'Content-Type: ' + this.body.contentType + '\r\n';
1804
+                        msg += 'Content-Length: ' + length + '\r\n\r\n';
1805
+                        msg += this.body.body;
1806
+                    }
1807
+                    else {
1808
+                        msg += 'Content-Length: ' + 0 + '\r\n\r\n';
1809
+                    }
1810
+                }
1811
+            }
1812
+            else {
1813
+                msg += 'Content-Length: ' + 0 + '\r\n\r\n';
1814
+            }
1815
+            return msg;
1816
+        }
1817
+    };
1818
+    /**
1819
+     * @augments SIP
1820
+     * @class Class for incoming SIP message.
1821
+     */
1822
+    IncomingMessage = function () {
1823
+        this.data = null;
1824
+        this.headers = null;
1825
+        this.method = null;
1826
+        this.via = null;
1827
+        this.via_branch = null;
1828
+        this.call_id = null;
1829
+        this.cseq = null;
1830
+        this.from = null;
1831
+        this.from_tag = null;
1832
+        this.to = null;
1833
+        this.to_tag = null;
1834
+        this.body = null;
1835
+    };
1836
+    IncomingMessage.prototype = {
1837
+        /**
1838
+        * Insert a header of the given name and value into the last position of the
1839
+        * header array.
1840
+        * @param {String} name header name
1841
+        * @param {String} value header value
1842
+        */
1843
+        addHeader: function (name, value) {
1844
+            var header = { raw: value };
1845
+            name = SIP.Utils.headerize(name);
1846
+            if (this.headers[name]) {
1847
+                this.headers[name].push(header);
1848
+            }
1849
+            else {
1850
+                this.headers[name] = [header];
1851
+            }
1852
+        },
1853
+        /**
1854
+         * Get the value of the given header name at the given position.
1855
+         * @param {String} name header name
1856
+         * @returns {String|undefined} Returns the specified header, null if header doesn't exist.
1857
+         */
1858
+        getHeader: function (name) {
1859
+            var header = this.headers[SIP.Utils.headerize(name)];
1860
+            if (header) {
1861
+                if (header[0]) {
1862
+                    return header[0].raw;
1863
+                }
1864
+            }
1865
+            else {
1866
+                return;
1867
+            }
1868
+        },
1869
+        /**
1870
+         * Get the header/s of the given name.
1871
+         * @param {String} name header name
1872
+         * @returns {Array} Array with all the headers of the specified name.
1873
+         */
1874
+        getHeaders: function (name) {
1875
+            var idx, length, header = this.headers[SIP.Utils.headerize(name)], result = [];
1876
+            if (!header) {
1877
+                return [];
1878
+            }
1879
+            length = header.length;
1880
+            for (idx = 0; idx < length; idx++) {
1881
+                result.push(header[idx].raw);
1882
+            }
1883
+            return result;
1884
+        },
1885
+        /**
1886
+         * Verify the existence of the given header.
1887
+         * @param {String} name header name
1888
+         * @returns {boolean} true if header with given name exists, false otherwise
1889
+         */
1890
+        hasHeader: function (name) {
1891
+            return (this.headers[SIP.Utils.headerize(name)]) ? true : false;
1892
+        },
1893
+        /**
1894
+        * Parse the given header on the given index.
1895
+        * @param {String} name header name
1896
+        * @param {Number} [idx=0] header index
1897
+        * @returns {Object|undefined} Parsed header object, undefined if the header is not present or in case of a parsing error.
1898
+        */
1899
+        parseHeader: function (name, idx) {
1900
+            var header, value, parsed;
1901
+            name = SIP.Utils.headerize(name);
1902
+            idx = idx || 0;
1903
+            if (!this.headers[name]) {
1904
+                this.logger.log('header "' + name + '" not present');
1905
+                return;
1906
+            }
1907
+            else if (idx >= this.headers[name].length) {
1908
+                this.logger.log('not so many "' + name + '" headers present');
1909
+                return;
1910
+            }
1911
+            header = this.headers[name][idx];
1912
+            value = header.raw;
1913
+            if (header.parsed) {
1914
+                return header.parsed;
1915
+            }
1916
+            //substitute '-' by '_' for grammar rule matching.
1917
+            parsed = SIP.Grammar.parse(value, name.replace(/-/g, '_'));
1918
+            if (parsed === -1) {
1919
+                this.headers[name].splice(idx, 1); //delete from headers
1920
+                this.logger.warn('error parsing "' + name + '" header field with value "' + value + '"');
1921
+                return;
1922
+            }
1923
+            else {
1924
+                header.parsed = parsed;
1925
+                return parsed;
1926
+            }
1927
+        },
1928
+        /**
1929
+         * Message Header attribute selector. Alias of parseHeader.
1930
+         * @param {String} name header name
1931
+         * @param {Number} [idx=0] header index
1932
+         * @returns {Object|undefined} Parsed header object, undefined if the header is not present or in case of a parsing error.
1933
+         *
1934
+         * @example
1935
+         * message.s('via',3).port
1936
+         */
1937
+        s: function (name, idx) {
1938
+            return this.parseHeader(name, idx);
1939
+        },
1940
+        /**
1941
+        * Replace the value of the given header by the value.
1942
+        * @param {String} name header name
1943
+        * @param {String} value header value
1944
+        */
1945
+        setHeader: function (name, value) {
1946
+            var header = { raw: value };
1947
+            this.headers[SIP.Utils.headerize(name)] = [header];
1948
+        },
1949
+        toString: function () {
1950
+            return this.data;
1951
+        }
1952
+    };
1953
+    /**
1954
+     * @augments IncomingMessage
1955
+     * @class Class for incoming SIP request.
1956
+     */
1957
+    IncomingRequest = function (ua) {
1958
+        this.logger = ua.getLogger('sip.sipmessage');
1959
+        this.ua = ua;
1960
+        this.headers = {};
1961
+        this.ruri = null;
1962
+        this.transport = null;
1963
+        this.server_transaction = null;
1964
+    };
1965
+    IncomingRequest.prototype = new IncomingMessage();
1966
+    /**
1967
+    * Stateful reply.
1968
+    * @param {Number} code status code
1969
+    * @param {String} reason reason phrase
1970
+    * @param {Object} headers extra headers
1971
+    * @param {String} body body
1972
+    * @param {Function} [onSuccess] onSuccess callback
1973
+    * @param {Function} [onFailure] onFailure callback
1974
+    */
1975
+    // TODO: Get rid of callbacks and make promise based
1976
+    IncomingRequest.prototype.reply = function (code, reason, extraHeaders, body, onSuccess, onFailure) {
1977
+        var rr, vias, length, idx, response, to = this.getHeader('To'), r = 0, v = 0;
1978
+        response = SIP.Utils.buildStatusLine(code, reason);
1979
+        extraHeaders = (extraHeaders || []).slice();
1980
+        if (this.method === SIP.C.INVITE && code > 100 && code <= 200) {
1981
+            rr = this.getHeaders('record-route');
1982
+            length = rr.length;
1983
+            for (r; r < length; r++) {
1984
+                response += 'Record-Route: ' + rr[r] + '\r\n';
1985
+            }
1986
+        }
1987
+        vias = this.getHeaders('via');
1988
+        length = vias.length;
1989
+        for (v; v < length; v++) {
1990
+            response += 'Via: ' + vias[v] + '\r\n';
1991
+        }
1992
+        if (!this.to_tag && code > 100) {
1993
+            to += ';tag=' + SIP.Utils.newTag();
1994
+        }
1995
+        else if (this.to_tag && !this.s('to').hasParam('tag')) {
1996
+            to += ';tag=' + this.to_tag;
1997
+        }
1998
+        response += 'To: ' + to + '\r\n';
1999
+        response += 'From: ' + this.getHeader('From') + '\r\n';
2000
+        response += 'Call-ID: ' + this.call_id + '\r\n';
2001
+        response += 'CSeq: ' + this.cseq + ' ' + this.method + '\r\n';
2002
+        length = extraHeaders.length;
2003
+        for (idx = 0; idx < length; idx++) {
2004
+            response += extraHeaders[idx].trim() + '\r\n';
2005
+        }
2006
+        response += getSupportedHeader(this);
2007
+        response += 'User-Agent: ' + this.ua.configuration.userAgentString + '\r\n';
2008
+        if (body) {
2009
+            if (typeof body === 'string') {
2010
+                length = SIP.Utils.str_utf8_length(body);
2011
+                response += 'Content-Type: application/sdp\r\n';
2012
+                response += 'Content-Length: ' + length + '\r\n\r\n';
2013
+                response += body;
2014
+            }
2015
+            else {
2016
+                if (body.body && body.contentType) {
2017
+                    length = SIP.Utils.str_utf8_length(body.body);
2018
+                    response += 'Content-Type: ' + body.contentType + '\r\n';
2019
+                    response += 'Content-Length: ' + length + '\r\n\r\n';
2020
+                    response += body.body;
2021
+                }
2022
+                else {
2023
+                    response += 'Content-Length: ' + 0 + '\r\n\r\n';
2024
+                }
2025
+            }
2026
+        }
2027
+        else {
2028
+            response += 'Content-Length: ' + 0 + '\r\n\r\n';
2029
+        }
2030
+        this.server_transaction.receiveResponse(code, response).then(onSuccess, onFailure);
2031
+        return response;
2032
+    };
2033
+    /**
2034
+    * Stateless reply.
2035
+    * @param {Number} code status code
2036
+    * @param {String} reason reason phrase
2037
+    */
2038
+    IncomingRequest.prototype.reply_sl = function (code, reason) {
2039
+        var to, response, v = 0, vias = this.getHeaders('via'), length = vias.length;
2040
+        response = SIP.Utils.buildStatusLine(code, reason);
2041
+        for (v; v < length; v++) {
2042
+            response += 'Via: ' + vias[v] + '\r\n';
2043
+        }
2044
+        to = this.getHeader('To');
2045
+        if (!this.to_tag && code > 100) {
2046
+            to += ';tag=' + SIP.Utils.newTag();
2047
+        }
2048
+        else if (this.to_tag && !this.s('to').hasParam('tag')) {
2049
+            to += ';tag=' + this.to_tag;
2050
+        }
2051
+        response += 'To: ' + to + '\r\n';
2052
+        response += 'From: ' + this.getHeader('From') + '\r\n';
2053
+        response += 'Call-ID: ' + this.call_id + '\r\n';
2054
+        response += 'CSeq: ' + this.cseq + ' ' + this.method + '\r\n';
2055
+        response += 'User-Agent: ' + this.ua.configuration.userAgentString + '\r\n';
2056
+        response += 'Content-Length: ' + 0 + '\r\n\r\n';
2057
+        this.transport.send(response);
2058
+    };
2059
+    /**
2060
+     * @augments IncomingMessage
2061
+     * @class Class for incoming SIP response.
2062
+     */
2063
+    IncomingResponse = function (ua) {
2064
+        this.logger = ua.getLogger('sip.sipmessage');
2065
+        this.headers = {};
2066
+        this.status_code = null;
2067
+        this.reason_phrase = null;
2068
+    };
2069
+    IncomingResponse.prototype = new IncomingMessage();
2070
+    SIP.OutgoingRequest = OutgoingRequest;
2071
+    SIP.IncomingRequest = IncomingRequest;
2072
+    SIP.IncomingResponse = IncomingResponse;
2073
+};
2074
+
2075
+
2076
+/***/ }),
2077
+/* 13 */
2078
+/***/ (function(module, exports, __webpack_require__) {
2079
+
2080
+"use strict";
2081
+
2082
+/**
2083
+ * @fileoverview SIP URI
2084
+ */
2085
+/**
2086
+ * @augments SIP
2087
+ * @class Class creating a SIP URI.
2088
+ *
2089
+ * @param {String} [scheme]
2090
+ * @param {String} [user]
2091
+ * @param {String} host
2092
+ * @param {String} [port]
2093
+ * @param {Object} [parameters]
2094
+ * @param {Object} [headers]
2095
+ *
2096
+ */
2097
+module.exports = function (SIP) {
2098
+    var URI;
2099
+    URI = function (scheme, user, host, port, parameters, headers) {
2100
+        var param, header, raw, normal;
2101
+        // Checks
2102
+        if (!host) {
2103
+            throw new TypeError('missing or invalid "host" parameter');
2104
+        }
2105
+        // Initialize parameters
2106
+        scheme = scheme || SIP.C.SIP;
2107
+        this.parameters = {};
2108
+        this.headers = {};
2109
+        for (param in parameters) {
2110
+            this.setParam(param, parameters[param]);
2111
+        }
2112
+        for (header in headers) {
2113
+            this.setHeader(header, headers[header]);
2114
+        }
2115
+        // Raw URI
2116
+        raw = {
2117
+            scheme: scheme,
2118
+            user: user,
2119
+            host: host,
2120
+            port: port
2121
+        };
2122
+        // Normalized URI
2123
+        normal = {
2124
+            scheme: scheme.toLowerCase(),
2125
+            user: user,
2126
+            host: host.toLowerCase(),
2127
+            port: port
2128
+        };
2129
+        Object.defineProperties(this, {
2130
+            _normal: {
2131
+                get: function () { return normal; }
2132
+            },
2133
+            _raw: {
2134
+                get: function () { return raw; }
2135
+            },
2136
+            scheme: {
2137
+                get: function () { return normal.scheme; },
2138
+                set: function (value) {
2139
+                    raw.scheme = value;
2140
+                    normal.scheme = value.toLowerCase();
2141
+                }
2142
+            },
2143
+            user: {
2144
+                get: function () { return normal.user; },
2145
+                set: function (value) {
2146
+                    normal.user = raw.user = value;
2147
+                }
2148
+            },
2149
+            host: {
2150
+                get: function () { return normal.host; },
2151
+                set: function (value) {
2152
+                    raw.host = value;
2153
+                    normal.host = value.toLowerCase();
2154
+                }
2155
+            },
2156
+            aor: {
2157
+                get: function () { return normal.user + '@' + normal.host; }
2158
+            },
2159
+            port: {
2160
+                get: function () { return normal.port; },
2161
+                set: function (value) {
2162
+                    normal.port = raw.port = value === 0 ? value : (parseInt(value, 10) || null);
2163
+                }
2164
+            }
2165
+        });
2166
+    };
2167
+    URI.prototype = {
2168
+        setParam: function (key, value) {
2169
+            if (key) {
2170
+                this.parameters[key.toLowerCase()] = (typeof value === 'undefined' || value === null) ? null : value.toString();
2171
+            }
2172
+        },
2173
+        getParam: function (key) {
2174
+            if (key) {
2175
+                return this.parameters[key.toLowerCase()];
2176
+            }
2177
+        },
2178
+        hasParam: function (key) {
2179
+            if (key) {
2180
+                return (this.parameters.hasOwnProperty(key.toLowerCase()) && true) || false;
2181
+            }
2182
+        },
2183
+        deleteParam: function (parameter) {
2184
+            var value;
2185
+            parameter = parameter.toLowerCase();
2186
+            if (this.parameters.hasOwnProperty(parameter)) {
2187
+                value = this.parameters[parameter];
2188
+                delete this.parameters[parameter];
2189
+                return value;
2190
+            }
2191
+        },
2192
+        clearParams: function () {
2193
+            this.parameters = {};
2194
+        },
2195
+        setHeader: function (name, value) {
2196
+            this.headers[SIP.Utils.headerize(name)] = (value instanceof Array) ? value : [value];
2197
+        },
2198
+        getHeader: function (name) {
2199
+            if (name) {
2200
+                return this.headers[SIP.Utils.headerize(name)];
2201
+            }
2202
+        },
2203
+        hasHeader: function (name) {
2204
+            if (name) {
2205
+                return (this.headers.hasOwnProperty(SIP.Utils.headerize(name)) && true) || false;
2206
+            }
2207
+        },
2208
+        deleteHeader: function (header) {
2209
+            var value;
2210
+            header = SIP.Utils.headerize(header);
2211
+            if (this.headers.hasOwnProperty(header)) {
2212
+                value = this.headers[header];
2213
+                delete this.headers[header];
2214
+                return value;
2215
+            }
2216
+        },
2217
+        clearHeaders: function () {
2218
+            this.headers = {};
2219
+        },
2220
+        clone: function () {
2221
+            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)));
2222
+        },
2223
+        toRaw: function () {
2224
+            return this._toString(this._raw);
2225
+        },
2226
+        toString: function () {
2227
+            return this._toString(this._normal);
2228
+        },
2229
+        _toString: function (uri) {
2230
+            var header, parameter, idx, uriString, headers = [];
2231
+            uriString = uri.scheme + ':';
2232
+            // add slashes if it's not a sip(s) URI
2233
+            if (!uri.scheme.toLowerCase().match("^sips?$")) {
2234
+                uriString += "//";
2235
+            }
2236
+            if (uri.user) {
2237
+                uriString += SIP.Utils.escapeUser(uri.user) + '@';
2238
+            }
2239
+            uriString += uri.host;
2240
+            if (uri.port || uri.port === 0) {
2241
+                uriString += ':' + uri.port;
2242
+            }
2243
+            for (parameter in this.parameters) {
2244
+                uriString += ';' + parameter;
2245
+                if (this.parameters[parameter] !== null) {
2246
+                    uriString += '=' + this.parameters[parameter];
2247
+                }
2248
+            }
2249
+            for (header in this.headers) {
2250
+                for (idx in this.headers[header]) {
2251
+                    headers.push(header + '=' + this.headers[header][idx]);
2252
+                }
2253
+            }
2254
+            if (headers.length > 0) {
2255
+                uriString += '?' + headers.join('&');
2256
+            }
2257
+            return uriString;
2258
+        }
2259
+    };
2260
+    /**
2261
+      * Parse the given string and returns a SIP.URI instance or undefined if
2262
+      * it is an invalid URI.
2263
+      * @public
2264
+      * @param {String} uri
2265
+      */
2266
+    URI.parse = function (uri) {
2267
+        uri = SIP.Grammar.parse(uri, 'SIP_URI');
2268
+        if (uri !== -1) {
2269
+            return uri;
2270
+        }
2271
+        else {
2272
+            return undefined;
2273
+        }
2274
+    };
2275
+    SIP.URI = URI;
2276
+};
2277
+
2278
+
2279
+/***/ }),
2280
+/* 14 */
2281
+/***/ (function(module, exports, __webpack_require__) {
2282
+
2283
+"use strict";
2284
+
2285
+/**
2286
+ * @fileoverview SIP NameAddrHeader
2287
+ */
2288
+/**
2289
+ * @augments SIP
2290
+ * @class Class creating a Name Address SIP header.
2291
+ *
2292
+ * @param {SIP.URI} uri
2293
+ * @param {String} [displayName]
2294
+ * @param {Object} [parameters]
2295
+ *
2296
+ */
2297
+module.exports = function (SIP) {
2298
+    var NameAddrHeader;
2299
+    NameAddrHeader = function (uri, displayName, parameters) {
2300
+        var param;
2301
+        // Checks
2302
+        if (!uri || !(uri instanceof SIP.URI)) {
2303
+            throw new TypeError('missing or invalid "uri" parameter');
2304
+        }
2305
+        // Initialize parameters
2306
+        this.uri = uri;
2307
+        this.parameters = {};
2308
+        for (param in parameters) {
2309
+            this.setParam(param, parameters[param]);
2310
+        }
2311
+        Object.defineProperties(this, {
2312
+            friendlyName: {
2313
+                get: function () { return this.displayName || uri.aor; }
2314
+            },
2315
+            displayName: {
2316
+                get: function () { return displayName; },
2317
+                set: function (value) {
2318
+                    displayName = (value === 0) ? '0' : value;
2319
+                }
2320
+            }
2321
+        });
2322
+    };
2323
+    NameAddrHeader.prototype = {
2324
+        setParam: function (key, value) {
2325
+            if (key) {
2326
+                this.parameters[key.toLowerCase()] = (typeof value === 'undefined' || value === null) ? null : value.toString();
2327
+            }
2328
+        },
2329
+        getParam: SIP.URI.prototype.getParam,
2330
+        hasParam: SIP.URI.prototype.hasParam,
2331
+        deleteParam: SIP.URI.prototype.deleteParam,
2332
+        clearParams: SIP.URI.prototype.clearParams,
2333
+        clone: function () {
2334
+            return new NameAddrHeader(this.uri.clone(), this.displayName, JSON.parse(JSON.stringify(this.parameters)));
2335
+        },
2336
+        toString: function () {
2337
+            var body, parameter;
2338
+            body = (this.displayName || this.displayName === 0) ? '"' + this.displayName + '" ' : '';
2339
+            body += '<' + this.uri.toString() + '>';
2340
+            for (parameter in this.parameters) {
2341
+                body += ';' + parameter;
2342
+                if (this.parameters[parameter] !== null) {
2343
+                    body += '=' + this.parameters[parameter];
2344
+                }
2345
+            }
2346
+            return body;
2347
+        }
2348
+    };
2349
+    /**
2350
+      * Parse the given string and returns a SIP.NameAddrHeader instance or undefined if
2351
+      * it is an invalid NameAddrHeader.
2352
+      * @public
2353
+      * @param {String} name_addr_header
2354
+      */
2355
+    NameAddrHeader.parse = function (name_addr_header) {
2356
+        name_addr_header = SIP.Grammar.parse(name_addr_header, 'Name_Addr_Header');
2357
+        if (name_addr_header !== -1) {
2358
+            return name_addr_header;
2359
+        }
2360
+        else {
2361
+            return undefined;
2362
+        }
2363
+    };
2364
+    SIP.NameAddrHeader = NameAddrHeader;
2365
+};
2366
+
2367
+
2368
+/***/ }),
2369
+/* 15 */
2370
+/***/ (function(module, exports, __webpack_require__) {
2371
+
2372
+"use strict";
2373
+
2374
+/**
2375
+ * @fileoverview SIP Transactions
2376
+ */
2377
+/**
2378
+ * SIP Transactions module.
2379
+ * @augments SIP
2380
+ */
2381
+module.exports = function (SIP) {
2382
+    var C = {
2383
+        // Transaction states
2384
+        STATUS_TRYING: 1,
2385
+        STATUS_PROCEEDING: 2,
2386
+        STATUS_CALLING: 3,
2387
+        STATUS_ACCEPTED: 4,
2388
+        STATUS_COMPLETED: 5,
2389
+        STATUS_TERMINATED: 6,
2390
+        STATUS_CONFIRMED: 7,
2391
+        // Transaction types
2392
+        NON_INVITE_CLIENT: 'nict',
2393
+        NON_INVITE_SERVER: 'nist',
2394
+        INVITE_CLIENT: 'ict',
2395
+        INVITE_SERVER: 'ist'
2396
+    };
2397
+    function buildViaHeader(request_sender, transport, id) {
2398
+        var via;
2399
+        via = 'SIP/2.0/' + (request_sender.ua.configuration.hackViaTcp ? 'TCP' : transport.server.scheme);
2400
+        via += ' ' + request_sender.ua.configuration.viaHost + ';branch=' + id;
2401
+        if (request_sender.ua.configuration.forceRport) {
2402
+            via += ';rport';
2403
+        }
2404
+        return via;
2405
+    }
2406
+    /**
2407
+    * @augments SIP.Transactions
2408
+    * @class Non Invite Client Transaction
2409
+    * @param {SIP.RequestSender} request_sender
2410
+    * @param {SIP.OutgoingRequest} request
2411
+    * @param {SIP.Transport} transport
2412
+    */
2413
+    var NonInviteClientTransaction = function (request_sender, request, transport) {
2414
+        var via;
2415
+        this.type = C.NON_INVITE_CLIENT;
2416
+        this.transport = transport;
2417
+        this.id = 'z9hG4bK' + Math.floor(Math.random() * 10000000);
2418
+        this.request_sender = request_sender;
2419
+        this.request = request;
2420
+        this.logger = request_sender.ua.getLogger('sip.transaction.nict', this.id);
2421
+        via = buildViaHeader(request_sender, transport, this.id);
2422
+        this.request.setHeader('via', via);
2423
+        this.request_sender.ua.newTransaction(this);
2424
+    };
2425
+    NonInviteClientTransaction.prototype = Object.create(SIP.EventEmitter.prototype);
2426
+    NonInviteClientTransaction.prototype.stateChanged = function (state) {
2427
+        this.state = state;
2428
+        this.emit('stateChanged');
2429
+    };
2430
+    NonInviteClientTransaction.prototype.send = function () {
2431
+        var tr = this;
2432
+        this.stateChanged(C.STATUS_TRYING);
2433
+        this.F = SIP.Timers.setTimeout(tr.timer_F.bind(tr), SIP.Timers.TIMER_F);
2434
+        this.transport.send(this.request).catch(function () {
2435
+            this.onTransportError();
2436
+        }.bind(this));
2437
+    };
2438
+    NonInviteClientTransaction.prototype.onTransportError = function () {
2439
+        this.logger.log('transport error occurred, deleting non-INVITE client transaction ' + this.id);
2440
+        SIP.Timers.clearTimeout(this.F);
2441
+        SIP.Timers.clearTimeout(this.K);
2442
+        this.stateChanged(C.STATUS_TERMINATED);
2443
+        this.request_sender.ua.destroyTransaction(this);
2444
+        this.request_sender.onTransportError();
2445
+    };
2446
+    NonInviteClientTransaction.prototype.timer_F = function () {
2447
+        this.logger.debug('Timer F expired for non-INVITE client transaction ' + this.id);
2448
+        this.stateChanged(C.STATUS_TERMINATED);
2449
+        this.request_sender.ua.destroyTransaction(this);
2450
+        this.request_sender.onRequestTimeout();
2451
+    };
2452
+    NonInviteClientTransaction.prototype.timer_K = function () {
2453
+        this.stateChanged(C.STATUS_TERMINATED);
2454
+        this.request_sender.ua.destroyTransaction(this);
2455
+    };
2456
+    NonInviteClientTransaction.prototype.receiveResponse = function (response) {
2457
+        var tr = this, status_code = response.status_code;
2458
+        if (status_code < 200) {
2459
+            switch (this.state) {
2460
+                case C.STATUS_TRYING:
2461
+                case C.STATUS_PROCEEDING:
2462
+                    this.stateChanged(C.STATUS_PROCEEDING);
2463
+                    this.request_sender.receiveResponse(response);
2464
+                    break;
2465
+            }
2466
+        }
2467
+        else {
2468
+            switch (this.state) {
2469
+                case C.STATUS_TRYING:
2470
+                case C.STATUS_PROCEEDING:
2471
+                    this.stateChanged(C.STATUS_COMPLETED);
2472
+                    SIP.Timers.clearTimeout(this.F);
2473
+                    if (status_code === 408) {
2474
+                        this.request_sender.onRequestTimeout();
2475
+                    }
2476
+                    else {
2477
+                        this.request_sender.receiveResponse(response);
2478
+                    }
2479
+                    this.K = SIP.Timers.setTimeout(tr.timer_K.bind(tr), SIP.Timers.TIMER_K);
2480
+                    break;
2481
+                case C.STATUS_COMPLETED:
2482
+                    break;
2483
+            }
2484
+        }
2485
+    };
2486
+    /**
2487
+    * @augments SIP.Transactions
2488
+    * @class Invite Client Transaction
2489
+    * @param {SIP.RequestSender} request_sender
2490
+    * @param {SIP.OutgoingRequest} request
2491
+    * @param {SIP.Transport} transport
2492
+    */
2493
+    var InviteClientTransaction = function (request_sender, request, transport) {
2494
+        var via, tr = this;
2495
+        this.type = C.INVITE_CLIENT;
2496
+        this.transport = transport;
2497
+        this.id = 'z9hG4bK' + Math.floor(Math.random() * 10000000);
2498
+        this.request_sender = request_sender;
2499
+        this.request = request;
2500
+        this.logger = request_sender.ua.getLogger('sip.transaction.ict', this.id);
2501
+        via = buildViaHeader(request_sender, transport, this.id);
2502
+        this.request.setHeader('via', via);
2503
+        this.request_sender.ua.newTransaction(this);
2504
+        // Add the cancel property to the request.
2505
+        //Will be called from the request instance, not the transaction itself.
2506
+        this.request.cancel = function (reason, extraHeaders) {
2507
+            extraHeaders = (extraHeaders || []).slice();
2508
+            var length = extraHeaders.length;
2509
+            var extraHeadersString = null;
2510
+            for (var idx = 0; idx < length; idx++) {
2511
+                extraHeadersString = (extraHeadersString || '') + extraHeaders[idx].trim() + '\r\n';
2512
+            }
2513
+            tr.cancel_request(tr, reason, extraHeadersString);
2514
+        };
2515
+    };
2516
+    InviteClientTransaction.prototype = Object.create(SIP.EventEmitter.prototype);
2517
+    InviteClientTransaction.prototype.stateChanged = function (state) {
2518
+        this.state = state;
2519
+        this.emit('stateChanged');
2520
+    };
2521
+    InviteClientTransaction.prototype.send = function () {
2522
+        var tr = this;
2523
+        this.stateChanged(C.STATUS_CALLING);
2524
+        this.B = SIP.Timers.setTimeout(tr.timer_B.bind(tr), SIP.Timers.TIMER_B);
2525
+        this.transport.send(this.request).catch(function () {
2526
+            this.onTransportError();
2527
+        }.bind(this));
2528
+    };
2529
+    InviteClientTransaction.prototype.onTransportError = function () {
2530
+        this.logger.log('transport error occurred, deleting INVITE client transaction ' + this.id);
2531
+        SIP.Timers.clearTimeout(this.B);
2532
+        SIP.Timers.clearTimeout(this.D);
2533
+        SIP.Timers.clearTimeout(this.M);
2534
+        this.stateChanged(C.STATUS_TERMINATED);
2535
+        this.request_sender.ua.destroyTransaction(this);
2536
+        if (this.state !== C.STATUS_ACCEPTED) {
2537
+            this.request_sender.onTransportError();
2538
+        }
2539
+    };
2540
+    // RFC 6026 7.2
2541
+    InviteClientTransaction.prototype.timer_M = function () {
2542
+        this.logger.debug('Timer M expired for INVITE client transaction ' + this.id);
2543
+        if (this.state === C.STATUS_ACCEPTED) {
2544
+            SIP.Timers.clearTimeout(this.B);
2545
+            this.stateChanged(C.STATUS_TERMINATED);
2546
+            this.request_sender.ua.destroyTransaction(this);
2547
+        }
2548
+    };
2549
+    // RFC 3261 17.1.1
2550
+    InviteClientTransaction.prototype.timer_B = function () {
2551
+        this.logger.debug('Timer B expired for INVITE client transaction ' + this.id);
2552
+        if (this.state === C.STATUS_CALLING) {
2553
+            this.stateChanged(C.STATUS_TERMINATED);
2554
+            this.request_sender.ua.destroyTransaction(this);
2555
+            this.request_sender.onRequestTimeout();
2556
+        }
2557
+    };
2558
+    InviteClientTransaction.prototype.timer_D = function () {
2559
+        this.logger.debug('Timer D expired for INVITE client transaction ' + this.id);
2560
+        SIP.Timers.clearTimeout(this.B);
2561
+        this.stateChanged(C.STATUS_TERMINATED);
2562
+        this.request_sender.ua.destroyTransaction(this);
2563
+    };
2564
+    InviteClientTransaction.prototype.sendACK = function (options) {
2565
+        // TODO: Move PRACK stuff into the transaction layer. That is really where it should be
2566
+        var self = this, ruri;
2567
+        options = options || {};
2568
+        if (this.response.getHeader('contact')) {
2569
+            ruri = this.response.parseHeader('contact').uri;
2570
+        }
2571
+        else {
2572
+            ruri = this.request.ruri;
2573
+        }
2574
+        var ack = new SIP.OutgoingRequest("ACK", ruri, this.request.ua, {
2575
+            cseq: this.response.cseq,
2576
+            call_id: this.response.call_id,
2577
+            from_uri: this.response.from.uri,
2578
+            from_tag: this.response.from_tag,
2579
+            to_uri: this.response.to.uri,
2580
+            to_tag: this.response.to_tag,
2581
+            route_set: this.response.getHeaders('record-route').reverse()
2582
+        }, options.extraHeaders || [], options.body);
2583
+        this.ackSender = new SIP.RequestSender({
2584
+            request: ack,
2585
+            onRequestTimeout: this.request_sender.applicant.applicant ? this.request_sender.applicant.applicant.onRequestTimeout : function () {
2586
+                self.logger.warn("ACK Request timed out");
2587
+            },
2588
+            onTransportError: this.request_sender.applicant.applicant ? this.request_sender.applicant.applicant.onRequestTransportError : function () {
2589
+                self.logger.warn("ACK Request had a transport error");
2590
+            },
2591
+            receiveResponse: options.receiveResponse || function () {
2592
+                self.logger.warn("Received a response to an ACK which was unexpected. Dropping Response.");
2593
+            }
2594
+        }, this.request.ua).send();
2595
+        return ack;
2596
+    };
2597
+    InviteClientTransaction.prototype.cancel_request = function (tr, reason, extraHeaders) {
2598
+        var request = tr.request;
2599
+        this.cancel = SIP.C.CANCEL + ' ' + request.ruri + ' SIP/2.0\r\n';
2600
+        this.cancel += 'Via: ' + request.headers['Via'].toString() + '\r\n';
2601
+        if (this.request.headers['Route']) {
2602
+            this.cancel += 'Route: ' + request.headers['Route'].toString() + '\r\n';
2603
+        }
2604
+        this.cancel += 'To: ' + request.headers['To'].toString() + '\r\n';
2605
+        this.cancel += 'From: ' + request.headers['From'].toString() + '\r\n';
2606
+        this.cancel += 'Call-ID: ' + request.headers['Call-ID'].toString() + '\r\n';
2607
+        this.cancel += 'Max-Forwards: ' + SIP.UA.C.MAX_FORWARDS + '\r\n';
2608
+        this.cancel += 'CSeq: ' + request.headers['CSeq'].toString().split(' ')[0] +
2609
+            ' CANCEL\r\n';
2610
+        if (reason) {
2611
+            this.cancel += 'Reason: ' + reason + '\r\n';
2612
+        }
2613
+        if (extraHeaders) {
2614
+            this.cancel += extraHeaders;
2615
+        }
2616
+        this.cancel += 'Content-Length: 0\r\n\r\n';
2617
+        // Send only if a provisional response (>100) has been received.
2618
+        if (this.state === C.STATUS_PROCEEDING) {
2619
+            this.transport.send(this.cancel);
2620
+        }
2621
+    };
2622
+    InviteClientTransaction.prototype.receiveResponse = function (response) {
2623
+        var tr = this, status_code = response.status_code;
2624
+        // This may create a circular dependency...
2625
+        response.transaction = this;
2626
+        if (this.response &&
2627
+            this.response.status_code === response.status_code &&
2628
+            this.response.cseq === response.cseq) {
2629
+            this.logger.debug("ICT Received a retransmission for cseq: " + response.cseq);
2630
+            if (this.ackSender) {
2631
+                this.ackSender.send();
2632
+            }
2633
+            return;
2634
+        }
2635
+        this.response = response;
2636
+        if (status_code >= 100 && status_code <= 199) {
2637
+            switch (this.state) {
2638
+                case C.STATUS_CALLING:
2639
+                    this.stateChanged(C.STATUS_PROCEEDING);
2640
+                    this.request_sender.receiveResponse(response);
2641
+                    if (this.cancel) {
2642
+                        this.transport.send(this.cancel);
2643
+                    }
2644
+                    break;
2645
+                case C.STATUS_PROCEEDING:
2646
+                    this.request_sender.receiveResponse(response);
2647
+                    break;
2648
+            }
2649
+        }
2650
+        else if (status_code >= 200 && status_code <= 299) {
2651
+            switch (this.state) {
2652
+                case C.STATUS_CALLING:
2653
+                case C.STATUS_PROCEEDING:
2654
+                    this.stateChanged(C.STATUS_ACCEPTED);
2655
+                    this.M = SIP.Timers.setTimeout(tr.timer_M.bind(tr), SIP.Timers.TIMER_M);
2656
+                    this.request_sender.receiveResponse(response);
2657
+                    break;
2658
+                case C.STATUS_ACCEPTED:
2659
+                    this.request_sender.receiveResponse(response);
2660
+                    break;
2661
+            }
2662
+        }
2663
+        else if (status_code >= 300 && status_code <= 699) {
2664
+            switch (this.state) {
2665
+                case C.STATUS_CALLING:
2666
+                case C.STATUS_PROCEEDING:
2667
+                    this.stateChanged(C.STATUS_COMPLETED);
2668
+                    this.sendACK();
2669
+                    this.request_sender.receiveResponse(response);
2670
+                    break;
2671
+                case C.STATUS_COMPLETED:
2672
+                    this.sendACK();
2673
+                    break;
2674
+            }
2675
+        }
2676
+    };
2677
+    /**
2678
+     * @augments SIP.Transactions
2679
+     * @class ACK Client Transaction
2680
+     * @param {SIP.RequestSender} request_sender
2681
+     * @param {SIP.OutgoingRequest} request
2682
+     * @param {SIP.Transport} transport
2683
+     */
2684
+    var AckClientTransaction = function (request_sender, request, transport) {
2685
+        var via;
2686
+        this.transport = transport;
2687
+        this.id = 'z9hG4bK' + Math.floor(Math.random() * 10000000);
2688
+        this.request_sender = request_sender;
2689
+        this.request = request;
2690
+        this.logger = request_sender.ua.getLogger('sip.transaction.nict', this.id);
2691
+        via = buildViaHeader(request_sender, transport, this.id);
2692
+        this.request.setHeader('via', via);
2693
+    };
2694
+    AckClientTransaction.prototype = Object.create(SIP.EventEmitter.prototype);
2695
+    AckClientTransaction.prototype.send = function () {
2696
+        this.transport.send(this.request).catch(function () {
2697
+            this.onTransportError();
2698
+        }.bind(this));
2699
+    };
2700
+    AckClientTransaction.prototype.onTransportError = function () {
2701
+        this.logger.log('transport error occurred, for an ACK client transaction ' + this.id);
2702
+        this.request_sender.onTransportError();
2703
+    };
2704
+    /**
2705
+    * @augments SIP.Transactions
2706
+    * @class Non Invite Server Transaction
2707
+    * @param {SIP.IncomingRequest} request
2708
+    * @param {SIP.UA} ua
2709
+    */
2710
+    var NonInviteServerTransaction = function (request, ua) {
2711
+        this.type = C.NON_INVITE_SERVER;
2712
+        this.id = request.via_branch;
2713
+        this.request = request;
2714
+        this.transport = ua.transport;
2715
+        this.ua = ua;
2716
+        this.last_response = '';
2717
+        request.server_transaction = this;
2718
+        this.logger = ua.getLogger('sip.transaction.nist', this.id);
2719
+        this.state = C.STATUS_TRYING;
2720
+        ua.newTransaction(this);
2721
+    };
2722
+    NonInviteServerTransaction.prototype = Object.create(SIP.EventEmitter.prototype);
2723
+    NonInviteServerTransaction.prototype.stateChanged = function (state) {
2724
+        this.state = state;
2725
+        this.emit('stateChanged');
2726
+    };
2727
+    NonInviteServerTransaction.prototype.timer_J = function () {
2728
+        this.logger.debug('Timer J expired for non-INVITE server transaction ' + this.id);
2729
+        this.stateChanged(C.STATUS_TERMINATED);
2730
+        this.ua.destroyTransaction(this);
2731
+    };
2732
+    NonInviteServerTransaction.prototype.onTransportError = function () {
2733
+        if (!this.transportError) {
2734
+            this.transportError = true;
2735
+            this.logger.log('transport error occurred, deleting non-INVITE server transaction ' + this.id);
2736
+            SIP.Timers.clearTimeout(this.J);
2737
+            this.stateChanged(C.STATUS_TERMINATED);
2738
+            this.ua.destroyTransaction(this);
2739
+        }
2740
+    };
2741
+    NonInviteServerTransaction.prototype.receiveResponse = function (status_code, response) {
2742
+        var tr = this;
2743
+        var deferred = SIP.Utils.defer();
2744
+        if (status_code === 100) {
2745
+            /* RFC 4320 4.1
2746
+             * 'A SIP element MUST NOT
2747
+             * send any provisional response with a
2748
+             * Status-Code other than 100 to a non-INVITE request.'
2749
+             */
2750
+            switch (this.state) {
2751
+                case C.STATUS_TRYING:
2752
+                    this.stateChanged(C.STATUS_PROCEEDING);
2753
+                    this.transport.send(response).catch(function () {
2754
+                        this.onTransportError();
2755
+                    }.bind(this));
2756
+                    break;
2757
+                case C.STATUS_PROCEEDING:
2758
+                    this.last_response = response;
2759
+                    this.transport.send(response).then(function () {
2760
+                        deferred.resolve();
2761
+                    }).catch(function () {
2762
+                        this.onTransportError();
2763
+                        deferred.reject();
2764
+                    }.bind(this));
2765
+                    break;
2766
+            }
2767
+        }
2768
+        else if (status_code >= 200 && status_code <= 699) {
2769
+            switch (this.state) {
2770
+                case C.STATUS_TRYING:
2771
+                case C.STATUS_PROCEEDING:
2772
+                    this.stateChanged(C.STATUS_COMPLETED);
2773
+                    this.last_response = response;
2774
+                    this.J = SIP.Timers.setTimeout(tr.timer_J.bind(tr), SIP.Timers.TIMER_J);
2775
+                    this.transport.send(response).then(function () {
2776
+                        deferred.resolve();
2777
+                    }).catch(function () {
2778
+                        this.onTransportError();
2779
+                        deferred.reject();
2780
+                    }.bind(this));
2781
+                    break;
2782
+                case C.STATUS_COMPLETED:
2783
+                    break;
2784
+            }
2785
+        }
2786
+        return deferred.promise;
2787
+    };
2788
+    /**
2789
+    * @augments SIP.Transactions
2790
+    * @class Invite Server Transaction
2791
+    * @param {SIP.IncomingRequest} request
2792
+    * @param {SIP.UA} ua
2793
+    */
2794
+    var InviteServerTransaction = function (request, ua) {
2795
+        this.type = C.INVITE_SERVER;
2796
+        this.id = request.via_branch;
2797
+        this.request = request;
2798
+        this.transport = ua.transport;
2799
+        this.ua = ua;
2800
+        this.last_response = '';
2801
+        request.server_transaction = this;
2802
+        this.logger = ua.getLogger('sip.transaction.ist', this.id);
2803
+        this.state = C.STATUS_PROCEEDING;
2804
+        ua.newTransaction(this);
2805
+        this.resendProvisionalTimer = null;
2806
+        request.reply(100);
2807
+    };
2808
+    InviteServerTransaction.prototype = Object.create(SIP.EventEmitter.prototype);
2809
+    InviteServerTransaction.prototype.stateChanged = function (state) {
2810
+        this.state = state;
2811
+        this.emit('stateChanged');
2812
+    };
2813
+    InviteServerTransaction.prototype.timer_H = function () {
2814
+        this.logger.debug('Timer H expired for INVITE server transaction ' + this.id);
2815
+        if (this.state === C.STATUS_COMPLETED) {
2816
+            this.logger.warn('transactions', 'ACK for INVITE server transaction was never received, call will be terminated');
2817
+        }
2818
+        this.stateChanged(C.STATUS_TERMINATED);
2819
+        this.ua.destroyTransaction(this);
2820
+    };
2821
+    InviteServerTransaction.prototype.timer_I = function () {
2822
+        this.stateChanged(C.STATUS_TERMINATED);
2823
+        this.ua.destroyTransaction(this);
2824
+    };
2825
+    // RFC 6026 7.1
2826
+    InviteServerTransaction.prototype.timer_L = function () {
2827
+        this.logger.debug('Timer L expired for INVITE server transaction ' + this.id);
2828
+        if (this.state === C.STATUS_ACCEPTED) {
2829
+            this.stateChanged(C.STATUS_TERMINATED);
2830
+            this.ua.destroyTransaction(this);
2831
+        }
2832
+    };
2833
+    InviteServerTransaction.prototype.onTransportError = function () {
2834
+        if (!this.transportError) {
2835
+            this.transportError = true;
2836
+            this.logger.log('transport error occurred, deleting INVITE server transaction ' + this.id);
2837
+            if (this.resendProvisionalTimer !== null) {
2838
+                SIP.Timers.clearInterval(this.resendProvisionalTimer);
2839
+                this.resendProvisionalTimer = null;
2840
+            }
2841
+            SIP.Timers.clearTimeout(this.L);
2842
+            SIP.Timers.clearTimeout(this.H);
2843
+            SIP.Timers.clearTimeout(this.I);
2844
+            this.stateChanged(C.STATUS_TERMINATED);
2845
+            this.ua.destroyTransaction(this);
2846
+        }
2847
+    };
2848
+    InviteServerTransaction.prototype.resend_provisional = function () {
2849
+        this.transport.send(this.request).catch(function () {
2850
+            this.onTransportError();
2851
+        }.bind(this));
2852
+    };
2853
+    // INVITE Server Transaction RFC 3261 17.2.1
2854
+    InviteServerTransaction.prototype.receiveResponse = function (status_code, response) {
2855
+        var tr = this;
2856
+        var deferred = SIP.Utils.defer();
2857
+        if (status_code >= 100 && status_code <= 199) {
2858
+            switch (this.state) {
2859
+                case C.STATUS_PROCEEDING:
2860
+                    this.transport.send(response).catch(function () {
2861
+                        this.onTransportError();
2862
+                    }.bind(this));
2863
+                    this.last_response = response;
2864
+                    break;
2865
+            }
2866
+        }
2867
+        if (status_code > 100 && status_code <= 199 && this.state === C.STATUS_PROCEEDING) {
2868
+            // Trigger the resendProvisionalTimer only for the first non 100 provisional response.
2869
+            if (this.resendProvisionalTimer === null) {
2870
+                this.resendProvisionalTimer = SIP.Timers.setInterval(tr.resend_provisional.bind(tr), SIP.Timers.PROVISIONAL_RESPONSE_INTERVAL);
2871
+            }
2872
+        }
2873
+        else if (status_code >= 200 && status_code <= 299) {
2874
+            switch (this.state) {
2875
+                case C.STATUS_PROCEEDING:
2876
+                    this.stateChanged(C.STATUS_ACCEPTED);
2877
+                    this.last_response = response;
2878
+                    this.L = SIP.Timers.setTimeout(tr.timer_L.bind(tr), SIP.Timers.TIMER_L);
2879
+                    if (this.resendProvisionalTimer !== null) {
2880
+                        SIP.Timers.clearInterval(this.resendProvisionalTimer);
2881
+                        this.resendProvisionalTimer = null;
2882
+                    }
2883
+                /* falls through */
2884
+                case C.STATUS_ACCEPTED:
2885
+                    // Note that this point will be reached for proceeding tr.state also.
2886
+                    this.transport.send(response).then(function () {
2887
+                        deferred.resolve();
2888
+                    }).catch(function (error) {
2889
+                        this.logger.error(error);
2890
+                        this.onTransportError();
2891
+                        deferred.reject();
2892
+                    }.bind(this));
2893
+                    break;
2894
+            }
2895
+        }
2896
+        else if (status_code >= 300 && status_code <= 699) {
2897
+            switch (this.state) {
2898
+                case C.STATUS_PROCEEDING:
2899
+                    if (this.resendProvisionalTimer !== null) {
2900
+                        SIP.Timers.clearInterval(this.resendProvisionalTimer);
2901
+                        this.resendProvisionalTimer = null;
2902
+                    }
2903
+                    this.transport.send(response).then(function () {
2904
+                        this.stateChanged(C.STATUS_COMPLETED);
2905
+                        this.H = SIP.Timers.setTimeout(tr.timer_H.bind(tr), SIP.Timers.TIMER_H);
2906
+                        deferred.resolve();
2907
+                    }.bind(this)).catch(function (error) {
2908
+                        this.logger.error(error);
2909
+                        this.onTransportError();
2910
+                        deferred.reject();
2911
+                    }.bind(this));
2912
+                    break;
2913
+            }
2914
+        }
2915
+        return deferred.promise;
2916
+    };
2917
+    /**
2918
+     * @function
2919
+     * @param {SIP.UA} ua
2920
+     * @param {SIP.IncomingRequest} request
2921
+     *
2922
+     * @return {boolean}
2923
+     * INVITE:
2924
+     *  _true_ if retransmission
2925
+     *  _false_ new request
2926
+     *
2927
+     * ACK:
2928
+     *  _true_  ACK to non2xx response
2929
+     *  _false_ ACK must be passed to TU (accepted state)
2930
+     *          ACK to 2xx response
2931
+     *
2932
+     * CANCEL:
2933
+     *  _true_  no matching invite transaction
2934
+     *  _false_ matching invite transaction and no final response sent
2935
+     *
2936
+     * OTHER:
2937
+     *  _true_  retransmission
2938
+     *  _false_ new request
2939
+     */
2940
+    var checkTransaction = function (ua, request) {
2941
+        var tr;
2942
+        switch (request.method) {
2943
+            case SIP.C.INVITE:
2944
+                tr = ua.transactions.ist[request.via_branch];
2945
+                if (tr) {
2946
+                    switch (tr.state) {
2947
+                        case C.STATUS_PROCEEDING:
2948
+                            tr.transport.send(tr.last_response);
2949
+                            break;
2950
+                        // RFC 6026 7.1 Invite retransmission
2951
+                        //received while in C.STATUS_ACCEPTED state. Absorb it.
2952
+                        case C.STATUS_ACCEPTED:
2953
+                            break;
2954
+                    }
2955
+                    return true;
2956
+                }
2957
+                break;
2958
+            case SIP.C.ACK:
2959
+                tr = ua.transactions.ist[request.via_branch];
2960
+                // RFC 6026 7.1
2961
+                if (tr) {
2962
+                    if (tr.state === C.STATUS_ACCEPTED) {
2963
+                        return false;
2964
+                    }
2965
+                    else if (tr.state === C.STATUS_COMPLETED) {
2966
+                        tr.stateChanged(C.STATUS_CONFIRMED);
2967
+                        tr.I = SIP.Timers.setTimeout(tr.timer_I.bind(tr), SIP.Timers.TIMER_I);
2968
+                        return true;
2969
+                    }
2970
+                }
2971
+                // ACK to 2XX Response.
2972
+                else {
2973
+                    return false;
2974
+                }
2975
+                break;
2976
+            case SIP.C.CANCEL:
2977
+                tr = ua.transactions.ist[request.via_branch];
2978
+                if (tr) {
2979
+                    request.reply_sl(200);
2980
+                    if (tr.state === C.STATUS_PROCEEDING) {
2981
+                        return false;
2982
+                    }
2983
+                    else {
2984
+                        return true;
2985
+                    }
2986
+                }
2987
+                else {
2988
+                    request.reply_sl(481);
2989
+                    return true;
2990
+                }
2991
+            default:
2992
+                // Non-INVITE Server Transaction RFC 3261 17.2.2
2993
+                tr = ua.transactions.nist[request.via_branch];
2994
+                if (tr) {
2995
+                    switch (tr.state) {
2996
+                        case C.STATUS_TRYING:
2997
+                            break;
2998
+                        case C.STATUS_PROCEEDING:
2999
+                        case C.STATUS_COMPLETED:
3000
+                            tr.transport.send(tr.last_response);
3001
+                            break;
3002
+                    }
3003
+                    return true;
3004
+                }
3005
+                break;
3006
+        }
3007
+    };
3008
+    SIP.Transactions = {
3009
+        C: C,
3010
+        checkTransaction: checkTransaction,
3011
+        NonInviteClientTransaction: NonInviteClientTransaction,
3012
+        InviteClientTransaction: InviteClientTransaction,
3013
+        AckClientTransaction: AckClientTransaction,
3014
+        NonInviteServerTransaction: NonInviteServerTransaction,
3015
+        InviteServerTransaction: InviteServerTransaction
3016
+    };
3017
+};
3018
+
3019
+
3020
+/***/ }),
3021
+/* 16 */
3022
+/***/ (function(module, exports, __webpack_require__) {
3023
+
3024
+"use strict";
3025
+
3026
+/**
3027
+ * @fileoverview SIP Dialog
3028
+ */
3029
+/**
3030
+ * @augments SIP
3031
+ * @class Class creating a SIP dialog.
3032
+ * @param {SIP.RTCSession} owner
3033
+ * @param {SIP.IncomingRequest|SIP.IncomingResponse} message
3034
+ * @param {Enum} type UAC / UAS
3035
+ * @param {Enum} state SIP.Dialog.C.STATUS_EARLY / SIP.Dialog.C.STATUS_CONFIRMED
3036
+ */
3037
+module.exports = function (SIP) {
3038
+    var RequestSender = __webpack_require__(17)(SIP);
3039
+    var Dialog, C = {
3040
+        // Dialog states
3041
+        STATUS_EARLY: 1,
3042
+        STATUS_CONFIRMED: 2
3043
+    };
3044
+    // RFC 3261 12.1
3045
+    Dialog = function (owner, message, type, state) {
3046
+        var contact;
3047
+        this.uac_pending_reply = false;
3048
+        this.uas_pending_reply = false;
3049
+        if (!message.hasHeader('contact')) {
3050
+            return {
3051
+                error: 'unable to create a Dialog without Contact header field'
3052
+            };
3053
+        }
3054
+        if (message instanceof SIP.IncomingResponse) {
3055
+            state = (message.status_code < 200) ? C.STATUS_EARLY : C.STATUS_CONFIRMED;
3056
+        }
3057
+        else {
3058
+            // Create confirmed dialog if state is not defined
3059
+            state = state || C.STATUS_CONFIRMED;
3060
+        }
3061
+        contact = message.parseHeader('contact');
3062
+        // RFC 3261 12.1.1
3063
+        if (type === 'UAS') {
3064
+            this.id = {
3065
+                call_id: message.call_id,
3066
+                local_tag: message.to_tag,
3067
+                remote_tag: message.from_tag,
3068
+                toString: function () {
3069
+                    return this.call_id + this.local_tag + this.remote_tag;
3070
+                }
3071
+            };
3072
+            this.state = state;
3073
+            this.remote_seqnum = message.cseq;
3074
+            this.local_uri = message.parseHeader('to').uri;
3075
+            this.remote_uri = message.parseHeader('from').uri;
3076
+            this.remote_target = contact.uri;
3077
+            this.route_set = message.getHeaders('record-route');
3078
+            this.invite_seqnum = message.cseq;
3079
+            this.local_seqnum = message.cseq;
3080
+        }
3081
+        // RFC 3261 12.1.2
3082
+        else if (type === 'UAC') {
3083
+            this.id = {
3084
+                call_id: message.call_id,
3085
+                local_tag: message.from_tag,
3086
+                remote_tag: message.to_tag,
3087
+                toString: function () {
3088
+                    return this.call_id + this.local_tag + this.remote_tag;
3089
+                }
3090
+            };
3091
+            this.state = state;
3092
+            this.invite_seqnum = message.cseq;
3093
+            this.local_seqnum = message.cseq;
3094
+            this.local_uri = message.parseHeader('from').uri;
3095
+            this.pracked = [];
3096
+            this.remote_uri = message.parseHeader('to').uri;
3097
+            this.remote_target = contact.uri;
3098
+            this.route_set = message.getHeaders('record-route').reverse();
3099
+        }
3100
+        this.logger = owner.ua.getLogger('sip.dialog', this.id.toString());
3101
+        this.owner = owner;
3102
+        owner.ua.dialogs[this.id.toString()] = this;
3103
+        this.logger.log('new ' + type + ' dialog created with status ' + (this.state === C.STATUS_EARLY ? 'EARLY' : 'CONFIRMED'));
3104
+        owner.emit('dialog', this);
3105
+    };
3106
+    Dialog.prototype = {
3107
+        /**
3108
+         * @param {SIP.IncomingMessage} message
3109
+         * @param {Enum} UAC/UAS
3110
+         */
3111
+        update: function (message, type) {
3112
+            this.state = C.STATUS_CONFIRMED;
3113
+            this.logger.log('dialog ' + this.id.toString() + '  changed to CONFIRMED state');
3114
+            if (type === 'UAC') {
3115
+                // RFC 3261 13.2.2.4
3116
+                this.route_set = message.getHeaders('record-route').reverse();
3117
+            }
3118
+        },
3119
+        terminate: function () {
3120
+            this.logger.log('dialog ' + this.id.toString() + ' deleted');
3121
+            if (this.sessionDescriptionHandler && this.state !== C.STATUS_CONFIRMED) {
3122
+                // TODO: This should call .close() on the handler when implemented
3123
+                this.sessionDescriptionHandler.close();
3124
+            }
3125
+            delete this.owner.ua.dialogs[this.id.toString()];
3126
+        },
3127
+        /**
3128
+        * @param {String} method request method
3129
+        * @param {Object} extraHeaders extra headers
3130
+        * @returns {SIP.OutgoingRequest}
3131
+        */
3132
+        // RFC 3261 12.2.1.1
3133
+        createRequest: function (method, extraHeaders, body) {
3134
+            var cseq, request;
3135
+            extraHeaders = (extraHeaders || []).slice();
3136
+            if (!this.local_seqnum) {
3137
+                this.local_seqnum = Math.floor(Math.random() * 10000);
3138
+            }
3139
+            cseq = (method === SIP.C.CANCEL || method === SIP.C.ACK) ? this.invite_seqnum : this.local_seqnum += 1;
3140
+            request = new SIP.OutgoingRequest(method, this.remote_target, this.owner.ua, {
3141
+                'cseq': cseq,
3142
+                'call_id': this.id.call_id,
3143
+                'from_uri': this.local_uri,
3144
+                'from_tag': this.id.local_tag,
3145
+                'to_uri': this.remote_uri,
3146
+                'to_tag': this.id.remote_tag,
3147
+                'route_set': this.route_set
3148
+            }, extraHeaders, body);
3149
+            request.dialog = this;
3150
+            return request;
3151
+        },
3152
+        /**
3153
+        * @param {SIP.IncomingRequest} request
3154
+        * @returns {Boolean}
3155
+        */
3156
+        // RFC 3261 12.2.2
3157
+        checkInDialogRequest: function (request) {
3158
+            var self = this;
3159
+            if (!this.remote_seqnum) {
3160
+                this.remote_seqnum = request.cseq;
3161
+            }
3162
+            else if (request.cseq < this.remote_seqnum) {
3163
+                //Do not try to reply to an ACK request.
3164
+                if (request.method !== SIP.C.ACK) {
3165
+                    request.reply(500);
3166
+                }
3167
+                if (request.cseq === this.invite_seqnum) {
3168
+                    return true;
3169
+                }
3170
+                return false;
3171
+            }
3172
+            switch (request.method) {
3173
+                // RFC3261 14.2 Modifying an Existing Session -UAS BEHAVIOR-
3174
+                case SIP.C.INVITE:
3175
+                    if (this.uac_pending_reply === true) {
3176
+                        request.reply(491);
3177
+                    }
3178
+                    else if (this.uas_pending_reply === true && request.cseq > this.remote_seqnum) {
3179
+                        var retryAfter = (Math.random() * 10 | 0) + 1;
3180
+                        request.reply(500, null, ['Retry-After:' + retryAfter]);
3181
+                        this.remote_seqnum = request.cseq;
3182
+                        return false;
3183
+                    }
3184
+                    else {
3185
+                        this.uas_pending_reply = true;
3186
+                        request.server_transaction.on('stateChanged', function stateChanged() {
3187
+                            if (this.state === SIP.Transactions.C.STATUS_ACCEPTED ||
3188
+                                this.state === SIP.Transactions.C.STATUS_COMPLETED ||
3189
+                                this.state === SIP.Transactions.C.STATUS_TERMINATED) {
3190
+                                this.removeListener('stateChanged', stateChanged);
3191
+                                self.uas_pending_reply = false;
3192
+                            }
3193
+                        });
3194
+                    }
3195
+                    // RFC3261 12.2.2 Replace the dialog`s remote target URI if the request is accepted
3196
+                    if (request.hasHeader('contact')) {
3197
+                        request.server_transaction.on('stateChanged', function () {
3198
+                            if (this.state === SIP.Transactions.C.STATUS_ACCEPTED) {
3199
+                                self.remote_target = request.parseHeader('contact').uri;
3200
+                            }
3201
+                        });
3202
+                    }
3203
+                    break;
3204
+                case SIP.C.NOTIFY:
3205
+                    // RFC6665 3.2 Replace the dialog`s remote target URI if the request is accepted
3206
+                    if (request.hasHeader('contact')) {
3207
+                        request.server_transaction.on('stateChanged', function () {
3208
+                            if (this.state === SIP.Transactions.C.STATUS_COMPLETED) {
3209
+                                self.remote_target = request.parseHeader('contact').uri;
3210
+                            }
3211
+                        });
3212
+                    }
3213
+                    break;
3214
+            }
3215
+            if (request.cseq > this.remote_seqnum) {
3216
+                this.remote_seqnum = request.cseq;
3217
+            }
3218
+            return true;
3219
+        },
3220
+        sendRequest: function (applicant, method, options) {
3221
+            options = options || {};
3222
+            var extraHeaders = (options.extraHeaders || []).slice();
3223
+            var body = null;
3224
+            if (options.body) {
3225
+                if (options.body.body) {
3226
+                    body = options.body;
3227
+                }
3228
+                else {
3229
+                    body = {};
3230
+                    body.body = options.body;
3231
+                    if (options.contentType) {
3232
+                        body.contentType = options.contentType;
3233
+                    }
3234
+                }
3235
+            }
3236
+            var request = this.createRequest(method, extraHeaders, body), request_sender = new RequestSender(this, applicant, request);
3237
+            request_sender.send();
3238
+            return request;
3239
+        },
3240
+        /**
3241
+        * @param {SIP.IncomingRequest} request
3242
+        */
3243
+        receiveRequest: function (request) {
3244
+            //Check in-dialog request
3245
+            if (!this.checkInDialogRequest(request)) {
3246
+                return;
3247
+            }
3248
+            this.owner.receiveRequest(request);
3249
+        }
3250
+    };
3251
+    Dialog.C = C;
3252
+    SIP.Dialog = Dialog;
3253
+};
3254
+
3255
+
3256
+/***/ }),
3257
+/* 17 */
3258
+/***/ (function(module, exports, __webpack_require__) {
3259
+
3260
+"use strict";
3261
+
3262
+/**
3263
+ * @fileoverview In-Dialog Request Sender
3264
+ */
3265
+/**
3266
+ * @augments SIP.Dialog
3267
+ * @class Class creating an In-dialog request sender.
3268
+ * @param {SIP.Dialog} dialog
3269
+ * @param {Object} applicant
3270
+ * @param {SIP.OutgoingRequest} request
3271
+ */
3272
+/**
3273
+ * @fileoverview in-Dialog Request Sender
3274
+ */
3275
+module.exports = function (SIP) {
3276
+    var RequestSender;
3277
+    RequestSender = function (dialog, applicant, request) {
3278
+        this.dialog = dialog;
3279
+        this.applicant = applicant;
3280
+        this.request = request;
3281
+        // RFC3261 14.1 Modifying an Existing Session. UAC Behavior.
3282
+        this.reattempt = false;
3283
+        this.reattemptTimer = null;
3284
+    };
3285
+    RequestSender.prototype = {
3286
+        send: function () {
3287
+            var self = this, request_sender = new SIP.RequestSender(this, this.dialog.owner.ua);
3288
+            request_sender.send();
3289
+            // RFC3261 14.2 Modifying an Existing Session -UAC BEHAVIOR-
3290
+            if (this.request.method === SIP.C.INVITE && request_sender.clientTransaction.state !== SIP.Transactions.C.STATUS_TERMINATED) {
3291
+                this.dialog.uac_pending_reply = true;
3292
+                request_sender.clientTransaction.on('stateChanged', function stateChanged() {
3293
+                    if (this.state === SIP.Transactions.C.STATUS_ACCEPTED ||
3294
+                        this.state === SIP.Transactions.C.STATUS_COMPLETED ||
3295
+                        this.state === SIP.Transactions.C.STATUS_TERMINATED) {
3296
+                        this.removeListener('stateChanged', stateChanged);
3297
+                        self.dialog.uac_pending_reply = false;
3298
+                    }
3299
+                });
3300
+            }
3301
+        },
3302
+        onRequestTimeout: function () {
3303
+            this.applicant.onRequestTimeout();
3304
+        },
3305
+        onTransportError: function () {
3306
+            this.applicant.onTransportError();
3307
+        },
3308
+        receiveResponse: function (response) {
3309
+            var self = this;
3310
+            // RFC3261 12.2.1.2 408 or 481 is received for a request within a dialog.
3311
+            if (response.status_code === 408 || response.status_code === 481) {
3312
+                this.applicant.onDialogError(response);
3313
+            }
3314
+            else if (response.method === SIP.C.INVITE && response.status_code === 491) {
3315
+                if (this.reattempt) {
3316
+                    this.applicant.receiveResponse(response);
3317
+                }
3318
+                else {
3319
+                    this.request.cseq.value = this.dialog.local_seqnum += 1;
3320
+                    this.reattemptTimer = SIP.Timers.setTimeout(function () {
3321
+                        if (self.applicant.owner.status !== SIP.Session.C.STATUS_TERMINATED) {
3322
+                            self.reattempt = true;
3323
+                            self.request_sender.send();
3324
+                        }
3325
+                    }, this.getReattemptTimeout());
3326
+                }
3327
+            }
3328
+            else {
3329
+                this.applicant.receiveResponse(response);
3330
+            }
3331
+        }
3332
+    };
3333
+    return RequestSender;
3334
+};
3335
+
3336
+
3337
+/***/ }),
3338
+/* 18 */
3339
+/***/ (function(module, exports, __webpack_require__) {
3340
+
3341
+"use strict";
3342
+
3343
+/**
3344
+ * @fileoverview Request Sender
3345
+ */
3346
+/**
3347
+ * @augments SIP
3348
+ * @class Class creating a request sender.
3349
+ * @param {Object} applicant
3350
+ * @param {SIP.UA} ua
3351
+ */
3352
+module.exports = function (SIP) {
3353
+    var RequestSender;
3354
+    RequestSender = function (applicant, ua) {
3355
+        this.logger = ua.getLogger('sip.requestsender');
3356
+        this.ua = ua;
3357
+        this.applicant = applicant;
3358
+        this.method = applicant.request.method;
3359
+        this.request = applicant.request;
3360
+        this.credentials = null;
3361
+        this.challenged = false;
3362
+        this.staled = false;
3363
+        // If ua is in closing process or even closed just allow sending Bye and ACK
3364
+        if (ua.status === SIP.UA.C.STATUS_USER_CLOSED && (this.method !== SIP.C.BYE || this.method !== SIP.C.ACK)) {
3365
+            this.onTransportError();
3366
+        }
3367
+    };
3368
+    /**
3369
+    * Create the client transaction and send the message.
3370
+    */
3371
+    RequestSender.prototype = {
3372
+        send: function () {
3373
+            switch (this.method) {
3374
+                case "INVITE":
3375
+                    this.clientTransaction = new SIP.Transactions.InviteClientTransaction(this, this.request, this.ua.transport);
3376
+                    break;
3377
+                case "ACK":
3378
+                    this.clientTransaction = new SIP.Transactions.AckClientTransaction(this, this.request, this.ua.transport);
3379
+                    break;
3380
+                default:
3381
+                    this.clientTransaction = new SIP.Transactions.NonInviteClientTransaction(this, this.request, this.ua.transport);
3382
+            }
3383
+            this.clientTransaction.send();
3384
+            return this.clientTransaction;
3385
+        },
3386
+        /**
3387
+        * Callback fired when receiving a request timeout error from the client transaction.
3388
+        * To be re-defined by the applicant.
3389
+        * @event
3390
+        */
3391
+        onRequestTimeout: function () {
3392
+            this.applicant.onRequestTimeout();
3393
+        },
3394
+        /**
3395
+        * Callback fired when receiving a transport error from the client transaction.
3396
+        * To be re-defined by the applicant.
3397
+        * @event
3398
+        */
3399
+        onTransportError: function () {
3400
+            this.applicant.onTransportError();
3401
+        },
3402
+        /**
3403
+        * Called from client transaction when receiving a correct response to the request.
3404
+        * Authenticate request if needed or pass the response back to the applicant.
3405
+        * @param {SIP.IncomingResponse} response
3406
+        */
3407
+        receiveResponse: function (response) {
3408
+            var cseq, challenge, authorization_header_name, status_code = response.status_code;
3409
+            /*
3410
+            * Authentication
3411
+            * Authenticate once. _challenged_ flag used to avoid infinite authentications.
3412
+            */
3413
+            if (status_code === 401 || status_code === 407) {
3414
+                // Get and parse the appropriate WWW-Authenticate or Proxy-Authenticate header.
3415
+                if (response.status_code === 401) {
3416
+                    challenge = response.parseHeader('www-authenticate');
3417
+                    authorization_header_name = 'authorization';
3418
+                }
3419
+                else {
3420
+                    challenge = response.parseHeader('proxy-authenticate');
3421
+                    authorization_header_name = 'proxy-authorization';
3422
+                }
3423
+                // Verify it seems a valid challenge.
3424
+                if (!challenge) {
3425
+                    this.logger.warn(response.status_code + ' with wrong or missing challenge, cannot authenticate');
3426
+                    this.applicant.receiveResponse(response);
3427
+                    return;
3428
+                }
3429
+                if (!this.challenged || (!this.staled && challenge.stale === true)) {
3430
+                    if (!this.credentials) {
3431
+                        this.credentials = this.ua.configuration.authenticationFactory(this.ua);
3432
+                    }
3433
+                    // Verify that the challenge is really valid.
3434
+                    if (!this.credentials.authenticate(this.request, challenge)) {
3435
+                        this.applicant.receiveResponse(response);
3436
+                        return;
3437
+                    }
3438
+                    this.challenged = true;
3439
+                    if (challenge.stale) {
3440
+                        this.staled = true;
3441
+                    }
3442
+                    if (response.method === SIP.C.REGISTER) {
3443
+                        cseq = this.applicant.cseq += 1;
3444
+                    }
3445
+                    else if (this.request.dialog) {
3446
+                        cseq = this.request.dialog.local_seqnum += 1;
3447
+                    }
3448
+                    else {
3449
+                        cseq = this.request.cseq + 1;
3450
+                        this.request.cseq = cseq;
3451
+                    }
3452
+                    this.request.setHeader('cseq', cseq + ' ' + this.method);
3453
+                    this.request.setHeader(authorization_header_name, this.credentials.toString());
3454
+                    this.send();
3455
+                }
3456
+                else {
3457
+                    this.applicant.receiveResponse(response);
3458
+                }
3459
+            }
3460
+            else {
3461
+                this.applicant.receiveResponse(response);
3462
+            }
3463
+        }
3464
+    };
3465
+    SIP.RequestSender = RequestSender;
3466
+};
3467
+
3468
+
3469
+/***/ }),
3470
+/* 19 */
3471
+/***/ (function(module, exports, __webpack_require__) {
3472
+
3473
+"use strict";
3474
+
3475
+module.exports = function (SIP) {
3476
+    var RegisterContext;
3477
+    RegisterContext = function (ua) {
3478
+        var params = {}, regId = 1;
3479
+        this.registrar = ua.configuration.registrarServer;
3480
+        this.expires = ua.configuration.registerExpires;
3481
+        // Contact header
3482
+        this.contact = ua.contact.toString();
3483
+        if (regId) {
3484
+            this.contact += ';reg-id=' + regId;
3485
+            this.contact += ';+sip.instance="<urn:uuid:' + ua.configuration.instanceId + '>"';
3486
+        }
3487
+        // Call-ID and CSeq values RFC3261 10.2
3488
+        this.call_id = SIP.Utils.createRandomToken(22);
3489
+        this.cseq = Math.floor(Math.random() * 10000);
3490
+        this.to_uri = ua.configuration.uri;
3491
+        params.to_uri = this.to_uri;
3492
+        params.to_displayName = ua.configuration.displayName;
3493
+        params.call_id = this.call_id;
3494
+        params.cseq = this.cseq;
3495
+        // Extends ClientContext
3496
+        SIP.Utils.augment(this, SIP.ClientContext, [ua, 'REGISTER', this.registrar, { params: params }]);
3497
+        this.registrationTimer = null;
3498
+        this.registrationExpiredTimer = null;
3499
+        // Set status
3500
+        this.registered = false;
3501
+        this.logger = ua.getLogger('sip.registercontext');
3502
+        ua.on('transportCreated', function (transport) {
3503
+            transport.on('disconnected', this.onTransportDisconnected.bind(this));
3504
+        }.bind(this));
3505
+    };
3506
+    RegisterContext.prototype = Object.create({}, {
3507
+        register: { writable: true, value: function register(options) {
3508
+                var self = this, extraHeaders;
3509
+                // Handle Options
3510
+                this.options = options || {};
3511
+                extraHeaders = (this.options.extraHeaders || []).slice();
3512
+                extraHeaders.push('Contact: ' + this.contact + ';expires=' + this.expires);
3513
+                extraHeaders.push('Allow: ' + SIP.UA.C.ALLOWED_METHODS.toString());
3514
+                // Save original extraHeaders to be used in .close
3515
+                this.closeHeaders = this.options.closeWithHeaders ?
3516
+                    (this.options.extraHeaders || []).slice() : [];
3517
+                this.receiveResponse = function (response) {
3518
+                    var contact, expires, contacts = response.getHeaders('contact').length, cause;
3519
+                    // Discard responses to older REGISTER/un-REGISTER requests.
3520
+                    if (response.cseq !== this.cseq) {
3521
+                        return;
3522
+                    }
3523
+                    // Clear registration timer
3524
+                    if (this.registrationTimer !== null) {
3525
+                        SIP.Timers.clearTimeout(this.registrationTimer);
3526
+                        this.registrationTimer = null;
3527
+                    }
3528
+                    switch (true) {
3529
+                        case /^1[0-9]{2}$/.test(response.status_code):
3530
+                            this.emit('progress', response);
3531
+                            break;
3532
+                        case /^2[0-9]{2}$/.test(response.status_code):
3533
+                            this.emit('accepted', response);
3534
+                            if (response.hasHeader('expires')) {
3535
+                                expires = response.getHeader('expires');
3536
+                            }
3537
+                            if (this.registrationExpiredTimer !== null) {
3538
+                                SIP.Timers.clearTimeout(this.registrationExpiredTimer);
3539
+                                this.registrationExpiredTimer = null;
3540
+                            }
3541
+                            // Search the Contact pointing to us and update the expires value accordingly.
3542
+                            if (!contacts) {
3543
+                                this.logger.warn('no Contact header in response to REGISTER, response ignored');
3544
+                                break;
3545
+                            }
3546
+                            while (contacts--) {
3547
+                                contact = response.parseHeader('contact', contacts);
3548
+                                if (contact.uri.user === this.ua.contact.uri.user) {
3549
+                                    expires = contact.getParam('expires');
3550
+                                    break;
3551
+                                }
3552
+                                else {
3553
+                                    contact = null;
3554
+                                }
3555
+                            }
3556
+                            if (!contact) {
3557
+                                this.logger.warn('no Contact header pointing to us, response ignored');
3558
+                                break;
3559
+                            }
3560
+                            if (!expires) {
3561
+                                expires = this.expires;
3562
+                            }
3563
+                            // Re-Register before the expiration interval has elapsed.
3564
+                            // For that, decrease the expires value. ie: 3 seconds
3565
+                            this.registrationTimer = SIP.Timers.setTimeout(function () {
3566
+                                self.registrationTimer = null;
3567
+                                self.register(self.options);
3568
+                            }, (expires * 1000) - 3000);
3569
+                            this.registrationExpiredTimer = SIP.Timers.setTimeout(function () {
3570
+                                self.logger.warn('registration expired');
3571
+                                if (self.registered) {
3572
+                                    self.unregistered(null, SIP.C.causes.EXPIRES);
3573
+                                }
3574
+                            }, expires * 1000);
3575
+                            //Save gruu values
3576
+                            if (contact.hasParam('temp-gruu')) {
3577
+                                this.ua.contact.temp_gruu = SIP.URI.parse(contact.getParam('temp-gruu').replace(/"/g, ''));
3578
+                            }
3579
+                            if (contact.hasParam('pub-gruu')) {
3580
+                                this.ua.contact.pub_gruu = SIP.URI.parse(contact.getParam('pub-gruu').replace(/"/g, ''));
3581
+                            }
3582
+                            this.registered = true;
3583
+                            this.emit('registered', response || null);
3584
+                            break;
3585
+                        // Interval too brief RFC3261 10.2.8
3586
+                        case /^423$/.test(response.status_code):
3587
+                            if (response.hasHeader('min-expires')) {
3588
+                                // Increase our registration interval to the suggested minimum
3589
+                                this.expires = response.getHeader('min-expires');
3590
+                                // Attempt the registration again immediately
3591
+                                this.register(this.options);
3592
+                            }
3593
+                            else { //This response MUST contain a Min-Expires header field
3594
+                                this.logger.warn('423 response received for REGISTER without Min-Expires');
3595
+                                this.registrationFailure(response, SIP.C.causes.SIP_FAILURE_CODE);
3596
+                            }
3597
+                            break;
3598
+                        default:
3599
+                            cause = SIP.Utils.sipErrorCause(response.status_code);
3600
+                            this.registrationFailure(response, cause);
3601
+                    }
3602
+                };
3603
+                this.onRequestTimeout = function () {
3604
+                    this.registrationFailure(null, SIP.C.causes.REQUEST_TIMEOUT);
3605
+                };
3606
+                this.onTransportError = function () {
3607
+                    this.registrationFailure(null, SIP.C.causes.CONNECTION_ERROR);
3608
+                };
3609
+                this.cseq++;
3610
+                this.request.cseq = this.cseq;
3611
+                this.request.setHeader('cseq', this.cseq + ' REGISTER');
3612
+                this.request.extraHeaders = extraHeaders;
3613
+                this.send();
3614
+            } },
3615
+        registrationFailure: { writable: true, value: function registrationFailure(response, cause) {
3616
+                this.emit('failed', response || null, cause || null);
3617
+            } },
3618
+        onTransportDisconnected: { writable: true, value: function onTransportDisconnected() {
3619
+                this.registered_before = this.registered;
3620
+                if (this.registrationTimer !== null) {
3621
+                    SIP.Timers.clearTimeout(this.registrationTimer);
3622
+                    this.registrationTimer = null;
3623
+                }
3624
+                if (this.registrationExpiredTimer !== null) {
3625
+                    SIP.Timers.clearTimeout(this.registrationExpiredTimer);
3626
+                    this.registrationExpiredTimer = null;
3627
+                }
3628
+                if (this.registered) {
3629
+                    this.unregistered(null, SIP.C.causes.CONNECTION_ERROR);
3630
+                }
3631
+            } },
3632
+        onTransportConnected: { writable: true, value: function onTransportConnected() {
3633
+                this.register(this.options);
3634
+            } },
3635
+        close: { writable: true, value: function close() {
3636
+                var options = {
3637
+                    all: false,
3638
+                    extraHeaders: this.closeHeaders
3639
+                };
3640
+                this.registered_before = this.registered;
3641
+                if (this.registered) {
3642
+                    this.unregister(options);
3643
+                }
3644
+            } },
3645
+        unregister: { writable: true, value: function unregister(options) {
3646
+                var extraHeaders;
3647
+                options = options || {};
3648
+                if (!this.registered && !options.all) {
3649
+                    this.logger.warn('Already unregistered, but sending an unregister anyways.');
3650
+                }
3651
+                extraHeaders = (options.extraHeaders || []).slice();
3652
+                this.registered = false;
3653
+                // Clear the registration timer.
3654
+                if (this.registrationTimer !== null) {
3655
+                    SIP.Timers.clearTimeout(this.registrationTimer);
3656
+                    this.registrationTimer = null;
3657
+                }
3658
+                if (options.all) {
3659
+                    extraHeaders.push('Contact: *');
3660
+                    extraHeaders.push('Expires: 0');
3661
+                }
3662
+                else {
3663
+                    extraHeaders.push('Contact: ' + this.contact + ';expires=0');
3664
+                }
3665
+                this.receiveResponse = function (response) {
3666
+                    var cause;
3667
+                    switch (true) {
3668
+                        case /^1[0-9]{2}$/.test(response.status_code):
3669
+                            this.emit('progress', response);
3670
+                            break;
3671
+                        case /^2[0-9]{2}$/.test(response.status_code):
3672
+                            this.emit('accepted', response);
3673
+                            if (this.registrationExpiredTimer !== null) {
3674
+                                SIP.Timers.clearTimeout(this.registrationExpiredTimer);
3675
+                                this.registrationExpiredTimer = null;
3676
+                            }
3677
+                            this.unregistered(response);
3678
+                            break;
3679
+                        default:
3680
+                            cause = SIP.Utils.sipErrorCause(response.status_code);
3681
+                            this.unregistered(response, cause);
3682
+                    }
3683
+                };
3684
+                this.onRequestTimeout = function () {
3685
+                    // Not actually unregistered...
3686
+                    //this.unregistered(null, SIP.C.causes.REQUEST_TIMEOUT);
3687
+                };
3688
+                this.cseq++;
3689
+                this.request.cseq = this.cseq;
3690
+                this.request.setHeader('cseq', this.cseq + ' REGISTER');
3691
+                this.request.extraHeaders = extraHeaders;
3692
+                this.send();
3693
+            } },
3694
+        unregistered: { writable: true, value: function unregistered(response, cause) {
3695
+                this.registered = false;
3696
+                this.emit('unregistered', response || null, cause || null);
3697
+            } }
3698
+    });
3699
+    SIP.RegisterContext = RegisterContext;
3700
+};
3701
+
3702
+
3703
+/***/ }),
3704
+/* 20 */
3705
+/***/ (function(module, exports, __webpack_require__) {
3706
+
3707
+"use strict";
3708
+
3709
+/* eslint-disable */
3710
+/**
3711
+ * @fileoverview SessionDescriptionHandler
3712
+ */
3713
+/* SessionDescriptionHandler
3714
+ * @class PeerConnection helper Class.
3715
+ * @param {SIP.Session} session
3716
+ * @param {Object} [options]
3717
+ */
3718
+module.exports = function (EventEmitter) {
3719
+    var SessionDescriptionHandler = function () { };
3720
+    SessionDescriptionHandler.prototype = Object.create(EventEmitter.prototype, {
3721
+        /**
3722
+         * Destructor
3723
+         */
3724
+        close: { value: function close() { } },
3725
+        /**
3726
+         * Gets the local description from the underlying media implementation
3727
+         * @param {Object} [options] Options object to be used by getDescription
3728
+         * @param {Array} [modifiers] Array with one time use description modifiers
3729
+         * @returns {Promise} Promise that resolves with the local description to be used for the session
3730
+         */
3731
+        getDescription: { value: function getDescription(options, modifiers) { } },
3732
+        /**
3733
+         * Check if the Session Description Handler can handle the Content-Type described by a SIP Message
3734
+         * @param {String} contentType The content type that is in the SIP Message
3735
+         * @returns {boolean}
3736
+         */
3737
+        hasDescription: { value: function hasSessionDescription(contentType) { } },
3738
+        /**
3739
+         * The modifier that should be used when the session would like to place the call on hold
3740
+         * @param {String} [sdp] The description that will be modified
3741
+         * @returns {Promise} Promise that resolves with modified SDP
3742
+         */
3743
+        holdModifier: { value: function holdModifier(sdp) { } },
3744
+        /**
3745
+         * Set the remote description to the underlying media implementation
3746
+         * @param {String} sessionDescription The description provided by a SIP message to be set on the media implementation
3747
+         * @param {Object} [options] Options object to be used by setDescription
3748
+         * @param {Array} [modifiers] Array with one time use description modifiers
3749
+         * @returns {Promise} Promise that resolves once the description is set
3750
+         */
3751
+        setDescription: { value: function setDescription(sessionDescription, options, modifiers) { } },
3752
+        /**
3753
+         * Send DTMF via RTP (RFC 4733)
3754
+         * @param {String} tones A string containing DTMF digits
3755
+         * @param {Object} [options] Options object to be used by sendDtmf
3756
+         * @returns {boolean} true if DTMF send is successful, false otherwise
3757
+         */
3758
+        sendDtmf: { value: function sendDtmf(tones, options) { } },
3759
+        /**
3760
+        * Get the direction of the session description
3761
+        * @returns {String} direction of the description
3762
+        */
3763
+        getDirection: { value: function getDirection() { } },
3764
+    });
3765
+    return SessionDescriptionHandler;
3766
+};
3767
+
3768
+
3769
+/***/ }),
3770
+/* 21 */
3771
+/***/ (function(module, exports, __webpack_require__) {
3772
+
3773
+"use strict";
3774
+
3775
+module.exports = function (SIP) {
3776
+    var ClientContext;
3777
+    ClientContext = function (ua, method, target, options) {
3778
+        var originalTarget = target;
3779
+        // Validate arguments
3780
+        if (target === undefined) {
3781
+            throw new TypeError('Not enough arguments');
3782
+        }
3783
+        this.ua = ua;
3784
+        this.logger = ua.getLogger('sip.clientcontext');
3785
+        this.method = method;
3786
+        target = ua.normalizeTarget(target);
3787
+        if (!target) {
3788
+            throw new TypeError('Invalid target: ' + originalTarget);
3789
+        }
3790
+        /* Options
3791
+         * - extraHeaders
3792
+         * - params
3793
+         * - contentType
3794
+         * - body
3795
+         */
3796
+        options = Object.create(options || Object.prototype);
3797
+        options.extraHeaders = (options.extraHeaders || []).slice();
3798
+        // Build the request
3799
+        this.request = new SIP.OutgoingRequest(this.method, target, this.ua, options.params, options.extraHeaders);
3800
+        if (options.body) {
3801
+            this.body = {};
3802
+            this.body.body = options.body;
3803
+            if (options.contentType) {
3804
+                this.body.contentType = options.contentType;
3805
+            }
3806
+            this.request.body = this.body;
3807
+        }
3808
+        /* Set other properties from the request */
3809
+        this.localIdentity = this.request.from;
3810
+        this.remoteIdentity = this.request.to;
3811
+        this.data = {};
3812
+    };
3813
+    ClientContext.prototype = Object.create(SIP.EventEmitter.prototype);
3814
+    ClientContext.prototype.send = function () {
3815
+        (new SIP.RequestSender(this, this.ua)).send();
3816
+        return this;
3817
+    };
3818
+    ClientContext.prototype.cancel = function (options) {
3819
+        options = options || {};
3820
+        options.extraHeaders = (options.extraHeaders || []).slice();
3821
+        var cancel_reason = SIP.Utils.getCancelReason(options.status_code, options.reason_phrase);
3822
+        this.request.cancel(cancel_reason, options.extraHeaders);
3823
+        this.emit('cancel');
3824
+    };
3825
+    ClientContext.prototype.receiveResponse = function (response) {
3826
+        var cause = SIP.Utils.getReasonPhrase(response.status_code);
3827
+        switch (true) {
3828
+            case /^1[0-9]{2}$/.test(response.status_code):
3829
+                this.emit('progress', response, cause);
3830
+                break;
3831
+            case /^2[0-9]{2}$/.test(response.status_code):
3832
+                if (this.ua.applicants[this]) {
3833
+                    delete this.ua.applicants[this];
3834
+                }
3835
+                this.emit('accepted', response, cause);
3836
+                break;
3837
+            default:
3838
+                if (this.ua.applicants[this]) {
3839
+                    delete this.ua.applicants[this];
3840
+                }
3841
+                this.emit('rejected', response, cause);
3842
+                this.emit('failed', response, cause);
3843
+                break;
3844
+        }
3845
+    };
3846
+    ClientContext.prototype.onRequestTimeout = function () {
3847
+        this.emit('failed', null, SIP.C.causes.REQUEST_TIMEOUT);
3848
+    };
3849
+    ClientContext.prototype.onTransportError = function () {
3850
+        this.emit('failed', null, SIP.C.causes.CONNECTION_ERROR);
3851
+    };
3852
+    SIP.ClientContext = ClientContext;
3853
+};
3854
+
3855
+
3856
+/***/ }),
3857
+/* 22 */
3858
+/***/ (function(module, exports, __webpack_require__) {
3859
+
3860
+"use strict";
3861
+
3862
+module.exports = function (SIP) {
3863
+    var ServerContext;
3864
+    ServerContext = function (ua, request) {
3865
+        this.ua = ua;
3866
+        this.logger = ua.getLogger('sip.servercontext');
3867
+        this.request = request;
3868
+        if (request.method === SIP.C.INVITE) {
3869
+            this.transaction = new SIP.Transactions.InviteServerTransaction(request, ua);
3870
+        }
3871
+        else {
3872
+            this.transaction = new SIP.Transactions.NonInviteServerTransaction(request, ua);
3873
+        }
3874
+        if (request.body) {
3875
+            this.body = request.body;
3876
+        }
3877
+        if (request.hasHeader('Content-Type')) {
3878
+            this.contentType = request.getHeader('Content-Type');
3879
+        }
3880
+        this.method = request.method;
3881
+        this.data = {};
3882
+        this.localIdentity = request.to;
3883
+        this.remoteIdentity = request.from;
3884
+        if (request.hasHeader('P-Asserted-Identity')) {
3885
+            this.assertedIdentity = new SIP.NameAddrHeader.parse(request.getHeader('P-Asserted-Identity'));
3886
+        }
3887
+    };
3888
+    ServerContext.prototype = Object.create(SIP.EventEmitter.prototype);
3889
+    ServerContext.prototype.progress = function (options) {
3890
+        options = Object.create(options || Object.prototype);
3891
+        options.statusCode || (options.statusCode = 180);
3892
+        options.minCode = 100;
3893
+        options.maxCode = 199;
3894
+        options.events = ['progress'];
3895
+        return this.reply(options);
3896
+    };
3897
+    ServerContext.prototype.accept = function (options) {
3898
+        options = Object.create(options || Object.prototype);
3899
+        options.statusCode || (options.statusCode = 200);
3900
+        options.minCode = 200;
3901
+        options.maxCode = 299;
3902
+        options.events = ['accepted'];
3903
+        return this.reply(options);
3904
+    };
3905
+    ServerContext.prototype.reject = function (options) {
3906
+        options = Object.create(options || Object.prototype);
3907
+        options.statusCode || (options.statusCode = 480);
3908
+        options.minCode = 300;
3909
+        options.maxCode = 699;
3910
+        options.events = ['rejected', 'failed'];
3911
+        return this.reply(options);
3912
+    };
3913
+    ServerContext.prototype.reply = function (options) {
3914
+        options = options || {}; // This is okay, so long as we treat options as read-only in this method
3915
+        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;
3916
+        if (statusCode < minCode || statusCode > maxCode) {
3917
+            throw new TypeError('Invalid statusCode: ' + statusCode);
3918
+        }
3919
+        response = this.request.reply(statusCode, reasonPhrase, extraHeaders, body);
3920
+        events.forEach(function (event) {
3921
+            this.emit(event, response, reasonPhrase);
3922
+        }, this);
3923
+        return this;
3924
+    };
3925
+    ServerContext.prototype.onRequestTimeout = function () {
3926
+        this.emit('failed', null, SIP.C.causes.REQUEST_TIMEOUT);
3927
+    };
3928
+    ServerContext.prototype.onTransportError = function () {
3929
+        this.emit('failed', null, SIP.C.causes.CONNECTION_ERROR);
3930
+    };
3931
+    SIP.ServerContext = ServerContext;
3932
+};
3933
+
3934
+
3935
+/***/ }),
3936
+/* 23 */
3937
+/***/ (function(module, exports, __webpack_require__) {
3938
+
3939
+"use strict";
3940
+
3941
+module.exports = function (SIP) {
3942
+    var DTMF = __webpack_require__(24)(SIP);
3943
+    var Session, InviteServerContext, InviteClientContext, ReferServerContext, ReferClientContext, C = {
3944
+        //Session states
3945
+        STATUS_NULL: 0,
3946
+        STATUS_INVITE_SENT: 1,
3947
+        STATUS_1XX_RECEIVED: 2,
3948
+        STATUS_INVITE_RECEIVED: 3,
3949
+        STATUS_WAITING_FOR_ANSWER: 4,
3950
+        STATUS_ANSWERED: 5,
3951
+        STATUS_WAITING_FOR_PRACK: 6,
3952
+        STATUS_WAITING_FOR_ACK: 7,
3953
+        STATUS_CANCELED: 8,
3954
+        STATUS_TERMINATED: 9,
3955
+        STATUS_ANSWERED_WAITING_FOR_PRACK: 10,
3956
+        STATUS_EARLY_MEDIA: 11,
3957
+        STATUS_CONFIRMED: 12
3958
+    };
3959
+    /*
3960
+     * @param {function returning SIP.sessionDescriptionHandler} [sessionDescriptionHandlerFactory]
3961
+     *        (See the documentation for the sessionDescriptionHandlerFactory argument of the UA constructor.)
3962
+     */
3963
+    Session = function (sessionDescriptionHandlerFactory) {
3964
+        this.status = C.STATUS_NULL;
3965
+        this.dialog = null;
3966
+        this.pendingReinvite = false;
3967
+        this.earlyDialogs = {};
3968
+        if (!sessionDescriptionHandlerFactory) {
3969
+            throw new SIP.Exceptions.SessionDescriptionHandlerMissing('A session description handler is required for the session to function');
3970
+        }
3971
+        this.sessionDescriptionHandlerFactory = sessionDescriptionHandlerFactory;
3972
+        this.hasOffer = false;
3973
+        this.hasAnswer = false;
3974
+        // Session Timers
3975
+        this.timers = {
3976
+            ackTimer: null,
3977
+            expiresTimer: null,
3978
+            invite2xxTimer: null,
3979
+            userNoAnswerTimer: null,
3980
+            rel1xxTimer: null,
3981
+            prackTimer: null
3982
+        };
3983
+        // Session info
3984
+        this.startTime = null;
3985
+        this.endTime = null;
3986
+        this.tones = null;
3987
+        // Hold state
3988
+        this.local_hold = false;
3989
+        this.early_sdp = null;
3990
+        this.rel100 = SIP.C.supported.UNSUPPORTED;
3991
+    };
3992
+    Session.prototype = {
3993
+        dtmf: function (tones, options) {
3994
+            var tone, dtmfs = [], self = this, dtmfType = this.ua.configuration.dtmfType;
3995
+            options = options || {};
3996
+            if (tones === undefined) {
3997
+                throw new TypeError('Not enough arguments');
3998
+            }
3999
+            // Check Session Status
4000
+            if (this.status !== C.STATUS_CONFIRMED && this.status !== C.STATUS_WAITING_FOR_ACK) {
4001
+                throw new SIP.Exceptions.InvalidStateError(this.status);
4002
+            }
4003
+            // Check tones
4004
+            if ((typeof tones !== 'string' && typeof tones !== 'number') || !tones.toString().match(/^[0-9A-D#*,]+$/i)) {
4005
+                throw new TypeError('Invalid tones: ' + tones);
4006
+            }
4007
+            var sendDTMF = function () {
4008
+                var dtmf, timeout;
4009
+                if (self.status === C.STATUS_TERMINATED || !self.tones || self.tones.length === 0) {
4010
+                    // Stop sending DTMF
4011
+                    self.tones = null;
4012
+                    return this;
4013
+                }
4014
+                dtmf = self.tones.shift();
4015
+                if (tone === ',') {
4016
+                    timeout = 2000;
4017
+                }
4018
+                else {
4019
+                    dtmf.on('failed', function () { self.tones = null; });
4020
+                    dtmf.send(options);
4021
+                    timeout = dtmf.duration + dtmf.interToneGap;
4022
+                }
4023
+                // Set timeout for the next tone
4024
+                SIP.Timers.setTimeout(sendDTMF, timeout);
4025
+            };
4026
+            tones = tones.toString();
4027
+            if (dtmfType === SIP.C.dtmfType.RTP) {
4028
+                var sent = this.sessionDescriptionHandler.sendDtmf(tones, options);
4029
+                if (!sent) {
4030
+                    this.logger.warn("Attempt to use dtmfType 'RTP' has failed, falling back to INFO packet method");
4031
+                    dtmfType = SIP.C.dtmfType.INFO;
4032
+                }
4033
+            }
4034
+            if (dtmfType === SIP.C.dtmfType.INFO) {
4035
+                tones = tones.split('');
4036
+                while (tones.length > 0) {
4037
+                    dtmfs.push(new DTMF(this, tones.shift(), options));
4038
+                }
4039
+                if (this.tones) {
4040
+                    // Tones are already queued, just add to the queue
4041
+                    this.tones = this.tones.concat(dtmfs);
4042
+                    return this;
4043
+                }
4044
+                this.tones = dtmfs;
4045
+                sendDTMF();
4046
+            }
4047
+            return this;
4048
+        },
4049
+        bye: function (options) {
4050
+            options = Object.create(options || Object.prototype);
4051
+            var statusCode = options.statusCode;
4052
+            // Check Session Status
4053
+            if (this.status === C.STATUS_TERMINATED) {
4054
+                this.logger.error('Error: Attempted to send BYE in a terminated session.');
4055
+                return this;
4056
+            }
4057
+            this.logger.log('terminating Session');
4058
+            if (statusCode && (statusCode < 200 || statusCode >= 700)) {
4059
+                throw new TypeError('Invalid statusCode: ' + statusCode);
4060
+            }
4061
+            options.receiveResponse = function () { };
4062
+            return this.
4063
+                sendRequest(SIP.C.BYE, options).
4064
+                terminated();
4065
+        },
4066
+        refer: function (target, options) {
4067
+            options = options || {};
4068
+            // Check Session Status
4069
+            if (this.status !== C.STATUS_CONFIRMED) {
4070
+                throw new SIP.Exceptions.InvalidStateError(this.status);
4071
+            }
4072
+            this.referContext = new SIP.ReferClientContext(this.ua, this, target, options);
4073
+            this.emit('referRequested', this.referContext);
4074
+            this.referContext.refer(options);
4075
+        },
4076
+        sendRequest: function (method, options) {
4077
+            options = options || {};
4078
+            var self = this;
4079
+            var request = new SIP.OutgoingRequest(method, this.dialog.remote_target, this.ua, {
4080
+                cseq: options.cseq || (this.dialog.local_seqnum += 1),
4081
+                call_id: this.dialog.id.call_id,
4082
+                from_uri: this.dialog.local_uri,
4083
+                from_tag: this.dialog.id.local_tag,
4084
+                to_uri: this.dialog.remote_uri,
4085
+                to_tag: this.dialog.id.remote_tag,
4086
+                route_set: this.dialog.route_set,
4087
+                statusCode: options.statusCode,
4088
+                reasonPhrase: options.reasonPhrase
4089
+            }, options.extraHeaders || [], options.body);
4090
+            new SIP.RequestSender({
4091
+                request: request,
4092
+                onRequestTimeout: function () {
4093
+                    self.onRequestTimeout();
4094
+                },
4095
+                onTransportError: function () {
4096
+                    self.onTransportError();
4097
+                },
4098
+                receiveResponse: options.receiveResponse || function (response) {
4099
+                    self.receiveNonInviteResponse(response);
4100
+                }
4101
+            }, this.ua).send();
4102
+            // Emit the request event
4103
+            this.emit(method.toLowerCase(), request);
4104
+            return this;
4105
+        },
4106
+        close: function () {
4107
+            var idx;
4108
+            if (this.status === C.STATUS_TERMINATED) {
4109
+                return this;
4110
+            }
4111
+            this.logger.log('closing INVITE session ' + this.id);
4112
+            // 1st Step. Terminate media.
4113
+            if (this.sessionDescriptionHandler) {
4114
+                this.sessionDescriptionHandler.close();
4115
+            }
4116
+            // 2nd Step. Terminate signaling.
4117
+            // Clear session timers
4118
+            for (idx in this.timers) {
4119
+                SIP.Timers.clearTimeout(this.timers[idx]);
4120
+            }
4121
+            // Terminate dialogs
4122
+            // Terminate confirmed dialog
4123
+            if (this.dialog) {
4124
+                this.dialog.terminate();
4125
+                delete this.dialog;
4126
+            }
4127
+            // Terminate early dialogs
4128
+            for (idx in this.earlyDialogs) {
4129
+                this.earlyDialogs[idx].terminate();
4130
+                delete this.earlyDialogs[idx];
4131
+            }
4132
+            this.status = C.STATUS_TERMINATED;
4133
+            this.ua.transport.removeListener("transportError", this.errorListener);
4134
+            delete this.ua.sessions[this.id];
4135
+            return this;
4136
+        },
4137
+        createDialog: function (message, type, early) {
4138
+            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;
4139
+            early_dialog = this.earlyDialogs[id];
4140
+            // Early Dialog
4141
+            if (early) {
4142
+                if (early_dialog) {
4143
+                    return true;
4144
+                }
4145
+                else {
4146
+                    early_dialog = new SIP.Dialog(this, message, type, SIP.Dialog.C.STATUS_EARLY);
4147
+                    // Dialog has been successfully created.
4148
+                    if (early_dialog.error) {
4149
+                        this.logger.error(early_dialog.error);
4150
+                        this.failed(message, SIP.C.causes.INTERNAL_ERROR);
4151
+                        return false;
4152
+                    }
4153
+                    else {
4154
+                        this.earlyDialogs[id] = early_dialog;
4155
+                        return true;
4156
+                    }
4157
+                }
4158
+            }
4159
+            // Confirmed Dialog
4160
+            else {
4161
+                // In case the dialog is in _early_ state, update it
4162
+                if (early_dialog) {
4163
+                    early_dialog.update(message, type);
4164
+                    this.dialog = early_dialog;
4165
+                    delete this.earlyDialogs[id];
4166
+                    for (var dia in this.earlyDialogs) {
4167
+                        this.earlyDialogs[dia].terminate();
4168
+                        delete this.earlyDialogs[dia];
4169
+                    }
4170
+                    return true;
4171
+                }
4172
+                // Otherwise, create a _confirmed_ dialog
4173
+                dialog = new SIP.Dialog(this, message, type);
4174
+                if (dialog.error) {
4175
+                    this.logger.error(dialog.error);
4176
+                    this.failed(message, SIP.C.causes.INTERNAL_ERROR);
4177
+                    return false;
4178
+                }
4179
+                else {
4180
+                    this.to_tag = message.to_tag;
4181
+                    this.dialog = dialog;
4182
+                    return true;
4183
+                }
4184
+            }
4185
+        },
4186
+        /**
4187
+         * Hold
4188
+         */
4189
+        hold: function (options, modifiers) {
4190
+            if (this.status !== C.STATUS_WAITING_FOR_ACK && this.status !== C.STATUS_CONFIRMED) {
4191
+                throw new SIP.Exceptions.InvalidStateError(this.status);
4192
+            }
4193
+            if (this.local_hold) {
4194
+                this.logger.log('Session is already on hold, cannot put it on hold again');
4195
+                return;
4196
+            }
4197
+            options = options || {};
4198
+            options.modifiers = modifiers || [];
4199
+            options.modifiers.push(this.sessionDescriptionHandler.holdModifier);
4200
+            this.local_hold = true;
4201
+            this.sendReinvite(options);
4202
+        },
4203
+        /**
4204
+         * Unhold
4205
+         */
4206
+        unhold: function (options, modifiers) {
4207
+            if (this.status !== C.STATUS_WAITING_FOR_ACK && this.status !== C.STATUS_CONFIRMED) {
4208
+                throw new SIP.Exceptions.InvalidStateError(this.status);
4209
+            }
4210
+            if (!this.local_hold) {
4211
+                this.logger.log('Session is not on hold, cannot unhold it');
4212
+                return;
4213
+            }
4214
+            options = options || {};
4215
+            if (modifiers) {
4216
+                options.modifiers = modifiers;
4217
+            }
4218
+            this.local_hold = false;
4219
+            this.sendReinvite(options);
4220
+        },
4221
+        reinvite: function (options, modifiers) {
4222
+            options = options || {};
4223
+            if (modifiers) {
4224
+                options.modifiers = modifiers;
4225
+            }
4226
+            return this.sendReinvite(options);
4227
+        },
4228
+        /**
4229
+         * In dialog INVITE Reception
4230
+         * @private
4231
+         */
4232
+        receiveReinvite: function (request) {
4233
+            var self = this, promise;
4234
+            // TODO: Should probably check state of the session
4235
+            self.emit('reinvite', this);
4236
+            if (request.hasHeader('P-Asserted-Identity')) {
4237
+                this.assertedIdentity = new SIP.NameAddrHeader.parse(request.getHeader('P-Asserted-Identity'));
4238
+            }
4239
+            // Invite w/o SDP
4240
+            if (request.getHeader('Content-Length') === '0' && !request.getHeader('Content-Type')) {
4241
+                promise = this.sessionDescriptionHandler.getDescription(this.sessionDescriptionHandlerOptions, this.modifiers);
4242
+                // Invite w/ SDP
4243
+            }
4244
+            else if (this.sessionDescriptionHandler.hasDescription(request.getHeader('Content-Type'))) {
4245
+                promise = this.sessionDescriptionHandler.setDescription(request.body, this.sessionDescriptionHandlerOptions, this.modifiers)
4246
+                    .then(this.sessionDescriptionHandler.getDescription.bind(this.sessionDescriptionHandler, this.sessionDescriptionHandlerOptions, this.modifiers));
4247
+                // Bad Packet (should never get hit)
4248
+            }
4249
+            else {
4250
+                request.reply(415);
4251
+                this.emit('reinviteFailed', self);
4252
+                return;
4253
+            }
4254
+            this.receiveRequest = function (request) {
4255
+                if (request.method === SIP.C.ACK && this.status === C.STATUS_WAITING_FOR_ACK) {
4256
+                    if (this.sessionDescriptionHandler.hasDescription(request.getHeader('Content-Type'))) {
4257
+                        this.hasAnswer = true;
4258
+                        this.sessionDescriptionHandler.setDescription(request.body, this.sessionDescriptionHandlerOptions, this.modifiers)
4259
+                            .then(function () {
4260
+                            SIP.Timers.clearTimeout(this.timers.ackTimer);
4261
+                            SIP.Timers.clearTimeout(this.timers.invite2xxTimer);
4262
+                            this.status = C.STATUS_CONFIRMED;
4263
+                            this.emit('confirmed', request);
4264
+                        }.bind(this));
4265
+                    }
4266
+                    else {
4267
+                        SIP.Timers.clearTimeout(this.timers.ackTimer);
4268
+                        SIP.Timers.clearTimeout(this.timers.invite2xxTimer);
4269
+                        this.status = C.STATUS_CONFIRMED;
4270
+                        this.emit('confirmed', request);
4271
+                    }
4272
+                }
4273
+                else {
4274
+                    SIP.Session.prototype.receiveRequest.apply(this, [request]);
4275
+                }
4276
+            }.bind(this);
4277
+            promise.catch(function onFailure(e) {
4278
+                var statusCode;
4279
+                if (e instanceof SIP.Exceptions.SessionDescriptionHandlerError) {
4280
+                    statusCode = 500;
4281
+                }
4282
+                else if (e instanceof SIP.Exceptions.RenegotiationError) {
4283
+                    self.emit('renegotiationError', e);
4284
+                    self.logger.warn(e);
4285
+                    statusCode = 488;
4286
+                }
4287
+                else {
4288
+                    self.logger.error(e);
4289
+                    statusCode = 488;
4290
+                }
4291
+                request.reply(statusCode);
4292
+                self.emit('reinviteFailed', self);
4293
+                // TODO: This could be better
4294
+                throw e;
4295
+            })
4296
+                .then(function (description) {
4297
+                var extraHeaders = ['Contact: ' + self.contact];
4298
+                request.reply(200, null, extraHeaders, description, function () {
4299
+                    self.status = C.STATUS_WAITING_FOR_ACK;
4300
+                    self.setACKTimer();
4301
+                    self.emit('reinviteAccepted', self);
4302
+                });
4303
+            });
4304
+        },
4305
+        sendReinvite: function (options) {
4306
+            if (this.pendingReinvite) {
4307
+                this.logger.warn('Reinvite in progress. Please wait until complete, then try again.');
4308
+                return;
4309
+            }
4310
+            this.pendingReinvite = true;
4311
+            options = options || {};
4312
+            options.modifiers = options.modifiers || [];
4313
+            var self = this, extraHeaders = (options.extraHeaders || []).slice();
4314
+            extraHeaders.push('Contact: ' + this.contact);
4315
+            extraHeaders.push('Allow: ' + SIP.UA.C.ALLOWED_METHODS.toString());
4316
+            this.sessionDescriptionHandler.getDescription(options.sessionDescriptionHandlerOptions, options.modifiers)
4317
+                .then(function (description) {
4318
+                self.sendRequest(SIP.C.INVITE, {
4319
+                    extraHeaders: extraHeaders,
4320
+                    body: description,
4321
+                    receiveResponse: self.receiveReinviteResponse.bind(self)
4322
+                });
4323
+            }).catch(function onFailure(e) {
4324
+                if (e instanceof SIP.Exceptions.RenegotiationError) {
4325
+                    self.pendingReinvite = false;
4326
+                    self.emit('renegotiationError', e);
4327
+                    self.logger.warn('Renegotiation Error');
4328
+                    self.logger.warn(e);
4329
+                    return;
4330
+                }
4331
+                self.logger.error('sessionDescriptionHandler error');
4332
+                self.logger.error(e);
4333
+            });
4334
+        },
4335
+        receiveRequest: function (request) {
4336
+            switch (request.method) {
4337
+                case SIP.C.BYE:
4338
+                    request.reply(200);
4339
+                    if (this.status === C.STATUS_CONFIRMED) {
4340
+                        this.emit('bye', request);
4341
+                        this.terminated(request, SIP.C.causes.BYE);
4342
+                    }
4343
+                    break;
4344
+                case SIP.C.INVITE:
4345
+                    if (this.status === C.STATUS_CONFIRMED) {
4346
+                        this.logger.log('re-INVITE received');
4347
+                        this.receiveReinvite(request);
4348
+                    }
4349
+                    break;
4350
+                case SIP.C.INFO:
4351
+                    if (this.status === C.STATUS_CONFIRMED || this.status === C.STATUS_WAITING_FOR_ACK) {
4352
+                        if (this.onInfo) {
4353
+                            return this.onInfo(request);
4354
+                        }
4355
+                        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)?.*/;
4356
+                        if (contentType) {
4357
+                            if (contentType.match(/^application\/dtmf-relay/i)) {
4358
+                                if (request.body) {
4359
+                                    body = request.body.split('\r\n', 2);
4360
+                                    if (body.length === 2) {
4361
+                                        if (reg_tone.test(body[0])) {
4362
+                                            tone = body[0].replace(reg_tone, "$2");
4363
+                                        }
4364
+                                        if (reg_duration.test(body[1])) {
4365
+                                            duration = parseInt(body[1].replace(reg_duration, "$2"), 10);
4366
+                                        }
4367
+                                    }
4368
+                                }
4369
+                                new DTMF(this, tone, { duration: duration }).init_incoming(request);
4370
+                            }
4371
+                            else {
4372
+                                request.reply(415, null, ["Accept: application/dtmf-relay"]);
4373
+                            }
4374
+                        }
4375
+                    }
4376
+                    break;
4377
+                case SIP.C.REFER:
4378
+                    if (this.status === C.STATUS_CONFIRMED) {
4379
+                        this.logger.log('REFER received');
4380
+                        this.referContext = new SIP.ReferServerContext(this.ua, request);
4381
+                        var hasReferListener = this.listeners('referRequested').length;
4382
+                        if (hasReferListener) {
4383
+                            this.emit('referRequested', this.referContext);
4384
+                        }
4385
+                        else {
4386
+                            this.logger.log('No referRequested listeners, automatically accepting and following the refer');
4387
+                            var options = { followRefer: true };
4388
+                            if (this.passedOptions) {
4389
+                                options.inviteOptions = this.passedOptions;
4390
+                            }
4391
+                            this.referContext.accept(options, this.modifiers);
4392
+                        }
4393
+                    }
4394
+                    break;
4395
+                case SIP.C.NOTIFY:
4396
+                    if ((this.referContext && this.referContext instanceof SIP.ReferClientContext) && request.hasHeader('event') && /^refer(;.*)?$/.test(request.getHeader('event'))) {
4397
+                        this.referContext.receiveNotify(request);
4398
+                        return;
4399
+                    }
4400
+                    request.reply(200, 'OK');
4401
+                    this.emit('notify', request);
4402
+                    break;
4403
+            }
4404
+        },
4405
+        /**
4406
+         * Reception of Response for in-dialog INVITE
4407
+         * @private
4408
+         */
4409
+        receiveReinviteResponse: function (response) {
4410
+            var self = this;
4411
+            if (this.status === C.STATUS_TERMINATED) {
4412
+                this.logger.error('Received reinvite response, but in STATUS_TERMINATED');
4413
+                // TODO: Do we need to send a SIP response?
4414
+                return;
4415
+            }
4416
+            if (!this.pendingReinvite) {
4417
+                this.logger.error('Received reinvite response, but have no pending reinvite');
4418
+                // TODO: Do we need to send a SIP response?
4419
+                return;
4420
+            }
4421
+            switch (true) {
4422
+                case /^1[0-9]{2}$/.test(response.status_code):
4423
+                    break;
4424
+                case /^2[0-9]{2}$/.test(response.status_code):
4425
+                    this.status = C.STATUS_CONFIRMED;
4426
+                    // 17.1.1.1 - For each final response that is received at the client transaction, the client transaction sends an ACK,
4427
+                    this.emit("ack", response.transaction.sendACK());
4428
+                    this.pendingReinvite = false;
4429
+                    // TODO: All of these timers should move into the Transaction layer
4430
+                    SIP.Timers.clearTimeout(self.timers.invite2xxTimer);
4431
+                    if (!this.sessionDescriptionHandler.hasDescription(response.getHeader('Content-Type'))) {
4432
+                        this.logger.error('2XX response received to re-invite but did not have a description');
4433
+                        this.emit('reinviteFailed', self);
4434
+                        this.emit('renegotiationError', new SIP.Exceptions.RenegotiationError('2XX response received to re-invite but did not have a description'));
4435
+                        break;
4436
+                    }
4437
+                    this.sessionDescriptionHandler.setDescription(response.body, this.sessionDescriptionHandlerOptions, this.modifiers)
4438
+                        .catch(function onFailure(e) {
4439
+                        self.logger.error('Could not set the description in 2XX response');
4440
+                        self.logger.error(e);
4441
+                        self.emit('reinviteFailed', self);
4442
+                        self.emit('renegotiationError', e);
4443
+                        self.sendRequest(SIP.C.BYE, {
4444
+                            extraHeaders: ['Reason: ' + SIP.Utils.getReasonHeaderValue(488, 'Not Acceptable Here')]
4445
+                        });
4446
+                        self.terminated(null, SIP.C.causes.INCOMPATIBLE_SDP);
4447
+                    }).then(function () {
4448
+                        self.emit('reinviteAccepted', self);
4449
+                    });
4450
+                    break;
4451
+                default:
4452
+                    this.pendingReinvite = false;
4453
+                    this.logger.log('Received a non 1XX or 2XX response to a re-invite');
4454
+                    this.emit('reinviteFailed', self);
4455
+                    this.emit('renegotiationError', new SIP.Exceptions.RenegotiationError('Invalid response to a re-invite'));
4456
+            }
4457
+        },
4458
+        acceptAndTerminate: function (response, status_code, reason_phrase) {
4459
+            var extraHeaders = [];
4460
+            if (status_code) {
4461
+                extraHeaders.push('Reason: ' + SIP.Utils.getReasonHeaderValue(status_code, reason_phrase));
4462
+            }
4463
+            // An error on dialog creation will fire 'failed' event
4464
+            if (this.dialog || this.createDialog(response, 'UAC')) {
4465
+                this.emit("ack", response.transaction.sendACK());
4466
+                this.sendRequest(SIP.C.BYE, {
4467
+                    extraHeaders: extraHeaders
4468
+                });
4469
+            }
4470
+            return this;
4471
+        },
4472
+        /**
4473
+         * RFC3261 13.3.1.4
4474
+         * Response retransmissions cannot be accomplished by transaction layer
4475
+         *  since it is destroyed when receiving the first 2xx answer
4476
+         */
4477
+        setInvite2xxTimer: function (request, description) {
4478
+            var self = this, timeout = SIP.Timers.T1;
4479
+            this.timers.invite2xxTimer = SIP.Timers.setTimeout(function invite2xxRetransmission() {
4480
+                if (self.status !== C.STATUS_WAITING_FOR_ACK) {
4481
+                    return;
4482
+                }
4483
+                self.logger.log('no ACK received, attempting to retransmit OK');
4484
+                var extraHeaders = ['Contact: ' + self.contact];
4485
+                request.reply(200, null, extraHeaders, description);
4486
+                timeout = Math.min(timeout * 2, SIP.Timers.T2);
4487
+                self.timers.invite2xxTimer = SIP.Timers.setTimeout(invite2xxRetransmission, timeout);
4488
+            }, timeout);
4489
+        },
4490
+        /**
4491
+         * RFC3261 14.2
4492
+         * If a UAS generates a 2xx response and never receives an ACK,
4493
+         *  it SHOULD generate a BYE to terminate the dialog.
4494
+         */
4495
+        setACKTimer: function () {
4496
+            var self = this;
4497
+            this.timers.ackTimer = SIP.Timers.setTimeout(function () {
4498
+                if (self.status === C.STATUS_WAITING_FOR_ACK) {
4499
+                    self.logger.log('no ACK received for an extended period of time, terminating the call');
4500
+                    SIP.Timers.clearTimeout(self.timers.invite2xxTimer);
4501
+                    self.sendRequest(SIP.C.BYE);
4502
+                    self.terminated(null, SIP.C.causes.NO_ACK);
4503
+                }
4504
+            }, SIP.Timers.TIMER_H);
4505
+        },
4506
+        /*
4507
+         * @private
4508
+         */
4509
+        onTransportError: function () {
4510
+            if (this.status !== C.STATUS_CONFIRMED && this.status !== C.STATUS_TERMINATED) {
4511
+                this.failed(null, SIP.C.causes.CONNECTION_ERROR);
4512
+            }
4513
+        },
4514
+        onRequestTimeout: function () {
4515
+            if (this.status === C.STATUS_CONFIRMED) {
4516
+                this.terminated(null, SIP.C.causes.REQUEST_TIMEOUT);
4517
+            }
4518
+            else if (this.status !== C.STATUS_TERMINATED) {
4519
+                this.failed(null, SIP.C.causes.REQUEST_TIMEOUT);
4520
+                this.terminated(null, SIP.C.causes.REQUEST_TIMEOUT);
4521
+            }
4522
+        },
4523
+        onDialogError: function (response) {
4524
+            if (this.status === C.STATUS_CONFIRMED) {
4525
+                this.terminated(response, SIP.C.causes.DIALOG_ERROR);
4526
+            }
4527
+            else if (this.status !== C.STATUS_TERMINATED) {
4528
+                this.failed(response, SIP.C.causes.DIALOG_ERROR);
4529
+                this.terminated(response, SIP.C.causes.DIALOG_ERROR);
4530
+            }
4531
+        },
4532
+        /**
4533
+         * @private
4534
+         */
4535
+        failed: function (response, cause) {
4536
+            if (this.status === C.STATUS_TERMINATED) {
4537
+                return this;
4538
+            }
4539
+            this.emit('failed', response || null, cause || null);
4540
+            return this;
4541
+        },
4542
+        rejected: function (response, cause) {
4543
+            this.emit('rejected', response || null, cause || null);
4544
+            return this;
4545
+        },
4546
+        canceled: function () {
4547
+            if (this.sessionDescriptionHandler) {
4548
+                this.sessionDescriptionHandler.close();
4549
+            }
4550
+            this.emit('cancel');
4551
+            return this;
4552
+        },
4553
+        accepted: function (response, cause) {
4554
+            cause = SIP.Utils.getReasonPhrase(response && response.status_code, cause);
4555
+            this.startTime = new Date();
4556
+            if (this.replacee) {
4557
+                this.replacee.emit('replaced', this);
4558
+                this.replacee.terminate();
4559
+            }
4560
+            this.emit('accepted', response, cause);
4561
+            return this;
4562
+        },
4563
+        terminated: function (message, cause) {
4564
+            if (this.status === C.STATUS_TERMINATED) {
4565
+                return this;
4566
+            }
4567
+            this.endTime = new Date();
4568
+            this.close();
4569
+            this.emit('terminated', message || null, cause || null);
4570
+            return this;
4571
+        },
4572
+        connecting: function (request) {
4573
+            this.emit('connecting', { request: request });
4574
+            return this;
4575
+        }
4576
+    };
4577
+    Session.C = C;
4578
+    SIP.Session = Session;
4579
+    InviteServerContext = function (ua, request) {
4580
+        var expires, self = this, contentType = request.getHeader('Content-Type'), contentDisp = request.parseHeader('Content-Disposition');
4581
+        SIP.Utils.augment(this, SIP.ServerContext, [ua, request]);
4582
+        SIP.Utils.augment(this, SIP.Session, [ua.configuration.sessionDescriptionHandlerFactory]);
4583
+        if (contentDisp && contentDisp.type === 'render') {
4584
+            this.renderbody = request.body;
4585
+            this.rendertype = contentType;
4586
+        }
4587
+        this.status = C.STATUS_INVITE_RECEIVED;
4588
+        this.from_tag = request.from_tag;
4589
+        this.id = request.call_id + this.from_tag;
4590
+        this.request = request;
4591
+        this.contact = this.ua.contact.toString();
4592
+        this.receiveNonInviteResponse = function () { }; // intentional no-op
4593
+        this.logger = ua.getLogger('sip.inviteservercontext', this.id);
4594
+        //Save the session into the ua sessions collection.
4595
+        this.ua.sessions[this.id] = this;
4596
+        //Get the Expires header value if exists
4597
+        if (request.hasHeader('expires')) {
4598
+            expires = request.getHeader('expires') * 1000;
4599
+        }
4600
+        //Set 100rel if necessary
4601
+        function set100rel(h, c) {
4602
+            if (request.hasHeader(h) && request.getHeader(h).toLowerCase().indexOf('100rel') >= 0) {
4603
+                self.rel100 = c;
4604
+            }
4605
+        }
4606
+        set100rel('require', SIP.C.supported.REQUIRED);
4607
+        set100rel('supported', SIP.C.supported.SUPPORTED);
4608
+        /* Set the to_tag before
4609
+         * replying a response code that will create a dialog.
4610
+         */
4611
+        request.to_tag = SIP.Utils.newTag();
4612
+        // An error on dialog creation will fire 'failed' event
4613
+        if (!this.createDialog(request, 'UAS', true)) {
4614
+            request.reply(500, 'Missing Contact header field');
4615
+            return;
4616
+        }
4617
+        var options = { extraHeaders: ['Contact: ' + self.contact] };
4618
+        if (self.rel100 !== SIP.C.supported.REQUIRED) {
4619
+            self.progress(options);
4620
+        }
4621
+        self.status = C.STATUS_WAITING_FOR_ANSWER;
4622
+        // Set userNoAnswerTimer
4623
+        self.timers.userNoAnswerTimer = SIP.Timers.setTimeout(function () {
4624
+            request.reply(408);
4625
+            self.failed(request, SIP.C.causes.NO_ANSWER);
4626
+            self.terminated(request, SIP.C.causes.NO_ANSWER);
4627
+        }, self.ua.configuration.noAnswerTimeout);
4628
+        /* Set expiresTimer
4629
+         * RFC3261 13.3.1
4630
+         */
4631
+        if (expires) {
4632
+            self.timers.expiresTimer = SIP.Timers.setTimeout(function () {
4633
+                if (self.status === C.STATUS_WAITING_FOR_ANSWER) {
4634
+                    request.reply(487);
4635
+                    self.failed(request, SIP.C.causes.EXPIRES);
4636
+                    self.terminated(request, SIP.C.causes.EXPIRES);
4637
+                }
4638
+            }, expires);
4639
+        }
4640
+        this.errorListener = this.onTransportError.bind(this);
4641
+        ua.transport.on('transportError', this.errorListener);
4642
+    };
4643
+    InviteServerContext.prototype = Object.create({}, {
4644
+        reject: { writable: true, value: function (options) {
4645
+                // Check Session Status
4646
+                if (this.status === C.STATUS_TERMINATED) {
4647
+                    throw new SIP.Exceptions.InvalidStateError(this.status);
4648
+                }
4649
+                this.logger.log('rejecting RTCSession');
4650
+                SIP.ServerContext.prototype.reject.call(this, options);
4651
+                return this.terminated();
4652
+            } },
4653
+        terminate: { writable: true, value: function (options) {
4654
+                options = options || {};
4655
+                var extraHeaders = (options.extraHeaders || []).slice(), body = options.body, dialog, self = this;
4656
+                if (this.status === C.STATUS_WAITING_FOR_ACK &&
4657
+                    this.request.server_transaction.state !== SIP.Transactions.C.STATUS_TERMINATED) {
4658
+                    dialog = this.dialog;
4659
+                    this.receiveRequest = function (request) {
4660
+                        if (request.method === SIP.C.ACK) {
4661
+                            this.sendRequest(SIP.C.BYE, {
4662
+                                extraHeaders: extraHeaders,
4663
+                                body: body
4664
+                            });
4665
+                            dialog.terminate();
4666
+                        }
4667
+                    };
4668
+                    this.request.server_transaction.on('stateChanged', function () {
4669
+                        if (this.state === SIP.Transactions.C.STATUS_TERMINATED && this.dialog) {
4670
+                            this.request = new SIP.OutgoingRequest(SIP.C.BYE, this.dialog.remote_target, this.ua, {
4671
+                                'cseq': this.dialog.local_seqnum += 1,
4672
+                                'call_id': this.dialog.id.call_id,
4673
+                                'from_uri': this.dialog.local_uri,
4674
+                                'from_tag': this.dialog.id.local_tag,
4675
+                                'to_uri': this.dialog.remote_uri,
4676
+                                'to_tag': this.dialog.id.remote_tag,
4677
+                                'route_set': this.dialog.route_set
4678
+                            }, extraHeaders, body);
4679
+                            new SIP.RequestSender({
4680
+                                request: this.request,
4681
+                                onRequestTimeout: function () {
4682
+                                    self.onRequestTimeout();
4683
+                                },
4684
+                                onTransportError: function () {
4685
+                                    self.onTransportError();
4686
+                                },
4687
+                                receiveResponse: function () {
4688
+                                    return;
4689
+                                }
4690
+                            }, this.ua).send();
4691
+                            dialog.terminate();
4692
+                        }
4693
+                    });
4694
+                    this.emit('bye', this.request);
4695
+                    this.terminated();
4696
+                    // Restore the dialog into 'this' in order to be able to send the in-dialog BYE :-)
4697
+                    this.dialog = dialog;
4698
+                    // Restore the dialog into 'ua' so the ACK can reach 'this' session
4699
+                    this.ua.dialogs[dialog.id.toString()] = dialog;
4700
+                }
4701
+                else if (this.status === C.STATUS_CONFIRMED) {
4702
+                    this.bye(options);
4703
+                }
4704
+                else {
4705
+                    this.reject(options);
4706
+                }
4707
+                return this;
4708
+            } },
4709
+        /*
4710
+         * @param {Object} [options.sessionDescriptionHandlerOptions] gets passed to SIP.SessionDescriptionHandler.getDescription as options
4711
+         */
4712
+        progress: { writable: true, value: function (options) {
4713
+                options = options || {};
4714
+                var statusCode = options.statusCode || 180, reasonPhrase = options.reasonPhrase, extraHeaders = (options.extraHeaders || []).slice(), body = options.body, response;
4715
+                if (statusCode < 100 || statusCode > 199) {
4716
+                    throw new TypeError('Invalid statusCode: ' + statusCode);
4717
+                }
4718
+                if (this.isCanceled || this.status === C.STATUS_TERMINATED) {
4719
+                    return this;
4720
+                }
4721
+                function do100rel() {
4722
+                    /* jshint validthis: true */
4723
+                    statusCode = options.statusCode || 183;
4724
+                    // Set status and add extra headers
4725
+                    this.status = C.STATUS_WAITING_FOR_PRACK;
4726
+                    extraHeaders.push('Contact: ' + this.contact);
4727
+                    extraHeaders.push('Require: 100rel');
4728
+                    extraHeaders.push('RSeq: ' + Math.floor(Math.random() * 10000));
4729
+                    // Get the session description to add to preaccept with
4730
+                    this.sessionDescriptionHandler.getDescription(options.sessionDescriptionHandlerOptions, options.modifiers)
4731
+                        .then(function onSuccess(description) {
4732
+                        if (this.isCanceled || this.status === C.STATUS_TERMINATED) {
4733
+                            return;
4734
+                        }
4735
+                        this.early_sdp = description.body;
4736
+                        this[this.hasOffer ? 'hasAnswer' : 'hasOffer'] = true;
4737
+                        // Retransmit until we get a response or we time out (see prackTimer below)
4738
+                        var timeout = SIP.Timers.T1;
4739
+                        this.timers.rel1xxTimer = SIP.Timers.setTimeout(function rel1xxRetransmission() {
4740
+                            this.request.reply(statusCode, null, extraHeaders, description);
4741
+                            timeout *= 2;
4742
+                            this.timers.rel1xxTimer = SIP.Timers.setTimeout(rel1xxRetransmission.bind(this), timeout);
4743
+                        }.bind(this), timeout);
4744
+                        // Timeout and reject INVITE if no response
4745
+                        this.timers.prackTimer = SIP.Timers.setTimeout(function () {
4746
+                            if (this.status !== C.STATUS_WAITING_FOR_PRACK) {
4747
+                                return;
4748
+                            }
4749
+                            this.logger.log('no PRACK received, rejecting the call');
4750
+                            SIP.Timers.clearTimeout(this.timers.rel1xxTimer);
4751
+                            this.request.reply(504);
4752
+                            this.terminated(null, SIP.C.causes.NO_PRACK);
4753
+                        }.bind(this), SIP.Timers.T1 * 64);
4754
+                        // Send the initial response
4755
+                        response = this.request.reply(statusCode, reasonPhrase, extraHeaders, description);
4756
+                        this.emit('progress', response, reasonPhrase);
4757
+                    }.bind(this), function onFailure() {
4758
+                        this.request.reply(480);
4759
+                        this.failed(null, SIP.C.causes.WEBRTC_ERROR);
4760
+                        this.terminated(null, SIP.C.causes.WEBRTC_ERROR);
4761
+                    }.bind(this));
4762
+                } // end do100rel
4763
+                function normalReply() {
4764
+                    /* jshint validthis:true */
4765
+                    response = this.request.reply(statusCode, reasonPhrase, extraHeaders, body);
4766
+                    this.emit('progress', response, reasonPhrase);
4767
+                }
4768
+                if (options.statusCode !== 100 &&
4769
+                    (this.rel100 === SIP.C.supported.REQUIRED ||
4770
+                        (this.rel100 === SIP.C.supported.SUPPORTED && options.rel100) ||
4771
+                        (this.rel100 === SIP.C.supported.SUPPORTED && (this.ua.configuration.rel100 === SIP.C.supported.REQUIRED)))) {
4772
+                    this.sessionDescriptionHandler = this.setupSessionDescriptionHandler();
4773
+                    this.emit('SessionDescriptionHandler-created', this.sessionDescriptionHandler);
4774
+                    if (this.sessionDescriptionHandler.hasDescription(this.request.getHeader('Content-Type'))) {
4775
+                        this.hasOffer = true;
4776
+                        this.sessionDescriptionHandler.setDescription(this.request.body, options.sessionDescriptionHandlerOptions, options.modifiers)
4777
+                            .then(do100rel.apply(this))
4778
+                            .catch(function onFailure(e) {
4779
+                            this.logger.warn('invalid description');
4780
+                            this.logger.warn(e);
4781
+                            this.failed(null, SIP.C.causes.WEBRTC_ERROR);
4782
+                            this.terminated(null, SIP.C.causes.WEBRTC_ERROR);
4783
+                        }.bind(this));
4784
+                    }
4785
+                    else {
4786
+                        do100rel.apply(this);
4787
+                    }
4788
+                }
4789
+                else {
4790
+                    normalReply.apply(this);
4791
+                }
4792
+                return this;
4793
+            } },
4794
+        /*
4795
+         * @param {Object} [options.sessionDescriptionHandlerOptions] gets passed to SIP.SessionDescriptionHandler.getDescription as options
4796
+         */
4797
+        accept: { writable: true, value: function (options) {
4798
+                options = options || {};
4799
+                this.onInfo = options.onInfo;
4800
+                var self = this, request = this.request, extraHeaders = (options.extraHeaders || []).slice(), descriptionCreationSucceeded = function (description) {
4801
+                    var response, 
4802
+                    // run for reply success callback
4803
+                    replySucceeded = function () {
4804
+                        self.status = C.STATUS_WAITING_FOR_ACK;
4805
+                        self.setInvite2xxTimer(request, description);
4806
+                        self.setACKTimer();
4807
+                    }, 
4808
+                    // run for reply failure callback
4809
+                    replyFailed = function () {
4810
+                        self.failed(null, SIP.C.causes.CONNECTION_ERROR);
4811
+                        self.terminated(null, SIP.C.causes.CONNECTION_ERROR);
4812
+                    };
4813
+                    extraHeaders.push('Contact: ' + self.contact);
4814
+                    extraHeaders.push('Allow: ' + SIP.UA.C.ALLOWED_METHODS.toString());
4815
+                    if (!self.hasOffer) {
4816
+                        self.hasOffer = true;
4817
+                    }
4818
+                    else {
4819
+                        self.hasAnswer = true;
4820
+                    }
4821
+                    response = request.reply(200, null, extraHeaders, description, replySucceeded, replyFailed);
4822
+                    if (self.status !== C.STATUS_TERMINATED) { // Didn't fail
4823
+                        self.accepted(response, SIP.Utils.getReasonPhrase(200));
4824
+                    }
4825
+                }, descriptionCreationFailed = function (err) {
4826
+                    if (err instanceof SIP.Exceptions.SessionDescriptionHandlerError) {
4827
+                        self.logger.log(err.message);
4828
+                        self.logger.log(err.error);
4829
+                    }
4830
+                    // TODO: This should check the actual error and make sure it is an
4831
+                    //        "expected" error. Otherwise it should throw.
4832
+                    if (self.status === C.STATUS_TERMINATED) {
4833
+                        return;
4834
+                    }
4835
+                    self.request.reply(480);
4836
+                    self.failed(null, SIP.C.causes.WEBRTC_ERROR);
4837
+                    self.terminated(null, SIP.C.causes.WEBRTC_ERROR);
4838
+                };
4839
+                // Check Session Status
4840
+                if (this.status === C.STATUS_WAITING_FOR_PRACK) {
4841
+                    this.status = C.STATUS_ANSWERED_WAITING_FOR_PRACK;
4842
+                    return this;
4843
+                }
4844
+                else if (this.status === C.STATUS_WAITING_FOR_ANSWER) {
4845
+                    this.status = C.STATUS_ANSWERED;
4846
+                }
4847
+                else if (this.status !== C.STATUS_EARLY_MEDIA) {
4848
+                    throw new SIP.Exceptions.InvalidStateError(this.status);
4849
+                }
4850
+                // An error on dialog creation will fire 'failed' event
4851
+                if (!this.createDialog(request, 'UAS')) {
4852
+                    request.reply(500, 'Missing Contact header field');
4853
+                    return this;
4854
+                }
4855
+                SIP.Timers.clearTimeout(this.timers.userNoAnswerTimer);
4856
+                if (this.status === C.STATUS_EARLY_MEDIA) {
4857
+                    descriptionCreationSucceeded({});
4858
+                }
4859
+                else {
4860
+                    this.sessionDescriptionHandler = this.setupSessionDescriptionHandler();
4861
+                    this.emit('SessionDescriptionHandler-created', this.sessionDescriptionHandler);
4862
+                    if (this.request.getHeader('Content-Length') === '0' && !this.request.getHeader('Content-Type')) {
4863
+                        this.sessionDescriptionHandler.getDescription(options.sessionDescriptionHandlerOptions, options.modifiers)
4864
+                            .catch(descriptionCreationFailed)
4865
+                            .then(descriptionCreationSucceeded);
4866
+                    }
4867
+                    else if (this.sessionDescriptionHandler.hasDescription(this.request.getHeader('Content-Type'))) {
4868
+                        this.hasOffer = true;
4869
+                        this.sessionDescriptionHandler.setDescription(this.request.body, options.sessionDescriptionHandlerOptions, options.modifiers)
4870
+                            .then(function () {
4871
+                            return this.sessionDescriptionHandler.getDescription(options.sessionDescriptionHandlerOptions, options.modifiers);
4872
+                        }.bind(this))
4873
+                            .catch(descriptionCreationFailed)
4874
+                            .then(descriptionCreationSucceeded);
4875
+                    }
4876
+                    else {
4877
+                        this.request.reply(415);
4878
+                        // TODO: Events
4879
+                        return;
4880
+                    }
4881
+                }
4882
+                return this;
4883
+            } },
4884
+        receiveRequest: { writable: true, value: function (request) {
4885
+                // ISC RECEIVE REQUEST
4886
+                function confirmSession() {
4887
+                    /* jshint validthis:true */
4888
+                    var contentType, contentDisp;
4889
+                    SIP.Timers.clearTimeout(this.timers.ackTimer);
4890
+                    SIP.Timers.clearTimeout(this.timers.invite2xxTimer);
4891
+                    this.status = C.STATUS_CONFIRMED;
4892
+                    contentType = request.getHeader('Content-Type');
4893
+                    contentDisp = request.getHeader('Content-Disposition');
4894
+                    if (contentDisp && contentDisp.type === 'render') {
4895
+                        this.renderbody = request.body;
4896
+                        this.rendertype = contentType;
4897
+                    }
4898
+                    this.emit('confirmed', request);
4899
+                }
4900
+                switch (request.method) {
4901
+                    case SIP.C.CANCEL:
4902
+                        /* RFC3261 15 States that a UAS may have accepted an invitation while a CANCEL
4903
+                         * was in progress and that the UAC MAY continue with the session established by
4904
+                         * any 2xx response, or MAY terminate with BYE. SIP does continue with the
4905
+                         * established session. So the CANCEL is processed only if the session is not yet
4906
+                         * established.
4907
+                         */
4908
+                        /*
4909
+                         * Terminate the whole session in case the user didn't accept (or yet to send the answer) nor reject the
4910
+                         *request opening the session.
4911
+                         */
4912
+                        if (this.status === C.STATUS_WAITING_FOR_ANSWER ||
4913
+                            this.status === C.STATUS_WAITING_FOR_PRACK ||
4914
+                            this.status === C.STATUS_ANSWERED_WAITING_FOR_PRACK ||
4915
+                            this.status === C.STATUS_EARLY_MEDIA ||
4916
+                            this.status === C.STATUS_ANSWERED) {
4917
+                            this.status = C.STATUS_CANCELED;
4918
+                            this.request.reply(487);
4919
+                            this.canceled(request);
4920
+                            this.rejected(request, SIP.C.causes.CANCELED);
4921
+                            this.failed(request, SIP.C.causes.CANCELED);
4922
+                            this.terminated(request, SIP.C.causes.CANCELED);
4923
+                        }
4924
+                        break;
4925
+                    case SIP.C.ACK:
4926
+                        if (this.status === C.STATUS_WAITING_FOR_ACK) {
4927
+                            if (this.sessionDescriptionHandler.hasDescription(request.getHeader('Content-Type'))) {
4928
+                                // ACK contains answer to an INVITE w/o SDP negotiation
4929
+                                this.hasAnswer = true;
4930
+                                this.sessionDescriptionHandler.setDescription(request.body, this.sessionDescriptionHandlerOptions, this.modifiers)
4931
+                                    .then(
4932
+                                // TODO: Catch then .then
4933
+                                confirmSession.bind(this), function onFailure(e) {
4934
+                                    this.logger.warn(e);
4935
+                                    this.terminate({
4936
+                                        statusCode: '488',
4937
+                                        reasonPhrase: 'Bad Media Description'
4938
+                                    });
4939
+                                    this.failed(request, SIP.C.causes.BAD_MEDIA_DESCRIPTION);
4940
+                                    this.terminated(request, SIP.C.causes.BAD_MEDIA_DESCRIPTION);
4941
+                                }.bind(this));
4942
+                            }
4943
+                            else {
4944
+                                confirmSession.apply(this);
4945
+                            }
4946
+                        }
4947
+                        break;
4948
+                    case SIP.C.PRACK:
4949
+                        if (this.status === C.STATUS_WAITING_FOR_PRACK || this.status === C.STATUS_ANSWERED_WAITING_FOR_PRACK) {
4950
+                            if (!this.hasAnswer) {
4951
+                                this.sessionDescriptionHandler = this.setupSessionDescriptionHandler();
4952
+                                this.emit('SessionDescriptionHandler-created', this.sessionDescriptionHandler);
4953
+                                if (this.sessionDescriptionHandler.hasDescription(request.getHeader('Content-Type'))) {
4954
+                                    this.hasAnswer = true;
4955
+                                    this.sessionDescriptionHandler.setDescription(request.body, this.sessionDescriptionHandlerOptions, this.modifiers)
4956
+                                        .then(function onSuccess() {
4957
+                                        SIP.Timers.clearTimeout(this.timers.rel1xxTimer);
4958
+                                        SIP.Timers.clearTimeout(this.timers.prackTimer);
4959
+                                        request.reply(200);
4960
+                                        if (this.status === C.STATUS_ANSWERED_WAITING_FOR_PRACK) {
4961
+                                            this.status = C.STATUS_EARLY_MEDIA;
4962
+                                            this.accept();
4963
+                                        }
4964
+                                        this.status = C.STATUS_EARLY_MEDIA;
4965
+                                    }.bind(this), function onFailure(e) {
4966
+                                        this.logger.warn(e);
4967
+                                        this.terminate({
4968
+                                            statusCode: '488',
4969
+                                            reasonPhrase: 'Bad Media Description'
4970
+                                        });
4971
+                                        this.failed(request, SIP.C.causes.BAD_MEDIA_DESCRIPTION);
4972
+                                        this.terminated(request, SIP.C.causes.BAD_MEDIA_DESCRIPTION);
4973
+                                    }.bind(this));
4974
+                                }
4975
+                                else {
4976
+                                    this.terminate({
4977
+                                        statusCode: '488',
4978
+                                        reasonPhrase: 'Bad Media Description'
4979
+                                    });
4980
+                                    this.failed(request, SIP.C.causes.BAD_MEDIA_DESCRIPTION);
4981
+                                    this.terminated(request, SIP.C.causes.BAD_MEDIA_DESCRIPTION);
4982
+                                }
4983
+                            }
4984
+                            else {
4985
+                                SIP.Timers.clearTimeout(this.timers.rel1xxTimer);
4986
+                                SIP.Timers.clearTimeout(this.timers.prackTimer);
4987
+                                request.reply(200);
4988
+                                if (this.status === C.STATUS_ANSWERED_WAITING_FOR_PRACK) {
4989
+                                    this.status = C.STATUS_EARLY_MEDIA;
4990
+                                    this.accept();
4991
+                                }
4992
+                                this.status = C.STATUS_EARLY_MEDIA;
4993
+                            }
4994
+                        }
4995
+                        else if (this.status === C.STATUS_EARLY_MEDIA) {
4996
+                            request.reply(200);
4997
+                        }
4998
+                        break;
4999
+                    default:
5000
+                        Session.prototype.receiveRequest.apply(this, [request]);
5001
+                        break;
5002
+                }
5003
+            } },
5004
+        // Internal Function to setup the handler consistently
5005
+        setupSessionDescriptionHandler: { writable: true, value: function () {
5006
+                if (this.sessionDescriptionHandler) {
5007
+                    return this.sessionDescriptionHandler;
5008
+                }
5009
+                return this.sessionDescriptionHandlerFactory(this, this.ua.configuration.sessionDescriptionHandlerFactoryOptions);
5010
+            } },
5011
+        onTransportError: { writable: true, value: function () {
5012
+                if (this.status !== C.STATUS_CONFIRMED && this.status !== C.STATUS_TERMINATED) {
5013
+                    this.failed(null, SIP.C.causes.CONNECTION_ERROR);
5014
+                }
5015
+            } },
5016
+        onRequestTimeout: { writable: true, value: function () {
5017
+                if (this.status === C.STATUS_CONFIRMED) {
5018
+                    this.terminated(null, SIP.C.causes.REQUEST_TIMEOUT);
5019
+                }
5020
+                else if (this.status !== C.STATUS_TERMINATED) {
5021
+                    this.failed(null, SIP.C.causes.REQUEST_TIMEOUT);
5022
+                    this.terminated(null, SIP.C.causes.REQUEST_TIMEOUT);
5023
+                }
5024
+            } }
5025
+    });
5026
+    SIP.InviteServerContext = InviteServerContext;
5027
+    InviteClientContext = function (ua, target, options, modifiers) {
5028
+        options = options || {};
5029
+        this.passedOptions = options; // Save for later to use with refer
5030
+        options.params = Object.create(options.params || Object.prototype);
5031
+        var extraHeaders = (options.extraHeaders || []).slice(), sessionDescriptionHandlerFactory = ua.configuration.sessionDescriptionHandlerFactory;
5032
+        this.sessionDescriptionHandlerFactoryOptions = ua.configuration.sessionDescriptionHandlerFactoryOptions || {};
5033
+        this.sessionDescriptionHandlerOptions = options.sessionDescriptionHandlerOptions || {};
5034
+        this.modifiers = modifiers;
5035
+        this.inviteWithoutSdp = options.inviteWithoutSdp || false;
5036
+        // Set anonymous property
5037
+        this.anonymous = options.anonymous || false;
5038
+        // Custom data to be sent either in INVITE or in ACK
5039
+        this.renderbody = options.renderbody || null;
5040
+        this.rendertype = options.rendertype || 'text/plain';
5041
+        // Session parameter initialization
5042
+        this.from_tag = SIP.Utils.newTag();
5043
+        options.params.from_tag = this.from_tag;
5044
+        /* Do not add ;ob in initial forming dialog requests if the registration over
5045
+         *  the current connection got a GRUU URI.
5046
+         */
5047
+        this.contact = ua.contact.toString({
5048
+            anonymous: this.anonymous,
5049
+            outbound: this.anonymous ? !ua.contact.temp_gruu : !ua.contact.pub_gruu
5050
+        });
5051
+        if (this.anonymous) {
5052
+            options.params.from_displayName = 'Anonymous';
5053
+            options.params.from_uri = 'sip:anonymous@anonymous.invalid';
5054
+            extraHeaders.push('P-Preferred-Identity: ' + ua.configuration.uri.toString());
5055
+            extraHeaders.push('Privacy: id');
5056
+        }
5057
+        extraHeaders.push('Contact: ' + this.contact);
5058
+        extraHeaders.push('Allow: ' + SIP.UA.C.ALLOWED_METHODS.toString());
5059
+        if (this.inviteWithoutSdp && this.renderbody) {
5060
+            extraHeaders.push('Content-Type: ' + this.rendertype);
5061
+            extraHeaders.push('Content-Disposition: render;handling=optional');
5062
+        }
5063
+        if (ua.configuration.rel100 === SIP.C.supported.REQUIRED) {
5064
+            extraHeaders.push('Require: 100rel');
5065
+        }
5066
+        if (ua.configuration.replaces === SIP.C.supported.REQUIRED) {
5067
+            extraHeaders.push('Require: replaces');
5068
+        }
5069
+        options.extraHeaders = extraHeaders;
5070
+        SIP.Utils.augment(this, SIP.ClientContext, [ua, SIP.C.INVITE, target, options]);
5071
+        SIP.Utils.augment(this, SIP.Session, [sessionDescriptionHandlerFactory]);
5072
+        // Check Session Status
5073
+        if (this.status !== C.STATUS_NULL) {
5074
+            throw new SIP.Exceptions.InvalidStateError(this.status);
5075
+        }
5076
+        // OutgoingSession specific parameters
5077
+        this.isCanceled = false;
5078
+        this.received_100 = false;
5079
+        this.method = SIP.C.INVITE;
5080
+        this.receiveNonInviteResponse = this.receiveResponse;
5081
+        this.receiveResponse = this.receiveInviteResponse;
5082
+        this.logger = ua.getLogger('sip.inviteclientcontext');
5083
+        ua.applicants[this] = this;
5084
+        this.id = this.request.call_id + this.from_tag;
5085
+        this.onInfo = options.onInfo;
5086
+        this.errorListener = this.onTransportError.bind(this);
5087
+        ua.transport.on('transportError', this.errorListener);
5088
+    };
5089
+    InviteClientContext.prototype = Object.create({}, {
5090
+        invite: { writable: true, value: function () {
5091
+                var self = this;
5092
+                //Save the session into the ua sessions collection.
5093
+                //Note: placing in constructor breaks call to request.cancel on close... User does not need this anyway
5094
+                this.ua.sessions[this.id] = this;
5095
+                // This should allow the function to return so that listeners can be set up for these events
5096
+                SIP.Utils.Promise.resolve().then(function () {
5097
+                    if (this.inviteWithoutSdp) {
5098
+                        //just send an invite with no sdp...
5099
+                        this.request.body = self.renderbody;
5100
+                        this.status = C.STATUS_INVITE_SENT;
5101
+                        this.send();
5102
+                    }
5103
+                    else {
5104
+                        //Initialize Media Session
5105
+                        this.sessionDescriptionHandler = this.sessionDescriptionHandlerFactory(this, this.sessionDescriptionHandlerFactoryOptions);
5106
+                        this.emit('SessionDescriptionHandler-created', this.sessionDescriptionHandler);
5107
+                        this.sessionDescriptionHandler.getDescription(this.sessionDescriptionHandlerOptions, this.modifiers)
5108
+                            .then(function onSuccess(description) {
5109
+                            if (self.isCanceled || self.status === C.STATUS_TERMINATED) {
5110
+                                return;
5111
+                            }
5112
+                            self.hasOffer = true;
5113
+                            self.request.body = description;
5114
+                            self.status = C.STATUS_INVITE_SENT;
5115
+                            self.send();
5116
+                        }, function onFailure(err) {
5117
+                            if (err instanceof SIP.Exceptions.SessionDescriptionHandlerError) {
5118
+                                self.logger.log(err.message);
5119
+                                self.logger.log(err.error);
5120
+                            }
5121
+                            if (self.status === C.STATUS_TERMINATED) {
5122
+                                return;
5123
+                            }
5124
+                            self.failed(null, SIP.C.causes.WEBRTC_ERROR);
5125
+                            self.terminated(null, SIP.C.causes.WEBRTC_ERROR);
5126
+                        });
5127
+                    }
5128
+                }.bind(this));
5129
+                return this;
5130
+            } },
5131
+        receiveInviteResponse: { writable: true, value: function (response) {
5132
+                var cause, session = this, id = response.call_id + response.from_tag + response.to_tag, extraHeaders = [], options = {};
5133
+                if (this.status === C.STATUS_TERMINATED || response.method !== SIP.C.INVITE) {
5134
+                    return;
5135
+                }
5136
+                if (this.dialog && (response.status_code >= 200 && response.status_code <= 299)) {
5137
+                    if (id !== this.dialog.id.toString()) {
5138
+                        if (!this.createDialog(response, 'UAC', true)) {
5139
+                            return;
5140
+                        }
5141
+                        this.emit("ack", response.transaction.sendACK({ body: SIP.Utils.generateFakeSDP(response.body) }));
5142
+                        this.earlyDialogs[id].sendRequest(this, SIP.C.BYE);
5143
+                        /* NOTE: This fails because the forking proxy does not recognize that an unanswerable
5144
+                         * leg (due to peerConnection limitations) has been answered first. If your forking
5145
+                         * proxy does not hang up all unanswered branches on the first branch answered, remove this.
5146
+                         */
5147
+                        if (this.status !== C.STATUS_CONFIRMED) {
5148
+                            this.failed(response, SIP.C.causes.WEBRTC_ERROR);
5149
+                            this.terminated(response, SIP.C.causes.WEBRTC_ERROR);
5150
+                        }
5151
+                        return;
5152
+                    }
5153
+                    else if (this.status === C.STATUS_CONFIRMED) {
5154
+                        this.emit("ack", response.transaction.sendACK());
5155
+                        return;
5156
+                    }
5157
+                    else if (!this.hasAnswer) {
5158
+                        // invite w/o sdp is waiting for callback
5159
+                        //an invite with sdp must go on, and hasAnswer is true
5160
+                        return;
5161
+                    }
5162
+                }
5163
+                if (this.dialog && response.status_code < 200) {
5164
+                    /*
5165
+                      Early media has been set up with at least one other different branch,
5166
+                      but a final 2xx response hasn't been received
5167
+                    */
5168
+                    if (this.dialog.pracked.indexOf(response.getHeader('rseq')) !== -1 ||
5169
+                        (this.dialog.pracked[this.dialog.pracked.length - 1] >= response.getHeader('rseq') && this.dialog.pracked.length > 0)) {
5170
+                        return;
5171
+                    }
5172
+                    if (!this.earlyDialogs[id] && !this.createDialog(response, 'UAC', true)) {
5173
+                        return;
5174
+                    }
5175
+                    if (this.earlyDialogs[id].pracked.indexOf(response.getHeader('rseq')) !== -1 ||
5176
+                        (this.earlyDialogs[id].pracked[this.earlyDialogs[id].pracked.length - 1] >= response.getHeader('rseq') && this.earlyDialogs[id].pracked.length > 0)) {
5177
+                        return;
5178
+                    }
5179
+                    extraHeaders.push('RAck: ' + response.getHeader('rseq') + ' ' + response.getHeader('cseq'));
5180
+                    this.earlyDialogs[id].pracked.push(response.getHeader('rseq'));
5181
+                    this.earlyDialogs[id].sendRequest(this, SIP.C.PRACK, {
5182
+                        extraHeaders: extraHeaders,
5183
+                        body: SIP.Utils.generateFakeSDP(response.body)
5184
+                    });
5185
+                    return;
5186
+                }
5187
+                // Proceed to cancellation if the user requested.
5188
+                if (this.isCanceled) {
5189
+                    if (response.status_code >= 100 && response.status_code < 200) {
5190
+                        this.request.cancel(this.cancelReason, extraHeaders);
5191
+                        this.canceled(null);
5192
+                    }
5193
+                    else if (response.status_code >= 200 && response.status_code < 299) {
5194
+                        this.acceptAndTerminate(response);
5195
+                        this.emit('bye', this.request);
5196
+                    }
5197
+                    else if (response.status_code >= 300) {
5198
+                        cause = SIP.C.REASON_PHRASE[response.status_code] || SIP.C.causes.CANCELED;
5199
+                        this.rejected(response, cause);
5200
+                        this.failed(response, cause);
5201
+                        this.terminated(response, cause);
5202
+                    }
5203
+                    return;
5204
+                }
5205
+                switch (true) {
5206
+                    case /^100$/.test(response.status_code):
5207
+                        this.received_100 = true;
5208
+                        this.emit('progress', response);
5209
+                        break;
5210
+                    case (/^1[0-9]{2}$/.test(response.status_code)):
5211
+                        // Do nothing with 1xx responses without To tag.
5212
+                        if (!response.to_tag) {
5213
+                            this.logger.warn('1xx response received without to tag');
5214
+                            break;
5215
+                        }
5216
+                        // Create Early Dialog if 1XX comes with contact
5217
+                        if (response.hasHeader('contact')) {
5218
+                            // An error on dialog creation will fire 'failed' event
5219
+                            if (!this.createDialog(response, 'UAC', true)) {
5220
+                                break;
5221
+                            }
5222
+                        }
5223
+                        this.status = C.STATUS_1XX_RECEIVED;
5224
+                        if (response.hasHeader('P-Asserted-Identity')) {
5225
+                            this.assertedIdentity = new SIP.NameAddrHeader.parse(response.getHeader('P-Asserted-Identity'));
5226
+                        }
5227
+                        if (response.hasHeader('require') &&
5228
+                            response.getHeader('require').indexOf('100rel') !== -1) {
5229
+                            // Do nothing if this.dialog is already confirmed
5230
+                            if (this.dialog || !this.earlyDialogs[id]) {
5231
+                                break;
5232
+                            }
5233
+                            if (this.earlyDialogs[id].pracked.indexOf(response.getHeader('rseq')) !== -1 ||
5234
+                                (this.earlyDialogs[id].pracked[this.earlyDialogs[id].pracked.length - 1] >= response.getHeader('rseq') && this.earlyDialogs[id].pracked.length > 0)) {
5235
+                                return;
5236
+                            }
5237
+                            // TODO: This may be broken. It may have to be on the early dialog
5238
+                            this.sessionDescriptionHandler = this.sessionDescriptionHandlerFactory(this, this.sessionDescriptionHandlerFactoryOptions);
5239
+                            this.emit('SessionDescriptionHandler-created', this.sessionDescriptionHandler);
5240
+                            if (!this.sessionDescriptionHandler.hasDescription(response.getHeader('Content-Type'))) {
5241
+                                extraHeaders.push('RAck: ' + response.getHeader('rseq') + ' ' + response.getHeader('cseq'));
5242
+                                this.earlyDialogs[id].pracked.push(response.getHeader('rseq'));
5243
+                                this.earlyDialogs[id].sendRequest(this, SIP.C.PRACK, {
5244
+                                    extraHeaders: extraHeaders
5245
+                                });
5246
+                                this.emit('progress', response);
5247
+                            }
5248
+                            else if (this.hasOffer) {
5249
+                                if (!this.createDialog(response, 'UAC')) {
5250
+                                    break;
5251
+                                }
5252
+                                this.hasAnswer = true;
5253
+                                this.dialog.pracked.push(response.getHeader('rseq'));
5254
+                                this.sessionDescriptionHandler.setDescription(response.body, this.sessionDescriptionHandlerOptions, this.modifiers)
5255
+                                    .then(function onSuccess() {
5256
+                                    extraHeaders.push('RAck: ' + response.getHeader('rseq') + ' ' + response.getHeader('cseq'));
5257
+                                    session.sendRequest(SIP.C.PRACK, {
5258
+                                        extraHeaders: extraHeaders,
5259
+                                        receiveResponse: function () { }
5260
+                                    });
5261
+                                    session.status = C.STATUS_EARLY_MEDIA;
5262
+                                    session.emit('progress', response);
5263
+                                }, function onFailure(e) {
5264
+                                    session.logger.warn(e);
5265
+                                    session.acceptAndTerminate(response, 488, 'Not Acceptable Here');
5266
+                                    session.failed(response, SIP.C.causes.BAD_MEDIA_DESCRIPTION);
5267
+                                });
5268
+                            }
5269
+                            else {
5270
+                                var earlyDialog = this.earlyDialogs[id];
5271
+                                var earlyMedia = earlyDialog.sessionDescriptionHandler = this.sessionDescriptionHandlerFactory(this, this.sessionDescriptionHandlerFactoryOptions);
5272
+                                this.emit('SessionDescriptionHandler-created', earlyMedia);
5273
+                                earlyDialog.pracked.push(response.getHeader('rseq'));
5274
+                                earlyMedia.setDescription(response.body, session.sessionDescriptionHandlerOptions, session.modifers)
5275
+                                    .then(earlyMedia.getDescription.bind(earlyMedia, session.sessionDescriptionHandlerOptions, session.modifiers))
5276
+                                    .then(function onSuccess(description) {
5277
+                                    extraHeaders.push('RAck: ' + response.getHeader('rseq') + ' ' + response.getHeader('cseq'));
5278
+                                    earlyDialog.sendRequest(session, SIP.C.PRACK, {
5279
+                                        extraHeaders: extraHeaders,
5280
+                                        body: description
5281
+                                    });
5282
+                                    session.status = C.STATUS_EARLY_MEDIA;
5283
+                                    session.emit('progress', response);
5284
+                                })
5285
+                                    .catch(function onFailure(e) {
5286
+                                    // TODO: This is a bit wonky
5287
+                                    if (e instanceof SIP.Exceptions.SessionDescriptionHandlerError) {
5288
+                                        earlyDialog.pracked.push(response.getHeader('rseq'));
5289
+                                        if (session.status === C.STATUS_TERMINATED) {
5290
+                                            return;
5291
+                                        }
5292
+                                        session.failed(null, SIP.C.causes.WEBRTC_ERROR);
5293
+                                        session.terminated(null, SIP.C.causes.WEBRTC_ERROR);
5294
+                                    }
5295
+                                    else {
5296
+                                        earlyDialog.pracked.splice(earlyDialog.pracked.indexOf(response.getHeader('rseq')), 1);
5297
+                                        // Could not set remote description
5298
+                                        session.logger.warn('invalid description');
5299
+                                        session.logger.warn(e);
5300
+                                    }
5301
+                                });
5302
+                            }
5303
+                        }
5304
+                        else {
5305
+                            this.emit('progress', response);
5306
+                        }
5307
+                        break;
5308
+                    case /^2[0-9]{2}$/.test(response.status_code):
5309
+                        var cseq = this.request.cseq + ' ' + this.request.method;
5310
+                        if (cseq !== response.getHeader('cseq')) {
5311
+                            break;
5312
+                        }
5313
+                        if (response.hasHeader('P-Asserted-Identity')) {
5314
+                            this.assertedIdentity = new SIP.NameAddrHeader.parse(response.getHeader('P-Asserted-Identity'));
5315
+                        }
5316
+                        if (this.status === C.STATUS_EARLY_MEDIA && this.dialog) {
5317
+                            this.status = C.STATUS_CONFIRMED;
5318
+                            options = {};
5319
+                            if (this.renderbody) {
5320
+                                extraHeaders.push('Content-Type: ' + this.rendertype);
5321
+                                options.extraHeaders = extraHeaders;
5322
+                                options.body = this.renderbody;
5323
+                            }
5324
+                            this.emit("ack", response.transaction.sendACK(options));
5325
+                            this.accepted(response);
5326
+                            break;
5327
+                        }
5328
+                        // Do nothing if this.dialog is already confirmed
5329
+                        if (this.dialog) {
5330
+                            break;
5331
+                        }
5332
+                        // This is an invite without sdp
5333
+                        if (!this.hasOffer) {
5334
+                            if (this.earlyDialogs[id] && this.earlyDialogs[id].sessionDescriptionHandler) {
5335
+                                //REVISIT
5336
+                                this.hasOffer = true;
5337
+                                this.hasAnswer = true;
5338
+                                this.sessionDescriptionHandler = this.earlyDialogs[id].sessionDescriptionHandler;
5339
+                                if (!this.createDialog(response, 'UAC')) {
5340
+                                    break;
5341
+                                }
5342
+                                this.status = C.STATUS_CONFIRMED;
5343
+                                this.emit("ack", response.transaction.sendACK());
5344
+                                this.accepted(response);
5345
+                            }
5346
+                            else {
5347
+                                this.sessionDescriptionHandler = this.sessionDescriptionHandlerFactory(this, this.sessionDescriptionHandlerFactoryOptions);
5348
+                                this.emit('SessionDescriptionHandler-created', this.sessionDescriptionHandler);
5349
+                                if (!this.sessionDescriptionHandler.hasDescription(response.getHeader('Content-Type'))) {
5350
+                                    this.acceptAndTerminate(response, 400, 'Missing session description');
5351
+                                    this.failed(response, SIP.C.causes.BAD_MEDIA_DESCRIPTION);
5352
+                                    break;
5353
+                                }
5354
+                                if (!this.createDialog(response, 'UAC')) {
5355
+                                    break;
5356
+                                }
5357
+                                this.hasOffer = true;
5358
+                                this.sessionDescriptionHandler.setDescription(response.body, this.sessionDescriptionHandlerOptions, this.modifiers)
5359
+                                    .then(this.sessionDescriptionHandler.getDescription.bind(this.sessionDescriptionHandler, this.sessionDescriptionHandlerOptions, this.modifiers))
5360
+                                    .then(function onSuccess(description) {
5361
+                                    //var localMedia;
5362
+                                    if (session.isCanceled || session.status === C.STATUS_TERMINATED) {
5363
+                                        return;
5364
+                                    }
5365
+                                    session.status = C.STATUS_CONFIRMED;
5366
+                                    session.hasAnswer = true;
5367
+                                    session.emit("ack", response.transaction.sendACK({ body: description }));
5368
+                                    session.accepted(response);
5369
+                                })
5370
+                                    .catch(function onFailure(e) {
5371
+                                    if (e instanceof SIP.Exceptions.SessionDescriptionHandlerError) {
5372
+                                        session.logger.warn('invalid description');
5373
+                                        session.logger.warn(e);
5374
+                                        // TODO: This message is inconsistent
5375
+                                        session.acceptAndTerminate(response, 488, 'Invalid session description');
5376
+                                        session.failed(response, SIP.C.causes.BAD_MEDIA_DESCRIPTION);
5377
+                                    }
5378
+                                });
5379
+                            }
5380
+                        }
5381
+                        else if (this.hasAnswer) {
5382
+                            if (this.renderbody) {
5383
+                                extraHeaders.push('Content-Type: ' + session.rendertype);
5384
+                                options.extraHeaders = extraHeaders;
5385
+                                options.body = this.renderbody;
5386
+                            }
5387
+                            this.emit("ack", response.transaction.sendACK(options));
5388
+                        }
5389
+                        else {
5390
+                            if (!this.sessionDescriptionHandler.hasDescription(response.getHeader('Content-Type'))) {
5391
+                                this.acceptAndTerminate(response, 400, 'Missing session description');
5392
+                                this.failed(response, SIP.C.causes.BAD_MEDIA_DESCRIPTION);
5393
+                                break;
5394
+                            }
5395
+                            if (!this.createDialog(response, 'UAC')) {
5396
+                                break;
5397
+                            }
5398
+                            this.hasAnswer = true;
5399
+                            this.sessionDescriptionHandler.setDescription(response.body, this.sessionDescriptionHandlerOptions, this.modifiers)
5400
+                                .then(function onSuccess() {
5401
+                                var options = {};
5402
+                                session.status = C.STATUS_CONFIRMED;
5403
+                                if (session.renderbody) {
5404
+                                    extraHeaders.push('Content-Type: ' + session.rendertype);
5405
+                                    options.extraHeaders = extraHeaders;
5406
+                                    options.body = session.renderbody;
5407
+                                }
5408
+                                session.emit("ack", response.transaction.sendACK(options));
5409
+                                session.accepted(response);
5410
+                            }, function onFailure(e) {
5411
+                                session.logger.warn(e);
5412
+                                session.acceptAndTerminate(response, 488, 'Not Acceptable Here');
5413
+                                session.failed(response, SIP.C.causes.BAD_MEDIA_DESCRIPTION);
5414
+                            });
5415
+                        }
5416
+                        break;
5417
+                    default:
5418
+                        cause = SIP.Utils.sipErrorCause(response.status_code);
5419
+                        this.rejected(response, cause);
5420
+                        this.failed(response, cause);
5421
+                        this.terminated(response, cause);
5422
+                }
5423
+            } },
5424
+        cancel: { writable: true, value: function (options) {
5425
+                options = options || {};
5426
+                options.extraHeaders = (options.extraHeaders || []).slice();
5427
+                if (this.isCanceled) {
5428
+                    throw new SIP.Exceptions.InvalidStateError('CANCELED');
5429
+                }
5430
+                // Check Session Status
5431
+                if (this.status === C.STATUS_TERMINATED || this.status === C.STATUS_CONFIRMED) {
5432
+                    throw new SIP.Exceptions.InvalidStateError(this.status);
5433
+                }
5434
+                this.logger.log('canceling RTCSession');
5435
+                this.isCanceled = true;
5436
+                var cancel_reason = SIP.Utils.getCancelReason(options.status_code, options.reason_phrase);
5437
+                // Check Session Status
5438
+                if (this.status === C.STATUS_NULL ||
5439
+                    (this.status === C.STATUS_INVITE_SENT && !this.received_100)) {
5440
+                    this.cancelReason = cancel_reason;
5441
+                }
5442
+                else if (this.status === C.STATUS_INVITE_SENT ||
5443
+                    this.status === C.STATUS_1XX_RECEIVED ||
5444
+                    this.status === C.STATUS_EARLY_MEDIA) {
5445
+                    this.request.cancel(cancel_reason, options.extraHeaders);
5446
+                }
5447
+                return this.canceled();
5448
+            } },
5449
+        terminate: { writable: true, value: function (options) {
5450
+                if (this.status === C.STATUS_TERMINATED) {
5451
+                    return this;
5452
+                }
5453
+                if (this.status === C.STATUS_WAITING_FOR_ACK || this.status === C.STATUS_CONFIRMED) {
5454
+                    this.bye(options);
5455
+                }
5456
+                else {
5457
+                    this.cancel(options);
5458
+                }
5459
+                return this;
5460
+            } },
5461
+        receiveRequest: { writable: true, value: function (request) {
5462
+                // ICC RECEIVE REQUEST
5463
+                // Reject CANCELs
5464
+                if (request.method === SIP.C.CANCEL) {
5465
+                    // TODO; make this a switch when it gets added
5466
+                }
5467
+                if (request.method === SIP.C.ACK && this.status === C.STATUS_WAITING_FOR_ACK) {
5468
+                    SIP.Timers.clearTimeout(this.timers.ackTimer);
5469
+                    SIP.Timers.clearTimeout(this.timers.invite2xxTimer);
5470
+                    this.status = C.STATUS_CONFIRMED;
5471
+                    this.accepted();
5472
+                }
5473
+                return Session.prototype.receiveRequest.apply(this, [request]);
5474
+            } },
5475
+        onTransportError: { writable: true, value: function () {
5476
+                if (this.status !== C.STATUS_CONFIRMED && this.status !== C.STATUS_TERMINATED) {
5477
+                    this.failed(null, SIP.C.causes.CONNECTION_ERROR);
5478
+                }
5479
+            } },
5480
+        onRequestTimeout: { writable: true, value: function () {
5481
+                if (this.status === C.STATUS_CONFIRMED) {
5482
+                    this.terminated(null, SIP.C.causes.REQUEST_TIMEOUT);
5483
+                }
5484
+                else if (this.status !== C.STATUS_TERMINATED) {
5485
+                    this.failed(null, SIP.C.causes.REQUEST_TIMEOUT);
5486
+                    this.terminated(null, SIP.C.causes.REQUEST_TIMEOUT);
5487
+                }
5488
+            } }
5489
+    });
5490
+    SIP.InviteClientContext = InviteClientContext;
5491
+    ReferClientContext = function (ua, applicant, target, options) {
5492
+        this.options = options || {};
5493
+        this.extraHeaders = (this.options.extraHeaders || []).slice();
5494
+        if (ua === undefined || applicant === undefined || target === undefined) {
5495
+            throw new TypeError('Not enough arguments');
5496
+        }
5497
+        SIP.Utils.augment(this, SIP.ClientContext, [ua, SIP.C.REFER, applicant.remoteIdentity.uri.toString(), options]);
5498
+        this.applicant = applicant;
5499
+        var withReplaces = target instanceof SIP.InviteServerContext ||
5500
+            target instanceof SIP.InviteClientContext;
5501
+        if (withReplaces) {
5502
+            // Attended Transfer
5503
+            // All of these fields should be defined based on the check above
5504
+            this.target = '"' + target.remoteIdentity.friendlyName + '" ' +
5505
+                '<' + target.dialog.remote_target.toString() +
5506
+                '?Replaces=' + target.dialog.id.call_id +
5507
+                '%3Bto-tag%3D' + target.dialog.id.remote_tag +
5508
+                '%3Bfrom-tag%3D' + target.dialog.id.local_tag + '>';
5509
+        }
5510
+        else {
5511
+            // Blind Transfer
5512
+            // Refer-To: <sip:bob@example.com>
5513
+            try {
5514
+                this.target = SIP.Grammar.parse(target, 'Refer_To').uri || target;
5515
+            }
5516
+            catch (e) {
5517
+                this.logger.debug(".refer() cannot parse Refer_To from", target);
5518
+                this.logger.debug("...falling through to normalizeTarget()");
5519
+            }
5520
+            // Check target validity
5521
+            this.target = this.ua.normalizeTarget(this.target);
5522
+            if (!this.target) {
5523
+                throw new TypeError('Invalid target: ' + target);
5524
+            }
5525
+        }
5526
+        if (this.ua) {
5527
+            this.extraHeaders.push('Referred-By: <' + this.ua.configuration.uri + '>');
5528
+        }
5529
+        // TODO: Check that this is correct isc/icc
5530
+        this.extraHeaders.push('Contact: ' + applicant.contact);
5531
+        this.extraHeaders.push('Allow: ' + SIP.UA.C.ALLOWED_METHODS.toString());
5532
+        this.extraHeaders.push('Refer-To: ' + this.target);
5533
+        this.errorListener = this.onTransportError.bind(this);
5534
+        ua.transport.on('transportError', this.errorListener);
5535
+    };
5536
+    ReferClientContext.prototype = Object.create({}, {
5537
+        refer: { writable: true, value: function (options) {
5538
+                options = options || {};
5539
+                var extraHeaders = (this.extraHeaders || []).slice();
5540
+                if (options.extraHeaders) {
5541
+                    extraHeaders.concat(options.extraHeaders);
5542
+                }
5543
+                this.applicant.sendRequest(SIP.C.REFER, {
5544
+                    extraHeaders: this.extraHeaders,
5545
+                    receiveResponse: function (response) {
5546
+                        if (/^1[0-9]{2}$/.test(response.status_code)) {
5547
+                            this.emit('referRequestProgress', this);
5548
+                        }
5549
+                        else if (/^2[0-9]{2}$/.test(response.status_code)) {
5550
+                            this.emit('referRequestAccepted', this);
5551
+                        }
5552
+                        else if (/^[4-6][0-9]{2}$/.test(response.status_code)) {
5553
+                            this.emit('referRequestRejected', this);
5554
+                        }
5555
+                        if (options.receiveResponse) {
5556
+                            options.receiveResponse(response);
5557
+                        }
5558
+                    }.bind(this)
5559
+                });
5560
+                return this;
5561
+            } },
5562
+        receiveNotify: { writable: true, value: function (request) {
5563
+                // If we can correctly handle this, then we need to send a 200 OK!
5564
+                if (request.hasHeader('Content-Type') && request.getHeader('Content-Type').search(/^message\/sipfrag/) !== -1) {
5565
+                    var messageBody = SIP.Grammar.parse(request.body, 'sipfrag');
5566
+                    if (messageBody === -1) {
5567
+                        request.reply(489, 'Bad Event');
5568
+                        return;
5569
+                    }
5570
+                    switch (true) {
5571
+                        case (/^1[0-9]{2}$/.test(messageBody.status_code)):
5572
+                            this.emit('referProgress', this);
5573
+                            break;
5574
+                        case (/^2[0-9]{2}$/.test(messageBody.status_code)):
5575
+                            this.emit('referAccepted', this);
5576
+                            if (!this.options.activeAfterTransfer && this.applicant.terminate) {
5577
+                                this.applicant.terminate();
5578
+                            }
5579
+                            break;
5580
+                        default:
5581
+                            this.emit('referRejected', this);
5582
+                            break;
5583
+                    }
5584
+                    request.reply(200);
5585
+                    this.emit('notify', request);
5586
+                    return;
5587
+                }
5588
+                request.reply(489, 'Bad Event');
5589
+            } }
5590
+    });
5591
+    SIP.ReferClientContext = ReferClientContext;
5592
+    ReferServerContext = function (ua, request) {
5593
+        SIP.Utils.augment(this, SIP.ServerContext, [ua, request]);
5594
+        this.ua = ua;
5595
+        this.status = C.STATUS_INVITE_RECEIVED;
5596
+        this.from_tag = request.from_tag;
5597
+        this.id = request.call_id + this.from_tag;
5598
+        this.request = request;
5599
+        this.contact = this.ua.contact.toString();
5600
+        this.logger = ua.getLogger('sip.referservercontext', this.id);
5601
+        // RFC 3515 2.4.1
5602
+        if (!this.request.hasHeader('refer-to')) {
5603
+            this.logger.warn('Invalid REFER packet. A refer-to header is required. Rejecting refer.');
5604
+            this.reject();
5605
+            return;
5606
+        }
5607
+        this.referTo = this.request.parseHeader('refer-to');
5608
+        // TODO: Must set expiration timer and send 202 if there is no response by then
5609
+        this.referredSession = this.ua.findSession(request);
5610
+        // Needed to send the NOTIFY's
5611
+        this.cseq = Math.floor(Math.random() * 10000);
5612
+        this.call_id = this.request.call_id;
5613
+        this.from_uri = this.request.to.uri;
5614
+        this.from_tag = this.request.to.parameters.tag;
5615
+        this.remote_target = this.request.headers.Contact[0].parsed.uri;
5616
+        this.to_uri = this.request.from.uri;
5617
+        this.to_tag = this.request.from_tag;
5618
+        this.route_set = this.request.getHeaders('record-route');
5619
+        this.receiveNonInviteResponse = function () { };
5620
+        if (this.request.hasHeader('referred-by')) {
5621
+            this.referredBy = this.request.getHeader('referred-by');
5622
+        }
5623
+        if (this.referTo.uri.hasHeader('replaces')) {
5624
+            this.replaces = this.referTo.uri.getHeader('replaces');
5625
+        }
5626
+        this.errorListener = this.onTransportError.bind(this);
5627
+        ua.transport.on('transportError', this.errorListener);
5628
+        this.status = C.STATUS_WAITING_FOR_ANSWER;
5629
+    };
5630
+    ReferServerContext.prototype = Object.create({}, {
5631
+        progress: { writable: true, value: function () {
5632
+                if (this.status !== C.STATUS_WAITING_FOR_ANSWER) {
5633
+                    throw new SIP.Exceptions.InvalidStateError(this.status);
5634
+                }
5635
+                this.request.reply(100);
5636
+            } },
5637
+        reject: { writable: true, value: function (options) {
5638
+                if (this.status === C.STATUS_TERMINATED) {
5639
+                    throw new SIP.Exceptions.InvalidStateError(this.status);
5640
+                }
5641
+                this.logger.log('Rejecting refer');
5642
+                this.status = C.STATUS_TERMINATED;
5643
+                SIP.ServerContext.prototype.reject.call(this, options);
5644
+                this.emit('referRequestRejected', this);
5645
+            } },
5646
+        accept: { writable: true, value: function (options, modifiers) {
5647
+                options = options || {};
5648
+                if (this.status === C.STATUS_WAITING_FOR_ANSWER) {
5649
+                    this.status = C.STATUS_ANSWERED;
5650
+                }
5651
+                else {
5652
+                    throw new SIP.Exceptions.InvalidStateError(this.status);
5653
+                }
5654
+                this.request.reply(202, 'Accepted');
5655
+                this.emit('referRequestAccepted', this);
5656
+                if (options.followRefer) {
5657
+                    this.logger.log('Accepted refer, attempting to automatically follow it');
5658
+                    var target = this.referTo.uri;
5659
+                    if (!target.scheme.match("^sips?$")) {
5660
+                        this.logger.error('SIP.js can only automatically follow SIP refer target');
5661
+                        this.reject();
5662
+                        return;
5663
+                    }
5664
+                    var inviteOptions = options.inviteOptions || {};
5665
+                    var extraHeaders = (inviteOptions.extraHeaders || []).slice();
5666
+                    if (this.replaces) {
5667
+                        // decodeURIComponent is a holdover from 2c086eb4. Not sure that it is actually necessary
5668
+                        extraHeaders.push('Replaces: ' + decodeURIComponent(this.replaces));
5669
+                    }
5670
+                    if (this.referredBy) {
5671
+                        extraHeaders.push('Referred-By: ' + this.referredBy);
5672
+                    }
5673
+                    inviteOptions.extraHeaders = extraHeaders;
5674
+                    target.clearHeaders();
5675
+                    this.targetSession = this.ua.invite(target, inviteOptions, modifiers);
5676
+                    this.emit('referInviteSent', this);
5677
+                    this.targetSession.once('progress', function () {
5678
+                        this.sendNotify('SIP/2.0 100 Trying');
5679
+                        this.emit('referProgress', this);
5680
+                        if (this.referredSession) {
5681
+                            this.referredSession.emit('referProgress', this);
5682
+                        }
5683
+                    }.bind(this));
5684
+                    this.targetSession.once('accepted', function () {
5685
+                        this.logger.log('Successfully followed the refer');
5686
+                        this.sendNotify('SIP/2.0 200 OK');
5687
+                        this.emit('referAccepted', this);
5688
+                        if (this.referredSession) {
5689
+                            this.referredSession.emit('referAccepted', this);
5690
+                        }
5691
+                    }.bind(this));
5692
+                    var referFailed = function (response) {
5693
+                        if (this.status === C.STATUS_TERMINATED) {
5694
+                            return; // No throw here because it is possible this gets called multiple times
5695
+                        }
5696
+                        this.logger.log('Refer was not successful. Resuming session');
5697
+                        if (response && response.status_code === 429) {
5698
+                            this.logger.log('Alerting referrer that identity is required.');
5699
+                            this.sendNotify('SIP/2.0 429 Provide Referrer Identity');
5700
+                            return;
5701
+                        }
5702
+                        this.sendNotify('SIP/2.0 603 Declined');
5703
+                        // Must change the status after sending the final Notify or it will not send due to check
5704
+                        this.status = C.STATUS_TERMINATED;
5705
+                        this.emit('referRejected', this);
5706
+                        if (this.referredSession) {
5707
+                            this.referredSession.emit('referRejected');
5708
+                        }
5709
+                    };
5710
+                    this.targetSession.once('rejected', referFailed.bind(this));
5711
+                    this.targetSession.once('failed', referFailed.bind(this));
5712
+                }
5713
+                else {
5714
+                    this.logger.log('Accepted refer, but did not automatically follow it');
5715
+                    this.sendNotify('SIP/2.0 200 OK');
5716
+                    this.emit('referAccepted', this);
5717
+                    if (this.referredSession) {
5718
+                        this.referredSession.emit('referAccepted', this);
5719
+                    }
5720
+                }
5721
+            } },
5722
+        sendNotify: { writable: true, value: function (body) {
5723
+                if (this.status !== C.STATUS_ANSWERED) {
5724
+                    throw new SIP.Exceptions.InvalidStateError(this.status);
5725
+                }
5726
+                if (SIP.Grammar.parse(body, 'sipfrag') === -1) {
5727
+                    throw new Error('sipfrag body is required to send notify for refer');
5728
+                }
5729
+                var request = new SIP.OutgoingRequest(SIP.C.NOTIFY, this.remote_target, this.ua, {
5730
+                    cseq: this.cseq += 1,
5731
+                    call_id: this.call_id,
5732
+                    from_uri: this.from_uri,
5733
+                    from_tag: this.from_tag,
5734
+                    to_uri: this.to_uri,
5735
+                    to_tag: this.to_tag,
5736
+                    route_set: this.route_set
5737
+                }, [
5738
+                    'Event: refer',
5739
+                    'Subscription-State: terminated',
5740
+                    'Content-Type: message/sipfrag'
5741
+                ], body);
5742
+                new SIP.RequestSender({
5743
+                    request: request,
5744
+                    onRequestTimeout: function () {
5745
+                        return;
5746
+                    },
5747
+                    onTransportError: function () {
5748
+                        return;
5749
+                    },
5750
+                    receiveResponse: function () {
5751
+                        return;
5752
+                    }
5753
+                }, this.ua).send();
5754
+            } }
5755
+    });
5756
+    SIP.ReferServerContext = ReferServerContext;
5757
+};
5758
+
5759
+
5760
+/***/ }),
5761
+/* 24 */
5762
+/***/ (function(module, exports, __webpack_require__) {
5763
+
5764
+"use strict";
5765
+
5766
+/**
5767
+ * @fileoverview DTMF
5768
+ */
5769
+/**
5770
+ * @class DTMF
5771
+ * @param {SIP.Session} session
5772
+ */
5773
+module.exports = function (SIP) {
5774
+    var DTMF, C = {
5775
+        MIN_DURATION: 70,
5776
+        MAX_DURATION: 6000,
5777
+        DEFAULT_DURATION: 100,
5778
+        MIN_INTER_TONE_GAP: 50,
5779
+        DEFAULT_INTER_TONE_GAP: 500
5780
+    };
5781
+    DTMF = function (session, tone, options) {
5782
+        var duration, interToneGap;
5783
+        if (tone === undefined) {
5784
+            throw new TypeError('Not enough arguments');
5785
+        }
5786
+        this.logger = session.ua.getLogger('sip.invitecontext.dtmf', session.id);
5787
+        this.owner = session;
5788
+        this.direction = null;
5789
+        options = options || {};
5790
+        duration = options.duration || null;
5791
+        interToneGap = options.interToneGap || null;
5792
+        // Check tone type
5793
+        if (typeof tone === 'string') {
5794
+            tone = tone.toUpperCase();
5795
+        }
5796
+        else if (typeof tone === 'number') {
5797
+            tone = tone.toString();
5798
+        }
5799
+        else {
5800
+            throw new TypeError('Invalid tone: ' + tone);
5801
+        }
5802
+        // Check tone value
5803
+        if (!tone.match(/^[0-9A-D#*]$/)) {
5804
+            throw new TypeError('Invalid tone: ' + tone);
5805
+        }
5806
+        else {
5807
+            this.tone = tone;
5808
+        }
5809
+        // Check duration
5810
+        if (duration && !SIP.Utils.isDecimal(duration)) {
5811
+            throw new TypeError('Invalid tone duration: ' + duration);
5812
+        }
5813
+        else if (!duration) {
5814
+            duration = DTMF.C.DEFAULT_DURATION;
5815
+        }
5816
+        else if (duration < DTMF.C.MIN_DURATION) {
5817
+            this.logger.warn('"duration" value is lower than the minimum allowed, setting it to ' + DTMF.C.MIN_DURATION + ' milliseconds');
5818
+            duration = DTMF.C.MIN_DURATION;
5819
+        }
5820
+        else if (duration > DTMF.C.MAX_DURATION) {
5821
+            this.logger.warn('"duration" value is greater than the maximum allowed, setting it to ' + DTMF.C.MAX_DURATION + ' milliseconds');
5822
+            duration = DTMF.C.MAX_DURATION;
5823
+        }
5824
+        else {
5825
+            duration = Math.abs(duration);
5826
+        }
5827
+        this.duration = duration;
5828
+        // Check interToneGap
5829
+        if (interToneGap && !SIP.Utils.isDecimal(interToneGap)) {
5830
+            throw new TypeError('Invalid interToneGap: ' + interToneGap);
5831
+        }
5832
+        else if (!interToneGap) {
5833
+            interToneGap = DTMF.C.DEFAULT_INTER_TONE_GAP;
5834
+        }
5835
+        else if (interToneGap < DTMF.C.MIN_INTER_TONE_GAP) {
5836
+            this.logger.warn('"interToneGap" value is lower than the minimum allowed, setting it to ' + DTMF.C.MIN_INTER_TONE_GAP + ' milliseconds');
5837
+            interToneGap = DTMF.C.MIN_INTER_TONE_GAP;
5838
+        }
5839
+        else {
5840
+            interToneGap = Math.abs(interToneGap);
5841
+        }
5842
+        this.interToneGap = interToneGap;
5843
+    };
5844
+    DTMF.prototype = Object.create(SIP.EventEmitter.prototype);
5845
+    DTMF.prototype.send = function (options) {
5846
+        var extraHeaders, body = {};
5847
+        this.direction = 'outgoing';
5848
+        // Check RTCSession Status
5849
+        if (this.owner.status !== SIP.Session.C.STATUS_CONFIRMED &&
5850
+            this.owner.status !== SIP.Session.C.STATUS_WAITING_FOR_ACK) {
5851
+            throw new SIP.Exceptions.InvalidStateError(this.owner.status);
5852
+        }
5853
+        // Get DTMF options
5854
+        options = options || {};
5855
+        extraHeaders = options.extraHeaders ? options.extraHeaders.slice() : [];
5856
+        body.contentType = 'application/dtmf-relay';
5857
+        body.body = "Signal= " + this.tone + "\r\n";
5858
+        body.body += "Duration= " + this.duration;
5859
+        this.request = this.owner.dialog.sendRequest(this, SIP.C.INFO, {
5860
+            extraHeaders: extraHeaders,
5861
+            body: body
5862
+        });
5863
+        this.owner.emit('dtmf', this.request, this);
5864
+    };
5865
+    /**
5866
+     * @private
5867
+     */
5868
+    DTMF.prototype.receiveResponse = function (response) {
5869
+        var cause;
5870
+        switch (true) {
5871
+            case /^1[0-9]{2}$/.test(response.status_code):
5872
+                // Ignore provisional responses.
5873
+                break;
5874
+            case /^2[0-9]{2}$/.test(response.status_code):
5875
+                this.emit('succeeded', {
5876
+                    originator: 'remote',
5877
+                    response: response
5878
+                });
5879
+                break;
5880
+            default:
5881
+                cause = SIP.Utils.sipErrorCause(response.status_code);
5882
+                this.emit('failed', response, cause);
5883
+                break;
5884
+        }
5885
+    };
5886
+    /**
5887
+     * @private
5888
+     */
5889
+    DTMF.prototype.onRequestTimeout = function () {
5890
+        this.emit('failed', null, SIP.C.causes.REQUEST_TIMEOUT);
5891
+        this.owner.onRequestTimeout();
5892
+    };
5893
+    /**
5894
+     * @private
5895
+     */
5896
+    DTMF.prototype.onTransportError = function () {
5897
+        this.emit('failed', null, SIP.C.causes.CONNECTION_ERROR);
5898
+        this.owner.onTransportError();
5899
+    };
5900
+    /**
5901
+     * @private
5902
+     */
5903
+    DTMF.prototype.onDialogError = function (response) {
5904
+        this.emit('failed', response, SIP.C.causes.DIALOG_ERROR);
5905
+        this.owner.onDialogError(response);
5906
+    };
5907
+    /**
5908
+     * @private
5909
+     */
5910
+    DTMF.prototype.init_incoming = function (request) {
5911
+        this.direction = 'incoming';
5912
+        this.request = request;
5913
+        request.reply(200);
5914
+        if (!this.tone || !this.duration) {
5915
+            this.logger.warn('invalid INFO DTMF received, discarded');
5916
+        }
5917
+        else {
5918
+            this.owner.emit('dtmf', request, this);
5919
+        }
5920
+    };
5921
+    DTMF.C = C;
5922
+    return DTMF;
5923
+};
5924
+
5925
+
5926
+/***/ }),
5927
+/* 25 */
5928
+/***/ (function(module, exports, __webpack_require__) {
5929
+
5930
+"use strict";
5931
+
5932
+/**
5933
+ * @fileoverview SIP Subscriber (SIP-Specific Event Notifications RFC6665)
5934
+ */
5935
+/**
5936
+ * @augments SIP
5937
+ * @class Class creating a SIP Subscription.
5938
+ */
5939
+module.exports = function (SIP) {
5940
+    SIP.Subscription = function (ua, target, event, options) {
5941
+        options = Object.create(options || Object.prototype);
5942
+        this.extraHeaders = options.extraHeaders = (options.extraHeaders || []).slice();
5943
+        this.id = null;
5944
+        this.state = 'init';
5945
+        if (!event) {
5946
+            throw new TypeError('Event necessary to create a subscription.');
5947
+        }
5948
+        else {
5949
+            //TODO: check for valid events here probably make a list in SIP.C; or leave it up to app to check?
5950
+            //The check may need to/should probably occur on the other side,
5951
+            this.event = event;
5952
+        }
5953
+        if (typeof options.expires !== 'number') {
5954
+            ua.logger.warn('expires must be a number. Using default of 3600.');
5955
+            this.expires = 3600;
5956
+        }
5957
+        else {
5958
+            this.expires = options.expires;
5959
+        }
5960
+        this.requestedExpires = this.expires;
5961
+        options.extraHeaders.push('Event: ' + this.event);
5962
+        options.extraHeaders.push('Expires: ' + this.expires);
5963
+        if (options.body) {
5964
+            this.body = options.body;
5965
+        }
5966
+        this.contact = ua.contact.toString();
5967
+        options.extraHeaders.push('Contact: ' + this.contact);
5968
+        options.extraHeaders.push('Allow: ' + SIP.UA.C.ALLOWED_METHODS.toString());
5969
+        SIP.Utils.augment(this, SIP.ClientContext, [ua, SIP.C.SUBSCRIBE, target, options]);
5970
+        this.logger = ua.getLogger('sip.subscription');
5971
+        this.dialog = null;
5972
+        this.timers = { N: null, sub_duration: null };
5973
+        this.errorCodes = [404, 405, 410, 416, 480, 481, 482, 483, 484, 485, 489, 501, 604];
5974
+    };
5975
+    SIP.Subscription.prototype = {
5976
+        subscribe: function () {
5977
+            var sub = this;
5978
+            //these states point to an existing subscription, no subscribe is necessary
5979
+            if (this.state === 'active') {
5980
+                this.refresh();
5981
+                return this;
5982
+            }
5983
+            else if (this.state === 'notify_wait') {
5984
+                return this;
5985
+            }
5986
+            SIP.Timers.clearTimeout(this.timers.sub_duration);
5987
+            SIP.Timers.clearTimeout(this.timers.N);
5988
+            this.timers.N = SIP.Timers.setTimeout(sub.timer_fire.bind(sub), SIP.Timers.TIMER_N);
5989
+            this.ua.earlySubscriptions[this.request.call_id + this.request.from.parameters.tag + this.event] = this;
5990
+            this.send();
5991
+            this.state = 'notify_wait';
5992
+            return this;
5993
+        },
5994
+        refresh: function () {
5995
+            if (this.state === 'terminated' || this.state === 'pending' || this.state === 'notify_wait') {
5996
+                return;
5997
+            }
5998
+            this.dialog.sendRequest(this, SIP.C.SUBSCRIBE, {
5999
+                extraHeaders: this.extraHeaders,
6000
+                body: this.body
6001
+            });
6002
+        },
6003
+        receiveResponse: function (response) {
6004
+            var expires, sub = this, cause = SIP.Utils.getReasonPhrase(response.status_code);
6005
+            if ((this.state === 'notify_wait' && response.status_code >= 300) ||
6006
+                (this.state !== 'notify_wait' && this.errorCodes.indexOf(response.status_code) !== -1)) {
6007
+                this.failed(response, null);
6008
+            }
6009
+            else if (/^2[0-9]{2}$/.test(response.status_code)) {
6010
+                this.emit('accepted', response, cause);
6011
+                //As we don't support RFC 5839 or other extensions where the NOTIFY is optional, timer N will not be cleared
6012
+                //SIP.Timers.clearTimeout(this.timers.N);
6013
+                expires = response.getHeader('Expires');
6014
+                if (expires && expires <= this.requestedExpires) {
6015
+                    // Preserve new expires value for subsequent requests
6016
+                    this.expires = expires;
6017
+                    this.timers.sub_duration = SIP.Timers.setTimeout(sub.refresh.bind(sub), expires * 900);
6018
+                }
6019
+                else {
6020
+                    if (!expires) {
6021
+                        this.logger.warn('Expires header missing in a 200-class response to SUBSCRIBE');
6022
+                        this.failed(response, SIP.C.EXPIRES_HEADER_MISSING);
6023
+                    }
6024
+                    else {
6025
+                        this.logger.warn('Expires header in a 200-class response to SUBSCRIBE with a higher value than the one in the request');
6026
+                        this.failed(response, SIP.C.INVALID_EXPIRES_HEADER);
6027
+                    }
6028
+                }
6029
+            }
6030
+            else if (response.statusCode > 300) {
6031
+                this.emit('failed', response, cause);
6032
+                this.emit('rejected', response, cause);
6033
+            }
6034
+        },
6035
+        unsubscribe: function () {
6036
+            var extraHeaders = [], sub = this;
6037
+            this.state = 'terminated';
6038
+            extraHeaders.push('Event: ' + this.event);
6039
+            extraHeaders.push('Expires: 0');
6040
+            extraHeaders.push('Contact: ' + this.contact);
6041
+            extraHeaders.push('Allow: ' + SIP.UA.C.ALLOWED_METHODS.toString());
6042
+            //makes sure expires isn't set, and other typical resubscribe behavior
6043
+            this.receiveResponse = function () { };
6044
+            this.dialog.sendRequest(this, this.method, {
6045
+                extraHeaders: extraHeaders,
6046
+                body: this.body
6047
+            });
6048
+            SIP.Timers.clearTimeout(this.timers.sub_duration);
6049
+            SIP.Timers.clearTimeout(this.timers.N);
6050
+            this.timers.N = SIP.Timers.setTimeout(sub.timer_fire.bind(sub), SIP.Timers.TIMER_N);
6051
+        },
6052
+        /**
6053
+        * @private
6054
+        */
6055
+        timer_fire: function () {
6056
+            if (this.state === 'terminated') {
6057
+                this.terminateDialog();
6058
+                SIP.Timers.clearTimeout(this.timers.N);
6059
+                SIP.Timers.clearTimeout(this.timers.sub_duration);
6060
+                delete this.ua.subscriptions[this.id];
6061
+            }
6062
+            else if (this.state === 'notify_wait' || this.state === 'pending') {
6063
+                this.close();
6064
+            }
6065
+            else {
6066
+                this.refresh();
6067
+            }
6068
+        },
6069
+        /**
6070
+        * @private
6071
+        */
6072
+        close: function () {
6073
+            if (this.state === 'notify_wait') {
6074
+                this.state = 'terminated';
6075
+                SIP.Timers.clearTimeout(this.timers.N);
6076
+                SIP.Timers.clearTimeout(this.timers.sub_duration);
6077
+                this.receiveResponse = function () { };
6078
+                delete this.ua.earlySubscriptions[this.request.call_id + this.request.from.parameters.tag + this.event];
6079
+            }
6080
+            else if (this.state !== 'terminated') {
6081
+                this.unsubscribe();
6082
+            }
6083
+        },
6084
+        /**
6085
+        * @private
6086
+        */
6087
+        createConfirmedDialog: function (message, type) {
6088
+            var dialog;
6089
+            this.terminateDialog();
6090
+            dialog = new SIP.Dialog(this, message, type);
6091
+            dialog.invite_seqnum = this.request.cseq;
6092
+            dialog.local_seqnum = this.request.cseq;
6093
+            if (!dialog.error) {
6094
+                this.dialog = dialog;
6095
+                return true;
6096
+            }
6097
+            // Dialog not created due to an error
6098
+            else {
6099
+                return false;
6100
+            }
6101
+        },
6102
+        /**
6103
+        * @private
6104
+        */
6105
+        terminateDialog: function () {
6106
+            if (this.dialog) {
6107
+                delete this.ua.subscriptions[this.id];
6108
+                this.dialog.terminate();
6109
+                delete this.dialog;
6110
+            }
6111
+        },
6112
+        /**
6113
+        * @private
6114
+        */
6115
+        receiveRequest: function (request) {
6116
+            var sub_state, sub = this;
6117
+            function setExpiresTimeout() {
6118
+                if (sub_state.expires) {
6119
+                    SIP.Timers.clearTimeout(sub.timers.sub_duration);
6120
+                    sub_state.expires = Math.min(sub.expires, Math.max(sub_state.expires, 0));
6121
+                    sub.timers.sub_duration = SIP.Timers.setTimeout(sub.refresh.bind(sub), sub_state.expires * 900);
6122
+                }
6123
+            }
6124
+            if (!this.matchEvent(request)) { //checks event and subscription_state headers
6125
+                request.reply(489);
6126
+                return;
6127
+            }
6128
+            if (!this.dialog) {
6129
+                if (this.createConfirmedDialog(request, 'UAS')) {
6130
+                    this.id = this.dialog.id.toString();
6131
+                    delete this.ua.earlySubscriptions[this.request.call_id + this.request.from.parameters.tag + this.event];
6132
+                    this.ua.subscriptions[this.id] = this;
6133
+                    // UPDATE ROUTE SET TO BE BACKWARDS COMPATIBLE?
6134
+                }
6135
+            }
6136
+            sub_state = request.parseHeader('Subscription-State');
6137
+            request.reply(200, SIP.C.REASON_200);
6138
+            SIP.Timers.clearTimeout(this.timers.N);
6139
+            this.emit('notify', { request: request });
6140
+            // if we've set state to terminated, no further processing should take place
6141
+            // and we are only interested in cleaning up after the appropriate NOTIFY
6142
+            if (this.state === 'terminated') {
6143
+                if (sub_state.state === 'terminated') {
6144
+                    this.terminateDialog();
6145
+                    SIP.Timers.clearTimeout(this.timers.N);
6146
+                    SIP.Timers.clearTimeout(this.timers.sub_duration);
6147
+                    delete this.ua.subscriptions[this.id];
6148
+                }
6149
+                return;
6150
+            }
6151
+            switch (sub_state.state) {
6152
+                case 'active':
6153
+                    this.state = 'active';
6154
+                    setExpiresTimeout();
6155
+                    break;
6156
+                case 'pending':
6157
+                    if (this.state === 'notify_wait') {
6158
+                        setExpiresTimeout();
6159
+                    }
6160
+                    this.state = 'pending';
6161
+                    break;
6162
+                case 'terminated':
6163
+                    SIP.Timers.clearTimeout(this.timers.sub_duration);
6164
+                    if (sub_state.reason) {
6165
+                        this.logger.log('terminating subscription with reason ' + sub_state.reason);
6166
+                        switch (sub_state.reason) {
6167
+                            case 'deactivated':
6168
+                            case 'timeout':
6169
+                                this.subscribe();
6170
+                                return;
6171
+                            case 'probation':
6172
+                            case 'giveup':
6173
+                                if (sub_state.params && sub_state.params['retry-after']) {
6174
+                                    this.timers.sub_duration = SIP.Timers.setTimeout(sub.subscribe.bind(sub), sub_state.params['retry-after']);
6175
+                                }
6176
+                                else {
6177
+                                    this.subscribe();
6178
+                                }
6179
+                                return;
6180
+                            case 'rejected':
6181
+                            case 'noresource':
6182
+                            case 'invariant':
6183
+                                break;
6184
+                        }
6185
+                    }
6186
+                    this.close();
6187
+                    break;
6188
+            }
6189
+        },
6190
+        failed: function (response, cause) {
6191
+            this.close();
6192
+            this.emit('failed', response, cause);
6193
+            this.emit('rejected', response, cause);
6194
+            return this;
6195
+        },
6196
+        onDialogError: function (response) {
6197
+            this.failed(response, SIP.C.causes.DIALOG_ERROR);
6198
+        },
6199
+        /**
6200
+        * @private
6201
+        */
6202
+        matchEvent: function (request) {
6203
+            var event;
6204
+            // Check mandatory header Event
6205
+            if (!request.hasHeader('Event')) {
6206
+                this.logger.warn('missing Event header');
6207
+                return false;
6208
+            }
6209
+            // Check mandatory header Subscription-State
6210
+            if (!request.hasHeader('Subscription-State')) {
6211
+                this.logger.warn('missing Subscription-State header');
6212
+                return false;
6213
+            }
6214
+            // Check whether the event in NOTIFY matches the event in SUBSCRIBE
6215
+            event = request.parseHeader('event').event;
6216
+            if (this.event !== event) {
6217
+                this.logger.warn('event match failed');
6218
+                request.reply(481, 'Event Match Failed');
6219
+                return false;
6220
+            }
6221
+            else {
6222
+                return true;
6223
+            }
6224
+        }
6225
+    };
6226
+};
6227
+
6228
+
6229
+/***/ }),
6230
+/* 26 */
6231
+/***/ (function(module, exports, __webpack_require__) {
6232
+
6233
+"use strict";
6234
+
6235
+/**
6236
+ * @fileoverview SIP Publish (SIP Extension for Event State Publication RFC3903)
6237
+ */
6238
+/**
6239
+ * @augments SIP
6240
+ * @class Class creating a SIP PublishContext.
6241
+ */
6242
+module.exports = function (SIP) {
6243
+    var PublishContext;
6244
+    PublishContext = function (ua, target, event, options) {
6245
+        this.options = options = (options || {});
6246
+        this.options.extraHeaders = (options.extraHeaders || []).slice();
6247
+        this.options.contentType = (options.contentType || 'text/plain');
6248
+        if (typeof options.expires !== 'number' || (options.expires % 1) !== 0) {
6249
+            this.options.expires = 3600;
6250
+        }
6251
+        else {
6252
+            this.options.expires = Number(options.expires);
6253
+        }
6254
+        if (typeof (options.unpublishOnClose) !== "boolean") {
6255
+            this.options.unpublishOnClose = true;
6256
+        }
6257
+        else {
6258
+            this.options.unpublishOnClose = options.unpublishOnClose;
6259
+        }
6260
+        if (target === undefined || target === null || target === '') {
6261
+            throw new SIP.Exceptions.MethodParameterError('Publish', 'Target', target);
6262
+        }
6263
+        else {
6264
+            this.target = ua.normalizeTarget(target);
6265
+        }
6266
+        if (event === undefined || event === null || event === '') {
6267
+            throw new SIP.Exceptions.MethodParameterError('Publish', 'Event', event);
6268
+        }
6269
+        else {
6270
+            this.event = event;
6271
+        }
6272
+        // Call parent constructor
6273
+        SIP.ClientContext.call(this, ua, SIP.C.PUBLISH, this.target, this.options);
6274
+        this.logger = this.ua.getLogger('sip.publish');
6275
+        this.pubRequestBody = null;
6276
+        this.pubRequestExpires = this.options.expires;
6277
+        this.pubRequestEtag = null;
6278
+        this.publish_refresh_timer = null;
6279
+        ua.on('transportCreated', function (transport) {
6280
+            transport.on('transportError', this.onTransportError.bind(this));
6281
+        }.bind(this));
6282
+    };
6283
+    // Extend ClientContext
6284
+    PublishContext.prototype = Object.create(SIP.ClientContext.prototype);
6285
+    // Restore the class constructor
6286
+    PublishContext.prototype.constructor = PublishContext;
6287
+    /**
6288
+     * Publish
6289
+     *
6290
+     * @param {string} Event body to publish, optional
6291
+     *
6292
+     */
6293
+    PublishContext.prototype.publish = function (body) {
6294
+        // Clean up before the run
6295
+        this.request = null;
6296
+        SIP.Timers.clearTimeout(this.publish_refresh_timer);
6297
+        if (body !== undefined && body !== null && body !== '') {
6298
+            // is Inital or Modify request
6299
+            this.options.body = body;
6300
+            this.pubRequestBody = this.options.body;
6301
+            if (this.pubRequestExpires === 0) {
6302
+                // This is Initial request after unpublish
6303
+                this.pubRequestExpires = this.options.expires;
6304
+                this.pubRequestEtag = null;
6305
+            }
6306
+            if (!(this.ua.publishers[this.target.toString() + ':' + this.event])) {
6307
+                this.ua.publishers[this.target.toString() + ':' + this.event] = this;
6308
+            }
6309
+        }
6310
+        else {
6311
+            // This is Refresh request
6312
+            this.pubRequestBody = null;
6313
+            if (this.pubRequestEtag === null) {
6314
+                //Request not valid
6315
+                throw new SIP.Exceptions.MethodParameterError('Publish', 'Body', body);
6316
+            }
6317
+            if (this.pubRequestExpires === 0) {
6318
+                //Request not valid
6319
+                throw new SIP.Exceptions.MethodParameterError('Publish', 'Expire', this.pubRequestExpires);
6320
+            }
6321
+        }
6322
+        this.sendPublishRequest();
6323
+    };
6324
+    /**
6325
+     * Unpublish
6326
+     *
6327
+     */
6328
+    PublishContext.prototype.unpublish = function () {
6329
+        // Clean up before the run
6330
+        this.request = null;
6331
+        SIP.Timers.clearTimeout(this.publish_refresh_timer);
6332
+        this.pubRequestBody = null;
6333
+        this.pubRequestExpires = 0;
6334
+        if (this.pubRequestEtag !== null) {
6335
+            this.sendPublishRequest();
6336
+        }
6337
+    };
6338
+    /**
6339
+     * Close
6340
+     *
6341
+     */
6342
+    PublishContext.prototype.close = function () {
6343
+        // Send unpublish, if requested
6344
+        if (this.options.unpublishOnClose) {
6345
+            this.unpublish();
6346
+        }
6347
+        else {
6348
+            this.request = null;
6349
+            SIP.Timers.clearTimeout(this.publish_refresh_timer);
6350
+            this.pubRequestBody = null;
6351
+            this.pubRequestExpires = 0;
6352
+            this.pubRequestEtag = null;
6353
+        }
6354
+        if (this.ua.publishers[this.target.toString() + ':' + this.event]) {
6355
+            delete this.ua.publishers[this.target.toString() + ':' + this.event];
6356
+        }
6357
+    };
6358
+    /**
6359
+     * @private
6360
+     *
6361
+     */
6362
+    PublishContext.prototype.sendPublishRequest = function () {
6363
+        var reqOptions;
6364
+        reqOptions = Object.create(this.options || Object.prototype);
6365
+        reqOptions.extraHeaders = (this.options.extraHeaders || []).slice();
6366
+        reqOptions.extraHeaders.push('Event: ' + this.event);
6367
+        reqOptions.extraHeaders.push('Expires: ' + this.pubRequestExpires);
6368
+        if (this.pubRequestEtag !== null) {
6369
+            reqOptions.extraHeaders.push('SIP-If-Match: ' + this.pubRequestEtag);
6370
+        }
6371
+        this.request = new SIP.OutgoingRequest(SIP.C.PUBLISH, this.target, this.ua, this.options.params, reqOptions.extraHeaders);
6372
+        if (this.pubRequestBody !== null) {
6373
+            this.request.body = {};
6374
+            this.request.body.body = this.pubRequestBody;
6375
+            this.request.body.contentType = this.options.contentType;
6376
+        }
6377
+        this.send();
6378
+    };
6379
+    /**
6380
+     * @private
6381
+     *
6382
+     */
6383
+    PublishContext.prototype.receiveResponse = function (response) {
6384
+        var expires, minExpires, cause = SIP.Utils.getReasonPhrase(response.status_code);
6385
+        switch (true) {
6386
+            case /^1[0-9]{2}$/.test(response.status_code):
6387
+                this.emit('progress', response, cause);
6388
+                break;
6389
+            case /^2[0-9]{2}$/.test(response.status_code):
6390
+                // Set SIP-Etag
6391
+                if (response.hasHeader('SIP-ETag')) {
6392
+                    this.pubRequestEtag = response.getHeader('SIP-ETag');
6393
+                }
6394
+                else {
6395
+                    this.logger.warn('SIP-ETag header missing in a 200-class response to PUBLISH');
6396
+                }
6397
+                // Update Expire
6398
+                if (response.hasHeader('Expires')) {
6399
+                    expires = Number(response.getHeader('Expires'));
6400
+                    if (typeof expires === 'number' && expires >= 0 && expires <= this.pubRequestExpires) {
6401
+                        this.pubRequestExpires = expires;
6402
+                    }
6403
+                    else {
6404
+                        this.logger.warn('Bad Expires header in a 200-class response to PUBLISH');
6405
+                    }
6406
+                }
6407
+                else {
6408
+                    this.logger.warn('Expires header missing in a 200-class response to PUBLISH');
6409
+                }
6410
+                if (this.pubRequestExpires !== 0) {
6411
+                    // Schedule refresh
6412
+                    this.publish_refresh_timer = SIP.Timers.setTimeout(this.publish.bind(this), this.pubRequestExpires * 900);
6413
+                    this.emit('published', response, cause);
6414
+                }
6415
+                else {
6416
+                    this.emit('unpublished', response, cause);
6417
+                }
6418
+                break;
6419
+            case /^412$/.test(response.status_code):
6420
+                // 412 code means no matching ETag - possibly the PUBLISH expired
6421
+                // Resubmit as new request, if the current request is not a "remove"
6422
+                if (this.pubRequestEtag !== null && this.pubRequestExpires !== 0) {
6423
+                    this.logger.warn('412 response to PUBLISH, recovering');
6424
+                    this.pubRequestEtag = null;
6425
+                    this.emit('progress', response, cause);
6426
+                    this.publish(this.options.body);
6427
+                }
6428
+                else {
6429
+                    this.logger.warn('412 response to PUBLISH, recovery failed');
6430
+                    this.pubRequestExpires = 0;
6431
+                    this.emit('failed', response, cause);
6432
+                    this.emit('unpublished', response, cause);
6433
+                }
6434
+                break;
6435
+            case /^423$/.test(response.status_code):
6436
+                // 423 code means we need to adjust the Expires interval up
6437
+                if (this.pubRequestExpires !== 0 && response.hasHeader('Min-Expires')) {
6438
+                    minExpires = Number(response.getHeader('Min-Expires'));
6439
+                    if (typeof minExpires === 'number' || minExpires > this.pubRequestExpires) {
6440
+                        this.logger.warn('423 code in response to PUBLISH, adjusting the Expires value and trying to recover');
6441
+                        this.pubRequestExpires = minExpires;
6442
+                        this.emit('progress', response, cause);
6443
+                        this.publish(this.options.body);
6444
+                    }
6445
+                    else {
6446
+                        this.logger.warn('Bad 423 response Min-Expires header received for PUBLISH');
6447
+                        this.pubRequestExpires = 0;
6448
+                        this.emit('failed', response, cause);
6449
+                        this.emit('unpublished', response, cause);
6450
+                    }
6451
+                }
6452
+                else {
6453
+                    this.logger.warn('423 response to PUBLISH, recovery failed');
6454
+                    this.pubRequestExpires = 0;
6455
+                    this.emit('failed', response, cause);
6456
+                    this.emit('unpublished', response, cause);
6457
+                }
6458
+                break;
6459
+            default:
6460
+                this.pubRequestExpires = 0;
6461
+                this.emit('failed', response, cause);
6462
+                this.emit('unpublished', response, cause);
6463
+                break;
6464
+        }
6465
+        // Do the cleanup
6466
+        if (this.pubRequestExpires === 0) {
6467
+            SIP.Timers.clearTimeout(this.publish_refresh_timer);
6468
+            this.pubRequestBody = null;
6469
+            this.pubRequestEtag = null;
6470
+        }
6471
+    };
6472
+    PublishContext.prototype.onRequestTimeout = function () {
6473
+        SIP.ClientContext.prototype.onRequestTimeout.call(this);
6474
+        this.emit('unpublished', null, SIP.C.causes.REQUEST_TIMEOUT);
6475
+    };
6476
+    PublishContext.prototype.onTransportError = function () {
6477
+        SIP.ClientContext.prototype.onTransportError.call(this);
6478
+        this.emit('unpublished', null, SIP.C.causes.CONNECTION_ERROR);
6479
+    };
6480
+    SIP.PublishContext = PublishContext;
6481
+};
6482
+
6483
+
6484
+/***/ }),
6485
+/* 27 */
6486
+/***/ (function(module, exports, __webpack_require__) {
6487
+
6488
+"use strict";
6489
+/* WEBPACK VAR INJECTION */(function(global) {
6490
+/**
6491
+ * @augments SIP
6492
+ * @class Class creating a SIP User Agent.
6493
+ * @param {function returning SIP.sessionDescriptionHandler} [configuration.sessionDescriptionHandlerFactory]
6494
+ *        A function will be invoked by each of the UA's Sessions to build the sessionDescriptionHandler for that Session.
6495
+ *        If no (or a falsy) value is provided, each Session will use a default (WebRTC) sessionDescriptionHandler.
6496
+ *
6497
+ * @param {Object} [configuration.media] gets passed to SIP.sessionDescriptionHandler.getDescription as mediaHint
6498
+ */
6499
+module.exports = function (SIP, environment) {
6500
+    var UA, C = {
6501
+        // UA status codes
6502
+        STATUS_INIT: 0,
6503
+        STATUS_STARTING: 1,
6504
+        STATUS_READY: 2,
6505
+        STATUS_USER_CLOSED: 3,
6506
+        STATUS_NOT_READY: 4,
6507
+        // UA error codes
6508
+        CONFIGURATION_ERROR: 1,
6509
+        NETWORK_ERROR: 2,
6510
+        ALLOWED_METHODS: [
6511
+            'ACK',
6512
+            'CANCEL',
6513
+            'INVITE',
6514
+            'MESSAGE',
6515
+            'BYE',
6516
+            'OPTIONS',
6517
+            'INFO',
6518
+            'NOTIFY',
6519
+            'REFER'
6520
+        ],
6521
+        ACCEPTED_BODY_TYPES: [
6522
+            'application/sdp',
6523
+            'application/dtmf-relay'
6524
+        ],
6525
+        MAX_FORWARDS: 70,
6526
+        TAG_LENGTH: 10
6527
+    };
6528
+    UA = function (configuration) {
6529
+        var self = this;
6530
+        // Helper function for forwarding events
6531
+        function selfEmit(type) {
6532
+            //registrationFailed handler is invoked with two arguments. Allow event handlers to be invoked with a variable no. of arguments
6533
+            return self.emit.bind(self, type);
6534
+        }
6535
+        // Set Accepted Body Types
6536
+        C.ACCEPTED_BODY_TYPES = C.ACCEPTED_BODY_TYPES.toString();
6537
+        this.log = new SIP.LoggerFactory();
6538
+        this.logger = this.getLogger('sip.ua');
6539
+        this.cache = {
6540
+            credentials: {}
6541
+        };
6542
+        this.configuration = {};
6543
+        this.dialogs = {};
6544
+        //User actions outside any session/dialog (MESSAGE)
6545
+        this.applicants = {};
6546
+        this.data = {};
6547
+        this.sessions = {};
6548
+        this.subscriptions = {};
6549
+        this.earlySubscriptions = {};
6550
+        this.publishers = {};
6551
+        this.transport = null;
6552
+        this.contact = null;
6553
+        this.status = C.STATUS_INIT;
6554
+        this.error = null;
6555
+        this.transactions = {
6556
+            nist: {},
6557
+            nict: {},
6558
+            ist: {},
6559
+            ict: {}
6560
+        };
6561
+        Object.defineProperties(this, {
6562
+            transactionsCount: {
6563
+                get: function () {
6564
+                    var type, transactions = ['nist', 'nict', 'ist', 'ict'], count = 0;
6565
+                    for (type in transactions) {
6566
+                        count += Object.keys(this.transactions[transactions[type]]).length;
6567
+                    }
6568
+                    return count;
6569
+                }
6570
+            },
6571
+            nictTransactionsCount: {
6572
+                get: function () {
6573
+                    return Object.keys(this.transactions['nict']).length;
6574
+                }
6575
+            },
6576
+            nistTransactionsCount: {
6577
+                get: function () {
6578
+                    return Object.keys(this.transactions['nist']).length;
6579
+                }
6580
+            },
6581
+            ictTransactionsCount: {
6582
+                get: function () {
6583
+                    return Object.keys(this.transactions['ict']).length;
6584
+                }
6585
+            },
6586
+            istTransactionsCount: {
6587
+                get: function () {
6588
+                    return Object.keys(this.transactions['ist']).length;
6589
+                }
6590
+            }
6591
+        });
6592
+        /**
6593
+         * Load configuration
6594
+         *
6595
+         * @throws {SIP.Exceptions.ConfigurationError}
6596
+         * @throws {TypeError}
6597
+         */
6598
+        if (configuration === undefined) {
6599
+            configuration = {};
6600
+        }
6601
+        else if (typeof configuration === 'string' || configuration instanceof String) {
6602
+            configuration = {
6603
+                uri: configuration
6604
+            };
6605
+        }
6606
+        // Apply log configuration if present
6607
+        if (configuration.log) {
6608
+            if (configuration.log.hasOwnProperty('builtinEnabled')) {
6609
+                this.log.builtinEnabled = configuration.log.builtinEnabled;
6610
+            }
6611
+            if (configuration.log.hasOwnProperty('level')) {
6612
+                this.log.level = configuration.log.level;
6613
+            }
6614
+            if (configuration.log.hasOwnProperty('connector')) {
6615
+                this.log.connector = configuration.log.connector;
6616
+            }
6617
+        }
6618
+        try {
6619
+            this.loadConfig(configuration);
6620
+        }
6621
+        catch (e) {
6622
+            this.status = C.STATUS_NOT_READY;
6623
+            this.error = C.CONFIGURATION_ERROR;
6624
+            throw e;
6625
+        }
6626
+        // Initialize registerContext
6627
+        this.registerContext = new SIP.RegisterContext(this);
6628
+        this.registerContext.on('failed', selfEmit('registrationFailed'));
6629
+        this.registerContext.on('registered', selfEmit('registered'));
6630
+        this.registerContext.on('unregistered', selfEmit('unregistered'));
6631
+        if (this.configuration.autostart) {
6632
+            this.start();
6633
+        }
6634
+    };
6635
+    UA.prototype = Object.create(SIP.EventEmitter.prototype);
6636
+    //=================
6637
+    //  High Level API
6638
+    //=================
6639
+    UA.prototype.register = function (options) {
6640
+        this.configuration.register = true;
6641
+        this.registerContext.register(options);
6642
+        return this;
6643
+    };
6644
+    /**
6645
+     * Unregister.
6646
+     *
6647
+     * @param {Boolean} [all] unregister all user bindings.
6648
+     *
6649
+     */
6650
+    UA.prototype.unregister = function (options) {
6651
+        this.configuration.register = false;
6652
+        var context = this.registerContext;
6653
+        this.transport.afterConnected(context.unregister.bind(context, options));
6654
+        return this;
6655
+    };
6656
+    UA.prototype.isRegistered = function () {
6657
+        return this.registerContext.registered;
6658
+    };
6659
+    /**
6660
+     * Make an outgoing call.
6661
+     *
6662
+     * @param {String} target
6663
+     * @param {Object} views
6664
+     * @param {Object} [options.media] gets passed to SIP.sessionDescriptionHandler.getDescription as mediaHint
6665
+     *
6666
+     * @throws {TypeError}
6667
+     *
6668
+     */
6669
+    UA.prototype.invite = function (target, options, modifiers) {
6670
+        var context = new SIP.InviteClientContext(this, target, options, modifiers);
6671
+        // Delay sending actual invite until the next 'tick' if we are already
6672
+        // connected, so that API consumers can register to events fired by the
6673
+        // the session.
6674
+        this.transport.afterConnected(function () {
6675
+            context.invite();
6676
+            this.emit('inviteSent', context);
6677
+        }.bind(this));
6678
+        return context;
6679
+    };
6680
+    UA.prototype.subscribe = function (target, event, options) {
6681
+        var sub = new SIP.Subscription(this, target, event, options);
6682
+        this.transport.afterConnected(sub.subscribe.bind(sub));
6683
+        return sub;
6684
+    };
6685
+    /**
6686
+     * Send PUBLISH Event State Publication (RFC3903)
6687
+     *
6688
+     * @param {String} target
6689
+     * @param {String} event
6690
+     * @param {String} body
6691
+     * @param {Object} [options]
6692
+     *
6693
+     * @throws {SIP.Exceptions.MethodParameterError}
6694
+     *
6695
+     */
6696
+    UA.prototype.publish = function (target, event, body, options) {
6697
+        var pub = new SIP.PublishContext(this, target, event, options);
6698
+        this.transport.afterConnected(pub.publish.bind(pub, body));
6699
+        return pub;
6700
+    };
6701
+    /**
6702
+     * Send a message.
6703
+     *
6704
+     * @param {String} target
6705
+     * @param {String} body
6706
+     * @param {Object} [options]
6707
+     *
6708
+     * @throws {TypeError}
6709
+     *
6710
+     */
6711
+    UA.prototype.message = function (target, body, options) {
6712
+        if (body === undefined) {
6713
+            throw new TypeError('Not enough arguments');
6714
+        }
6715
+        // There is no Message module, so it is okay that the UA handles defaults here.
6716
+        options = Object.create(options || Object.prototype);
6717
+        options.contentType || (options.contentType = 'text/plain');
6718
+        options.body = body;
6719
+        return this.request(SIP.C.MESSAGE, target, options);
6720
+    };
6721
+    UA.prototype.request = function (method, target, options) {
6722
+        var req = new SIP.ClientContext(this, method, target, options);
6723
+        this.transport.afterConnected(req.send.bind(req));
6724
+        return req;
6725
+    };
6726
+    /**
6727
+     * Gracefully close.
6728
+     *
6729
+     */
6730
+    UA.prototype.stop = function () {
6731
+        var session, subscription, applicant, publisher, ua = this;
6732
+        function transactionsListener() {
6733
+            if (ua.nistTransactionsCount === 0 && ua.nictTransactionsCount === 0) {
6734
+                ua.removeListener('transactionDestroyed', transactionsListener);
6735
+                ua.transport.disconnect();
6736
+            }
6737
+        }
6738
+        this.logger.log('user requested closure...');
6739
+        if (this.status === C.STATUS_USER_CLOSED) {
6740
+            this.logger.warn('UA already closed');
6741
+            return this;
6742
+        }
6743
+        // Close registerContext
6744
+        this.logger.log('closing registerContext');
6745
+        this.registerContext.close();
6746
+        // Run  _terminate_ on every Session
6747
+        for (session in this.sessions) {
6748
+            this.logger.log('closing session ' + session);
6749
+            this.sessions[session].terminate();
6750
+        }
6751
+        //Run _close_ on every confirmed Subscription
6752
+        for (subscription in this.subscriptions) {
6753
+            this.logger.log('unsubscribing from subscription ' + subscription);
6754
+            this.subscriptions[subscription].close();
6755
+        }
6756
+        //Run _close_ on every early Subscription
6757
+        for (subscription in this.earlySubscriptions) {
6758
+            this.logger.log('unsubscribing from early subscription ' + subscription);
6759
+            this.earlySubscriptions[subscription].close();
6760
+        }
6761
+        //Run _close_ on every Publisher
6762
+        for (publisher in this.publishers) {
6763
+            this.logger.log('unpublish ' + publisher);
6764
+            this.publishers[publisher].close();
6765
+        }
6766
+        // Run  _close_ on every applicant
6767
+        for (applicant in this.applicants) {
6768
+            this.applicants[applicant].close();
6769
+        }
6770
+        this.status = C.STATUS_USER_CLOSED;
6771
+        /*
6772
+         * If the remaining transactions are all INVITE transactions, there is no need to
6773
+         * wait anymore because every session has already been closed by this method.
6774
+         * - locally originated sessions where terminated (CANCEL or BYE)
6775
+         * - remotely originated sessions where rejected (4XX) or terminated (BYE)
6776
+         * Remaining INVITE transactions belong tho sessions that where answered. This are in
6777
+         * 'accepted' state due to timers 'L' and 'M' defined in [RFC 6026]
6778
+         */
6779
+        if (this.nistTransactionsCount === 0 && this.nictTransactionsCount === 0) {
6780
+            this.transport.disconnect();
6781
+        }
6782
+        else {
6783
+            this.on('transactionDestroyed', transactionsListener);
6784
+        }
6785
+        if (typeof environment.removeEventListener === 'function') {
6786
+            // Google Chrome Packaged Apps don't allow 'unload' listeners:
6787
+            // unload is not available in packaged apps
6788
+            if (!(global.chrome && global.chrome.app && global.chrome.app.runtime)) {
6789
+                environment.removeEventListener('unload', this.environListener);
6790
+            }
6791
+        }
6792
+        return this;
6793
+    };
6794
+    /**
6795
+     * Connect to the WS server if status = STATUS_INIT.
6796
+     * Resume UA after being closed.
6797
+     *
6798
+     */
6799
+    UA.prototype.start = function () {
6800
+        // var server;
6801
+        this.logger.log('user requested startup...');
6802
+        if (this.status === C.STATUS_INIT) {
6803
+            this.status = C.STATUS_STARTING;
6804
+            if (!this.configuration.transportConstructor) {
6805
+                throw new SIP.Exceptions.TransportError("Transport constructor not set");
6806
+            }
6807
+            this.transport = new this.configuration.transportConstructor(this.getLogger('sip.transport'), this.configuration.transportOptions);
6808
+            this.setTransportListeners();
6809
+            this.emit('transportCreated', this.transport);
6810
+            this.transport.connect();
6811
+        }
6812
+        else if (this.status === C.STATUS_USER_CLOSED) {
6813
+            this.logger.log('resuming');
6814
+            this.status = C.STATUS_READY;
6815
+            this.transport.connect();
6816
+        }
6817
+        else if (this.status === C.STATUS_STARTING) {
6818
+            this.logger.log('UA is in STARTING status, not opening new connection');
6819
+        }
6820
+        else if (this.status === C.STATUS_READY) {
6821
+            this.logger.log('UA is in READY status, not resuming');
6822
+        }
6823
+        else {
6824
+            this.logger.error('Connection is down. Auto-Recovery system is trying to connect');
6825
+        }
6826
+        if (this.configuration.autostop && typeof environment.addEventListener === 'function') {
6827
+            // Google Chrome Packaged Apps don't allow 'unload' listeners:
6828
+            // unload is not available in packaged apps
6829
+            if (!(global.chrome && global.chrome.app && global.chrome.app.runtime)) {
6830
+                this.environListener = this.stop.bind(this);
6831
+                environment.addEventListener('unload', this.environListener);
6832
+            }
6833
+        }
6834
+        return this;
6835
+    };
6836
+    /**
6837
+     * Normalize a string into a valid SIP request URI
6838
+     *
6839
+     * @param {String} target
6840
+     *
6841
+     * @returns {SIP.URI|undefined}
6842
+     */
6843
+    UA.prototype.normalizeTarget = function (target) {
6844
+        return SIP.Utils.normalizeTarget(target, this.configuration.hostportParams);
6845
+    };
6846
+    //===============================
6847
+    //  Private (For internal use)
6848
+    //===============================
6849
+    UA.prototype.saveCredentials = function (credentials) {
6850
+        this.cache.credentials[credentials.realm] = this.cache.credentials[credentials.realm] || {};
6851
+        this.cache.credentials[credentials.realm][credentials.uri] = credentials;
6852
+        return this;
6853
+    };
6854
+    UA.prototype.getCredentials = function (request) {
6855
+        var realm, credentials;
6856
+        realm = request.ruri.host;
6857
+        if (this.cache.credentials[realm] && this.cache.credentials[realm][request.ruri]) {
6858
+            credentials = this.cache.credentials[realm][request.ruri];
6859
+            credentials.method = request.method;
6860
+        }
6861
+        return credentials;
6862
+    };
6863
+    UA.prototype.getLogger = function (category, label) {
6864
+        return this.log.getLogger(category, label);
6865
+    };
6866
+    //==============================
6867
+    // Event Handlers
6868
+    //==============================
6869
+    UA.prototype.onTransportError = function () {
6870
+        if (this.status === C.STATUS_USER_CLOSED) {
6871
+            return;
6872
+        }
6873
+        if (!this.error || this.error !== C.NETWORK_ERROR) {
6874
+            this.status = C.STATUS_NOT_READY;
6875
+            this.error = C.NETWORK_ERROR;
6876
+        }
6877
+    };
6878
+    /**
6879
+     * Helper function. Sets transport listeners
6880
+     * @private
6881
+     */
6882
+    UA.prototype.setTransportListeners = function () {
6883
+        this.transport.on('connected', this.onTransportConnected.bind(this));
6884
+        this.transport.on('message', this.onTransportReceiveMsg.bind(this));
6885
+        this.transport.on('transportError', this.onTransportError.bind(this));
6886
+    };
6887
+    /**
6888
+     * Transport connection event.
6889
+     * @private
6890
+     * @event
6891
+     * @param {SIP.Transport} transport.
6892
+     */
6893
+    UA.prototype.onTransportConnected = function () {
6894
+        if (this.configuration.register) {
6895
+            this.configuration.authenticationFactory.initialize().then(function () {
6896
+                this.registerContext.onTransportConnected();
6897
+            }.bind(this));
6898
+        }
6899
+    };
6900
+    /**
6901
+     * Transport message receipt event.
6902
+     * @private
6903
+     * @event
6904
+     * @param {String} message
6905
+     */
6906
+    UA.prototype.onTransportReceiveMsg = function (message) {
6907
+        var transaction;
6908
+        message = SIP.Parser.parseMessage(message, this);
6909
+        if (this.status === SIP.UA.C.STATUS_USER_CLOSED && message instanceof SIP.IncomingRequest) {
6910
+            this.logger.warn('UA received message when status = USER_CLOSED - aborting');
6911
+            return;
6912
+        }
6913
+        // Do some sanity check
6914
+        if (SIP.sanityCheck(message, this, this.transport)) {
6915
+            if (message instanceof SIP.IncomingRequest) {
6916
+                message.transport = this.transport;
6917
+                this.receiveRequest(message);
6918
+            }
6919
+            else if (message instanceof SIP.IncomingResponse) {
6920
+                /* Unike stated in 18.1.2, if a response does not match
6921
+                * any transaction, it is discarded here and no passed to the core
6922
+                * in order to be discarded there.
6923
+                */
6924
+                switch (message.method) {
6925
+                    case SIP.C.INVITE:
6926
+                        transaction = this.transactions.ict[message.via_branch];
6927
+                        if (transaction) {
6928
+                            transaction.receiveResponse(message);
6929
+                        }
6930
+                        break;
6931
+                    case SIP.C.ACK:
6932
+                        // Just in case ;-)
6933
+                        break;
6934
+                    default:
6935
+                        transaction = this.transactions.nict[message.via_branch];
6936
+                        if (transaction) {
6937
+                            transaction.receiveResponse(message);
6938
+                        }
6939
+                        break;
6940
+                }
6941
+            }
6942
+        }
6943
+    };
6944
+    /**
6945
+     * new Transaction
6946
+     * @private
6947
+     * @param {SIP.Transaction} transaction.
6948
+     */
6949
+    UA.prototype.newTransaction = function (transaction) {
6950
+        this.transactions[transaction.type][transaction.id] = transaction;
6951
+        this.emit('newTransaction', { transaction: transaction });
6952
+    };
6953
+    /**
6954
+     * destroy Transaction
6955
+     * @private
6956
+     * @param {SIP.Transaction} transaction.
6957
+     */
6958
+    UA.prototype.destroyTransaction = function (transaction) {
6959
+        delete this.transactions[transaction.type][transaction.id];
6960
+        this.emit('transactionDestroyed', {
6961
+            transaction: transaction
6962
+        });
6963
+    };
6964
+    //=========================
6965
+    // receiveRequest
6966
+    //=========================
6967
+    /**
6968
+     * Request reception
6969
+     * @private
6970
+     * @param {SIP.IncomingRequest} request.
6971
+     */
6972
+    UA.prototype.receiveRequest = function (request) {
6973
+        var dialog, session, message, earlySubscription, method = request.method, replaces, replacedDialog, self = this;
6974
+        function ruriMatches(uri) {
6975
+            return uri && uri.user === request.ruri.user;
6976
+        }
6977
+        // Check that request URI points to us
6978
+        if (!(ruriMatches(this.configuration.uri) ||
6979
+            ruriMatches(this.contact.uri) ||
6980
+            ruriMatches(this.contact.pub_gruu) ||
6981
+            ruriMatches(this.contact.temp_gruu))) {
6982
+            this.logger.warn('Request-URI does not point to us');
6983
+            if (request.method !== SIP.C.ACK) {
6984
+                request.reply_sl(404);
6985
+            }
6986
+            return;
6987
+        }
6988
+        // Check request URI scheme
6989
+        if (request.ruri.scheme === SIP.C.SIPS) {
6990
+            request.reply_sl(416);
6991
+            return;
6992
+        }
6993
+        // Check transaction
6994
+        if (SIP.Transactions.checkTransaction(this, request)) {
6995
+            return;
6996
+        }
6997
+        /* RFC3261 12.2.2
6998
+         * Requests that do not change in any way the state of a dialog may be
6999
+         * received within a dialog (for example, an OPTIONS request).
7000
+         * They are processed as if they had been received outside the dialog.
7001
+         */
7002
+        if (method === SIP.C.OPTIONS) {
7003
+            new SIP.Transactions.NonInviteServerTransaction(request, this);
7004
+            request.reply(200, null, [
7005
+                'Allow: ' + SIP.UA.C.ALLOWED_METHODS.toString(),
7006
+                'Accept: ' + C.ACCEPTED_BODY_TYPES
7007
+            ]);
7008
+        }
7009
+        else if (method === SIP.C.MESSAGE) {
7010
+            message = new SIP.ServerContext(this, request);
7011
+            message.body = request.body;
7012
+            message.content_type = request.getHeader('Content-Type') || 'text/plain';
7013
+            request.reply(200, null);
7014
+            this.emit('message', message);
7015
+        }
7016
+        else if (method !== SIP.C.INVITE &&
7017
+            method !== SIP.C.ACK) {
7018
+            // Let those methods pass through to normal processing for now.
7019
+            new SIP.ServerContext(this, request);
7020
+        }
7021
+        // Initial Request
7022
+        if (!request.to_tag) {
7023
+            switch (method) {
7024
+                case SIP.C.INVITE:
7025
+                    replaces =
7026
+                        this.configuration.replaces !== SIP.C.supported.UNSUPPORTED &&
7027
+                            request.parseHeader('replaces');
7028
+                    if (replaces) {
7029
+                        replacedDialog = this.dialogs[replaces.call_id + replaces.replaces_to_tag + replaces.replaces_from_tag];
7030
+                        if (!replacedDialog) {
7031
+                            //Replaced header without a matching dialog, reject
7032
+                            request.reply_sl(481, null);
7033
+                            return;
7034
+                        }
7035
+                        else if (replacedDialog.owner.status === SIP.Session.C.STATUS_TERMINATED) {
7036
+                            request.reply_sl(603, null);
7037
+                            return;
7038
+                        }
7039
+                        else if (replacedDialog.state === SIP.Dialog.C.STATUS_CONFIRMED && replaces.early_only) {
7040
+                            request.reply_sl(486, null);
7041
+                            return;
7042
+                        }
7043
+                    }
7044
+                    session = new SIP.InviteServerContext(this, request);
7045
+                    session.replacee = replacedDialog && replacedDialog.owner;
7046
+                    self.emit('invite', session);
7047
+                    break;
7048
+                case SIP.C.BYE:
7049
+                    // Out of dialog BYE received
7050
+                    request.reply(481);
7051
+                    break;
7052
+                case SIP.C.CANCEL:
7053
+                    session = this.findSession(request);
7054
+                    if (session) {
7055
+                        session.receiveRequest(request);
7056
+                    }
7057
+                    else {
7058
+                        this.logger.warn('received CANCEL request for a non existent session');
7059
+                    }
7060
+                    break;
7061
+                case SIP.C.ACK:
7062
+                    /* Absorb it.
7063
+                     * ACK request without a corresponding Invite Transaction
7064
+                     * and without To tag.
7065
+                     */
7066
+                    break;
7067
+                case SIP.C.NOTIFY:
7068
+                    if (this.configuration.allowLegacyNotifications && this.listeners('notify').length > 0) {
7069
+                        request.reply(200, null);
7070
+                        self.emit('notify', { request: request });
7071
+                    }
7072
+                    else {
7073
+                        request.reply(481, 'Subscription does not exist');
7074
+                    }
7075
+                    break;
7076
+                case SIP.C.REFER:
7077
+                    this.logger.log('Received an out of dialog refer');
7078
+                    if (this.configuration.allowOutOfDialogRefers) {
7079
+                        this.logger.log('Allow out of dialog refers is enabled on the UA');
7080
+                        var referContext = new SIP.ReferServerContext(this, request);
7081
+                        var hasReferListener = this.listeners('outOfDialogReferRequested').length;
7082
+                        if (hasReferListener) {
7083
+                            this.emit('outOfDialogReferRequested', referContext);
7084
+                        }
7085
+                        else {
7086
+                            this.logger.log('No outOfDialogReferRequest listeners, automatically accepting and following the out of dialog refer');
7087
+                            referContext.accept({ followRefer: true });
7088
+                        }
7089
+                        break;
7090
+                    }
7091
+                    request.reply(405);
7092
+                    break;
7093
+                default:
7094
+                    request.reply(405);
7095
+                    break;
7096
+            }
7097
+        }
7098
+        // In-dialog request
7099
+        else {
7100
+            dialog = this.findDialog(request);
7101
+            if (dialog) {
7102
+                if (method === SIP.C.INVITE) {
7103
+                    new SIP.Transactions.InviteServerTransaction(request, this);
7104
+                }
7105
+                dialog.receiveRequest(request);
7106
+            }
7107
+            else if (method === SIP.C.NOTIFY) {
7108
+                session = this.findSession(request);
7109
+                earlySubscription = this.findEarlySubscription(request);
7110
+                if (session) {
7111
+                    session.receiveRequest(request);
7112
+                }
7113
+                else if (earlySubscription) {
7114
+                    earlySubscription.receiveRequest(request);
7115
+                }
7116
+                else {
7117
+                    this.logger.warn('received NOTIFY request for a non existent session or subscription');
7118
+                    request.reply(481, 'Subscription does not exist');
7119
+                }
7120
+            }
7121
+            /* RFC3261 12.2.2
7122
+             * Request with to tag, but no matching dialog found.
7123
+             * Exception: ACK for an Invite request for which a dialog has not
7124
+             * been created.
7125
+             */
7126
+            else {
7127
+                if (method !== SIP.C.ACK) {
7128
+                    request.reply(481);
7129
+                }
7130
+            }
7131
+        }
7132
+    };
7133
+    //=================
7134
+    // Utils
7135
+    //=================
7136
+    /**
7137
+     * Get the session to which the request belongs to, if any.
7138
+     * @private
7139
+     * @param {SIP.IncomingRequest} request.
7140
+     * @returns {SIP.OutgoingSession|SIP.IncomingSession|null}
7141
+     */
7142
+    UA.prototype.findSession = function (request) {
7143
+        return this.sessions[request.call_id + request.from_tag] ||
7144
+            this.sessions[request.call_id + request.to_tag] ||
7145
+            null;
7146
+    };
7147
+    /**
7148
+     * Get the dialog to which the request belongs to, if any.
7149
+     * @private
7150
+     * @param {SIP.IncomingRequest}
7151
+     * @returns {SIP.Dialog|null}
7152
+     */
7153
+    UA.prototype.findDialog = function (request) {
7154
+        return this.dialogs[request.call_id + request.from_tag + request.to_tag] ||
7155
+            this.dialogs[request.call_id + request.to_tag + request.from_tag] ||
7156
+            null;
7157
+    };
7158
+    /**
7159
+     * Get the subscription which has not been confirmed to which the request belongs to, if any
7160
+     * @private
7161
+     * @param {SIP.IncomingRequest}
7162
+     * @returns {SIP.Subscription|null}
7163
+     */
7164
+    UA.prototype.findEarlySubscription = function (request) {
7165
+        return this.earlySubscriptions[request.call_id + request.to_tag + request.getHeader('event')] || null;
7166
+    };
7167
+    function checkAuthenticationFactory(authenticationFactory) {
7168
+        if (!(authenticationFactory instanceof Function)) {
7169
+            return;
7170
+        }
7171
+        if (!authenticationFactory.initialize) {
7172
+            authenticationFactory.initialize = function initialize() {
7173
+                return SIP.Utils.Promise.resolve();
7174
+            };
7175
+        }
7176
+        return authenticationFactory;
7177
+    }
7178
+    /**
7179
+     * Configuration load.
7180
+     * @private
7181
+     * returns {Boolean}
7182
+     */
7183
+    UA.prototype.loadConfig = function (configuration) {
7184
+        // Settings and default values
7185
+        var parameter, value, checked_value, hostportParams, registrarServer, settings = {
7186
+            /* Host address
7187
+            * Value to be set in Via sent_by and host part of Contact FQDN
7188
+            */
7189
+            viaHost: SIP.Utils.createRandomToken(12) + '.invalid',
7190
+            uri: new SIP.URI('sip', 'anonymous.' + SIP.Utils.createRandomToken(6), 'anonymous.invalid', null, null),
7191
+            //Custom Configuration Settings
7192
+            custom: {},
7193
+            //Display name
7194
+            displayName: '',
7195
+            // Password
7196
+            password: null,
7197
+            // Registration parameters
7198
+            registerExpires: 600,
7199
+            register: true,
7200
+            registrarServer: null,
7201
+            // Transport related parameters
7202
+            transportConstructor: __webpack_require__(29)(SIP),
7203
+            transportOptions: {},
7204
+            //string to be inserted into User-Agent request header
7205
+            userAgentString: SIP.C.USER_AGENT,
7206
+            // Session parameters
7207
+            noAnswerTimeout: 60,
7208
+            // Hacks
7209
+            hackViaTcp: false,
7210
+            hackIpInContact: false,
7211
+            hackWssInTransport: false,
7212
+            hackAllowUnregisteredOptionTags: false,
7213
+            // Session Description Handler Options
7214
+            sessionDescriptionHandlerFactoryOptions: {
7215
+                constraints: {},
7216
+                peerConnectionOptions: {}
7217
+            },
7218
+            contactName: SIP.Utils.createRandomToken(8),
7219
+            contactTransport: 'ws',
7220
+            forceRport: false,
7221
+            //autostarting
7222
+            autostart: true,
7223
+            autostop: true,
7224
+            //Reliable Provisional Responses
7225
+            rel100: SIP.C.supported.UNSUPPORTED,
7226
+            // DTMF type: 'info' or 'rtp' (RFC 4733)
7227
+            // RTP Payload Spec: https://tools.ietf.org/html/rfc4733
7228
+            // WebRTC Audio Spec: https://tools.ietf.org/html/rfc7874
7229
+            dtmfType: SIP.C.dtmfType.INFO,
7230
+            // Replaces header (RFC 3891)
7231
+            // http://tools.ietf.org/html/rfc3891
7232
+            replaces: SIP.C.supported.UNSUPPORTED,
7233
+            sessionDescriptionHandlerFactory: __webpack_require__(30)(SIP).defaultFactory,
7234
+            authenticationFactory: checkAuthenticationFactory(function authenticationFactory(ua) {
7235
+                return new SIP.DigestAuthentication(ua);
7236
+            }),
7237
+            allowLegacyNotifications: false,
7238
+            allowOutOfDialogRefers: false,
7239
+        };
7240
+        // Pre-Configuration
7241
+        function aliasUnderscored(parameter, logger) {
7242
+            var underscored = parameter.replace(/([a-z][A-Z])/g, function (m) {
7243
+                return m[0] + '_' + m[1].toLowerCase();
7244
+            });
7245
+            if (parameter === underscored) {
7246
+                return;
7247
+            }
7248
+            var hasParameter = configuration.hasOwnProperty(parameter);
7249
+            if (configuration.hasOwnProperty(underscored)) {
7250
+                logger.warn(underscored + ' is deprecated, please use ' + parameter);
7251
+                if (hasParameter) {
7252
+                    logger.warn(parameter + ' overriding ' + underscored);
7253
+                }
7254
+            }
7255
+            configuration[parameter] = hasParameter ? configuration[parameter] : configuration[underscored];
7256
+        }
7257
+        var configCheck = this.getConfigurationCheck();
7258
+        // Check Mandatory parameters
7259
+        for (parameter in configCheck.mandatory) {
7260
+            aliasUnderscored(parameter, this.logger);
7261
+            if (!configuration.hasOwnProperty(parameter)) {
7262
+                throw new SIP.Exceptions.ConfigurationError(parameter);
7263
+            }
7264
+            else {
7265
+                value = configuration[parameter];
7266
+                checked_value = configCheck.mandatory[parameter](value);
7267
+                if (checked_value !== undefined) {
7268
+                    settings[parameter] = checked_value;
7269
+                }
7270
+                else {
7271
+                    throw new SIP.Exceptions.ConfigurationError(parameter, value);
7272
+                }
7273
+            }
7274
+        }
7275
+        // Check Optional parameters
7276
+        for (parameter in configCheck.optional) {
7277
+            aliasUnderscored(parameter, this.logger);
7278
+            if (configuration.hasOwnProperty(parameter)) {
7279
+                value = configuration[parameter];
7280
+                // If the parameter value is an empty array, but shouldn't be, apply its default value.
7281
+                if (value instanceof Array && value.length === 0) {
7282
+                    continue;
7283
+                }
7284
+                // If the parameter value is null, empty string, or undefined then apply its default value.
7285
+                if (value === null || value === "" || value === undefined) {
7286
+                    continue;
7287
+                }
7288
+                // If it's a number with NaN value then also apply its default value.
7289
+                // NOTE: JS does not allow "value === NaN", the following does the work:
7290
+                else if (typeof (value) === 'number' && isNaN(value)) {
7291
+                    continue;
7292
+                }
7293
+                checked_value = configCheck.optional[parameter](value);
7294
+                if (checked_value !== undefined) {
7295
+                    settings[parameter] = checked_value;
7296
+                }
7297
+                else {
7298
+                    throw new SIP.Exceptions.ConfigurationError(parameter, value);
7299
+                }
7300
+            }
7301
+        }
7302
+        // Post Configuration Process
7303
+        // Allow passing 0 number as displayName.
7304
+        if (settings.displayName === 0) {
7305
+            settings.displayName = '0';
7306
+        }
7307
+        // Instance-id for GRUU
7308
+        if (!settings.instanceId) {
7309
+            settings.instanceId = SIP.Utils.newUUID();
7310
+        }
7311
+        // sipjsId instance parameter. Static random tag of length 5
7312
+        settings.sipjsId = SIP.Utils.createRandomToken(5);
7313
+        // String containing settings.uri without scheme and user.
7314
+        hostportParams = settings.uri.clone();
7315
+        hostportParams.user = null;
7316
+        settings.hostportParams = hostportParams.toRaw().replace(/^sip:/i, '');
7317
+        /* Check whether authorizationUser is explicitly defined.
7318
+         * Take 'settings.uri.user' value if not.
7319
+         */
7320
+        if (!settings.authorizationUser) {
7321
+            settings.authorizationUser = settings.uri.user;
7322
+        }
7323
+        /* If no 'registrarServer' is set use the 'uri' value without user portion. */
7324
+        if (!settings.registrarServer) {
7325
+            registrarServer = settings.uri.clone();
7326
+            registrarServer.user = null;
7327
+            settings.registrarServer = registrarServer;
7328
+        }
7329
+        // User noAnswerTimeout
7330
+        settings.noAnswerTimeout = settings.noAnswerTimeout * 1000;
7331
+        // Via Host
7332
+        if (settings.hackIpInContact) {
7333
+            if (typeof settings.hackIpInContact === 'boolean') {
7334
+                settings.viaHost = SIP.Utils.getRandomTestNetIP();
7335
+            }
7336
+            else if (typeof settings.hackIpInContact === 'string') {
7337
+                settings.viaHost = settings.hackIpInContact;
7338
+            }
7339
+        }
7340
+        // Contact transport parameter
7341
+        if (settings.hackWssInTransport) {
7342
+            settings.contactTransport = 'wss';
7343
+        }
7344
+        this.contact = {
7345
+            pub_gruu: null,
7346
+            temp_gruu: null,
7347
+            uri: new SIP.URI('sip', settings.contactName, settings.viaHost, null, { transport: settings.contactTransport }),
7348
+            toString: function (options) {
7349
+                options = options || {};
7350
+                var anonymous = options.anonymous || null, outbound = options.outbound || null, contact = '<';
7351
+                if (anonymous) {
7352
+                    contact += (this.temp_gruu || ('sip:anonymous@anonymous.invalid;transport=' + settings.contactTransport)).toString();
7353
+                }
7354
+                else {
7355
+                    contact += (this.pub_gruu || this.uri).toString();
7356
+                }
7357
+                if (outbound) {
7358
+                    contact += ';ob';
7359
+                }
7360
+                contact += '>';
7361
+                return contact;
7362
+            }
7363
+        };
7364
+        var skeleton = {};
7365
+        // Fill the value of the configuration_skeleton
7366
+        for (parameter in settings) {
7367
+            skeleton[parameter] = settings[parameter];
7368
+        }
7369
+        Object.assign(this.configuration, skeleton);
7370
+        this.logger.log('configuration parameters after validation:');
7371
+        for (parameter in settings) {
7372
+            switch (parameter) {
7373
+                case 'uri':
7374
+                case 'registrarServer':
7375
+                case 'sessionDescriptionHandlerFactory':
7376
+                    this.logger.log('· ' + parameter + ': ' + settings[parameter]);
7377
+                    break;
7378
+                case 'password':
7379
+                    this.logger.log('· ' + parameter + ': ' + 'NOT SHOWN');
7380
+                    break;
7381
+                case 'transportConstructor':
7382
+                    this.logger.log('· ' + parameter + ': ' + settings[parameter].name);
7383
+                    break;
7384
+                default:
7385
+                    this.logger.log('· ' + parameter + ': ' + JSON.stringify(settings[parameter]));
7386
+            }
7387
+        }
7388
+        return;
7389
+    };
7390
+    /**
7391
+     * Configuration checker.
7392
+     * @private
7393
+     * @return {Boolean}
7394
+     */
7395
+    UA.prototype.getConfigurationCheck = function () {
7396
+        return {
7397
+            mandatory: {},
7398
+            optional: {
7399
+                uri: function (uri) {
7400
+                    var parsed;
7401
+                    if (!(/^sip:/i).test(uri)) {
7402
+                        uri = SIP.C.SIP + ':' + uri;
7403
+                    }
7404
+                    parsed = SIP.URI.parse(uri);
7405
+                    if (!parsed) {
7406
+                        return;
7407
+                    }
7408
+                    else if (!parsed.user) {
7409
+                        return;
7410
+                    }
7411
+                    else {
7412
+                        return parsed;
7413
+                    }
7414
+                },
7415
+                transportConstructor: function (transportConstructor) {
7416
+                    if (transportConstructor instanceof Function) {
7417
+                        return transportConstructor;
7418
+                    }
7419
+                },
7420
+                transportOptions: function (transportOptions) {
7421
+                    if (typeof transportOptions === 'object') {
7422
+                        return transportOptions;
7423
+                    }
7424
+                },
7425
+                authorizationUser: function (authorizationUser) {
7426
+                    if (SIP.Grammar.parse('"' + authorizationUser + '"', 'quoted_string') === -1) {
7427
+                        return;
7428
+                    }
7429
+                    else {
7430
+                        return authorizationUser;
7431
+                    }
7432
+                },
7433
+                displayName: function (displayName) {
7434
+                    if (SIP.Grammar.parse('"' + displayName + '"', 'displayName') === -1) {
7435
+                        return;
7436
+                    }
7437
+                    else {
7438
+                        return displayName;
7439
+                    }
7440
+                },
7441
+                dtmfType: function (dtmfType) {
7442
+                    switch (dtmfType) {
7443
+                        case SIP.C.dtmfType.RTP:
7444
+                            return SIP.C.dtmfType.RTP;
7445
+                        case SIP.C.dtmfType.INFO:
7446
+                        // Fall through
7447
+                        default:
7448
+                            return SIP.C.dtmfType.INFO;
7449
+                    }
7450
+                },
7451
+                hackViaTcp: function (hackViaTcp) {
7452
+                    if (typeof hackViaTcp === 'boolean') {
7453
+                        return hackViaTcp;
7454
+                    }
7455
+                },
7456
+                hackIpInContact: function (hackIpInContact) {
7457
+                    if (typeof hackIpInContact === 'boolean') {
7458
+                        return hackIpInContact;
7459
+                    }
7460
+                    else if (typeof hackIpInContact === 'string' && SIP.Grammar.parse(hackIpInContact, 'host') !== -1) {
7461
+                        return hackIpInContact;
7462
+                    }
7463
+                },
7464
+                hackWssInTransport: function (hackWssInTransport) {
7465
+                    if (typeof hackWssInTransport === 'boolean') {
7466
+                        return hackWssInTransport;
7467
+                    }
7468
+                },
7469
+                hackAllowUnregisteredOptionTags: function (hackAllowUnregisteredOptionTags) {
7470
+                    if (typeof hackAllowUnregisteredOptionTags === 'boolean') {
7471
+                        return hackAllowUnregisteredOptionTags;
7472
+                    }
7473
+                },
7474
+                contactTransport: function (contactTransport) {
7475
+                    if (typeof contactTransport === 'string') {
7476
+                        return contactTransport;
7477
+                    }
7478
+                },
7479
+                forceRport: function (forceRport) {
7480
+                    if (typeof forceRport === 'boolean') {
7481
+                        return forceRport;
7482
+                    }
7483
+                },
7484
+                instanceId: function (instanceId) {
7485
+                    if (typeof instanceId !== 'string') {
7486
+                        return;
7487
+                    }
7488
+                    if ((/^uuid:/i.test(instanceId))) {
7489
+                        instanceId = instanceId.substr(5);
7490
+                    }
7491
+                    if (SIP.Grammar.parse(instanceId, 'uuid') === -1) {
7492
+                        return;
7493
+                    }
7494
+                    else {
7495
+                        return instanceId;
7496
+                    }
7497
+                },
7498
+                noAnswerTimeout: function (noAnswerTimeout) {
7499
+                    var value;
7500
+                    if (SIP.Utils.isDecimal(noAnswerTimeout)) {
7501
+                        value = Number(noAnswerTimeout);
7502
+                        if (value > 0) {
7503
+                            return value;
7504
+                        }
7505
+                    }
7506
+                },
7507
+                password: function (password) {
7508
+                    return String(password);
7509
+                },
7510
+                rel100: function (rel100) {
7511
+                    if (rel100 === SIP.C.supported.REQUIRED) {
7512
+                        return SIP.C.supported.REQUIRED;
7513
+                    }
7514
+                    else if (rel100 === SIP.C.supported.SUPPORTED) {
7515
+                        return SIP.C.supported.SUPPORTED;
7516
+                    }
7517
+                    else {
7518
+                        return SIP.C.supported.UNSUPPORTED;
7519
+                    }
7520
+                },
7521
+                replaces: function (replaces) {
7522
+                    if (replaces === SIP.C.supported.REQUIRED) {
7523
+                        return SIP.C.supported.REQUIRED;
7524
+                    }
7525
+                    else if (replaces === SIP.C.supported.SUPPORTED) {
7526
+                        return SIP.C.supported.SUPPORTED;
7527
+                    }
7528
+                    else {
7529
+                        return SIP.C.supported.UNSUPPORTED;
7530
+                    }
7531
+                },
7532
+                register: function (register) {
7533
+                    if (typeof register === 'boolean') {
7534
+                        return register;
7535
+                    }
7536
+                },
7537
+                registerExpires: function (registerExpires) {
7538
+                    var value;
7539
+                    if (SIP.Utils.isDecimal(registerExpires)) {
7540
+                        value = Number(registerExpires);
7541
+                        if (value > 0) {
7542
+                            return value;
7543
+                        }
7544
+                    }
7545
+                },
7546
+                registrarServer: function (registrarServer) {
7547
+                    var parsed;
7548
+                    if (typeof registrarServer !== 'string') {
7549
+                        return;
7550
+                    }
7551
+                    if (!/^sip:/i.test(registrarServer)) {
7552
+                        registrarServer = SIP.C.SIP + ':' + registrarServer;
7553
+                    }
7554
+                    parsed = SIP.URI.parse(registrarServer);
7555
+                    if (!parsed) {
7556
+                        return;
7557
+                    }
7558
+                    else if (parsed.user) {
7559
+                        return;
7560
+                    }
7561
+                    else {
7562
+                        return parsed;
7563
+                    }
7564
+                },
7565
+                userAgentString: function (userAgentString) {
7566
+                    if (typeof userAgentString === 'string') {
7567
+                        return userAgentString;
7568
+                    }
7569
+                },
7570
+                autostart: function (autostart) {
7571
+                    if (typeof autostart === 'boolean') {
7572
+                        return autostart;
7573
+                    }
7574
+                },
7575
+                autostop: function (autostop) {
7576
+                    if (typeof autostop === 'boolean') {
7577
+                        return autostop;
7578
+                    }
7579
+                },
7580
+                sessionDescriptionHandlerFactory: function (sessionDescriptionHandlerFactory) {
7581
+                    if (sessionDescriptionHandlerFactory instanceof Function) {
7582
+                        return sessionDescriptionHandlerFactory;
7583
+                    }
7584
+                },
7585
+                sessionDescriptionHandlerFactoryOptions: function (options) {
7586
+                    if (typeof options === 'object') {
7587
+                        return options;
7588
+                    }
7589
+                },
7590
+                authenticationFactory: checkAuthenticationFactory,
7591
+                allowLegacyNotifications: function (allowLegacyNotifications) {
7592
+                    if (typeof allowLegacyNotifications === 'boolean') {
7593
+                        return allowLegacyNotifications;
7594
+                    }
7595
+                },
7596
+                custom: function (custom) {
7597
+                    if (typeof custom === 'object') {
7598
+                        return custom;
7599
+                    }
7600
+                },
7601
+                contactName: function (contactName) {
7602
+                    if (typeof contactName === 'string') {
7603
+                        return contactName;
7604
+                    }
7605
+                },
7606
+            }
7607
+        };
7608
+    };
7609
+    UA.C = C;
7610
+    SIP.UA = UA;
7611
+};
7612
+
7613
+/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(28)))
7614
+
7615
+/***/ }),
7616
+/* 28 */
7617
+/***/ (function(module, exports) {
7618
+
7619
+var g;
7620
+
7621
+// This works in non-strict mode
7622
+g = (function() {
7623
+	return this;
7624
+})();
7625
+
7626
+try {
7627
+	// This works if eval is allowed (see CSP)
7628
+	g = g || Function("return this")() || (1, eval)("this");
7629
+} catch (e) {
7630
+	// This works if the window reference is available
7631
+	if (typeof window === "object") g = window;
7632
+}
7633
+
7634
+// g can still be undefined, but nothing to do about it...
7635
+// We return undefined, instead of nothing here, so it's
7636
+// easier to handle this case. if(!global) { ...}
7637
+
7638
+module.exports = g;
7639
+
7640
+
7641
+/***/ }),
7642
+/* 29 */
7643
+/***/ (function(module, exports, __webpack_require__) {
7644
+
7645
+"use strict";
7646
+/* WEBPACK VAR INJECTION */(function(global) {
7647
+/**
7648
+ * @fileoverview Transport
7649
+ */
7650
+/**
7651
+ * @augments SIP
7652
+ * @class Transport
7653
+ * @param {Object} options
7654
+ */
7655
+module.exports = function (SIP) {
7656
+    var Transport, C = {
7657
+        // Transport status codes
7658
+        STATUS_CONNECTING: 0,
7659
+        STATUS_OPEN: 1,
7660
+        STATUS_CLOSING: 2,
7661
+        STATUS_CLOSED: 3,
7662
+    };
7663
+    var WebSocket = (global.window || global).WebSocket;
7664
+    /**
7665
+     * Compute an amount of time in seconds to wait before sending another
7666
+     * keep-alive.
7667
+     * @returns {Number}
7668
+     */
7669
+    function computeKeepAliveTimeout(upperBound) {
7670
+        var lowerBound = upperBound * 0.8;
7671
+        return 1000 * (Math.random() * (upperBound - lowerBound) + lowerBound);
7672
+    }
7673
+    Transport = function (logger, options) {
7674
+        options = SIP.Utils.defaultOptions({}, options);
7675
+        this.logger = logger;
7676
+        this.ws = null;
7677
+        this.server = null;
7678
+        this.connectionPromise = null;
7679
+        this.connectDeferredResolve = null;
7680
+        this.connectionTimeout = null;
7681
+        this.disconnectionPromise = null;
7682
+        this.disconnectDeferredResolve = null;
7683
+        this.boundOnOpen = null;
7684
+        this.boundOnMessage = null;
7685
+        this.boundOnClose = null;
7686
+        this.boundOnError = null;
7687
+        this.reconnectionAttempts = 0;
7688
+        this.reconnectTimer = null;
7689
+        // Keep alive
7690
+        this.keepAliveInterval = null;
7691
+        this.keepAliveDebounceTimeout = null;
7692
+        this.status = C.STATUS_CONNECTING;
7693
+        this.configuration = {};
7694
+        this.loadConfig(options);
7695
+    };
7696
+    Transport.prototype = Object.create(SIP.Transport.prototype, {
7697
+        /**
7698
+        *
7699
+        * @returns {Boolean}
7700
+        */
7701
+        isConnected: { writable: true, value: function isConnected() {
7702
+                return this.status === C.STATUS_OPEN;
7703
+            } },
7704
+        /**
7705
+         * Send a message.
7706
+         * @param {SIP.OutgoingRequest|String} msg
7707
+         * @param {Object} [options]
7708
+         * @returns {Promise}
7709
+         */
7710
+        sendPromise: { writable: true, value: function sendPromise(msg, options) {
7711
+                options = options || {};
7712
+                if (!this.statusAssert(C.STATUS_OPEN, options.force)) {
7713
+                    this.onError('unable to send message - WebSocket not open');
7714
+                    return SIP.Utils.Promise.reject();
7715
+                }
7716
+                var message = msg.toString();
7717
+                if (this.ws) {
7718
+                    if (this.configuration.traceSip === true) {
7719
+                        this.logger.log('sending WebSocket message:\n\n' + message + '\n');
7720
+                    }
7721
+                    this.ws.send(message);
7722
+                    return SIP.Utils.Promise.resolve({ msg: message });
7723
+                }
7724
+                else {
7725
+                    this.onError('unable to send message - WebSocket does not exist');
7726
+                    return SIP.Utils.Promise.reject();
7727
+                }
7728
+            } },
7729
+        /**
7730
+        * Disconnect socket.
7731
+        */
7732
+        disconnectPromise: { writable: true, value: function disconnectPromise(options) {
7733
+                if (this.disconnectionPromise) {
7734
+                    return this.disconnectionPromise;
7735
+                }
7736
+                options = options || {};
7737
+                if (!this.statusTransition(C.STATUS_CLOSING, options.force)) {
7738
+                    return SIP.Utils.Promise.reject('Failed status transition - attempted to disconnect a socket that was not open');
7739
+                }
7740
+                this.disconnectionPromise = new SIP.Utils.Promise(function (resolve, reject) {
7741
+                    this.disconnectDeferredResolve = resolve;
7742
+                    if (this.reconnectTimer) {
7743
+                        SIP.Timers.clearTimeout(this.reconnectTimer);
7744
+                        this.reconnectTimer = null;
7745
+                    }
7746
+                    if (this.ws) {
7747
+                        this.stopSendingKeepAlives();
7748
+                        this.logger.log('closing WebSocket ' + this.server.ws_uri);
7749
+                        this.ws.close(options.code, options.reason);
7750
+                    }
7751
+                    else {
7752
+                        reject('Attempted to disconnect but the websocket doesn\'t exist');
7753
+                    }
7754
+                }.bind(this));
7755
+                return this.disconnectionPromise;
7756
+            } },
7757
+        /**
7758
+        * Connect socket.
7759
+        */
7760
+        connectPromise: { writable: true, value: function connectPromise(options) {
7761
+                if (this.connectionPromise) {
7762
+                    return this.connectionPromise;
7763
+                }
7764
+                options = options || {};
7765
+                this.server = this.server || this.getNextWsServer(options.force);
7766
+                this.connectionPromise = new SIP.Utils.Promise(function (resolve, reject) {
7767
+                    if ((this.status === C.STATUS_OPEN || this.status === C.STATUS_CLOSING) && !options.force) {
7768
+                        this.logger.warn('WebSocket ' + this.server.ws_uri + ' is already connected');
7769
+                        reject('Failed status check - attempted to open a connection but already open/closing');
7770
+                        return;
7771
+                    }
7772
+                    this.connectDeferredResolve = resolve;
7773
+                    this.status = C.STATUS_CONNECTING;
7774
+                    this.logger.log('connecting to WebSocket ' + this.server.ws_uri);
7775
+                    this.disposeWs();
7776
+                    try {
7777
+                        this.ws = new WebSocket(this.server.ws_uri, 'sip');
7778
+                    }
7779
+                    catch (e) {
7780
+                        this.ws = null;
7781
+                        this.status = C.STATUS_CLOSED; // force status to closed in error case
7782
+                        this.onError('error connecting to WebSocket ' + this.server.ws_uri + ':' + e);
7783
+                        reject('Failed to create a websocket');
7784
+                        return;
7785
+                    }
7786
+                    if (!this.ws) {
7787
+                        reject('Unexpected instance websocket not set');
7788
+                        return;
7789
+                    }
7790
+                    this.connectionTimeout = SIP.Timers.setTimeout(function () {
7791
+                        this.onError('took too long to connect - exceeded time set in configuration.connectionTimeout: ' + this.configuration.connectionTimeout + 's');
7792
+                    }.bind(this), this.configuration.connectionTimeout * 1000);
7793
+                    this.boundOnOpen = this.onOpen.bind(this);
7794
+                    this.boundOnMessage = this.onMessage.bind(this);
7795
+                    this.boundOnClose = this.onClose.bind(this);
7796
+                    this.boundOnError = this.onError.bind(this);
7797
+                    this.ws.addEventListener('open', this.boundOnOpen);
7798
+                    this.ws.addEventListener('message', this.boundOnMessage);
7799
+                    this.ws.addEventListener('close', this.boundOnClose);
7800
+                    this.ws.addEventListener('error', this.boundOnError);
7801
+                }.bind(this));
7802
+                return this.connectionPromise;
7803
+            } },
7804
+        // Transport Event Handlers
7805
+        /**
7806
+        * @event
7807
+        * @param {event} e
7808
+        */
7809
+        onOpen: { writable: true, value: function onOpen() {
7810
+                this.status = C.STATUS_OPEN; // quietly force status to open
7811
+                this.emit('connected');
7812
+                SIP.Timers.clearTimeout(this.connectionTimeout);
7813
+                this.logger.log('WebSocket ' + this.server.ws_uri + ' connected');
7814
+                // Clear reconnectTimer since we are not disconnected
7815
+                if (this.reconnectTimer !== null) {
7816
+                    SIP.Timers.clearTimeout(this.reconnectTimer);
7817
+                    this.reconnectTimer = null;
7818
+                }
7819
+                // Reset reconnectionAttempts
7820
+                this.reconnectionAttempts = 0;
7821
+                // Reset disconnection promise so we can disconnect from a fresh state
7822
+                this.disconnectionPromise = null;
7823
+                this.disconnectDeferredResolve = null;
7824
+                // Start sending keep-alives
7825
+                this.startSendingKeepAlives();
7826
+                if (this.connectDeferredResolve) {
7827
+                    this.connectDeferredResolve({ overrideEvent: true });
7828
+                }
7829
+                else {
7830
+                    this.logger.warn('Unexpected websocket.onOpen with no connectDeferredResolve');
7831
+                }
7832
+            } },
7833
+        /**
7834
+        * @event
7835
+        * @param {event} e
7836
+        */
7837
+        onClose: { writable: true, value: function onClose(e) {
7838
+                this.logger.log('WebSocket disconnected (code: ' + e.code + (e.reason ? '| reason: ' + e.reason : '') + ')');
7839
+                this.emit('disconnected', { code: e.code, reason: e.reason });
7840
+                if (this.status !== C.STATUS_CLOSING) {
7841
+                    this.logger.warn('WebSocket abrupt disconnection');
7842
+                    this.emit('transportError');
7843
+                }
7844
+                this.stopSendingKeepAlives();
7845
+                // Clean up connection variables so we can connect again from a fresh state
7846
+                SIP.Timers.clearTimeout(this.connectionTimeout);
7847
+                this.connectionTimeout = null;
7848
+                this.connectionPromise = null;
7849
+                this.connectDeferredResolve = null;
7850
+                // Check whether the user requested to close.
7851
+                if (this.disconnectDeferredResolve) {
7852
+                    this.disconnectDeferredResolve({ overrideEvent: true });
7853
+                    this.statusTransition(C.STATUS_CLOSED);
7854
+                    this.disconnectDeferredResolve = null;
7855
+                    return;
7856
+                }
7857
+                this.status = C.STATUS_CLOSED; // quietly force status to closed
7858
+                this.reconnect();
7859
+            } },
7860
+        /**
7861
+        * Removes event listeners and clears the instance ws
7862
+        * @private
7863
+        * @param {event} e
7864
+        */
7865
+        disposeWs: { writable: true, value: function disposeWs() {
7866
+                if (this.ws) {
7867
+                    this.ws.removeEventListener('open', this.boundOnOpen);
7868
+                    this.ws.removeEventListener('message', this.boundOnMessage);
7869
+                    this.ws.removeEventListener('close', this.boundOnClose);
7870
+                    this.ws.removeEventListener('error', this.boundOnError);
7871
+                    this.boundOnOpen = null;
7872
+                    this.boundOnMessage = null;
7873
+                    this.boundOnClose = null;
7874
+                    this.boundOnError = null;
7875
+                    this.ws = null;
7876
+                }
7877
+            } },
7878
+        /**
7879
+        * @event
7880
+        * @param {event} e
7881
+        */
7882
+        onMessage: { writable: true, value: function onMessage(e) {
7883
+                var data = e.data;
7884
+                // CRLF Keep Alive response from server. Clear our keep alive timeout.
7885
+                if (/^(\r\n)+$/.test(data)) {
7886
+                    this.clearKeepAliveTimeout();
7887
+                    if (this.configuration.traceSip === true) {
7888
+                        this.logger.log('received WebSocket message with CRLF Keep Alive response');
7889
+                    }
7890
+                    return;
7891
+                }
7892
+                else if (!data) {
7893
+                    this.logger.warn('received empty message, message discarded');
7894
+                    return;
7895
+                }
7896
+                // WebSocket binary message.
7897
+                else if (typeof data !== 'string') {
7898
+                    try {
7899
+                        data = String.fromCharCode.apply(null, new Uint8Array(data));
7900
+                    }
7901
+                    catch (err) {
7902
+                        this.logger.warn('received WebSocket binary message failed to be converted into string, message discarded');
7903
+                        return;
7904
+                    }
7905
+                    if (this.configuration.traceSip === true) {
7906
+                        this.logger.log('received WebSocket binary message:\n\n' + data + '\n');
7907
+                    }
7908
+                }
7909
+                // WebSocket text message.
7910
+                else {
7911
+                    if (this.configuration.traceSip === true) {
7912
+                        this.logger.log('received WebSocket text message:\n\n' + data + '\n');
7913
+                    }
7914
+                }
7915
+                this.emit('message', data);
7916
+            } },
7917
+        /**
7918
+        * @event
7919
+        * @param {event} e
7920
+        */
7921
+        onError: { writable: true, value: function onError(e) {
7922
+                this.logger.warn('Transport error: ' + e);
7923
+                this.emit('transportError');
7924
+            } },
7925
+        /**
7926
+        * Reconnection attempt logic.
7927
+        * @private
7928
+        */
7929
+        reconnect: { writable: true, value: function reconnect() {
7930
+                if (this.reconnectionAttempts > 0) {
7931
+                    this.logger.log('Reconnection attempt ' + this.reconnectionAttempts + ' failed');
7932
+                }
7933
+                if (this.noAvailableServers()) {
7934
+                    this.logger.warn('no available ws servers left - going to closed state');
7935
+                    this.status = C.STATUS_CLOSED;
7936
+                    this.emit('closed');
7937
+                    this.resetServerErrorStatus();
7938
+                    return;
7939
+                }
7940
+                if (this.isConnected()) {
7941
+                    this.logger.warn('attempted to reconnect while connected - forcing disconnect');
7942
+                    this.disconnect({ force: true });
7943
+                }
7944
+                this.reconnectionAttempts += 1;
7945
+                if (this.reconnectionAttempts > this.configuration.maxReconnectionAttempts) {
7946
+                    this.logger.warn('maximum reconnection attempts for WebSocket ' + this.server.ws_uri);
7947
+                    this.logger.log('transport ' + this.server.ws_uri + ' failed | connection state set to \'error\'');
7948
+                    this.server.isError = true;
7949
+                    this.emit('transportError');
7950
+                    this.server = this.getNextWsServer();
7951
+                    this.reconnectionAttempts = 0;
7952
+                    this.reconnect();
7953
+                }
7954
+                else {
7955
+                    this.logger.log('trying to reconnect to WebSocket ' + this.server.ws_uri + ' (reconnection attempt ' + this.reconnectionAttempts + ')');
7956
+                    this.reconnectTimer = SIP.Timers.setTimeout(function () {
7957
+                        this.connect();
7958
+                        this.reconnectTimer = null;
7959
+                    }.bind(this), (this.reconnectionAttempts === 1) ? 0 : this.configuration.reconnectionTimeout * 1000);
7960
+                }
7961
+            } },
7962
+        /**
7963
+        * Resets the error state of all servers in the configuration
7964
+        */
7965
+        resetServerErrorStatus: { writable: true, value: function resetServerErrorStatus() {
7966
+                var idx, length = this.configuration.wsServers.length;
7967
+                for (idx = 0; idx < length; idx++) {
7968
+                    this.configuration.wsServers[idx].isError = false;
7969
+                }
7970
+            } },
7971
+        /**
7972
+        * Retrieve the next server to which connect.
7973
+        * @private
7974
+        * @param {Boolean} force allows bypass of server error status checking
7975
+        * @returns {Object} wsServer
7976
+        */
7977
+        getNextWsServer: { writable: true, value: function getNextWsServer(force) {
7978
+                if (this.noAvailableServers()) {
7979
+                    this.logger.warn('attempted to get next ws server but there are no available ws servers left');
7980
+                    return;
7981
+                }
7982
+                // Order servers by weight
7983
+                var idx, length, wsServer, candidates = [];
7984
+                length = this.configuration.wsServers.length;
7985
+                for (idx = 0; idx < length; idx++) {
7986
+                    wsServer = this.configuration.wsServers[idx];
7987
+                    if (wsServer.isError && !force) {
7988
+                        continue;
7989
+                    }
7990
+                    else if (candidates.length === 0) {
7991
+                        candidates.push(wsServer);
7992
+                    }
7993
+                    else if (wsServer.weight > candidates[0].weight) {
7994
+                        candidates = [wsServer];
7995
+                    }
7996
+                    else if (wsServer.weight === candidates[0].weight) {
7997
+                        candidates.push(wsServer);
7998
+                    }
7999
+                }
8000
+                idx = Math.floor(Math.random() * candidates.length);
8001
+                return candidates[idx];
8002
+            } },
8003
+        /**
8004
+        * Checks all configuration servers, returns true if all of them have isError: true and false otherwise
8005
+        * @private
8006
+        * @returns {Boolean}
8007
+        */
8008
+        noAvailableServers: { writable: true, value: function noAvailableServers() {
8009
+                var server;
8010
+                for (server in this.configuration.wsServers) {
8011
+                    if (!this.configuration.wsServers[server].isError) {
8012
+                        return false;
8013
+                    }
8014
+                }
8015
+                return true;
8016
+            } },
8017
+        //==============================
8018
+        // KeepAlive Stuff
8019
+        //==============================
8020
+        /**
8021
+         * Send a keep-alive (a double-CRLF sequence).
8022
+         * @private
8023
+         * @returns {Boolean}
8024
+         */
8025
+        sendKeepAlive: { writable: true, value: function sendKeepAlive() {
8026
+                if (this.keepAliveDebounceTimeout) {
8027
+                    // We already have an outstanding keep alive, do not send another.
8028
+                    return;
8029
+                }
8030
+                this.keepAliveDebounceTimeout = SIP.Timers.setTimeout(function () {
8031
+                    this.emit('keepAliveDebounceTimeout');
8032
+                    this.clearKeepAliveTimeout();
8033
+                }.bind(this), this.configuration.keepAliveDebounce * 1000);
8034
+                return this.send('\r\n\r\n');
8035
+            } },
8036
+        clearKeepAliveTimeout: { writable: true, value: function clearKeepAliveTimeout() {
8037
+                SIP.Timers.clearTimeout(this.keepAliveDebounceTimeout);
8038
+                this.keepAliveDebounceTimeout = null;
8039
+            } },
8040
+        /**
8041
+         * Start sending keep-alives.
8042
+         * @private
8043
+         */
8044
+        startSendingKeepAlives: { writable: true, value: function startSendingKeepAlives() {
8045
+                if (this.configuration.keepAliveInterval && !this.keepAliveInterval) {
8046
+                    this.keepAliveInterval = SIP.Timers.setInterval(function () {
8047
+                        this.sendKeepAlive();
8048
+                        this.startSendingKeepAlives();
8049
+                    }.bind(this), computeKeepAliveTimeout(this.configuration.keepAliveInterval));
8050
+                }
8051
+            } },
8052
+        /**
8053
+         * Stop sending keep-alives.
8054
+         * @private
8055
+         */
8056
+        stopSendingKeepAlives: { writable: true, value: function stopSendingKeepAlives() {
8057
+                SIP.Timers.clearInterval(this.keepAliveInterval);
8058
+                SIP.Timers.clearTimeout(this.keepAliveDebounceTimeout);
8059
+                this.keepAliveInterval = null;
8060
+                this.keepAliveDebounceTimeout = null;
8061
+            } },
8062
+        //==============================
8063
+        // Status Stuff
8064
+        //==============================
8065
+        /**
8066
+        * Checks given status against instance current status. Returns true if they match
8067
+        * @private
8068
+        * @param {Number} status
8069
+        * @param {Boolean} [force]
8070
+        * @returns {Boolean}
8071
+        */
8072
+        statusAssert: { writable: true, value: function statusAssert(status, force) {
8073
+                if (status === this.status) {
8074
+                    return true;
8075
+                }
8076
+                else {
8077
+                    if (force) {
8078
+                        this.logger.warn('Attempted to assert ' + Object.keys(C)[this.status] + ' as ' + Object.keys(C)[status] + '- continuing with option: \'force\'');
8079
+                        return true;
8080
+                    }
8081
+                    else {
8082
+                        this.logger.warn('Tried to assert ' + Object.keys(C)[status] + ' but is currently ' + Object.keys(C)[this.status]);
8083
+                        return false;
8084
+                    }
8085
+                }
8086
+            } },
8087
+        /**
8088
+        * Transitions the status. Checks for legal transition via assertion beforehand
8089
+        * @private
8090
+        * @param {Number} status
8091
+        * @param {Boolean} [force]
8092
+        * @returns {Boolean}
8093
+        */
8094
+        statusTransition: { writable: true, value: function statusTransition(status, force) {
8095
+                this.logger.log('Attempting to transition status from ' + Object.keys(C)[this.status] + ' to ' + Object.keys(C)[status]);
8096
+                if ((status === C.STATUS_OPEN && this.statusAssert(C.STATUS_CONNECTING, force)) ||
8097
+                    (status === C.STATUS_CLOSING && this.statusAssert(C.STATUS_OPEN, force)) ||
8098
+                    (status === C.STATUS_CLOSED && this.statusAssert(C.STATUS_CLOSING, force))) {
8099
+                    this.status = status;
8100
+                    return true;
8101
+                }
8102
+                else {
8103
+                    this.logger.warn('Status transition failed - result: no-op - reason: either gave an nonexistent status or attempted illegal transition');
8104
+                    return false;
8105
+                }
8106
+            } },
8107
+        //==============================
8108
+        // Configuration Handling
8109
+        //==============================
8110
+        /**
8111
+         * Configuration load.
8112
+         * @private
8113
+         * returns {Boolean}
8114
+         */
8115
+        loadConfig: { writable: true, value: function loadConfig(configuration) {
8116
+                var parameter, value, checked_value, settings = {
8117
+                    wsServers: [{
8118
+                            scheme: 'WSS',
8119
+                            sip_uri: '<sip:edge.sip.onsip.com;transport=ws;lr>',
8120
+                            weight: 0,
8121
+                            ws_uri: 'wss://edge.sip.onsip.com',
8122
+                            isError: false
8123
+                        }],
8124
+                    connectionTimeout: 5,
8125
+                    maxReconnectionAttempts: 3,
8126
+                    reconnectionTimeout: 4,
8127
+                    keepAliveInterval: 0,
8128
+                    keepAliveDebounce: 10,
8129
+                    // Logging
8130
+                    traceSip: false,
8131
+                };
8132
+                // Pre-Configuration
8133
+                function aliasUnderscored(parameter, logger) {
8134
+                    var underscored = parameter.replace(/([a-z][A-Z])/g, function (m) {
8135
+                        return m[0] + '_' + m[1].toLowerCase();
8136
+                    });
8137
+                    if (parameter === underscored) {
8138
+                        return;
8139
+                    }
8140
+                    var hasParameter = configuration.hasOwnProperty(parameter);
8141
+                    if (configuration.hasOwnProperty(underscored)) {
8142
+                        logger.warn(underscored + ' is deprecated, please use ' + parameter);
8143
+                        if (hasParameter) {
8144
+                            logger.warn(parameter + ' overriding ' + underscored);
8145
+                        }
8146
+                    }
8147
+                    configuration[parameter] = hasParameter ? configuration[parameter] : configuration[underscored];
8148
+                }
8149
+                var configCheck = this.getConfigurationCheck();
8150
+                // Check Mandatory parameters
8151
+                for (parameter in configCheck.mandatory) {
8152
+                    aliasUnderscored(parameter, this.logger);
8153
+                    if (!configuration.hasOwnProperty(parameter)) {
8154
+                        throw new SIP.Exceptions.ConfigurationError(parameter);
8155
+                    }
8156
+                    else {
8157
+                        value = configuration[parameter];
8158
+                        checked_value = configCheck.mandatory[parameter](value);
8159
+                        if (checked_value !== undefined) {
8160
+                            settings[parameter] = checked_value;
8161
+                        }
8162
+                        else {
8163
+                            throw new SIP.Exceptions.ConfigurationError(parameter, value);
8164
+                        }
8165
+                    }
8166
+                }
8167
+                // Check Optional parameters
8168
+                for (parameter in configCheck.optional) {
8169
+                    aliasUnderscored(parameter, this.logger);
8170
+                    if (configuration.hasOwnProperty(parameter)) {
8171
+                        value = configuration[parameter];
8172
+                        // If the parameter value is an empty array, but shouldn't be, apply its default value.
8173
+                        if (value instanceof Array && value.length === 0) {
8174
+                            continue;
8175
+                        }
8176
+                        // If the parameter value is null, empty string, or undefined then apply its default value.
8177
+                        if (value === null || value === '' || value === undefined) {
8178
+                            continue;
8179
+                        }
8180
+                        // If it's a number with NaN value then also apply its default value.
8181
+                        // NOTE: JS does not allow "value === NaN", the following does the work:
8182
+                        else if (typeof (value) === 'number' && isNaN(value)) {
8183
+                            continue;
8184
+                        }
8185
+                        checked_value = configCheck.optional[parameter](value);
8186
+                        if (checked_value !== undefined) {
8187
+                            settings[parameter] = checked_value;
8188
+                        }
8189
+                        else {
8190
+                            throw new SIP.Exceptions.ConfigurationError(parameter, value);
8191
+                        }
8192
+                    }
8193
+                }
8194
+                var skeleton = {};
8195
+                // Fill the value of the configuration_skeleton
8196
+                for (parameter in settings) {
8197
+                    skeleton[parameter] = {
8198
+                        value: settings[parameter],
8199
+                    };
8200
+                }
8201
+                Object.defineProperties(this.configuration, skeleton);
8202
+                this.logger.log('configuration parameters after validation:');
8203
+                for (parameter in settings) {
8204
+                    this.logger.log('· ' + parameter + ': ' + JSON.stringify(settings[parameter]));
8205
+                }
8206
+                return;
8207
+            } },
8208
+        /**
8209
+         * Configuration checker.
8210
+         * @private
8211
+         * @return {Boolean}
8212
+         */
8213
+        getConfigurationCheck: { writable: true, value: function getConfigurationCheck() {
8214
+                return {
8215
+                    mandatory: {},
8216
+                    optional: {
8217
+                        //Note: this function used to call 'this.logger.error' but calling 'this' with anything here is invalid
8218
+                        wsServers: function (wsServers) {
8219
+                            var idx, length, url;
8220
+                            /* Allow defining wsServers parameter as:
8221
+                             *  String: "host"
8222
+                             *  Array of Strings: ["host1", "host2"]
8223
+                             *  Array of Objects: [{ws_uri:"host1", weight:1}, {ws_uri:"host2", weight:0}]
8224
+                             *  Array of Objects and Strings: [{ws_uri:"host1"}, "host2"]
8225
+                             */
8226
+                            if (typeof wsServers === 'string') {
8227
+                                wsServers = [{ ws_uri: wsServers }];
8228
+                            }
8229
+                            else if (wsServers instanceof Array) {
8230
+                                length = wsServers.length;
8231
+                                for (idx = 0; idx < length; idx++) {
8232
+                                    if (typeof wsServers[idx] === 'string') {
8233
+                                        wsServers[idx] = { ws_uri: wsServers[idx] };
8234
+                                    }
8235
+                                }
8236
+                            }
8237
+                            else {
8238
+                                return;
8239
+                            }
8240
+                            if (wsServers.length === 0) {
8241
+                                return false;
8242
+                            }
8243
+                            length = wsServers.length;
8244
+                            for (idx = 0; idx < length; idx++) {
8245
+                                if (!wsServers[idx].ws_uri) {
8246
+                                    return;
8247
+                                }
8248
+                                if (wsServers[idx].weight && !Number(wsServers[idx].weight)) {
8249
+                                    return;
8250
+                                }
8251
+                                url = SIP.Grammar.parse(wsServers[idx].ws_uri, 'absoluteURI');
8252
+                                if (url === -1) {
8253
+                                    return;
8254
+                                }
8255
+                                else if (['wss', 'ws', 'udp'].indexOf(url.scheme) < 0) {
8256
+                                    return;
8257
+                                }
8258
+                                else {
8259
+                                    wsServers[idx].sip_uri = '<sip:' + url.host + (url.port ? ':' + url.port : '') + ';transport=' + url.scheme.replace(/^wss$/i, 'ws') + ';lr>';
8260
+                                    if (!wsServers[idx].weight) {
8261
+                                        wsServers[idx].weight = 0;
8262
+                                    }
8263
+                                    wsServers[idx].isError = false;
8264
+                                    wsServers[idx].scheme = url.scheme.toUpperCase();
8265
+                                }
8266
+                            }
8267
+                            return wsServers;
8268
+                        },
8269
+                        keepAliveInterval: function (keepAliveInterval) {
8270
+                            var value;
8271
+                            if (SIP.Utils.isDecimal(keepAliveInterval)) {
8272
+                                value = Number(keepAliveInterval);
8273
+                                if (value > 0) {
8274
+                                    return value;
8275
+                                }
8276
+                            }
8277
+                        },
8278
+                        keepAliveDebounce: function (keepAliveDebounce) {
8279
+                            var value;
8280
+                            if (SIP.Utils.isDecimal(keepAliveDebounce)) {
8281
+                                value = Number(keepAliveDebounce);
8282
+                                if (value > 0) {
8283
+                                    return value;
8284
+                                }
8285
+                            }
8286
+                        },
8287
+                        traceSip: function (traceSip) {
8288
+                            if (typeof traceSip === 'boolean') {
8289
+                                return traceSip;
8290
+                            }
8291
+                        },
8292
+                        connectionTimeout: function (connectionTimeout) {
8293
+                            var value;
8294
+                            if (SIP.Utils.isDecimal(connectionTimeout)) {
8295
+                                value = Number(connectionTimeout);
8296
+                                if (value > 0) {
8297
+                                    return value;
8298
+                                }
8299
+                            }
8300
+                        },
8301
+                        maxReconnectionAttempts: function (maxReconnectionAttempts) {
8302
+                            var value;
8303
+                            if (SIP.Utils.isDecimal(maxReconnectionAttempts)) {
8304
+                                value = Number(maxReconnectionAttempts);
8305
+                                if (value >= 0) {
8306
+                                    return value;
8307
+                                }
8308
+                            }
8309
+                        },
8310
+                        reconnectionTimeout: function (reconnectionTimeout) {
8311
+                            var value;
8312
+                            if (SIP.Utils.isDecimal(reconnectionTimeout)) {
8313
+                                value = Number(reconnectionTimeout);
8314
+                                if (value > 0) {
8315
+                                    return value;
8316
+                                }
8317
+                            }
8318
+                        }
8319
+                    }
8320
+                };
8321
+            } }
8322
+    });
8323
+    Transport.C = C;
8324
+    SIP.Web.Transport = Transport;
8325
+    return Transport;
8326
+};
8327
+
8328
+/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(28)))
8329
+
8330
+/***/ }),
8331
+/* 30 */
8332
+/***/ (function(module, exports, __webpack_require__) {
8333
+
8334
+"use strict";
8335
+/* WEBPACK VAR INJECTION */(function(global) {
8336
+/**
8337
+ * @fileoverview SessionDescriptionHandler
8338
+ */
8339
+/* SessionDescriptionHandler
8340
+ * @class PeerConnection helper Class.
8341
+ * @param {SIP.Session} session
8342
+ * @param {Object} [options]
8343
+ */
8344
+module.exports = function (SIP) {
8345
+    // Constructor
8346
+    var SessionDescriptionHandler = function (logger, observer, options) {
8347
+        // TODO: Validate the options
8348
+        this.options = options || {};
8349
+        this.logger = logger;
8350
+        this.observer = observer;
8351
+        this.dtmfSender = null;
8352
+        this.shouldAcquireMedia = true;
8353
+        this.CONTENT_TYPE = 'application/sdp';
8354
+        this.C = {};
8355
+        this.C.DIRECTION = {
8356
+            NULL: null,
8357
+            SENDRECV: "sendrecv",
8358
+            SENDONLY: "sendonly",
8359
+            RECVONLY: "recvonly",
8360
+            INACTIVE: "inactive"
8361
+        };
8362
+        this.logger.log('SessionDescriptionHandlerOptions: ' + JSON.stringify(this.options));
8363
+        this.direction = this.C.DIRECTION.NULL;
8364
+        this.modifiers = this.options.modifiers || [];
8365
+        if (!Array.isArray(this.modifiers)) {
8366
+            this.modifiers = [this.modifiers];
8367
+        }
8368
+        var environment = global.window || global;
8369
+        this.WebRTC = {
8370
+            MediaStream: environment.MediaStream,
8371
+            getUserMedia: environment.navigator.mediaDevices.getUserMedia.bind(environment.navigator.mediaDevices),
8372
+            RTCPeerConnection: environment.RTCPeerConnection
8373
+        };
8374
+        this.iceGatheringDeferred = null;
8375
+        this.iceGatheringTimeout = false;
8376
+        this.iceGatheringTimer = null;
8377
+        this.initPeerConnection(this.options.peerConnectionOptions);
8378
+        this.constraints = this.checkAndDefaultConstraints(this.options.constraints);
8379
+    };
8380
+    /**
8381
+     * @param {SIP.Session} session
8382
+     * @param {Object} [options]
8383
+     */
8384
+    SessionDescriptionHandler.defaultFactory = function defaultFactory(session, options) {
8385
+        var logger = session.ua.getLogger('sip.invitecontext.sessionDescriptionHandler', session.id);
8386
+        var SessionDescriptionHandlerObserver = __webpack_require__(31);
8387
+        var observer = new SessionDescriptionHandlerObserver(session, options);
8388
+        return new SessionDescriptionHandler(logger, observer, options);
8389
+    };
8390
+    SessionDescriptionHandler.prototype = Object.create(SIP.SessionDescriptionHandler.prototype, {
8391
+        // Functions the sesssion can use
8392
+        /**
8393
+         * Destructor
8394
+         */
8395
+        close: { writable: true, value: function () {
8396
+                this.logger.log('closing PeerConnection');
8397
+                // have to check signalingState since this.close() gets called multiple times
8398
+                if (this.peerConnection && this.peerConnection.signalingState !== 'closed') {
8399
+                    if (this.peerConnection.getSenders) {
8400
+                        this.peerConnection.getSenders().forEach(function (sender) {
8401
+                            if (sender.track) {
8402
+                                sender.track.stop();
8403
+                            }
8404
+                        });
8405
+                    }
8406
+                    else {
8407
+                        this.logger.warn('Using getLocalStreams which is deprecated');
8408
+                        this.peerConnection.getLocalStreams().forEach(function (stream) {
8409
+                            stream.getTracks().forEach(function (track) {
8410
+                                track.stop();
8411
+                            });
8412
+                        });
8413
+                    }
8414
+                    if (this.peerConnection.getReceivers) {
8415
+                        this.peerConnection.getReceivers().forEach(function (receiver) {
8416
+                            if (receiver.track) {
8417
+                                receiver.track.stop();
8418
+                            }
8419
+                        });
8420
+                    }
8421
+                    else {
8422
+                        this.logger.warn('Using getRemoteStreams which is deprecated');
8423
+                        this.peerConnection.getRemoteStreams().forEach(function (stream) {
8424
+                            stream.getTracks().forEach(function (track) {
8425
+                                track.stop();
8426
+                            });
8427
+                        });
8428
+                    }
8429
+                    this.resetIceGatheringComplete();
8430
+                    this.peerConnection.close();
8431
+                }
8432
+            } },
8433
+        /**
8434
+         * Gets the local description from the underlying media implementation
8435
+         * @param {Object} [options] Options object to be used by getDescription
8436
+         * @param {MediaStreamConstraints} [options.constraints] MediaStreamConstraints https://developer.mozilla.org/en-US/docs/Web/API/MediaStreamConstraints
8437
+         * @param {Object} [options.peerConnectionOptions] If this is set it will recreate the peer connection with the new options
8438
+         * @param {Array} [modifiers] Array with one time use description modifiers
8439
+         * @returns {Promise} Promise that resolves with the local description to be used for the session
8440
+         */
8441
+        getDescription: { writable: true, value: function (options, modifiers) {
8442
+                options = options || {};
8443
+                if (options.peerConnectionOptions) {
8444
+                    this.initPeerConnection(options.peerConnectionOptions);
8445
+                }
8446
+                // Merge passed constraints with saved constraints and save
8447
+                var newConstraints = Object.assign({}, this.constraints, options.constraints);
8448
+                newConstraints = this.checkAndDefaultConstraints(newConstraints);
8449
+                if (JSON.stringify(newConstraints) !== JSON.stringify(this.constraints)) {
8450
+                    this.constraints = newConstraints;
8451
+                    this.shouldAcquireMedia = true;
8452
+                }
8453
+                modifiers = modifiers || [];
8454
+                if (!Array.isArray(modifiers)) {
8455
+                    modifiers = [modifiers];
8456
+                }
8457
+                modifiers = modifiers.concat(this.modifiers);
8458
+                return SIP.Utils.Promise.resolve()
8459
+                    .then(function () {
8460
+                    if (this.shouldAcquireMedia) {
8461
+                        return this.acquire(this.constraints).then(function () {
8462
+                            this.shouldAcquireMedia = false;
8463
+                        }.bind(this));
8464
+                    }
8465
+                }.bind(this))
8466
+                    .then(function () {
8467
+                    return this.createOfferOrAnswer(options.RTCOfferOptions, modifiers);
8468
+                }.bind(this))
8469
+                    .then(function (description) {
8470
+                    this.emit('getDescription', description);
8471
+                    return {
8472
+                        body: description.sdp,
8473
+                        contentType: this.CONTENT_TYPE
8474
+                    };
8475
+                }.bind(this));
8476
+            } },
8477
+        /**
8478
+         * Check if the Session Description Handler can handle the Content-Type described by a SIP Message
8479
+         * @param {String} contentType The content type that is in the SIP Message
8480
+         * @returns {boolean}
8481
+         */
8482
+        hasDescription: { writable: true, value: function hasDescription(contentType) {
8483
+                return contentType === this.CONTENT_TYPE;
8484
+            } },
8485
+        /**
8486
+         * The modifier that should be used when the session would like to place the call on hold
8487
+         * @param {String} [sdp] The description that will be modified
8488
+         * @returns {Promise} Promise that resolves with modified SDP
8489
+         */
8490
+        holdModifier: { writable: true, value: function holdModifier(description) {
8491
+                if (!(/a=(sendrecv|sendonly|recvonly|inactive)/).test(description.sdp)) {
8492
+                    description.sdp = description.sdp.replace(/(m=[^\r]*\r\n)/g, '$1a=sendonly\r\n');
8493
+                }
8494
+                else {
8495
+                    description.sdp = description.sdp.replace(/a=sendrecv\r\n/g, 'a=sendonly\r\n');
8496
+                    description.sdp = description.sdp.replace(/a=recvonly\r\n/g, 'a=inactive\r\n');
8497
+                }
8498
+                return SIP.Utils.Promise.resolve(description);
8499
+            } },
8500
+        /**
8501
+         * Set the remote description to the underlying media implementation
8502
+         * @param {String} sessionDescription The description provided by a SIP message to be set on the media implementation
8503
+         * @param {Object} [options] Options object to be used by getDescription
8504
+         * @param {MediaStreamConstraints} [options.constraints] MediaStreamConstraints https://developer.mozilla.org/en-US/docs/Web/API/MediaStreamConstraints
8505
+         * @param {Object} [options.peerConnectionOptions] If this is set it will recreate the peer connection with the new options
8506
+         * @param {Array} [modifiers] Array with one time use description modifiers
8507
+         * @returns {Promise} Promise that resolves once the description is set
8508
+         */
8509
+        setDescription: { writable: true, value: function setDescription(sessionDescription, options, modifiers) {
8510
+                var _this = this;
8511
+                var self = this;
8512
+                options = options || {};
8513
+                if (options.peerConnectionOptions) {
8514
+                    this.initPeerConnection(options.peerConnectionOptions);
8515
+                }
8516
+                modifiers = modifiers || [];
8517
+                if (!Array.isArray(modifiers)) {
8518
+                    modifiers = [modifiers];
8519
+                }
8520
+                modifiers = modifiers.concat(this.modifiers);
8521
+                var description = {
8522
+                    type: this.hasOffer('local') ? 'answer' : 'offer',
8523
+                    sdp: sessionDescription
8524
+                };
8525
+                return SIP.Utils.Promise.resolve()
8526
+                    .then(function () {
8527
+                    // Media should be acquired in getDescription unless we need to do it sooner for some reason (FF61+)
8528
+                    if (this.shouldAcquireMedia && this.options.alwaysAcquireMediaFirst) {
8529
+                        return this.acquire(this.constraints).then(function () {
8530
+                            this.shouldAcquireMedia = false;
8531
+                        }.bind(this));
8532
+                    }
8533
+                }.bind(this))
8534
+                    .then(function () {
8535
+                    return SIP.Utils.reducePromises(modifiers, description);
8536
+                })
8537
+                    .catch(function (e) {
8538
+                    if (e instanceof SIP.Exceptions.SessionDescriptionHandlerError) {
8539
+                        throw e;
8540
+                    }
8541
+                    var error = new SIP.Exceptions.SessionDescriptionHandlerError("setDescription", e, "The modifiers did not resolve successfully");
8542
+                    _this.logger.error(error.message);
8543
+                    self.emit('peerConnection-setRemoteDescriptionFailed', error);
8544
+                    throw error;
8545
+                })
8546
+                    .then(function (modifiedDescription) {
8547
+                    self.emit('setDescription', modifiedDescription);
8548
+                    return self.peerConnection.setRemoteDescription(modifiedDescription);
8549
+                })
8550
+                    .catch(function (e) {
8551
+                    if (e instanceof SIP.Exceptions.SessionDescriptionHandlerError) {
8552
+                        throw e;
8553
+                    }
8554
+                    // Check the original SDP for video, and ensure that we have want to do audio fallback
8555
+                    if ((/^m=video.+$/gm).test(sessionDescription) && !options.disableAudioFallback) {
8556
+                        // Do not try to audio fallback again
8557
+                        options.disableAudioFallback = true;
8558
+                        // Remove video first, then do the other modifiers
8559
+                        return _this.setDescription(sessionDescription, options, [SIP.Web.Modifiers.stripVideo].concat(modifiers));
8560
+                    }
8561
+                    var error = new SIP.Exceptions.SessionDescriptionHandlerError("setDescription", e);
8562
+                    _this.logger.error(error.error);
8563
+                    _this.emit('peerConnection-setRemoteDescriptionFailed', error);
8564
+                    throw error;
8565
+                })
8566
+                    .then(function setRemoteDescriptionSuccess() {
8567
+                    if (self.peerConnection.getReceivers) {
8568
+                        self.emit('setRemoteDescription', self.peerConnection.getReceivers());
8569
+                    }
8570
+                    else {
8571
+                        self.emit('setRemoteDescription', self.peerConnection.getRemoteStreams());
8572
+                    }
8573
+                    self.emit('confirmed', self);
8574
+                });
8575
+            } },
8576
+        /**
8577
+         * Send DTMF via RTP (RFC 4733)
8578
+         * @param {String} tones A string containing DTMF digits
8579
+         * @param {Object} [options] Options object to be used by sendDtmf
8580
+         * @returns {boolean} true if DTMF send is successful, false otherwise
8581
+         */
8582
+        sendDtmf: { writable: true, value: function sendDtmf(tones, options) {
8583
+                if (!this.dtmfSender && this.hasBrowserGetSenderSupport()) {
8584
+                    var senders = this.peerConnection.getSenders();
8585
+                    if (senders.length > 0) {
8586
+                        this.dtmfSender = senders[0].dtmf;
8587
+                    }
8588
+                }
8589
+                if (!this.dtmfSender && this.hasBrowserTrackSupport()) {
8590
+                    var streams = this.peerConnection.getLocalStreams();
8591
+                    if (streams.length > 0) {
8592
+                        var audioTracks = streams[0].getAudioTracks();
8593
+                        if (audioTracks.length > 0) {
8594
+                            this.dtmfSender = this.peerConnection.createDTMFSender(audioTracks[0]);
8595
+                        }
8596
+                    }
8597
+                }
8598
+                if (!this.dtmfSender) {
8599
+                    return false;
8600
+                }
8601
+                try {
8602
+                    this.dtmfSender.insertDTMF(tones, options.duration, options.interToneGap);
8603
+                }
8604
+                catch (e) {
8605
+                    if (e.type === "InvalidStateError" || e.type === "InvalidCharacterError") {
8606
+                        this.logger.error(e);
8607
+                        return false;
8608
+                    }
8609
+                    else {
8610
+                        throw e;
8611
+                    }
8612
+                }
8613
+                this.logger.log('DTMF sent via RTP: ' + tones.toString());
8614
+                return true;
8615
+            } },
8616
+        getDirection: { writable: true, value: function getDirection() {
8617
+                return this.direction;
8618
+            } },
8619
+        // Internal functions
8620
+        createOfferOrAnswer: { writable: true, value: function createOfferOrAnswer(RTCOfferOptions, modifiers) {
8621
+                var _this = this;
8622
+                var self = this;
8623
+                var methodName;
8624
+                var pc = this.peerConnection;
8625
+                RTCOfferOptions = RTCOfferOptions || {};
8626
+                methodName = self.hasOffer('remote') ? 'createAnswer' : 'createOffer';
8627
+                return pc[methodName](RTCOfferOptions)
8628
+                    .catch(function (e) {
8629
+                    if (e instanceof SIP.Exceptions.SessionDescriptionHandlerError) {
8630
+                        throw e;
8631
+                    }
8632
+                    var error = new SIP.Exceptions.SessionDescriptionHandlerError("createOfferOrAnswer", e, 'peerConnection-' + methodName + 'Failed');
8633
+                    _this.emit('peerConnection-' + methodName + 'Failed', error);
8634
+                    throw error;
8635
+                })
8636
+                    .then(function (sdp) {
8637
+                    return SIP.Utils.reducePromises(modifiers, self.createRTCSessionDescriptionInit(sdp));
8638
+                })
8639
+                    .then(function (sdp) {
8640
+                    self.resetIceGatheringComplete();
8641
+                    return pc.setLocalDescription(sdp);
8642
+                })
8643
+                    .catch(function (e) {
8644
+                    if (e instanceof SIP.Exceptions.SessionDescriptionHandlerError) {
8645
+                        throw e;
8646
+                    }
8647
+                    var error = new SIP.Exceptions.SessionDescriptionHandlerError("createOfferOrAnswer", e, 'peerConnection-SetLocalDescriptionFailed');
8648
+                    _this.emit('peerConnection-SetLocalDescriptionFailed', error);
8649
+                    throw error;
8650
+                })
8651
+                    .then(function onSetLocalDescriptionSuccess() {
8652
+                    return self.waitForIceGatheringComplete();
8653
+                })
8654
+                    .then(function readySuccess() {
8655
+                    var localDescription = self.createRTCSessionDescriptionInit(self.peerConnection.localDescription);
8656
+                    return SIP.Utils.reducePromises(modifiers, localDescription);
8657
+                })
8658
+                    .then(function (localDescription) {
8659
+                    self.setDirection(localDescription.sdp);
8660
+                    return localDescription;
8661
+                })
8662
+                    .catch(function (e) {
8663
+                    if (e instanceof SIP.Exceptions.SessionDescriptionHandlerError) {
8664
+                        throw e;
8665
+                    }
8666
+                    var error = new SIP.Exceptions.SessionDescriptionHandlerError("createOfferOrAnswer", e);
8667
+                    _this.logger.error(error);
8668
+                    throw error;
8669
+                });
8670
+            } },
8671
+        // Creates an RTCSessionDescriptionInit from an RTCSessionDescription
8672
+        createRTCSessionDescriptionInit: { writable: true, value: function createRTCSessionDescriptionInit(RTCSessionDescription) {
8673
+                return {
8674
+                    type: RTCSessionDescription.type,
8675
+                    sdp: RTCSessionDescription.sdp
8676
+                };
8677
+            } },
8678
+        addDefaultIceCheckingTimeout: { writable: true, value: function addDefaultIceCheckingTimeout(peerConnectionOptions) {
8679
+                if (peerConnectionOptions.iceCheckingTimeout === undefined) {
8680
+                    peerConnectionOptions.iceCheckingTimeout = 5000;
8681
+                }
8682
+                return peerConnectionOptions;
8683
+            } },
8684
+        addDefaultIceServers: { writable: true, value: function addDefaultIceServers(rtcConfiguration) {
8685
+                if (!rtcConfiguration.iceServers) {
8686
+                    rtcConfiguration.iceServers = [{ urls: 'stun:stun.l.google.com:19302' }];
8687
+                }
8688
+                return rtcConfiguration;
8689
+            } },
8690
+        checkAndDefaultConstraints: { writable: true, value: function checkAndDefaultConstraints(constraints) {
8691
+                var defaultConstraints = { audio: true, video: !this.options.alwaysAcquireMediaFirst };
8692
+                constraints = constraints || defaultConstraints;
8693
+                // Empty object check
8694
+                if (Object.keys(constraints).length === 0 && constraints.constructor === Object) {
8695
+                    return defaultConstraints;
8696
+                }
8697
+                return constraints;
8698
+            } },
8699
+        hasBrowserTrackSupport: { writable: true, value: function hasBrowserTrackSupport() {
8700
+                return Boolean(this.peerConnection.addTrack);
8701
+            } },
8702
+        hasBrowserGetSenderSupport: { writable: true, value: function hasBrowserGetSenderSupport() {
8703
+                return Boolean(this.peerConnection.getSenders);
8704
+            } },
8705
+        initPeerConnection: { writable: true, value: function initPeerConnection(options) {
8706
+                var self = this;
8707
+                options = options || {};
8708
+                options = this.addDefaultIceCheckingTimeout(options);
8709
+                options.rtcConfiguration = options.rtcConfiguration || {};
8710
+                options.rtcConfiguration = this.addDefaultIceServers(options.rtcConfiguration);
8711
+                this.logger.log('initPeerConnection');
8712
+                if (this.peerConnection) {
8713
+                    this.logger.log('Already have a peer connection for this session. Tearing down.');
8714
+                    this.resetIceGatheringComplete();
8715
+                    this.peerConnection.close();
8716
+                }
8717
+                this.peerConnection = new this.WebRTC.RTCPeerConnection(options.rtcConfiguration);
8718
+                this.logger.log('New peer connection created');
8719
+                if ('ontrack' in this.peerConnection) {
8720
+                    this.peerConnection.addEventListener('track', function (e) {
8721
+                        self.logger.log('track added');
8722
+                        self.observer.trackAdded();
8723
+                        self.emit('addTrack', e);
8724
+                    });
8725
+                }
8726
+                else {
8727
+                    this.logger.warn('Using onaddstream which is deprecated');
8728
+                    this.peerConnection.onaddstream = function (e) {
8729
+                        self.logger.log('stream added');
8730
+                        self.emit('addStream', e);
8731
+                    };
8732
+                }
8733
+                this.peerConnection.onicecandidate = function (e) {
8734
+                    self.emit('iceCandidate', e);
8735
+                    if (e.candidate) {
8736
+                        self.logger.log('ICE candidate received: ' + (e.candidate.candidate === null ? null : e.candidate.candidate.trim()));
8737
+                    }
8738
+                    else if (e.candidate === null) {
8739
+                        // indicates the end of candidate gathering
8740
+                        self.logger.log('ICE candidate gathering complete');
8741
+                        self.triggerIceGatheringComplete();
8742
+                    }
8743
+                };
8744
+                this.peerConnection.onicegatheringstatechange = function () {
8745
+                    self.logger.log('RTCIceGatheringState changed: ' + this.iceGatheringState);
8746
+                    switch (this.iceGatheringState) {
8747
+                        case 'gathering':
8748
+                            self.emit('iceGathering', this);
8749
+                            if (!self.iceGatheringTimer && options.iceCheckingTimeout) {
8750
+                                self.iceGatheringTimeout = false;
8751
+                                self.iceGatheringTimer = SIP.Timers.setTimeout(function () {
8752
+                                    self.logger.log('RTCIceChecking Timeout Triggered after ' + options.iceCheckingTimeout + ' milliseconds');
8753
+                                    self.iceGatheringTimeout = true;
8754
+                                    self.triggerIceGatheringComplete();
8755
+                                }, options.iceCheckingTimeout);
8756
+                            }
8757
+                            break;
8758
+                        case 'complete':
8759
+                            self.triggerIceGatheringComplete();
8760
+                            break;
8761
+                    }
8762
+                };
8763
+                this.peerConnection.oniceconnectionstatechange = function () {
8764
+                    var stateEvent;
8765
+                    switch (this.iceConnectionState) {
8766
+                        case 'new':
8767
+                            stateEvent = 'iceConnection';
8768
+                            break;
8769
+                        case 'checking':
8770
+                            stateEvent = 'iceConnectionChecking';
8771
+                            break;
8772
+                        case 'connected':
8773
+                            stateEvent = 'iceConnectionConnected';
8774
+                            break;
8775
+                        case 'completed':
8776
+                            stateEvent = 'iceConnectionCompleted';
8777
+                            break;
8778
+                        case 'failed':
8779
+                            stateEvent = 'iceConnectionFailed';
8780
+                            break;
8781
+                        case 'disconnected':
8782
+                            stateEvent = 'iceConnectionDisconnected';
8783
+                            break;
8784
+                        case 'closed':
8785
+                            stateEvent = 'iceConnectionClosed';
8786
+                            break;
8787
+                        default:
8788
+                            self.logger.warn('Unknown iceConnection state:', this.iceConnectionState);
8789
+                            return;
8790
+                    }
8791
+                    self.emit(stateEvent, this);
8792
+                };
8793
+            } },
8794
+        acquire: { writable: true, value: function acquire(constraints) {
8795
+                var _this = this;
8796
+                // Default audio & video to true
8797
+                constraints = this.checkAndDefaultConstraints(constraints);
8798
+                return new SIP.Utils.Promise(function (resolve, reject) {
8799
+                    /*
8800
+                     * Make the call asynchronous, so that ICCs have a chance
8801
+                     * to define callbacks to `userMediaRequest`
8802
+                     */
8803
+                    this.logger.log('acquiring local media');
8804
+                    this.emit('userMediaRequest', constraints);
8805
+                    if (constraints.audio || constraints.video) {
8806
+                        this.WebRTC.getUserMedia(constraints)
8807
+                            .then(function (streams) {
8808
+                            this.observer.trackAdded();
8809
+                            this.emit('userMedia', streams);
8810
+                            resolve(streams);
8811
+                        }.bind(this)).catch(function (e) {
8812
+                            this.emit('userMediaFailed', e);
8813
+                            reject(e);
8814
+                        }.bind(this));
8815
+                    }
8816
+                    else {
8817
+                        // Local streams were explicitly excluded.
8818
+                        resolve([]);
8819
+                    }
8820
+                }.bind(this))
8821
+                    .catch(function (e) {
8822
+                    // TODO: This propogates downwards
8823
+                    if (e instanceof SIP.Exceptions.SessionDescriptionHandlerError) {
8824
+                        throw e;
8825
+                    }
8826
+                    var error = new SIP.Exceptions.SessionDescriptionHandlerError("acquire", e, "unable to acquire streams");
8827
+                    _this.logger.error(error.message);
8828
+                    _this.logger.error(error.error);
8829
+                    throw error;
8830
+                })
8831
+                    .then(function acquireSucceeded(streams) {
8832
+                    this.logger.log('acquired local media streams');
8833
+                    try {
8834
+                        // Remove old tracks
8835
+                        if (this.peerConnection.removeTrack) {
8836
+                            this.peerConnection.getSenders().forEach(function (sender) {
8837
+                                this.peerConnection.removeTrack(sender);
8838
+                            }, this);
8839
+                        }
8840
+                        return streams;
8841
+                    }
8842
+                    catch (e) {
8843
+                        return SIP.Utils.Promise.reject(e);
8844
+                    }
8845
+                }.bind(this))
8846
+                    .catch(function (e) {
8847
+                    if (e instanceof SIP.Exceptions.SessionDescriptionHandlerError) {
8848
+                        throw e;
8849
+                    }
8850
+                    var error = new SIP.Exceptions.SessionDescriptionHandlerError("acquire", e, "error removing streams");
8851
+                    _this.logger.error(error.message);
8852
+                    _this.logger.error(error.error);
8853
+                    throw error;
8854
+                })
8855
+                    .then(function addStreams(streams) {
8856
+                    try {
8857
+                        streams = [].concat(streams);
8858
+                        streams.forEach(function (stream) {
8859
+                            if (this.peerConnection.addTrack) {
8860
+                                stream.getTracks().forEach(function (track) {
8861
+                                    this.peerConnection.addTrack(track, stream);
8862
+                                }, this);
8863
+                            }
8864
+                            else {
8865
+                                // Chrome 59 does not support addTrack
8866
+                                this.peerConnection.addStream(stream);
8867
+                            }
8868
+                        }, this);
8869
+                    }
8870
+                    catch (e) {
8871
+                        return SIP.Utils.Promise.reject(e);
8872
+                    }
8873
+                    return SIP.Utils.Promise.resolve();
8874
+                }.bind(this))
8875
+                    .catch(function (e) {
8876
+                    if (e instanceof SIP.Exceptions.SessionDescriptionHandlerError) {
8877
+                        throw e;
8878
+                    }
8879
+                    var error = new SIP.Exceptions.SessionDescriptionHandlerError("acquire", e, "error adding stream");
8880
+                    _this.logger.error(error.message);
8881
+                    _this.logger.error(error.error);
8882
+                    throw error;
8883
+                });
8884
+            } },
8885
+        hasOffer: { writable: true, value: function hasOffer(where) {
8886
+                var offerState = 'have-' + where + '-offer';
8887
+                return this.peerConnection.signalingState === offerState;
8888
+            } },
8889
+        // ICE gathering state handling
8890
+        isIceGatheringComplete: { writable: true, value: function isIceGatheringComplete() {
8891
+                return this.peerConnection.iceGatheringState === 'complete' || this.iceGatheringTimeout;
8892
+            } },
8893
+        resetIceGatheringComplete: { writable: true, value: function resetIceGatheringComplete() {
8894
+                this.iceGatheringTimeout = false;
8895
+                if (this.iceGatheringTimer) {
8896
+                    SIP.Timers.clearTimeout(this.iceGatheringTimer);
8897
+                    this.iceGatheringTimer = null;
8898
+                }
8899
+                if (this.iceGatheringDeferred) {
8900
+                    this.iceGatheringDeferred.reject();
8901
+                    this.iceGatheringDeferred = null;
8902
+                }
8903
+            } },
8904
+        setDirection: { writable: true, value: function setDirection(sdp) {
8905
+                var match = sdp.match(/a=(sendrecv|sendonly|recvonly|inactive)/);
8906
+                if (match === null) {
8907
+                    this.direction = this.C.DIRECTION.NULL;
8908
+                    this.observer.directionChanged();
8909
+                    return;
8910
+                }
8911
+                var direction = match[1];
8912
+                switch (direction) {
8913
+                    case this.C.DIRECTION.SENDRECV:
8914
+                    case this.C.DIRECTION.SENDONLY:
8915
+                    case this.C.DIRECTION.RECVONLY:
8916
+                    case this.C.DIRECTION.INACTIVE:
8917
+                        this.direction = direction;
8918
+                        break;
8919
+                    default:
8920
+                        this.direction = this.C.DIRECTION.NULL;
8921
+                        break;
8922
+                }
8923
+                this.observer.directionChanged();
8924
+            } },
8925
+        triggerIceGatheringComplete: { writable: true, value: function triggerIceGatheringComplete() {
8926
+                if (this.isIceGatheringComplete()) {
8927
+                    this.emit('iceGatheringComplete', this);
8928
+                    if (this.iceGatheringTimer) {
8929
+                        SIP.Timers.clearTimeout(this.iceGatheringTimer);
8930
+                        this.iceGatheringTimer = null;
8931
+                    }
8932
+                    if (this.iceGatheringDeferred) {
8933
+                        this.iceGatheringDeferred.resolve();
8934
+                        this.iceGatheringDeferred = null;
8935
+                    }
8936
+                }
8937
+            } },
8938
+        waitForIceGatheringComplete: { writable: true, value: function waitForIceGatheringComplete() {
8939
+                if (this.isIceGatheringComplete()) {
8940
+                    return SIP.Utils.Promise.resolve();
8941
+                }
8942
+                else if (!this.isIceGatheringDeferred) {
8943
+                    this.iceGatheringDeferred = SIP.Utils.defer();
8944
+                }
8945
+                return this.iceGatheringDeferred.promise;
8946
+            } }
8947
+    });
8948
+    return SessionDescriptionHandler;
8949
+};
8950
+
8951
+/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(28)))
8952
+
8953
+/***/ }),
8954
+/* 31 */
8955
+/***/ (function(module, exports, __webpack_require__) {
8956
+
8957
+"use strict";
8958
+
8959
+/**
8960
+ * @fileoverview SessionDescriptionHandlerObserver
8961
+ */
8962
+/* SessionDescriptionHandlerObserver
8963
+ * @class SessionDescriptionHandler Observer Class.
8964
+ * @param {SIP.Session} session
8965
+ * @param {Object} [options]
8966
+ */
8967
+// Constructor
8968
+var SessionDescriptionHandlerObserver = function (session, options) {
8969
+    this.session = session || {};
8970
+    this.options = options || {};
8971
+};
8972
+SessionDescriptionHandlerObserver.prototype = {
8973
+    trackAdded: function () {
8974
+        this.session.emit('trackAdded');
8975
+    },
8976
+    directionChanged: function () {
8977
+        this.session.emit('directionChanged');
8978
+    },
8979
+};
8980
+module.exports = SessionDescriptionHandlerObserver;
8981
+
8982
+
8983
+/***/ }),
8984
+/* 32 */
8985
+/***/ (function(module, exports, __webpack_require__) {
8986
+
8987
+"use strict";
8988
+
8989
+/**
8990
+ * @fileoverview Incoming SIP Message Sanity Check
8991
+ */
8992
+/**
8993
+ * SIP message sanity check.
8994
+ * @augments SIP
8995
+ * @function
8996
+ * @param {SIP.IncomingMessage} message
8997
+ * @param {SIP.UA} ua
8998
+ * @param {SIP.Transport} transport
8999
+ * @returns {Boolean}
9000
+ */
9001
+module.exports = function (SIP) {
9002
+    var sanityCheck, requests = [], responses = [], all = [];
9003
+    // Reply
9004
+    function reply(status_code, message, transport) {
9005
+        var to, response = SIP.Utils.buildStatusLine(status_code), vias = message.getHeaders('via'), length = vias.length, idx = 0;
9006
+        for (idx; idx < length; idx++) {
9007
+            response += "Via: " + vias[idx] + "\r\n";
9008
+        }
9009
+        to = message.getHeader('To');
9010
+        if (!message.to_tag) {
9011
+            to += ';tag=' + SIP.Utils.newTag();
9012
+        }
9013
+        response += "To: " + to + "\r\n";
9014
+        response += "From: " + message.getHeader('From') + "\r\n";
9015
+        response += "Call-ID: " + message.call_id + "\r\n";
9016
+        response += "CSeq: " + message.cseq + " " + message.method + "\r\n";
9017
+        response += "\r\n";
9018
+        transport.send(response);
9019
+    }
9020
+    /*
9021
+     * Sanity Check for incoming Messages
9022
+     *
9023
+     * Requests:
9024
+     *  - _rfc3261_8_2_2_1_ Receive a Request with a non supported URI scheme
9025
+     *  - _rfc3261_16_3_4_ Receive a Request already sent by us
9026
+     *   Does not look at via sent-by but at sipjsId, which is inserted as
9027
+     *   a prefix in all initial requests generated by the ua
9028
+     *  - _rfc3261_18_3_request_ Body Content-Length
9029
+     *  - _rfc3261_8_2_2_2_ Merged Requests
9030
+     *
9031
+     * Responses:
9032
+     *  - _rfc3261_8_1_3_3_ Multiple Via headers
9033
+     *  - _rfc3261_18_1_2_ sent-by mismatch
9034
+     *  - _rfc3261_18_3_response_ Body Content-Length
9035
+     *
9036
+     * All:
9037
+     *  - Minimum headers in a SIP message
9038
+     */
9039
+    // Sanity Check functions for requests
9040
+    function rfc3261_8_2_2_1(message, ua, transport) {
9041
+        if (!message.ruri || message.ruri.scheme !== 'sip') {
9042
+            reply(416, message, transport);
9043
+            return false;
9044
+        }
9045
+    }
9046
+    function rfc3261_16_3_4(message, ua, transport) {
9047
+        if (!message.to_tag) {
9048
+            if (message.call_id.substr(0, 5) === ua.configuration.sipjsId) {
9049
+                reply(482, message, transport);
9050
+                return false;
9051
+            }
9052
+        }
9053
+    }
9054
+    function rfc3261_18_3_request(message, ua, transport) {
9055
+        var len = SIP.Utils.str_utf8_length(message.body), contentLength = message.getHeader('content-length');
9056
+        if (len < contentLength) {
9057
+            reply(400, message, transport);
9058
+            return false;
9059
+        }
9060
+    }
9061
+    function rfc3261_8_2_2_2(message, ua, transport) {
9062
+        var tr, idx, fromTag = message.from_tag, call_id = message.call_id, cseq = message.cseq;
9063
+        if (!message.to_tag) {
9064
+            if (message.method === SIP.C.INVITE) {
9065
+                tr = ua.transactions.ist[message.via_branch];
9066
+                if (tr) {
9067
+                    return;
9068
+                }
9069
+                else {
9070
+                    for (idx in ua.transactions.ist) {
9071
+                        tr = ua.transactions.ist[idx];
9072
+                        if (tr.request.from_tag === fromTag && tr.request.call_id === call_id && tr.request.cseq === cseq) {
9073
+                            reply(482, message, transport);
9074
+                            return false;
9075
+                        }
9076
+                    }
9077
+                }
9078
+            }
9079
+            else {
9080
+                tr = ua.transactions.nist[message.via_branch];
9081
+                if (tr) {
9082
+                    return;
9083
+                }
9084
+                else {
9085
+                    for (idx in ua.transactions.nist) {
9086
+                        tr = ua.transactions.nist[idx];
9087
+                        if (tr.request.from_tag === fromTag && tr.request.call_id === call_id && tr.request.cseq === cseq) {
9088
+                            reply(482, message, transport);
9089
+                            return false;
9090
+                        }
9091
+                    }
9092
+                }
9093
+            }
9094
+        }
9095
+    }
9096
+    // Sanity Check functions for responses
9097
+    function rfc3261_8_1_3_3(message, ua) {
9098
+        if (message.getHeaders('via').length > 1) {
9099
+            ua.getLogger('sip.sanitycheck').warn('More than one Via header field present in the response. Dropping the response');
9100
+            return false;
9101
+        }
9102
+    }
9103
+    function rfc3261_18_1_2(message, ua) {
9104
+        var viaHost = ua.configuration.viaHost;
9105
+        if (message.via.host !== viaHost || message.via.port !== undefined) {
9106
+            ua.getLogger('sip.sanitycheck').warn('Via sent-by in the response does not match UA Via host value. Dropping the response');
9107
+            return false;
9108
+        }
9109
+    }
9110
+    function rfc3261_18_3_response(message, ua) {
9111
+        var len = SIP.Utils.str_utf8_length(message.body), contentLength = message.getHeader('content-length');
9112
+        if (len < contentLength) {
9113
+            ua.getLogger('sip.sanitycheck').warn('Message body length is lower than the value in Content-Length header field. Dropping the response');
9114
+            return false;
9115
+        }
9116
+    }
9117
+    // Sanity Check functions for requests and responses
9118
+    function minimumHeaders(message, ua) {
9119
+        var mandatoryHeaders = ['from', 'to', 'call_id', 'cseq', 'via'], idx = mandatoryHeaders.length;
9120
+        while (idx--) {
9121
+            if (!message.hasHeader(mandatoryHeaders[idx])) {
9122
+                ua.getLogger('sip.sanitycheck').warn('Missing mandatory header field : ' + mandatoryHeaders[idx] + '. Dropping the response');
9123
+                return false;
9124
+            }
9125
+        }
9126
+    }
9127
+    requests.push(rfc3261_8_2_2_1);
9128
+    requests.push(rfc3261_16_3_4);
9129
+    requests.push(rfc3261_18_3_request);
9130
+    requests.push(rfc3261_8_2_2_2);
9131
+    responses.push(rfc3261_8_1_3_3);
9132
+    responses.push(rfc3261_18_1_2);
9133
+    responses.push(rfc3261_18_3_response);
9134
+    all.push(minimumHeaders);
9135
+    sanityCheck = function (message, ua, transport) {
9136
+        var len, pass;
9137
+        len = all.length;
9138
+        while (len--) {
9139
+            pass = all[len](message, ua, transport);
9140
+            if (pass === false) {
9141
+                return false;
9142
+            }
9143
+        }
9144
+        if (message instanceof SIP.IncomingRequest) {
9145
+            len = requests.length;
9146
+            while (len--) {
9147
+                pass = requests[len](message, ua, transport);
9148
+                if (pass === false) {
9149
+                    return false;
9150
+                }
9151
+            }
9152
+        }
9153
+        else if (message instanceof SIP.IncomingResponse) {
9154
+            len = responses.length;
9155
+            while (len--) {
9156
+                pass = responses[len](message, ua, transport);
9157
+                if (pass === false) {
9158
+                    return false;
9159
+                }
9160
+            }
9161
+        }
9162
+        //Everything is OK
9163
+        return true;
9164
+    };
9165
+    SIP.sanityCheck = sanityCheck;
9166
+};
9167
+
9168
+
9169
+/***/ }),
9170
+/* 33 */
9171
+/***/ (function(module, exports, __webpack_require__) {
9172
+
9173
+"use strict";
9174
+
9175
+var md5 = __webpack_require__(34);
9176
+/**
9177
+ * @fileoverview SIP Digest Authentication
9178
+ */
9179
+/**
9180
+ * SIP Digest Authentication.
9181
+ * @augments SIP.
9182
+ * @function Digest Authentication
9183
+ * @param {SIP.UA} ua
9184
+ */
9185
+module.exports = function (Utils) {
9186
+    var DigestAuthentication;
9187
+    DigestAuthentication = function (ua) {
9188
+        this.logger = ua.getLogger('sipjs.digestauthentication');
9189
+        this.username = ua.configuration.authorizationUser;
9190
+        this.password = ua.configuration.password;
9191
+        this.cnonce = null;
9192
+        this.nc = 0;
9193
+        this.ncHex = '00000000';
9194
+        this.response = null;
9195
+    };
9196
+    /**
9197
+    * Performs Digest authentication given a SIP request and the challenge
9198
+    * received in a response to that request.
9199
+    * Returns true if credentials were successfully generated, false otherwise.
9200
+    *
9201
+    * @param {SIP.OutgoingRequest} request
9202
+    * @param {Object} challenge
9203
+    */
9204
+    DigestAuthentication.prototype.authenticate = function (request, challenge) {
9205
+        // Inspect and validate the challenge.
9206
+        this.algorithm = challenge.algorithm;
9207
+        this.realm = challenge.realm;
9208
+        this.nonce = challenge.nonce;
9209
+        this.opaque = challenge.opaque;
9210
+        this.stale = challenge.stale;
9211
+        if (this.algorithm) {
9212
+            if (this.algorithm !== 'MD5') {
9213
+                this.logger.warn('challenge with Digest algorithm different than "MD5", authentication aborted');
9214
+                return false;
9215
+            }
9216
+        }
9217
+        else {
9218
+            this.algorithm = 'MD5';
9219
+        }
9220
+        if (!this.realm) {
9221
+            this.logger.warn('challenge without Digest realm, authentication aborted');
9222
+            return false;
9223
+        }
9224
+        if (!this.nonce) {
9225
+            this.logger.warn('challenge without Digest nonce, authentication aborted');
9226
+            return false;
9227
+        }
9228
+        // 'qop' can contain a list of values (Array). Let's choose just one.
9229
+        if (challenge.qop) {
9230
+            if (challenge.qop.indexOf('auth') > -1) {
9231
+                this.qop = 'auth';
9232
+            }
9233
+            else if (challenge.qop.indexOf('auth-int') > -1) {
9234
+                this.qop = 'auth-int';
9235
+            }
9236
+            else {
9237
+                // Otherwise 'qop' is present but does not contain 'auth' or 'auth-int', so abort here.
9238
+                this.logger.warn('challenge without Digest qop different than "auth" or "auth-int", authentication aborted');
9239
+                return false;
9240
+            }
9241
+        }
9242
+        else {
9243
+            this.qop = null;
9244
+        }
9245
+        // Fill other attributes.
9246
+        this.method = request.method;
9247
+        this.uri = request.ruri;
9248
+        this.cnonce = Utils.createRandomToken(12);
9249
+        this.nc += 1;
9250
+        this.updateNcHex();
9251
+        // nc-value = 8LHEX. Max value = 'FFFFFFFF'.
9252
+        if (this.nc === 4294967296) {
9253
+            this.nc = 1;
9254
+            this.ncHex = '00000001';
9255
+        }
9256
+        // Calculate the Digest "response" value.
9257
+        this.calculateResponse();
9258
+        return true;
9259
+    };
9260
+    /**
9261
+    * Generate Digest 'response' value.
9262
+    * @private
9263
+    */
9264
+    DigestAuthentication.prototype.calculateResponse = function () {
9265
+        var ha1, ha2;
9266
+        // HA1 = MD5(A1) = MD5(username:realm:password)
9267
+        ha1 = md5(this.username + ":" + this.realm + ":" + this.password);
9268
+        if (this.qop === 'auth') {
9269
+            // HA2 = MD5(A2) = MD5(method:digestURI)
9270
+            ha2 = md5(this.method + ":" + this.uri);
9271
+            // response = MD5(HA1:nonce:nonceCount:credentialsNonce:qop:HA2)
9272
+            this.response = md5(ha1 + ":" + this.nonce + ":" + this.ncHex + ":" + this.cnonce + ":auth:" + ha2);
9273
+        }
9274
+        else if (this.qop === 'auth-int') {
9275
+            // HA2 = MD5(A2) = MD5(method:digestURI:MD5(entityBody))
9276
+            ha2 = md5(this.method + ":" + this.uri + ":" + md5(this.body ? this.body : ""));
9277
+            // response = MD5(HA1:nonce:nonceCount:credentialsNonce:qop:HA2)
9278
+            this.response = md5(ha1 + ":" + this.nonce + ":" + this.ncHex + ":" + this.cnonce + ":auth-int:" + ha2);
9279
+        }
9280
+        else if (this.qop === null) {
9281
+            // HA2 = MD5(A2) = MD5(method:digestURI)
9282
+            ha2 = md5(this.method + ":" + this.uri);
9283
+            // response = MD5(HA1:nonce:HA2)
9284
+            this.response = md5(ha1 + ":" + this.nonce + ":" + ha2);
9285
+        }
9286
+    };
9287
+    /**
9288
+    * Return the Proxy-Authorization or WWW-Authorization header value.
9289
+    */
9290
+    DigestAuthentication.prototype.toString = function () {
9291
+        var auth_params = [];
9292
+        if (!this.response) {
9293
+            throw new Error('response field does not exist, cannot generate Authorization header');
9294
+        }
9295
+        auth_params.push('algorithm=' + this.algorithm);
9296
+        auth_params.push('username="' + this.username + '"');
9297
+        auth_params.push('realm="' + this.realm + '"');
9298
+        auth_params.push('nonce="' + this.nonce + '"');
9299
+        auth_params.push('uri="' + this.uri + '"');
9300
+        auth_params.push('response="' + this.response + '"');
9301
+        if (this.opaque) {
9302
+            auth_params.push('opaque="' + this.opaque + '"');
9303
+        }
9304
+        if (this.qop) {
9305
+            auth_params.push('qop=' + this.qop);
9306
+            auth_params.push('cnonce="' + this.cnonce + '"');
9307
+            auth_params.push('nc=' + this.ncHex);
9308
+        }
9309
+        return 'Digest ' + auth_params.join(', ');
9310
+    };
9311
+    /**
9312
+    * Generate the 'nc' value as required by Digest in this.ncHex by reading this.nc.
9313
+    * @private
9314
+    */
9315
+    DigestAuthentication.prototype.updateNcHex = function () {
9316
+        var hex = Number(this.nc).toString(16);
9317
+        this.ncHex = '00000000'.substr(0, 8 - hex.length) + hex;
9318
+    };
9319
+    return DigestAuthentication;
9320
+};
9321
+
9322
+
9323
+/***/ }),
9324
+/* 34 */
9325
+/***/ (function(module, exports, __webpack_require__) {
9326
+
9327
+;(function (root, factory) {
9328
+	if (true) {
9329
+		// CommonJS
9330
+		module.exports = exports = factory(__webpack_require__(35));
9331
+	}
9332
+	else {}
9333
+}(this, function (CryptoJS) {
9334
+
9335
+	(function (Math) {
9336
+	    // Shortcuts
9337
+	    var C = CryptoJS;
9338
+	    var C_lib = C.lib;
9339
+	    var WordArray = C_lib.WordArray;
9340
+	    var Hasher = C_lib.Hasher;
9341
+	    var C_algo = C.algo;
9342
+
9343
+	    // Constants table
9344
+	    var T = [];
9345
+
9346
+	    // Compute constants
9347
+	    (function () {
9348
+	        for (var i = 0; i < 64; i++) {
9349
+	            T[i] = (Math.abs(Math.sin(i + 1)) * 0x100000000) | 0;
9350
+	        }
9351
+	    }());
9352
+
9353
+	    /**
9354
+	     * MD5 hash algorithm.
9355
+	     */
9356
+	    var MD5 = C_algo.MD5 = Hasher.extend({
9357
+	        _doReset: function () {
9358
+	            this._hash = new WordArray.init([
9359
+	                0x67452301, 0xefcdab89,
9360
+	                0x98badcfe, 0x10325476
9361
+	            ]);
9362
+	        },
9363
+
9364
+	        _doProcessBlock: function (M, offset) {
9365
+	            // Swap endian
9366
+	            for (var i = 0; i < 16; i++) {
9367
+	                // Shortcuts
9368
+	                var offset_i = offset + i;
9369
+	                var M_offset_i = M[offset_i];
9370
+
9371
+	                M[offset_i] = (
9372
+	                    (((M_offset_i << 8)  | (M_offset_i >>> 24)) & 0x00ff00ff) |
9373
+	                    (((M_offset_i << 24) | (M_offset_i >>> 8))  & 0xff00ff00)
9374
+	                );
9375
+	            }
9376
+
9377
+	            // Shortcuts
9378
+	            var H = this._hash.words;
9379
+
9380
+	            var M_offset_0  = M[offset + 0];
9381
+	            var M_offset_1  = M[offset + 1];
9382
+	            var M_offset_2  = M[offset + 2];
9383
+	            var M_offset_3  = M[offset + 3];
9384
+	            var M_offset_4  = M[offset + 4];
9385
+	            var M_offset_5  = M[offset + 5];
9386
+	            var M_offset_6  = M[offset + 6];
9387
+	            var M_offset_7  = M[offset + 7];
9388
+	            var M_offset_8  = M[offset + 8];
9389
+	            var M_offset_9  = M[offset + 9];
9390
+	            var M_offset_10 = M[offset + 10];
9391
+	            var M_offset_11 = M[offset + 11];
9392
+	            var M_offset_12 = M[offset + 12];
9393
+	            var M_offset_13 = M[offset + 13];
9394
+	            var M_offset_14 = M[offset + 14];
9395
+	            var M_offset_15 = M[offset + 15];
9396
+
9397
+	            // Working varialbes
9398
+	            var a = H[0];
9399
+	            var b = H[1];
9400
+	            var c = H[2];
9401
+	            var d = H[3];
9402
+
9403
+	            // Computation
9404
+	            a = FF(a, b, c, d, M_offset_0,  7,  T[0]);
9405
+	            d = FF(d, a, b, c, M_offset_1,  12, T[1]);
9406
+	            c = FF(c, d, a, b, M_offset_2,  17, T[2]);
9407
+	            b = FF(b, c, d, a, M_offset_3,  22, T[3]);
9408
+	            a = FF(a, b, c, d, M_offset_4,  7,  T[4]);
9409
+	            d = FF(d, a, b, c, M_offset_5,  12, T[5]);
9410
+	            c = FF(c, d, a, b, M_offset_6,  17, T[6]);
9411
+	            b = FF(b, c, d, a, M_offset_7,  22, T[7]);
9412
+	            a = FF(a, b, c, d, M_offset_8,  7,  T[8]);
9413
+	            d = FF(d, a, b, c, M_offset_9,  12, T[9]);
9414
+	            c = FF(c, d, a, b, M_offset_10, 17, T[10]);
9415
+	            b = FF(b, c, d, a, M_offset_11, 22, T[11]);
9416
+	            a = FF(a, b, c, d, M_offset_12, 7,  T[12]);
9417
+	            d = FF(d, a, b, c, M_offset_13, 12, T[13]);
9418
+	            c = FF(c, d, a, b, M_offset_14, 17, T[14]);
9419
+	            b = FF(b, c, d, a, M_offset_15, 22, T[15]);
9420
+
9421
+	            a = GG(a, b, c, d, M_offset_1,  5,  T[16]);
9422
+	            d = GG(d, a, b, c, M_offset_6,  9,  T[17]);
9423
+	            c = GG(c, d, a, b, M_offset_11, 14, T[18]);
9424
+	            b = GG(b, c, d, a, M_offset_0,  20, T[19]);
9425
+	            a = GG(a, b, c, d, M_offset_5,  5,  T[20]);
9426
+	            d = GG(d, a, b, c, M_offset_10, 9,  T[21]);
9427
+	            c = GG(c, d, a, b, M_offset_15, 14, T[22]);
9428
+	            b = GG(b, c, d, a, M_offset_4,  20, T[23]);
9429
+	            a = GG(a, b, c, d, M_offset_9,  5,  T[24]);
9430
+	            d = GG(d, a, b, c, M_offset_14, 9,  T[25]);
9431
+	            c = GG(c, d, a, b, M_offset_3,  14, T[26]);
9432
+	            b = GG(b, c, d, a, M_offset_8,  20, T[27]);
9433
+	            a = GG(a, b, c, d, M_offset_13, 5,  T[28]);
9434
+	            d = GG(d, a, b, c, M_offset_2,  9,  T[29]);
9435
+	            c = GG(c, d, a, b, M_offset_7,  14, T[30]);
9436
+	            b = GG(b, c, d, a, M_offset_12, 20, T[31]);
9437
+
9438
+	            a = HH(a, b, c, d, M_offset_5,  4,  T[32]);
9439
+	            d = HH(d, a, b, c, M_offset_8,  11, T[33]);
9440
+	            c = HH(c, d, a, b, M_offset_11, 16, T[34]);
9441
+	            b = HH(b, c, d, a, M_offset_14, 23, T[35]);
9442
+	            a = HH(a, b, c, d, M_offset_1,  4,  T[36]);
9443
+	            d = HH(d, a, b, c, M_offset_4,  11, T[37]);
9444
+	            c = HH(c, d, a, b, M_offset_7,  16, T[38]);
9445
+	            b = HH(b, c, d, a, M_offset_10, 23, T[39]);
9446
+	            a = HH(a, b, c, d, M_offset_13, 4,  T[40]);
9447
+	            d = HH(d, a, b, c, M_offset_0,  11, T[41]);
9448
+	            c = HH(c, d, a, b, M_offset_3,  16, T[42]);
9449
+	            b = HH(b, c, d, a, M_offset_6,  23, T[43]);
9450
+	            a = HH(a, b, c, d, M_offset_9,  4,  T[44]);
9451
+	            d = HH(d, a, b, c, M_offset_12, 11, T[45]);
9452
+	            c = HH(c, d, a, b, M_offset_15, 16, T[46]);
9453
+	            b = HH(b, c, d, a, M_offset_2,  23, T[47]);
9454
+
9455
+	            a = II(a, b, c, d, M_offset_0,  6,  T[48]);
9456
+	            d = II(d, a, b, c, M_offset_7,  10, T[49]);
9457
+	            c = II(c, d, a, b, M_offset_14, 15, T[50]);
9458
+	            b = II(b, c, d, a, M_offset_5,  21, T[51]);
9459
+	            a = II(a, b, c, d, M_offset_12, 6,  T[52]);
9460
+	            d = II(d, a, b, c, M_offset_3,  10, T[53]);
9461
+	            c = II(c, d, a, b, M_offset_10, 15, T[54]);
9462
+	            b = II(b, c, d, a, M_offset_1,  21, T[55]);
9463
+	            a = II(a, b, c, d, M_offset_8,  6,  T[56]);
9464
+	            d = II(d, a, b, c, M_offset_15, 10, T[57]);
9465
+	            c = II(c, d, a, b, M_offset_6,  15, T[58]);
9466
+	            b = II(b, c, d, a, M_offset_13, 21, T[59]);
9467
+	            a = II(a, b, c, d, M_offset_4,  6,  T[60]);
9468
+	            d = II(d, a, b, c, M_offset_11, 10, T[61]);
9469
+	            c = II(c, d, a, b, M_offset_2,  15, T[62]);
9470
+	            b = II(b, c, d, a, M_offset_9,  21, T[63]);
9471
+
9472
+	            // Intermediate hash value
9473
+	            H[0] = (H[0] + a) | 0;
9474
+	            H[1] = (H[1] + b) | 0;
9475
+	            H[2] = (H[2] + c) | 0;
9476
+	            H[3] = (H[3] + d) | 0;
9477
+	        },
9478
+
9479
+	        _doFinalize: function () {
9480
+	            // Shortcuts
9481
+	            var data = this._data;
9482
+	            var dataWords = data.words;
9483
+
9484
+	            var nBitsTotal = this._nDataBytes * 8;
9485
+	            var nBitsLeft = data.sigBytes * 8;
9486
+
9487
+	            // Add padding
9488
+	            dataWords[nBitsLeft >>> 5] |= 0x80 << (24 - nBitsLeft % 32);
9489
+
9490
+	            var nBitsTotalH = Math.floor(nBitsTotal / 0x100000000);
9491
+	            var nBitsTotalL = nBitsTotal;
9492
+	            dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 15] = (
9493
+	                (((nBitsTotalH << 8)  | (nBitsTotalH >>> 24)) & 0x00ff00ff) |
9494
+	                (((nBitsTotalH << 24) | (nBitsTotalH >>> 8))  & 0xff00ff00)
9495
+	            );
9496
+	            dataWords[(((nBitsLeft + 64) >>> 9) << 4) + 14] = (
9497
+	                (((nBitsTotalL << 8)  | (nBitsTotalL >>> 24)) & 0x00ff00ff) |
9498
+	                (((nBitsTotalL << 24) | (nBitsTotalL >>> 8))  & 0xff00ff00)
9499
+	            );
9500
+
9501
+	            data.sigBytes = (dataWords.length + 1) * 4;
9502
+
9503
+	            // Hash final blocks
9504
+	            this._process();
9505
+
9506
+	            // Shortcuts
9507
+	            var hash = this._hash;
9508
+	            var H = hash.words;
9509
+
9510
+	            // Swap endian
9511
+	            for (var i = 0; i < 4; i++) {
9512
+	                // Shortcut
9513
+	                var H_i = H[i];
9514
+
9515
+	                H[i] = (((H_i << 8)  | (H_i >>> 24)) & 0x00ff00ff) |
9516
+	                       (((H_i << 24) | (H_i >>> 8))  & 0xff00ff00);
9517
+	            }
9518
+
9519
+	            // Return final computed hash
9520
+	            return hash;
9521
+	        },
9522
+
9523
+	        clone: function () {
9524
+	            var clone = Hasher.clone.call(this);
9525
+	            clone._hash = this._hash.clone();
9526
+
9527
+	            return clone;
9528
+	        }
9529
+	    });
9530
+
9531
+	    function FF(a, b, c, d, x, s, t) {
9532
+	        var n = a + ((b & c) | (~b & d)) + x + t;
9533
+	        return ((n << s) | (n >>> (32 - s))) + b;
9534
+	    }
9535
+
9536
+	    function GG(a, b, c, d, x, s, t) {
9537
+	        var n = a + ((b & d) | (c & ~d)) + x + t;
9538
+	        return ((n << s) | (n >>> (32 - s))) + b;
9539
+	    }
9540
+
9541
+	    function HH(a, b, c, d, x, s, t) {
9542
+	        var n = a + (b ^ c ^ d) + x + t;
9543
+	        return ((n << s) | (n >>> (32 - s))) + b;
9544
+	    }
9545
+
9546
+	    function II(a, b, c, d, x, s, t) {
9547
+	        var n = a + (c ^ (b | ~d)) + x + t;
9548
+	        return ((n << s) | (n >>> (32 - s))) + b;
9549
+	    }
9550
+
9551
+	    /**
9552
+	     * Shortcut function to the hasher's object interface.
9553
+	     *
9554
+	     * @param {WordArray|string} message The message to hash.
9555
+	     *
9556
+	     * @return {WordArray} The hash.
9557
+	     *
9558
+	     * @static
9559
+	     *
9560
+	     * @example
9561
+	     *
9562
+	     *     var hash = CryptoJS.MD5('message');
9563
+	     *     var hash = CryptoJS.MD5(wordArray);
9564
+	     */
9565
+	    C.MD5 = Hasher._createHelper(MD5);
9566
+
9567
+	    /**
9568
+	     * Shortcut function to the HMAC's object interface.
9569
+	     *
9570
+	     * @param {WordArray|string} message The message to hash.
9571
+	     * @param {WordArray|string} key The secret key.
9572
+	     *
9573
+	     * @return {WordArray} The HMAC.
9574
+	     *
9575
+	     * @static
9576
+	     *
9577
+	     * @example
9578
+	     *
9579
+	     *     var hmac = CryptoJS.HmacMD5(message, key);
9580
+	     */
9581
+	    C.HmacMD5 = Hasher._createHmacHelper(MD5);
9582
+	}(Math));
9583
+
9584
+
9585
+	return CryptoJS.MD5;
9586
+
9587
+}));
9588
+
9589
+/***/ }),
9590
+/* 35 */
9591
+/***/ (function(module, exports, __webpack_require__) {
9592
+
9593
+;(function (root, factory) {
9594
+	if (true) {
9595
+		// CommonJS
9596
+		module.exports = exports = factory();
9597
+	}
9598
+	else {}
9599
+}(this, function () {
9600
+
9601
+	/**
9602
+	 * CryptoJS core components.
9603
+	 */
9604
+	var CryptoJS = CryptoJS || (function (Math, undefined) {
9605
+	    /*
9606
+	     * Local polyfil of Object.create
9607
+	     */
9608
+	    var create = Object.create || (function () {
9609
+	        function F() {};
9610
+
9611
+	        return function (obj) {
9612
+	            var subtype;
9613
+
9614
+	            F.prototype = obj;
9615
+
9616
+	            subtype = new F();
9617
+
9618
+	            F.prototype = null;
9619
+
9620
+	            return subtype;
9621
+	        };
9622
+	    }())
9623
+
9624
+	    /**
9625
+	     * CryptoJS namespace.
9626
+	     */
9627
+	    var C = {};
9628
+
9629
+	    /**
9630
+	     * Library namespace.
9631
+	     */
9632
+	    var C_lib = C.lib = {};
9633
+
9634
+	    /**
9635
+	     * Base object for prototypal inheritance.
9636
+	     */
9637
+	    var Base = C_lib.Base = (function () {
9638
+
9639
+
9640
+	        return {
9641
+	            /**
9642
+	             * Creates a new object that inherits from this object.
9643
+	             *
9644
+	             * @param {Object} overrides Properties to copy into the new object.
9645
+	             *
9646
+	             * @return {Object} The new object.
9647
+	             *
9648
+	             * @static
9649
+	             *
9650
+	             * @example
9651
+	             *
9652
+	             *     var MyType = CryptoJS.lib.Base.extend({
9653
+	             *         field: 'value',
9654
+	             *
9655
+	             *         method: function () {
9656
+	             *         }
9657
+	             *     });
9658
+	             */
9659
+	            extend: function (overrides) {
9660
+	                // Spawn
9661
+	                var subtype = create(this);
9662
+
9663
+	                // Augment
9664
+	                if (overrides) {
9665
+	                    subtype.mixIn(overrides);
9666
+	                }
9667
+
9668
+	                // Create default initializer
9669
+	                if (!subtype.hasOwnProperty('init') || this.init === subtype.init) {
9670
+	                    subtype.init = function () {
9671
+	                        subtype.$super.init.apply(this, arguments);
9672
+	                    };
9673
+	                }
9674
+
9675
+	                // Initializer's prototype is the subtype object
9676
+	                subtype.init.prototype = subtype;
9677
+
9678
+	                // Reference supertype
9679
+	                subtype.$super = this;
9680
+
9681
+	                return subtype;
9682
+	            },
9683
+
9684
+	            /**
9685
+	             * Extends this object and runs the init method.
9686
+	             * Arguments to create() will be passed to init().
9687
+	             *
9688
+	             * @return {Object} The new object.
9689
+	             *
9690
+	             * @static
9691
+	             *
9692
+	             * @example
9693
+	             *
9694
+	             *     var instance = MyType.create();
9695
+	             */
9696
+	            create: function () {
9697
+	                var instance = this.extend();
9698
+	                instance.init.apply(instance, arguments);
9699
+
9700
+	                return instance;
9701
+	            },
9702
+
9703
+	            /**
9704
+	             * Initializes a newly created object.
9705
+	             * Override this method to add some logic when your objects are created.
9706
+	             *
9707
+	             * @example
9708
+	             *
9709
+	             *     var MyType = CryptoJS.lib.Base.extend({
9710
+	             *         init: function () {
9711
+	             *             // ...
9712
+	             *         }
9713
+	             *     });
9714
+	             */
9715
+	            init: function () {
9716
+	            },
9717
+
9718
+	            /**
9719
+	             * Copies properties into this object.
9720
+	             *
9721
+	             * @param {Object} properties The properties to mix in.
9722
+	             *
9723
+	             * @example
9724
+	             *
9725
+	             *     MyType.mixIn({
9726
+	             *         field: 'value'
9727
+	             *     });
9728
+	             */
9729
+	            mixIn: function (properties) {
9730
+	                for (var propertyName in properties) {
9731
+	                    if (properties.hasOwnProperty(propertyName)) {
9732
+	                        this[propertyName] = properties[propertyName];
9733
+	                    }
9734
+	                }
9735
+
9736
+	                // IE won't copy toString using the loop above
9737
+	                if (properties.hasOwnProperty('toString')) {
9738
+	                    this.toString = properties.toString;
9739
+	                }
9740
+	            },
9741
+
9742
+	            /**
9743
+	             * Creates a copy of this object.
9744
+	             *
9745
+	             * @return {Object} The clone.
9746
+	             *
9747
+	             * @example
9748
+	             *
9749
+	             *     var clone = instance.clone();
9750
+	             */
9751
+	            clone: function () {
9752
+	                return this.init.prototype.extend(this);
9753
+	            }
9754
+	        };
9755
+	    }());
9756
+
9757
+	    /**
9758
+	     * An array of 32-bit words.
9759
+	     *
9760
+	     * @property {Array} words The array of 32-bit words.
9761
+	     * @property {number} sigBytes The number of significant bytes in this word array.
9762
+	     */
9763
+	    var WordArray = C_lib.WordArray = Base.extend({
9764
+	        /**
9765
+	         * Initializes a newly created word array.
9766
+	         *
9767
+	         * @param {Array} words (Optional) An array of 32-bit words.
9768
+	         * @param {number} sigBytes (Optional) The number of significant bytes in the words.
9769
+	         *
9770
+	         * @example
9771
+	         *
9772
+	         *     var wordArray = CryptoJS.lib.WordArray.create();
9773
+	         *     var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607]);
9774
+	         *     var wordArray = CryptoJS.lib.WordArray.create([0x00010203, 0x04050607], 6);
9775
+	         */
9776
+	        init: function (words, sigBytes) {
9777
+	            words = this.words = words || [];
9778
+
9779
+	            if (sigBytes != undefined) {
9780
+	                this.sigBytes = sigBytes;
9781
+	            } else {
9782
+	                this.sigBytes = words.length * 4;
9783
+	            }
9784
+	        },
9785
+
9786
+	        /**
9787
+	         * Converts this word array to a string.
9788
+	         *
9789
+	         * @param {Encoder} encoder (Optional) The encoding strategy to use. Default: CryptoJS.enc.Hex
9790
+	         *
9791
+	         * @return {string} The stringified word array.
9792
+	         *
9793
+	         * @example
9794
+	         *
9795
+	         *     var string = wordArray + '';
9796
+	         *     var string = wordArray.toString();
9797
+	         *     var string = wordArray.toString(CryptoJS.enc.Utf8);
9798
+	         */
9799
+	        toString: function (encoder) {
9800
+	            return (encoder || Hex).stringify(this);
9801
+	        },
9802
+
9803
+	        /**
9804
+	         * Concatenates a word array to this word array.
9805
+	         *
9806
+	         * @param {WordArray} wordArray The word array to append.
9807
+	         *
9808
+	         * @return {WordArray} This word array.
9809
+	         *
9810
+	         * @example
9811
+	         *
9812
+	         *     wordArray1.concat(wordArray2);
9813
+	         */
9814
+	        concat: function (wordArray) {
9815
+	            // Shortcuts
9816
+	            var thisWords = this.words;
9817
+	            var thatWords = wordArray.words;
9818
+	            var thisSigBytes = this.sigBytes;
9819
+	            var thatSigBytes = wordArray.sigBytes;
9820
+
9821
+	            // Clamp excess bits
9822
+	            this.clamp();
9823
+
9824
+	            // Concat
9825
+	            if (thisSigBytes % 4) {
9826
+	                // Copy one byte at a time
9827
+	                for (var i = 0; i < thatSigBytes; i++) {
9828
+	                    var thatByte = (thatWords[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;
9829
+	                    thisWords[(thisSigBytes + i) >>> 2] |= thatByte << (24 - ((thisSigBytes + i) % 4) * 8);
9830
+	                }
9831
+	            } else {
9832
+	                // Copy one word at a time
9833
+	                for (var i = 0; i < thatSigBytes; i += 4) {
9834
+	                    thisWords[(thisSigBytes + i) >>> 2] = thatWords[i >>> 2];
9835
+	                }
9836
+	            }
9837
+	            this.sigBytes += thatSigBytes;
9838
+
9839
+	            // Chainable
9840
+	            return this;
9841
+	        },
9842
+
9843
+	        /**
9844
+	         * Removes insignificant bits.
9845
+	         *
9846
+	         * @example
9847
+	         *
9848
+	         *     wordArray.clamp();
9849
+	         */
9850
+	        clamp: function () {
9851
+	            // Shortcuts
9852
+	            var words = this.words;
9853
+	            var sigBytes = this.sigBytes;
9854
+
9855
+	            // Clamp
9856
+	            words[sigBytes >>> 2] &= 0xffffffff << (32 - (sigBytes % 4) * 8);
9857
+	            words.length = Math.ceil(sigBytes / 4);
9858
+	        },
9859
+
9860
+	        /**
9861
+	         * Creates a copy of this word array.
9862
+	         *
9863
+	         * @return {WordArray} The clone.
9864
+	         *
9865
+	         * @example
9866
+	         *
9867
+	         *     var clone = wordArray.clone();
9868
+	         */
9869
+	        clone: function () {
9870
+	            var clone = Base.clone.call(this);
9871
+	            clone.words = this.words.slice(0);
9872
+
9873
+	            return clone;
9874
+	        },
9875
+
9876
+	        /**
9877
+	         * Creates a word array filled with random bytes.
9878
+	         *
9879
+	         * @param {number} nBytes The number of random bytes to generate.
9880
+	         *
9881
+	         * @return {WordArray} The random word array.
9882
+	         *
9883
+	         * @static
9884
+	         *
9885
+	         * @example
9886
+	         *
9887
+	         *     var wordArray = CryptoJS.lib.WordArray.random(16);
9888
+	         */
9889
+	        random: function (nBytes) {
9890
+	            var words = [];
9891
+
9892
+	            var r = (function (m_w) {
9893
+	                var m_w = m_w;
9894
+	                var m_z = 0x3ade68b1;
9895
+	                var mask = 0xffffffff;
9896
+
9897
+	                return function () {
9898
+	                    m_z = (0x9069 * (m_z & 0xFFFF) + (m_z >> 0x10)) & mask;
9899
+	                    m_w = (0x4650 * (m_w & 0xFFFF) + (m_w >> 0x10)) & mask;
9900
+	                    var result = ((m_z << 0x10) + m_w) & mask;
9901
+	                    result /= 0x100000000;
9902
+	                    result += 0.5;
9903
+	                    return result * (Math.random() > .5 ? 1 : -1);
9904
+	                }
9905
+	            });
9906
+
9907
+	            for (var i = 0, rcache; i < nBytes; i += 4) {
9908
+	                var _r = r((rcache || Math.random()) * 0x100000000);
9909
+
9910
+	                rcache = _r() * 0x3ade67b7;
9911
+	                words.push((_r() * 0x100000000) | 0);
9912
+	            }
9913
+
9914
+	            return new WordArray.init(words, nBytes);
9915
+	        }
9916
+	    });
9917
+
9918
+	    /**
9919
+	     * Encoder namespace.
9920
+	     */
9921
+	    var C_enc = C.enc = {};
9922
+
9923
+	    /**
9924
+	     * Hex encoding strategy.
9925
+	     */
9926
+	    var Hex = C_enc.Hex = {
9927
+	        /**
9928
+	         * Converts a word array to a hex string.
9929
+	         *
9930
+	         * @param {WordArray} wordArray The word array.
9931
+	         *
9932
+	         * @return {string} The hex string.
9933
+	         *
9934
+	         * @static
9935
+	         *
9936
+	         * @example
9937
+	         *
9938
+	         *     var hexString = CryptoJS.enc.Hex.stringify(wordArray);
9939
+	         */
9940
+	        stringify: function (wordArray) {
9941
+	            // Shortcuts
9942
+	            var words = wordArray.words;
9943
+	            var sigBytes = wordArray.sigBytes;
9944
+
9945
+	            // Convert
9946
+	            var hexChars = [];
9947
+	            for (var i = 0; i < sigBytes; i++) {
9948
+	                var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;
9949
+	                hexChars.push((bite >>> 4).toString(16));
9950
+	                hexChars.push((bite & 0x0f).toString(16));
9951
+	            }
9952
+
9953
+	            return hexChars.join('');
9954
+	        },
9955
+
9956
+	        /**
9957
+	         * Converts a hex string to a word array.
9958
+	         *
9959
+	         * @param {string} hexStr The hex string.
9960
+	         *
9961
+	         * @return {WordArray} The word array.
9962
+	         *
9963
+	         * @static
9964
+	         *
9965
+	         * @example
9966
+	         *
9967
+	         *     var wordArray = CryptoJS.enc.Hex.parse(hexString);
9968
+	         */
9969
+	        parse: function (hexStr) {
9970
+	            // Shortcut
9971
+	            var hexStrLength = hexStr.length;
9972
+
9973
+	            // Convert
9974
+	            var words = [];
9975
+	            for (var i = 0; i < hexStrLength; i += 2) {
9976
+	                words[i >>> 3] |= parseInt(hexStr.substr(i, 2), 16) << (24 - (i % 8) * 4);
9977
+	            }
9978
+
9979
+	            return new WordArray.init(words, hexStrLength / 2);
9980
+	        }
9981
+	    };
9982
+
9983
+	    /**
9984
+	     * Latin1 encoding strategy.
9985
+	     */
9986
+	    var Latin1 = C_enc.Latin1 = {
9987
+	        /**
9988
+	         * Converts a word array to a Latin1 string.
9989
+	         *
9990
+	         * @param {WordArray} wordArray The word array.
9991
+	         *
9992
+	         * @return {string} The Latin1 string.
9993
+	         *
9994
+	         * @static
9995
+	         *
9996
+	         * @example
9997
+	         *
9998
+	         *     var latin1String = CryptoJS.enc.Latin1.stringify(wordArray);
9999
+	         */
10000
+	        stringify: function (wordArray) {
10001
+	            // Shortcuts
10002
+	            var words = wordArray.words;
10003
+	            var sigBytes = wordArray.sigBytes;
10004
+
10005
+	            // Convert
10006
+	            var latin1Chars = [];
10007
+	            for (var i = 0; i < sigBytes; i++) {
10008
+	                var bite = (words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff;
10009
+	                latin1Chars.push(String.fromCharCode(bite));
10010
+	            }
10011
+
10012
+	            return latin1Chars.join('');
10013
+	        },
10014
+
10015
+	        /**
10016
+	         * Converts a Latin1 string to a word array.
10017
+	         *
10018
+	         * @param {string} latin1Str The Latin1 string.
10019
+	         *
10020
+	         * @return {WordArray} The word array.
10021
+	         *
10022
+	         * @static
10023
+	         *
10024
+	         * @example
10025
+	         *
10026
+	         *     var wordArray = CryptoJS.enc.Latin1.parse(latin1String);
10027
+	         */
10028
+	        parse: function (latin1Str) {
10029
+	            // Shortcut
10030
+	            var latin1StrLength = latin1Str.length;
10031
+
10032
+	            // Convert
10033
+	            var words = [];
10034
+	            for (var i = 0; i < latin1StrLength; i++) {
10035
+	                words[i >>> 2] |= (latin1Str.charCodeAt(i) & 0xff) << (24 - (i % 4) * 8);
10036
+	            }
10037
+
10038
+	            return new WordArray.init(words, latin1StrLength);
10039
+	        }
10040
+	    };
10041
+
10042
+	    /**
10043
+	     * UTF-8 encoding strategy.
10044
+	     */
10045
+	    var Utf8 = C_enc.Utf8 = {
10046
+	        /**
10047
+	         * Converts a word array to a UTF-8 string.
10048
+	         *
10049
+	         * @param {WordArray} wordArray The word array.
10050
+	         *
10051
+	         * @return {string} The UTF-8 string.
10052
+	         *
10053
+	         * @static
10054
+	         *
10055
+	         * @example
10056
+	         *
10057
+	         *     var utf8String = CryptoJS.enc.Utf8.stringify(wordArray);
10058
+	         */
10059
+	        stringify: function (wordArray) {
10060
+	            try {
10061
+	                return decodeURIComponent(escape(Latin1.stringify(wordArray)));
10062
+	            } catch (e) {
10063
+	                throw new Error('Malformed UTF-8 data');
10064
+	            }
10065
+	        },
10066
+
10067
+	        /**
10068
+	         * Converts a UTF-8 string to a word array.
10069
+	         *
10070
+	         * @param {string} utf8Str The UTF-8 string.
10071
+	         *
10072
+	         * @return {WordArray} The word array.
10073
+	         *
10074
+	         * @static
10075
+	         *
10076
+	         * @example
10077
+	         *
10078
+	         *     var wordArray = CryptoJS.enc.Utf8.parse(utf8String);
10079
+	         */
10080
+	        parse: function (utf8Str) {
10081
+	            return Latin1.parse(unescape(encodeURIComponent(utf8Str)));
10082
+	        }
10083
+	    };
10084
+
10085
+	    /**
10086
+	     * Abstract buffered block algorithm template.
10087
+	     *
10088
+	     * The property blockSize must be implemented in a concrete subtype.
10089
+	     *
10090
+	     * @property {number} _minBufferSize The number of blocks that should be kept unprocessed in the buffer. Default: 0
10091
+	     */
10092
+	    var BufferedBlockAlgorithm = C_lib.BufferedBlockAlgorithm = Base.extend({
10093
+	        /**
10094
+	         * Resets this block algorithm's data buffer to its initial state.
10095
+	         *
10096
+	         * @example
10097
+	         *
10098
+	         *     bufferedBlockAlgorithm.reset();
10099
+	         */
10100
+	        reset: function () {
10101
+	            // Initial values
10102
+	            this._data = new WordArray.init();
10103
+	            this._nDataBytes = 0;
10104
+	        },
10105
+
10106
+	        /**
10107
+	         * Adds new data to this block algorithm's buffer.
10108
+	         *
10109
+	         * @param {WordArray|string} data The data to append. Strings are converted to a WordArray using UTF-8.
10110
+	         *
10111
+	         * @example
10112
+	         *
10113
+	         *     bufferedBlockAlgorithm._append('data');
10114
+	         *     bufferedBlockAlgorithm._append(wordArray);
10115
+	         */
10116
+	        _append: function (data) {
10117
+	            // Convert string to WordArray, else assume WordArray already
10118
+	            if (typeof data == 'string') {
10119
+	                data = Utf8.parse(data);
10120
+	            }
10121
+
10122
+	            // Append
10123
+	            this._data.concat(data);
10124
+	            this._nDataBytes += data.sigBytes;
10125
+	        },
10126
+
10127
+	        /**
10128
+	         * Processes available data blocks.
10129
+	         *
10130
+	         * This method invokes _doProcessBlock(offset), which must be implemented by a concrete subtype.
10131
+	         *
10132
+	         * @param {boolean} doFlush Whether all blocks and partial blocks should be processed.
10133
+	         *
10134
+	         * @return {WordArray} The processed data.
10135
+	         *
10136
+	         * @example
10137
+	         *
10138
+	         *     var processedData = bufferedBlockAlgorithm._process();
10139
+	         *     var processedData = bufferedBlockAlgorithm._process(!!'flush');
10140
+	         */
10141
+	        _process: function (doFlush) {
10142
+	            // Shortcuts
10143
+	            var data = this._data;
10144
+	            var dataWords = data.words;
10145
+	            var dataSigBytes = data.sigBytes;
10146
+	            var blockSize = this.blockSize;
10147
+	            var blockSizeBytes = blockSize * 4;
10148
+
10149
+	            // Count blocks ready
10150
+	            var nBlocksReady = dataSigBytes / blockSizeBytes;
10151
+	            if (doFlush) {
10152
+	                // Round up to include partial blocks
10153
+	                nBlocksReady = Math.ceil(nBlocksReady);
10154
+	            } else {
10155
+	                // Round down to include only full blocks,
10156
+	                // less the number of blocks that must remain in the buffer
10157
+	                nBlocksReady = Math.max((nBlocksReady | 0) - this._minBufferSize, 0);
10158
+	            }
10159
+
10160
+	            // Count words ready
10161
+	            var nWordsReady = nBlocksReady * blockSize;
10162
+
10163
+	            // Count bytes ready
10164
+	            var nBytesReady = Math.min(nWordsReady * 4, dataSigBytes);
10165
+
10166
+	            // Process blocks
10167
+	            if (nWordsReady) {
10168
+	                for (var offset = 0; offset < nWordsReady; offset += blockSize) {
10169
+	                    // Perform concrete-algorithm logic
10170
+	                    this._doProcessBlock(dataWords, offset);
10171
+	                }
10172
+
10173
+	                // Remove processed words
10174
+	                var processedWords = dataWords.splice(0, nWordsReady);
10175
+	                data.sigBytes -= nBytesReady;
10176
+	            }
10177
+
10178
+	            // Return processed words
10179
+	            return new WordArray.init(processedWords, nBytesReady);
10180
+	        },
10181
+
10182
+	        /**
10183
+	         * Creates a copy of this object.
10184
+	         *
10185
+	         * @return {Object} The clone.
10186
+	         *
10187
+	         * @example
10188
+	         *
10189
+	         *     var clone = bufferedBlockAlgorithm.clone();
10190
+	         */
10191
+	        clone: function () {
10192
+	            var clone = Base.clone.call(this);
10193
+	            clone._data = this._data.clone();
10194
+
10195
+	            return clone;
10196
+	        },
10197
+
10198
+	        _minBufferSize: 0
10199
+	    });
10200
+
10201
+	    /**
10202
+	     * Abstract hasher template.
10203
+	     *
10204
+	     * @property {number} blockSize The number of 32-bit words this hasher operates on. Default: 16 (512 bits)
10205
+	     */
10206
+	    var Hasher = C_lib.Hasher = BufferedBlockAlgorithm.extend({
10207
+	        /**
10208
+	         * Configuration options.
10209
+	         */
10210
+	        cfg: Base.extend(),
10211
+
10212
+	        /**
10213
+	         * Initializes a newly created hasher.
10214
+	         *
10215
+	         * @param {Object} cfg (Optional) The configuration options to use for this hash computation.
10216
+	         *
10217
+	         * @example
10218
+	         *
10219
+	         *     var hasher = CryptoJS.algo.SHA256.create();
10220
+	         */
10221
+	        init: function (cfg) {
10222
+	            // Apply config defaults
10223
+	            this.cfg = this.cfg.extend(cfg);
10224
+
10225
+	            // Set initial values
10226
+	            this.reset();
10227
+	        },
10228
+
10229
+	        /**
10230
+	         * Resets this hasher to its initial state.
10231
+	         *
10232
+	         * @example
10233
+	         *
10234
+	         *     hasher.reset();
10235
+	         */
10236
+	        reset: function () {
10237
+	            // Reset data buffer
10238
+	            BufferedBlockAlgorithm.reset.call(this);
10239
+
10240
+	            // Perform concrete-hasher logic
10241
+	            this._doReset();
10242
+	        },
10243
+
10244
+	        /**
10245
+	         * Updates this hasher with a message.
10246
+	         *
10247
+	         * @param {WordArray|string} messageUpdate The message to append.
10248
+	         *
10249
+	         * @return {Hasher} This hasher.
10250
+	         *
10251
+	         * @example
10252
+	         *
10253
+	         *     hasher.update('message');
10254
+	         *     hasher.update(wordArray);
10255
+	         */
10256
+	        update: function (messageUpdate) {
10257
+	            // Append
10258
+	            this._append(messageUpdate);
10259
+
10260
+	            // Update the hash
10261
+	            this._process();
10262
+
10263
+	            // Chainable
10264
+	            return this;
10265
+	        },
10266
+
10267
+	        /**
10268
+	         * Finalizes the hash computation.
10269
+	         * Note that the finalize operation is effectively a destructive, read-once operation.
10270
+	         *
10271
+	         * @param {WordArray|string} messageUpdate (Optional) A final message update.
10272
+	         *
10273
+	         * @return {WordArray} The hash.
10274
+	         *
10275
+	         * @example
10276
+	         *
10277
+	         *     var hash = hasher.finalize();
10278
+	         *     var hash = hasher.finalize('message');
10279
+	         *     var hash = hasher.finalize(wordArray);
10280
+	         */
10281
+	        finalize: function (messageUpdate) {
10282
+	            // Final message update
10283
+	            if (messageUpdate) {
10284
+	                this._append(messageUpdate);
10285
+	            }
10286
+
10287
+	            // Perform concrete-hasher logic
10288
+	            var hash = this._doFinalize();
10289
+
10290
+	            return hash;
10291
+	        },
10292
+
10293
+	        blockSize: 512/32,
10294
+
10295
+	        /**
10296
+	         * Creates a shortcut function to a hasher's object interface.
10297
+	         *
10298
+	         * @param {Hasher} hasher The hasher to create a helper for.
10299
+	         *
10300
+	         * @return {Function} The shortcut function.
10301
+	         *
10302
+	         * @static
10303
+	         *
10304
+	         * @example
10305
+	         *
10306
+	         *     var SHA256 = CryptoJS.lib.Hasher._createHelper(CryptoJS.algo.SHA256);
10307
+	         */
10308
+	        _createHelper: function (hasher) {
10309
+	            return function (message, cfg) {
10310
+	                return new hasher.init(cfg).finalize(message);
10311
+	            };
10312
+	        },
10313
+
10314
+	        /**
10315
+	         * Creates a shortcut function to the HMAC's object interface.
10316
+	         *
10317
+	         * @param {Hasher} hasher The hasher to use in this HMAC helper.
10318
+	         *
10319
+	         * @return {Function} The shortcut function.
10320
+	         *
10321
+	         * @static
10322
+	         *
10323
+	         * @example
10324
+	         *
10325
+	         *     var HmacSHA256 = CryptoJS.lib.Hasher._createHmacHelper(CryptoJS.algo.SHA256);
10326
+	         */
10327
+	        _createHmacHelper: function (hasher) {
10328
+	            return function (message, key) {
10329
+	                return new C_algo.HMAC.init(hasher, key).finalize(message);
10330
+	            };
10331
+	        }
10332
+	    });
10333
+
10334
+	    /**
10335
+	     * Algorithm namespace.
10336
+	     */
10337
+	    var C_algo = C.algo = {};
10338
+
10339
+	    return C;
10340
+	}(Math));
10341
+
10342
+
10343
+	return CryptoJS;
10344
+
10345
+}));
10346
+
10347
+/***/ }),
10348
+/* 36 */
10349
+/***/ (function(module, exports, __webpack_require__) {
10350
+
10351
+"use strict";
10352
+
10353
+var Grammar = __webpack_require__(37);
10354
+module.exports = function (SIP) {
10355
+    return {
10356
+        parse: function parseCustom(input, startRule) {
10357
+            var options = { startRule: startRule, SIP: SIP };
10358
+            try {
10359
+                Grammar.parse(input, options);
10360
+            }
10361
+            catch (e) {
10362
+                options.data = -1;
10363
+            }
10364
+            return options.data;
10365
+        }
10366
+    };
10367
+};
10368
+
10369
+
10370
+/***/ }),
10371
+/* 37 */
10372
+/***/ (function(module, exports, __webpack_require__) {
10373
+
10374
+"use strict";
10375
+/*
10376
+ * Generated by PEG.js 0.10.0.
10377
+ *
10378
+ * http://pegjs.org/
10379
+ */
10380
+
10381
+
10382
+
10383
+function peg$subclass(child, parent) {
10384
+  function ctor() { this.constructor = child; }
10385
+  ctor.prototype = parent.prototype;
10386
+  child.prototype = new ctor();
10387
+}
10388
+
10389
+function peg$SyntaxError(message, expected, found, location) {
10390
+  this.message  = message;
10391
+  this.expected = expected;
10392
+  this.found    = found;
10393
+  this.location = location;
10394
+  this.name     = "SyntaxError";
10395
+
10396
+  if (typeof Error.captureStackTrace === "function") {
10397
+    Error.captureStackTrace(this, peg$SyntaxError);
10398
+  }
10399
+}
10400
+
10401
+peg$subclass(peg$SyntaxError, Error);
10402
+
10403
+peg$SyntaxError.buildMessage = function(expected, found) {
10404
+  var DESCRIBE_EXPECTATION_FNS = {
10405
+        literal: function(expectation) {
10406
+          return "\"" + literalEscape(expectation.text) + "\"";
10407
+        },
10408
+
10409
+        "class": function(expectation) {
10410
+          var escapedParts = "",
10411
+              i;
10412
+
10413
+          for (i = 0; i < expectation.parts.length; i++) {
10414
+            escapedParts += expectation.parts[i] instanceof Array
10415
+              ? classEscape(expectation.parts[i][0]) + "-" + classEscape(expectation.parts[i][1])
10416
+              : classEscape(expectation.parts[i]);
10417
+          }
10418
+
10419
+          return "[" + (expectation.inverted ? "^" : "") + escapedParts + "]";
10420
+        },
10421
+
10422
+        any: function(expectation) {
10423
+          return "any character";
10424
+        },
10425
+
10426
+        end: function(expectation) {
10427
+          return "end of input";
10428
+        },
10429
+
10430
+        other: function(expectation) {
10431
+          return expectation.description;
10432
+        }
10433
+      };
10434
+
10435
+  function hex(ch) {
10436
+    return ch.charCodeAt(0).toString(16).toUpperCase();
10437
+  }
10438
+
10439
+  function literalEscape(s) {
10440
+    return s
10441
+      .replace(/\\/g, '\\\\')
10442
+      .replace(/"/g,  '\\"')
10443
+      .replace(/\0/g, '\\0')
10444
+      .replace(/\t/g, '\\t')
10445
+      .replace(/\n/g, '\\n')
10446
+      .replace(/\r/g, '\\r')
10447
+      .replace(/[\x00-\x0F]/g,          function(ch) { return '\\x0' + hex(ch); })
10448
+      .replace(/[\x10-\x1F\x7F-\x9F]/g, function(ch) { return '\\x'  + hex(ch); });
10449
+  }
10450
+
10451
+  function classEscape(s) {
10452
+    return s
10453
+      .replace(/\\/g, '\\\\')
10454
+      .replace(/\]/g, '\\]')
10455
+      .replace(/\^/g, '\\^')
10456
+      .replace(/-/g,  '\\-')
10457
+      .replace(/\0/g, '\\0')
10458
+      .replace(/\t/g, '\\t')
10459
+      .replace(/\n/g, '\\n')
10460
+      .replace(/\r/g, '\\r')
10461
+      .replace(/[\x00-\x0F]/g,          function(ch) { return '\\x0' + hex(ch); })
10462
+      .replace(/[\x10-\x1F\x7F-\x9F]/g, function(ch) { return '\\x'  + hex(ch); });
10463
+  }
10464
+
10465
+  function describeExpectation(expectation) {
10466
+    return DESCRIBE_EXPECTATION_FNS[expectation.type](expectation);
10467
+  }
10468
+
10469
+  function describeExpected(expected) {
10470
+    var descriptions = new Array(expected.length),
10471
+        i, j;
10472
+
10473
+    for (i = 0; i < expected.length; i++) {
10474
+      descriptions[i] = describeExpectation(expected[i]);
10475
+    }
10476
+
10477
+    descriptions.sort();
10478
+
10479
+    if (descriptions.length > 0) {
10480
+      for (i = 1, j = 1; i < descriptions.length; i++) {
10481
+        if (descriptions[i - 1] !== descriptions[i]) {
10482
+          descriptions[j] = descriptions[i];
10483
+          j++;
10484
+        }
10485
+      }
10486
+      descriptions.length = j;
10487
+    }
10488
+
10489
+    switch (descriptions.length) {
10490
+      case 1:
10491
+        return descriptions[0];
10492
+
10493
+      case 2:
10494
+        return descriptions[0] + " or " + descriptions[1];
10495
+
10496
+      default:
10497
+        return descriptions.slice(0, -1).join(", ")
10498
+          + ", or "
10499
+          + descriptions[descriptions.length - 1];
10500
+    }
10501
+  }
10502
+
10503
+  function describeFound(found) {
10504
+    return found ? "\"" + literalEscape(found) + "\"" : "end of input";
10505
+  }
10506
+
10507
+  return "Expected " + describeExpected(expected) + " but " + describeFound(found) + " found.";
10508
+};
10509
+
10510
+function peg$parse(input, options) {
10511
+  options = options !== void 0 ? options : {};
10512
+
10513
+  var peg$FAILED = {},
10514
+
10515
+      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 },
10516
+      peg$startRuleIndex   = 119,
10517
+
10518
+      peg$consts = [
10519
+        "\r\n",
10520
+        peg$literalExpectation("\r\n", false),
10521
+        /^[0-9]/,
10522
+        peg$classExpectation([["0", "9"]], false, false),
10523
+        /^[a-zA-Z]/,
10524
+        peg$classExpectation([["a", "z"], ["A", "Z"]], false, false),
10525
+        /^[0-9a-fA-F]/,
10526
+        peg$classExpectation([["0", "9"], ["a", "f"], ["A", "F"]], false, false),
10527
+        /^[\0-\xFF]/,
10528
+        peg$classExpectation([["\0", "\xFF"]], false, false),
10529
+        /^["]/,
10530
+        peg$classExpectation(["\""], false, false),
10531
+        " ",
10532
+        peg$literalExpectation(" ", false),
10533
+        "\t",
10534
+        peg$literalExpectation("\t", false),
10535
+        /^[a-zA-Z0-9]/,
10536
+        peg$classExpectation([["a", "z"], ["A", "Z"], ["0", "9"]], false, false),
10537
+        ";",
10538
+        peg$literalExpectation(";", false),
10539
+        "/",
10540
+        peg$literalExpectation("/", false),
10541
+        "?",
10542
+        peg$literalExpectation("?", false),
10543
+        ":",
10544
+        peg$literalExpectation(":", false),
10545
+        "@",
10546
+        peg$literalExpectation("@", false),
10547
+        "&",
10548
+        peg$literalExpectation("&", false),
10549
+        "=",
10550
+        peg$literalExpectation("=", false),
10551
+        "+",
10552
+        peg$literalExpectation("+", false),
10553
+        "$",
10554
+        peg$literalExpectation("$", false),
10555
+        ",",
10556
+        peg$literalExpectation(",", false),
10557
+        "-",
10558
+        peg$literalExpectation("-", false),
10559
+        "_",
10560
+        peg$literalExpectation("_", false),
10561
+        ".",
10562
+        peg$literalExpectation(".", false),
10563
+        "!",
10564
+        peg$literalExpectation("!", false),
10565
+        "~",
10566
+        peg$literalExpectation("~", false),
10567
+        "*",
10568
+        peg$literalExpectation("*", false),
10569
+        "'",
10570
+        peg$literalExpectation("'", false),
10571
+        "(",
10572
+        peg$literalExpectation("(", false),
10573
+        ")",
10574
+        peg$literalExpectation(")", false),
10575
+        "%",
10576
+        peg$literalExpectation("%", false),
10577
+        function() {return " "; },
10578
+        function() {return ':'; },
10579
+        /^[!-~]/,
10580
+        peg$classExpectation([["!", "~"]], false, false),
10581
+        /^[\x80-\uFFFF]/,
10582
+        peg$classExpectation([["\x80", "\uFFFF"]], false, false),
10583
+        /^[\x80-\xBF]/,
10584
+        peg$classExpectation([["\x80", "\xBF"]], false, false),
10585
+        /^[a-f]/,
10586
+        peg$classExpectation([["a", "f"]], false, false),
10587
+        "`",
10588
+        peg$literalExpectation("`", false),
10589
+        "<",
10590
+        peg$literalExpectation("<", false),
10591
+        ">",
10592
+        peg$literalExpectation(">", false),
10593
+        "\\",
10594
+        peg$literalExpectation("\\", false),
10595
+        "[",
10596
+        peg$literalExpectation("[", false),
10597
+        "]",
10598
+        peg$literalExpectation("]", false),
10599
+        "{",
10600
+        peg$literalExpectation("{", false),
10601
+        "}",
10602
+        peg$literalExpectation("}", false),
10603
+        function() {return "*"; },
10604
+        function() {return "/"; },
10605
+        function() {return "="; },
10606
+        function() {return "("; },
10607
+        function() {return ")"; },
10608
+        function() {return ">"; },
10609
+        function() {return "<"; },
10610
+        function() {return ","; },
10611
+        function() {return ";"; },
10612
+        function() {return ":"; },
10613
+        function() {return "\""; },
10614
+        /^[!-']/,
10615
+        peg$classExpectation([["!", "'"]], false, false),
10616
+        /^[*-[]/,
10617
+        peg$classExpectation([["*", "["]], false, false),
10618
+        /^[\]-~]/,
10619
+        peg$classExpectation([["]", "~"]], false, false),
10620
+        function(contents) {
10621
+                                return contents; },
10622
+        /^[#-[]/,
10623
+        peg$classExpectation([["#", "["]], false, false),
10624
+        /^[\0-\t]/,
10625
+        peg$classExpectation([["\0", "\t"]], false, false),
10626
+        /^[\x0B-\f]/,
10627
+        peg$classExpectation([["\x0B", "\f"]], false, false),
10628
+        /^[\x0E-\x7F]/,
10629
+        peg$classExpectation([["\x0E", "\x7F"]], false, false),
10630
+        function() {
10631
+                                options.data.uri = new options.SIP.URI(options.data.scheme, options.data.user, options.data.host, options.data.port);
10632
+                                delete options.data.scheme;
10633
+                                delete options.data.user;
10634
+                                delete options.data.host;
10635
+                                delete options.data.host_type;
10636
+                                delete options.data.port;
10637
+                              },
10638
+        function() {
10639
+                                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);
10640
+                                delete options.data.scheme;
10641
+                                delete options.data.user;
10642
+                                delete options.data.host;
10643
+                                delete options.data.host_type;
10644
+                                delete options.data.port;
10645
+                                delete options.data.uri_params;
10646
+
10647
+                                if (options.startRule === 'SIP_URI') { options.data = options.data.uri;}
10648
+                              },
10649
+        "sips",
10650
+        peg$literalExpectation("sips", true),
10651
+        "sip",
10652
+        peg$literalExpectation("sip", true),
10653
+        function(uri_scheme) {
10654
+                            options.data.scheme = uri_scheme; },
10655
+        function() {
10656
+                            options.data.user = decodeURIComponent(text().slice(0, -1));},
10657
+        function() {
10658
+                            options.data.password = text(); },
10659
+        function() {
10660
+                            options.data.host = text();
10661
+                            return options.data.host; },
10662
+        function() {
10663
+                          options.data.host_type = 'domain';
10664
+                          return text(); },
10665
+        /^[a-zA-Z0-9_\-]/,
10666
+        peg$classExpectation([["a", "z"], ["A", "Z"], ["0", "9"], "_", "-"], false, false),
10667
+        /^[a-zA-Z0-9\-]/,
10668
+        peg$classExpectation([["a", "z"], ["A", "Z"], ["0", "9"], "-"], false, false),
10669
+        function() {
10670
+                            options.data.host_type = 'IPv6';
10671
+                            return text(); },
10672
+        "::",
10673
+        peg$literalExpectation("::", false),
10674
+        function() {
10675
+                          options.data.host_type = 'IPv6';
10676
+                          return text(); },
10677
+        function() {
10678
+                            options.data.host_type = 'IPv4';
10679
+                            return text(); },
10680
+        "25",
10681
+        peg$literalExpectation("25", false),
10682
+        /^[0-5]/,
10683
+        peg$classExpectation([["0", "5"]], false, false),
10684
+        "2",
10685
+        peg$literalExpectation("2", false),
10686
+        /^[0-4]/,
10687
+        peg$classExpectation([["0", "4"]], false, false),
10688
+        "1",
10689
+        peg$literalExpectation("1", false),
10690
+        /^[1-9]/,
10691
+        peg$classExpectation([["1", "9"]], false, false),
10692
+        function(port) {
10693
+                            port = parseInt(port.join(''));
10694
+                            options.data.port = port;
10695
+                            return port; },
10696
+        "transport=",
10697
+        peg$literalExpectation("transport=", true),
10698
+        "udp",
10699
+        peg$literalExpectation("udp", true),
10700
+        "tcp",
10701
+        peg$literalExpectation("tcp", true),
10702
+        "sctp",
10703
+        peg$literalExpectation("sctp", true),
10704
+        "tls",
10705
+        peg$literalExpectation("tls", true),
10706
+        function(transport) {
10707
+                              if(!options.data.uri_params) options.data.uri_params={};
10708
+                              options.data.uri_params['transport'] = transport.toLowerCase(); },
10709
+        "user=",
10710
+        peg$literalExpectation("user=", true),
10711
+        "phone",
10712
+        peg$literalExpectation("phone", true),
10713
+        "ip",
10714
+        peg$literalExpectation("ip", true),
10715
+        function(user) {
10716
+                              if(!options.data.uri_params) options.data.uri_params={};
10717
+                              options.data.uri_params['user'] = user.toLowerCase(); },
10718
+        "method=",
10719
+        peg$literalExpectation("method=", true),
10720
+        function(method) {
10721
+                              if(!options.data.uri_params) options.data.uri_params={};
10722
+                              options.data.uri_params['method'] = method; },
10723
+        "ttl=",
10724
+        peg$literalExpectation("ttl=", true),
10725
+        function(ttl) {
10726
+                              if(!options.data.params) options.data.params={};
10727
+                              options.data.params['ttl'] = ttl; },
10728
+        "maddr=",
10729
+        peg$literalExpectation("maddr=", true),
10730
+        function(maddr) {
10731
+                              if(!options.data.uri_params) options.data.uri_params={};
10732
+                              options.data.uri_params['maddr'] = maddr; },
10733
+        "lr",
10734
+        peg$literalExpectation("lr", true),
10735
+        function() {
10736
+                              if(!options.data.uri_params) options.data.uri_params={};
10737
+                              options.data.uri_params['lr'] = undefined; },
10738
+        function(param, value) {
10739
+                              if(!options.data.uri_params) options.data.uri_params = {};
10740
+                              if (value === null){
10741
+                                value = undefined;
10742
+                              }
10743
+                              else {
10744
+                                value = value[1];
10745
+                              }
10746
+                              options.data.uri_params[param.toLowerCase()] = value;},
10747
+        function(hname, hvalue) {
10748
+                              hname = hname.join('').toLowerCase();
10749
+                              hvalue = hvalue.join('');
10750
+                              if(!options.data.uri_headers) options.data.uri_headers = {};
10751
+                              if (!options.data.uri_headers[hname]) {
10752
+                                options.data.uri_headers[hname] = [hvalue];
10753
+                              } else {
10754
+                                options.data.uri_headers[hname].push(hvalue);
10755
+                              }},
10756
+        function() {
10757
+                              // lots of tests fail if this isn't guarded...
10758
+                              if (options.startRule === 'Refer_To') {
10759
+                                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);
10760
+                                delete options.data.scheme;
10761
+                                delete options.data.user;
10762
+                                delete options.data.host;
10763
+                                delete options.data.host_type;
10764
+                                delete options.data.port;
10765
+                                delete options.data.uri_params;
10766
+                              }
10767
+                            },
10768
+        "//",
10769
+        peg$literalExpectation("//", false),
10770
+        function() {
10771
+                            options.data.scheme= text(); },
10772
+        peg$literalExpectation("SIP", true),
10773
+        function() {
10774
+                            options.data.sip_version = text(); },
10775
+        "INVITE",
10776
+        peg$literalExpectation("INVITE", false),
10777
+        "ACK",
10778
+        peg$literalExpectation("ACK", false),
10779
+        "VXACH",
10780
+        peg$literalExpectation("VXACH", false),
10781
+        "OPTIONS",
10782
+        peg$literalExpectation("OPTIONS", false),
10783
+        "BYE",
10784
+        peg$literalExpectation("BYE", false),
10785
+        "CANCEL",
10786
+        peg$literalExpectation("CANCEL", false),
10787
+        "REGISTER",
10788
+        peg$literalExpectation("REGISTER", false),
10789
+        "SUBSCRIBE",
10790
+        peg$literalExpectation("SUBSCRIBE", false),
10791
+        "NOTIFY",
10792
+        peg$literalExpectation("NOTIFY", false),
10793
+        "REFER",
10794
+        peg$literalExpectation("REFER", false),
10795
+        "PUBLISH",
10796
+        peg$literalExpectation("PUBLISH", false),
10797
+        function() {
10798
+
10799
+                            options.data.method = text();
10800
+                            return options.data.method; },
10801
+        function(status_code) {
10802
+                          options.data.status_code = parseInt(status_code.join('')); },
10803
+        function() {
10804
+                          options.data.reason_phrase = text(); },
10805
+        function() {
10806
+                      options.data = text(); },
10807
+        function() {
10808
+                                var idx, length;
10809
+                                length = options.data.multi_header.length;
10810
+                                for (idx = 0; idx < length; idx++) {
10811
+                                  if (options.data.multi_header[idx].parsed === null) {
10812
+                                    options.data = null;
10813
+                                    break;
10814
+                                  }
10815
+                                }
10816
+                                if (options.data !== null) {
10817
+                                  options.data = options.data.multi_header;
10818
+                                } else {
10819
+                                  options.data = -1;
10820
+                                }},
10821
+        function() {
10822
+                                var header;
10823
+                                if(!options.data.multi_header) options.data.multi_header = [];
10824
+                                try {
10825
+                                  header = new options.SIP.NameAddrHeader(options.data.uri, options.data.displayName, options.data.params);
10826
+                                  delete options.data.uri;
10827
+                                  delete options.data.displayName;
10828
+                                  delete options.data.params;
10829
+                                } catch(e) {
10830
+                                  header = null;
10831
+                                }
10832
+                                options.data.multi_header.push( { 'position': peg$currPos,
10833
+                                                          'offset': location().start.offset,
10834
+                                                          'parsed': header
10835
+                                                        });},
10836
+        function(displayName) {
10837
+                                displayName = text().trim();
10838
+                                if (displayName[0] === '\"') {
10839
+                                  displayName = displayName.substring(1, displayName.length-1);
10840
+                                }
10841
+                                options.data.displayName = displayName; },
10842
+        "q",
10843
+        peg$literalExpectation("q", true),
10844
+        function(q) {
10845
+                                if(!options.data.params) options.data.params = {};
10846
+                                options.data.params['q'] = q; },
10847
+        "expires",
10848
+        peg$literalExpectation("expires", true),
10849
+        function(expires) {
10850
+                                if(!options.data.params) options.data.params = {};
10851
+                                options.data.params['expires'] = expires; },
10852
+        function(delta_seconds) {
10853
+                                return parseInt(delta_seconds.join('')); },
10854
+        "0",
10855
+        peg$literalExpectation("0", false),
10856
+        function() {
10857
+                                return parseFloat(text()); },
10858
+        function(param, value) {
10859
+                                if(!options.data.params) options.data.params = {};
10860
+                                if (value === null){
10861
+                                  value = undefined;
10862
+                                }
10863
+                                else {
10864
+                                  value = value[1];
10865
+                                }
10866
+                                options.data.params[param.toLowerCase()] = value;},
10867
+        "render",
10868
+        peg$literalExpectation("render", true),
10869
+        "session",
10870
+        peg$literalExpectation("session", true),
10871
+        "icon",
10872
+        peg$literalExpectation("icon", true),
10873
+        "alert",
10874
+        peg$literalExpectation("alert", true),
10875
+        function() {
10876
+                                    if (options.startRule === 'Content_Disposition') {
10877
+                                      options.data.type = text().toLowerCase();
10878
+                                    }
10879
+                                  },
10880
+        "handling",
10881
+        peg$literalExpectation("handling", true),
10882
+        "optional",
10883
+        peg$literalExpectation("optional", true),
10884
+        "required",
10885
+        peg$literalExpectation("required", true),
10886
+        function(length) {
10887
+                                options.data = parseInt(length.join('')); },
10888
+        function() {
10889
+                                options.data = text(); },
10890
+        "text",
10891
+        peg$literalExpectation("text", true),
10892
+        "image",
10893
+        peg$literalExpectation("image", true),
10894
+        "audio",
10895
+        peg$literalExpectation("audio", true),
10896
+        "video",
10897
+        peg$literalExpectation("video", true),
10898
+        "application",
10899
+        peg$literalExpectation("application", true),
10900
+        "message",
10901
+        peg$literalExpectation("message", true),
10902
+        "multipart",
10903
+        peg$literalExpectation("multipart", true),
10904
+        "x-",
10905
+        peg$literalExpectation("x-", true),
10906
+        function(cseq_value) {
10907
+                          options.data.value=parseInt(cseq_value.join('')); },
10908
+        function(expires) {options.data = expires; },
10909
+        function(event_type) {
10910
+                               options.data.event = event_type.toLowerCase(); },
10911
+        function() {
10912
+                        var tag = options.data.tag;
10913
+                          options.data = new options.SIP.NameAddrHeader(options.data.uri, options.data.displayName, options.data.params);
10914
+                          if (tag) {options.data.setParam('tag',tag)}
10915
+                        },
10916
+        "tag",
10917
+        peg$literalExpectation("tag", true),
10918
+        function(tag) {options.data.tag = tag; },
10919
+        function(forwards) {
10920
+                          options.data = parseInt(forwards.join('')); },
10921
+        function(min_expires) {options.data = min_expires; },
10922
+        function() {
10923
+                                options.data = new options.SIP.NameAddrHeader(options.data.uri, options.data.displayName, options.data.params);
10924
+                              },
10925
+        "digest",
10926
+        peg$literalExpectation("Digest", true),
10927
+        "realm",
10928
+        peg$literalExpectation("realm", true),
10929
+        function(realm) { options.data.realm = realm; },
10930
+        "domain",
10931
+        peg$literalExpectation("domain", true),
10932
+        "nonce",
10933
+        peg$literalExpectation("nonce", true),
10934
+        function(nonce) { options.data.nonce=nonce; },
10935
+        "opaque",
10936
+        peg$literalExpectation("opaque", true),
10937
+        function(opaque) { options.data.opaque=opaque; },
10938
+        "stale",
10939
+        peg$literalExpectation("stale", true),
10940
+        "true",
10941
+        peg$literalExpectation("true", true),
10942
+        function() { options.data.stale=true; },
10943
+        "false",
10944
+        peg$literalExpectation("false", true),
10945
+        function() { options.data.stale=false; },
10946
+        "algorithm",
10947
+        peg$literalExpectation("algorithm", true),
10948
+        "md5",
10949
+        peg$literalExpectation("MD5", true),
10950
+        "md5-sess",
10951
+        peg$literalExpectation("MD5-sess", true),
10952
+        function(algorithm) {
10953
+                              options.data.algorithm=algorithm.toUpperCase(); },
10954
+        "qop",
10955
+        peg$literalExpectation("qop", true),
10956
+        "auth-int",
10957
+        peg$literalExpectation("auth-int", true),
10958
+        "auth",
10959
+        peg$literalExpectation("auth", true),
10960
+        function(qop_value) {
10961
+                                options.data.qop || (options.data.qop=[]);
10962
+                                options.data.qop.push(qop_value.toLowerCase()); },
10963
+        function(rack_value) {
10964
+                          options.data.value=parseInt(rack_value.join('')); },
10965
+        function() {
10966
+                          var idx, length;
10967
+                          length = options.data.multi_header.length;
10968
+                          for (idx = 0; idx < length; idx++) {
10969
+                            if (options.data.multi_header[idx].parsed === null) {
10970
+                              options.data = null;
10971
+                              break;
10972
+                            }
10973
+                          }
10974
+                          if (options.data !== null) {
10975
+                            options.data = options.data.multi_header;
10976
+                          } else {
10977
+                            options.data = -1;
10978
+                          }},
10979
+        function() {
10980
+                          var header;
10981
+                          if(!options.data.multi_header) options.data.multi_header = [];
10982
+                          try {
10983
+                            header = new options.SIP.NameAddrHeader(options.data.uri, options.data.displayName, options.data.params);
10984
+                            delete options.data.uri;
10985
+                            delete options.data.displayName;
10986
+                            delete options.data.params;
10987
+                          } catch(e) {
10988
+                            header = null;
10989
+                          }
10990
+                          options.data.multi_header.push( { 'position': peg$currPos,
10991
+                                                    'offset': location().start.offset,
10992
+                                                    'parsed': header
10993
+                                                  });},
10994
+        function() {
10995
+                      options.data = new options.SIP.NameAddrHeader(options.data.uri, options.data.displayName, options.data.params);
10996
+                    },
10997
+        function() {
10998
+                              if (!(options.data.replaces_from_tag && options.data.replaces_to_tag)) {
10999
+                                options.data = -1;
11000
+                              }
11001
+                            },
11002
+        function() {
11003
+                              options.data = {
11004
+                                call_id: options.data
11005
+                              };
11006
+                            },
11007
+        "from-tag",
11008
+        peg$literalExpectation("from-tag", true),
11009
+        function(from_tag) {
11010
+                              options.data.replaces_from_tag = from_tag;
11011
+                            },
11012
+        "to-tag",
11013
+        peg$literalExpectation("to-tag", true),
11014
+        function(to_tag) {
11015
+                              options.data.replaces_to_tag = to_tag;
11016
+                            },
11017
+        "early-only",
11018
+        peg$literalExpectation("early-only", true),
11019
+        function() {
11020
+                              options.data.early_only = true;
11021
+                            },
11022
+        function(head, r) {return r;},
11023
+        function(head, tail) { return list(head, tail); },
11024
+        function(value) {
11025
+                        if (options.startRule === 'Require') {
11026
+                          options.data = value || [];
11027
+                        }
11028
+                      },
11029
+        function(rseq_value) {
11030
+                          options.data.value=parseInt(rseq_value.join('')); },
11031
+        "active",
11032
+        peg$literalExpectation("active", true),
11033
+        "pending",
11034
+        peg$literalExpectation("pending", true),
11035
+        "terminated",
11036
+        peg$literalExpectation("terminated", true),
11037
+        function() {
11038
+                                options.data.state = text(); },
11039
+        "reason",
11040
+        peg$literalExpectation("reason", true),
11041
+        function(reason) {
11042
+                                if (typeof reason !== 'undefined') options.data.reason = reason; },
11043
+        function(expires) {
11044
+                                if (typeof expires !== 'undefined') options.data.expires = expires; },
11045
+        "retry_after",
11046
+        peg$literalExpectation("retry_after", true),
11047
+        function(retry_after) {
11048
+                                if (typeof retry_after !== 'undefined') options.data.retry_after = retry_after; },
11049
+        "deactivated",
11050
+        peg$literalExpectation("deactivated", true),
11051
+        "probation",
11052
+        peg$literalExpectation("probation", true),
11053
+        "rejected",
11054
+        peg$literalExpectation("rejected", true),
11055
+        "timeout",
11056
+        peg$literalExpectation("timeout", true),
11057
+        "giveup",
11058
+        peg$literalExpectation("giveup", true),
11059
+        "noresource",
11060
+        peg$literalExpectation("noresource", true),
11061
+        "invariant",
11062
+        peg$literalExpectation("invariant", true),
11063
+        function(value) {
11064
+                        if (options.startRule === 'Supported') {
11065
+                          options.data = value || [];
11066
+                        }
11067
+                      },
11068
+        function() {
11069
+                      var tag = options.data.tag;
11070
+                        options.data = new options.SIP.NameAddrHeader(options.data.uri, options.data.displayName, options.data.params);
11071
+                        if (tag) {options.data.setParam('tag',tag)}
11072
+                      },
11073
+        "ttl",
11074
+        peg$literalExpectation("ttl", true),
11075
+        function(via_ttl_value) {
11076
+                              options.data.ttl = via_ttl_value; },
11077
+        "maddr",
11078
+        peg$literalExpectation("maddr", true),
11079
+        function(via_maddr) {
11080
+                              options.data.maddr = via_maddr; },
11081
+        "received",
11082
+        peg$literalExpectation("received", true),
11083
+        function(via_received) {
11084
+                              options.data.received = via_received; },
11085
+        "branch",
11086
+        peg$literalExpectation("branch", true),
11087
+        function(via_branch) {
11088
+                              options.data.branch = via_branch; },
11089
+        "rport",
11090
+        peg$literalExpectation("rport", true),
11091
+        function() {
11092
+                              if(typeof response_port !== 'undefined')
11093
+                                options.data.rport = response_port.join(''); },
11094
+        function(via_protocol) {
11095
+                              options.data.protocol = via_protocol; },
11096
+        peg$literalExpectation("UDP", true),
11097
+        peg$literalExpectation("TCP", true),
11098
+        peg$literalExpectation("TLS", true),
11099
+        peg$literalExpectation("SCTP", true),
11100
+        function(via_transport) {
11101
+                              options.data.transport = via_transport; },
11102
+        function() {
11103
+                              options.data.host = text(); },
11104
+        function(via_sent_by_port) {
11105
+                              options.data.port = parseInt(via_sent_by_port.join('')); },
11106
+        function(ttl) {
11107
+                              return parseInt(ttl.join('')); },
11108
+        function(deltaSeconds) {
11109
+                              if (options.startRule === 'Session_Expires') {
11110
+                                options.data.deltaSeconds = deltaSeconds;
11111
+                              }
11112
+                            },
11113
+        "refresher",
11114
+        peg$literalExpectation("refresher", false),
11115
+        "uas",
11116
+        peg$literalExpectation("uas", false),
11117
+        "uac",
11118
+        peg$literalExpectation("uac", false),
11119
+        function(endpoint) {
11120
+                              if (options.startRule === 'Session_Expires') {
11121
+                                options.data.refresher = endpoint;
11122
+                              }
11123
+                            },
11124
+        function(deltaSeconds) {
11125
+                              if (options.startRule === 'Min_SE') {
11126
+                                options.data = deltaSeconds;
11127
+                              }
11128
+                            },
11129
+        "stuns",
11130
+        peg$literalExpectation("stuns", true),
11131
+        "stun",
11132
+        peg$literalExpectation("stun", true),
11133
+        function(scheme) {
11134
+                              options.data.scheme = scheme; },
11135
+        function(host) {
11136
+                              options.data.host = host; },
11137
+        "?transport=",
11138
+        peg$literalExpectation("?transport=", false),
11139
+        "turns",
11140
+        peg$literalExpectation("turns", true),
11141
+        "turn",
11142
+        peg$literalExpectation("turn", true),
11143
+        function() {
11144
+                              options.data.transport = transport; },
11145
+        function() {
11146
+                          options.data = text(); },
11147
+        "Referred-By",
11148
+        peg$literalExpectation("Referred-By", false),
11149
+        "b",
11150
+        peg$literalExpectation("b", false),
11151
+        "cid",
11152
+        peg$literalExpectation("cid", false)
11153
+      ],
11154
+
11155
+      peg$bytecode = [
11156
+        peg$decode("2 \"\"6 7!"),
11157
+        peg$decode("4\"\"\"5!7#"),
11158
+        peg$decode("4$\"\"5!7%"),
11159
+        peg$decode("4&\"\"5!7'"),
11160
+        peg$decode(";'.# &;("),
11161
+        peg$decode("4(\"\"5!7)"),
11162
+        peg$decode("4*\"\"5!7+"),
11163
+        peg$decode("2,\"\"6,7-"),
11164
+        peg$decode("2.\"\"6.7/"),
11165
+        peg$decode("40\"\"5!71"),
11166
+        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"),
11167
+        peg$decode(";).# &;,"),
11168
+        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"),
11169
+        peg$decode("%%2X\"\"6X7Y/5#;#/,$;#/#$+#)(#'#(\"'#&'#/\"!&,)"),
11170
+        peg$decode("%%$;$0#*;$&/,#; /#$+\")(\"'#&'#.\" &\"/=#$;$/&#0#*;$&&&#/'$8\":Z\" )(\"'#&'#"),
11171
+        peg$decode(";..\" &\""),
11172
+        peg$decode("%$;'.# &;(0)*;'.# &;(&/?#28\"\"6879/0$;//'$8#:[# )(#'#(\"'#&'#"),
11173
+        peg$decode("%%$;2/&#0#*;2&&&#/g#$%$;.0#*;.&/,#;2/#$+\")(\"'#&'#0=*%$;.0#*;.&/,#;2/#$+\")(\"'#&'#&/#$+\")(\"'#&'#/\"!&,)"),
11174
+        peg$decode("4\\\"\"5!7].# &;3"),
11175
+        peg$decode("4^\"\"5!7_"),
11176
+        peg$decode("4`\"\"5!7a"),
11177
+        peg$decode(";!.) &4b\"\"5!7c"),
11178
+        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&&&#/\"!&,)"),
11179
+        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&&&#/\"!&,)"),
11180
+        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.) &;'.# &;("),
11181
+        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&&&#/\"!&,)"),
11182
+        peg$decode("%;//?#2P\"\"6P7Q/0$;//'$8#:t# )(#'#(\"'#&'#"),
11183
+        peg$decode("%;//?#24\"\"6475/0$;//'$8#:u# )(#'#(\"'#&'#"),
11184
+        peg$decode("%;//?#2>\"\"6>7?/0$;//'$8#:v# )(#'#(\"'#&'#"),
11185
+        peg$decode("%;//?#2T\"\"6T7U/0$;//'$8#:w# )(#'#(\"'#&'#"),
11186
+        peg$decode("%;//?#2V\"\"6V7W/0$;//'$8#:x# )(#'#(\"'#&'#"),
11187
+        peg$decode("%2h\"\"6h7i/0#;//'$8\":y\" )(\"'#&'#"),
11188
+        peg$decode("%;//6#2f\"\"6f7g/'$8\":z\" )(\"'#&'#"),
11189
+        peg$decode("%;//?#2D\"\"6D7E/0$;//'$8#:{# )(#'#(\"'#&'#"),
11190
+        peg$decode("%;//?#22\"\"6273/0$;//'$8#:|# )(#'#(\"'#&'#"),
11191
+        peg$decode("%;//?#28\"\"6879/0$;//'$8#:}# )(#'#(\"'#&'#"),
11192
+        peg$decode("%;//0#;&/'$8\":~\" )(\"'#&'#"),
11193
+        peg$decode("%;&/0#;//'$8\":~\" )(\"'#&'#"),
11194
+        peg$decode("%;=/T#$;G.) &;K.# &;F0/*;G.) &;K.# &;F&/,$;>/#$+#)(#'#(\"'#&'#"),
11195
+        peg$decode("4\x7F\"\"5!7\x80.A &4\x81\"\"5!7\x82.5 &4\x83\"\"5!7\x84.) &;3.# &;."),
11196
+        peg$decode("%%;//Q#;&/H$$;J.# &;K0)*;J.# &;K&/,$;&/#$+$)($'#(#'#(\"'#&'#/\"!&,)"),
11197
+        peg$decode("%;//]#;&/T$%$;J.# &;K0)*;J.# &;K&/\"!&,)/1$;&/($8$:\x85$!!)($'#(#'#(\"'#&'#"),
11198
+        peg$decode(";..G &2L\"\"6L7M.; &4\x86\"\"5!7\x87./ &4\x83\"\"5!7\x84.# &;3"),
11199
+        peg$decode("%2j\"\"6j7k/J#4\x88\"\"5!7\x89.5 &4\x8A\"\"5!7\x8B.) &4\x8C\"\"5!7\x8D/#$+\")(\"'#&'#"),
11200
+        peg$decode("%;N/M#28\"\"6879/>$;O.\" &\"/0$;S/'$8$:\x8E$ )($'#(#'#(\"'#&'#"),
11201
+        peg$decode("%;N/d#28\"\"6879/U$;O.\" &\"/G$;S/>$;_/5$;l.\" &\"/'$8&:\x8F& )(&'#(%'#($'#(#'#(\"'#&'#"),
11202
+        peg$decode("%3\x90\"\"5$7\x91.) &3\x92\"\"5#7\x93/' 8!:\x94!! )"),
11203
+        peg$decode("%;P/]#%28\"\"6879/,#;R/#$+\")(\"'#&'#.\" &\"/6$2:\"\"6:7;/'$8#:\x95# )(#'#(\"'#&'#"),
11204
+        peg$decode("$;+.) &;-.# &;Q/2#0/*;+.) &;-.# &;Q&&&#"),
11205
+        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"),
11206
+        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! )"),
11207
+        peg$decode("%;T/J#%28\"\"6879/,#;^/#$+\")(\"'#&'#.\" &\"/#$+\")(\"'#&'#"),
11208
+        peg$decode("%;U.) &;\\.# &;X/& 8!:\x97! )"),
11209
+        peg$decode("%$%;V/2#2J\"\"6J7K/#$+\")(\"'#&'#0<*%;V/2#2J\"\"6J7K/#$+\")(\"'#&'#&/D#;W/;$2J\"\"6J7K.\" &\"/'$8#:\x98# )(#'#(\"'#&'#"),
11210
+        peg$decode("$4\x99\"\"5!7\x9A/,#0)*4\x99\"\"5!7\x9A&&&#"),
11211
+        peg$decode("%4$\"\"5!7%/?#$4\x9B\"\"5!7\x9C0)*4\x9B\"\"5!7\x9C&/#$+\")(\"'#&'#"),
11212
+        peg$decode("%2l\"\"6l7m/?#;Y/6$2n\"\"6n7o/'$8#:\x9D# )(#'#(\"'#&'#"),
11213
+        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! )"),
11214
+        peg$decode("%;#/M#;#.\" &\"/?$;#.\" &\"/1$;#.\" &\"/#$+$)($'#(#'#(\"'#&'#"),
11215
+        peg$decode("%;Z/;#28\"\"6879/,$;Z/#$+#)(#'#(\"'#&'#.# &;\\"),
11216
+        peg$decode("%;]/o#2J\"\"6J7K/`$;]/W$2J\"\"6J7K/H$;]/?$2J\"\"6J7K/0$;]/'$8':\xA1' )(''#(&'#(%'#($'#(#'#(\"'#&'#"),
11217
+        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/,#;!/#$+\")(\"'#&'#.# &;!"),
11218
+        peg$decode("%%;!.\" &\"/[#;!.\" &\"/M$;!.\" &\"/?$;!.\" &\"/1$;!.\" &\"/#$+%)(%'#($'#(#'#(\"'#&'#/' 8!:\xAE!! )"),
11219
+        peg$decode("$%22\"\"6273/,#;`/#$+\")(\"'#&'#0<*%22\"\"6273/,#;`/#$+\")(\"'#&'#&"),
11220
+        peg$decode(";a.A &;b.; &;c.5 &;d./ &;e.) &;f.# &;g"),
11221
+        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\"! )(\"'#&'#"),
11222
+        peg$decode("%3\xBA\"\"5%7\xBB/I#3\xBC\"\"5%7\xBD./ &3\xBE\"\"5\"7\xBF.# &;6/($8\":\xC0\"! )(\"'#&'#"),
11223
+        peg$decode("%3\xC1\"\"5'7\xC2/1#;\x90/($8\":\xC3\"! )(\"'#&'#"),
11224
+        peg$decode("%3\xC4\"\"5$7\xC5/1#;\xF0/($8\":\xC6\"! )(\"'#&'#"),
11225
+        peg$decode("%3\xC7\"\"5&7\xC8/1#;T/($8\":\xC9\"! )(\"'#&'#"),
11226
+        peg$decode("%3\xCA\"\"5\"7\xCB/N#%2>\"\"6>7?/,#;6/#$+\")(\"'#&'#.\" &\"/'$8\":\xCC\" )(\"'#&'#"),
11227
+        peg$decode("%;h/P#%2>\"\"6>7?/,#;i/#$+\")(\"'#&'#.\" &\"/)$8\":\xCD\"\"! )(\"'#&'#"),
11228
+        peg$decode("%$;j/&#0#*;j&&&#/\"!&,)"),
11229
+        peg$decode("%$;j/&#0#*;j&&&#/\"!&,)"),
11230
+        peg$decode(";k.) &;+.# &;-"),
11231
+        peg$decode("2l\"\"6l7m.e &2n\"\"6n7o.Y &24\"\"6475.M &28\"\"6879.A &2<\"\"6<7=.5 &2@\"\"6@7A.) &2B\"\"6B7C"),
11232
+        peg$decode("%26\"\"6677/n#;m/e$$%2<\"\"6<7=/,#;m/#$+\")(\"'#&'#0<*%2<\"\"6<7=/,#;m/#$+\")(\"'#&'#&/#$+#)(#'#(\"'#&'#"),
11233
+        peg$decode("%;n/A#2>\"\"6>7?/2$;o/)$8#:\xCE#\"\" )(#'#(\"'#&'#"),
11234
+        peg$decode("$;p.) &;+.# &;-/2#0/*;p.) &;+.# &;-&&&#"),
11235
+        peg$decode("$;p.) &;+.# &;-0/*;p.) &;+.# &;-&"),
11236
+        peg$decode("2l\"\"6l7m.e &2n\"\"6n7o.Y &24\"\"6475.M &26\"\"6677.A &28\"\"6879.5 &2@\"\"6@7A.) &2B\"\"6B7C"),
11237
+        peg$decode(";\x91.# &;r"),
11238
+        peg$decode("%;\x90/G#;'/>$;s/5$;'/,$;\x84/#$+%)(%'#($'#(#'#(\"'#&'#"),
11239
+        peg$decode(";M.# &;t"),
11240
+        peg$decode("%;\x7F/E#28\"\"6879/6$;u.# &;x/'$8#:\xCF# )(#'#(\"'#&'#"),
11241
+        peg$decode("%;v.# &;w/J#%26\"\"6677/,#;\x83/#$+\")(\"'#&'#.\" &\"/#$+\")(\"'#&'#"),
11242
+        peg$decode("%2\xD0\"\"6\xD07\xD1/:#;\x80/1$;w.\" &\"/#$+#)(#'#(\"'#&'#"),
11243
+        peg$decode("%24\"\"6475/,#;{/#$+\")(\"'#&'#"),
11244
+        peg$decode("%;z/3#$;y0#*;y&/#$+\")(\"'#&'#"),
11245
+        peg$decode(";*.) &;+.# &;-"),
11246
+        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"),
11247
+        peg$decode("%;|/e#$%24\"\"6475/,#;|/#$+\")(\"'#&'#0<*%24\"\"6475/,#;|/#$+\")(\"'#&'#&/#$+\")(\"'#&'#"),
11248
+        peg$decode("%$;~0#*;~&/e#$%22\"\"6273/,#;}/#$+\")(\"'#&'#0<*%22\"\"6273/,#;}/#$+\")(\"'#&'#&/#$+\")(\"'#&'#"),
11249
+        peg$decode("$;~0#*;~&"),
11250
+        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"),
11251
+        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! )"),
11252
+        peg$decode(";\x81.# &;\x82"),
11253
+        peg$decode("%%;O/2#2:\"\"6:7;/#$+\")(\"'#&'#.\" &\"/,#;S/#$+\")(\"'#&'#.\" &\""),
11254
+        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&&&#"),
11255
+        peg$decode("$;y0#*;y&"),
11256
+        peg$decode("%3\x92\"\"5#7\xD3/q#24\"\"6475/b$$;!/&#0#*;!&&&#/L$2J\"\"6J7K/=$$;!/&#0#*;!&&&#/'$8%:\xD4% )(%'#($'#(#'#(\"'#&'#"),
11257
+        peg$decode("2\xD5\"\"6\xD57\xD6"),
11258
+        peg$decode("2\xD7\"\"6\xD77\xD8"),
11259
+        peg$decode("2\xD9\"\"6\xD97\xDA"),
11260
+        peg$decode("2\xDB\"\"6\xDB7\xDC"),
11261
+        peg$decode("2\xDD\"\"6\xDD7\xDE"),
11262
+        peg$decode("2\xDF\"\"6\xDF7\xE0"),
11263
+        peg$decode("2\xE1\"\"6\xE17\xE2"),
11264
+        peg$decode("2\xE3\"\"6\xE37\xE4"),
11265
+        peg$decode("2\xE5\"\"6\xE57\xE6"),
11266
+        peg$decode("2\xE7\"\"6\xE77\xE8"),
11267
+        peg$decode("2\xE9\"\"6\xE97\xEA"),
11268
+        peg$decode("%;\x85.Y &;\x86.S &;\x88.M &;\x89.G &;\x8A.A &;\x8B.; &;\x8C.5 &;\x8F./ &;\x8D.) &;\x8E.# &;6/& 8!:\xEB! )"),
11269
+        peg$decode("%;\x84/G#;'/>$;\x92/5$;'/,$;\x94/#$+%)(%'#($'#(#'#(\"'#&'#"),
11270
+        peg$decode("%;\x93/' 8!:\xEC!! )"),
11271
+        peg$decode("%;!/5#;!/,$;!/#$+#)(#'#(\"'#&'#"),
11272
+        peg$decode("%$;*.A &;+.; &;-.5 &;3./ &;4.) &;'.# &;(0G*;*.A &;+.; &;-.5 &;3./ &;4.) &;'.# &;(&/& 8!:\xED! )"),
11273
+        peg$decode("%;\xB6/Y#$%;A/,#;\xB6/#$+\")(\"'#&'#06*%;A/,#;\xB6/#$+\")(\"'#&'#&/#$+\")(\"'#&'#"),
11274
+        peg$decode("%;9/N#%2:\"\"6:7;/,#;9/#$+\")(\"'#&'#.\" &\"/'$8\":\xEE\" )(\"'#&'#"),
11275
+        peg$decode("%;:.c &%;\x98/Y#$%;A/,#;\x98/#$+\")(\"'#&'#06*%;A/,#;\x98/#$+\")(\"'#&'#&/#$+\")(\"'#&'#/& 8!:\xEF! )"),
11276
+        peg$decode("%;L.# &;\x99/]#$%;B/,#;\x9B/#$+\")(\"'#&'#06*%;B/,#;\x9B/#$+\")(\"'#&'#&/'$8\":\xF0\" )(\"'#&'#"),
11277
+        peg$decode("%;\x9A.\" &\"/>#;@/5$;M/,$;?/#$+$)($'#(#'#(\"'#&'#"),
11278
+        peg$decode("%%;6/Y#$%;./,#;6/#$+\")(\"'#&'#06*%;./,#;6/#$+\")(\"'#&'#&/#$+\")(\"'#&'#.# &;H/' 8!:\xF1!! )"),
11279
+        peg$decode(";\x9C.) &;\x9D.# &;\xA0"),
11280
+        peg$decode("%3\xF2\"\"5!7\xF3/:#;</1$;\x9F/($8#:\xF4#! )(#'#(\"'#&'#"),
11281
+        peg$decode("%3\xF5\"\"5'7\xF6/:#;</1$;\x9E/($8#:\xF7#! )(#'#(\"'#&'#"),
11282
+        peg$decode("%$;!/&#0#*;!&&&#/' 8!:\xF8!! )"),
11283
+        peg$decode("%2\xF9\"\"6\xF97\xFA/o#%2J\"\"6J7K/M#;!.\" &\"/?$;!.\" &\"/1$;!.\" &\"/#$+$)($'#(#'#(\"'#&'#.\" &\"/'$8\":\xFB\" )(\"'#&'#"),
11284
+        peg$decode("%;6/J#%;</,#;\xA1/#$+\")(\"'#&'#.\" &\"/)$8\":\xFC\"\"! )(\"'#&'#"),
11285
+        peg$decode(";6.) &;T.# &;H"),
11286
+        peg$decode("%;\xA3/Y#$%;B/,#;\xA4/#$+\")(\"'#&'#06*%;B/,#;\xA4/#$+\")(\"'#&'#&/#$+\")(\"'#&'#"),
11287
+        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! )"),
11288
+        peg$decode(";\xA5.# &;\xA0"),
11289
+        peg$decode("%3\u0106\"\"5(7\u0107/M#;</D$3\u0108\"\"5(7\u0109./ &3\u010A\"\"5(7\u010B.# &;6/#$+#)(#'#(\"'#&'#"),
11290
+        peg$decode("%;6/Y#$%;A/,#;6/#$+\")(\"'#&'#06*%;A/,#;6/#$+\")(\"'#&'#&/#$+\")(\"'#&'#"),
11291
+        peg$decode("%$;!/&#0#*;!&&&#/' 8!:\u010C!! )"),
11292
+        peg$decode("%;\xA9/& 8!:\u010D! )"),
11293
+        peg$decode("%;\xAA/k#;;/b$;\xAF/Y$$%;B/,#;\xB0/#$+\")(\"'#&'#06*%;B/,#;\xB0/#$+\")(\"'#&'#&/#$+$)($'#(#'#(\"'#&'#"),
11294
+        peg$decode(";\xAB.# &;\xAC"),
11295
+        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"),
11296
+        peg$decode("3\u0118\"\"5'7\u0119./ &3\u011A\"\"5)7\u011B.# &;\xAD"),
11297
+        peg$decode(";6.# &;\xAE"),
11298
+        peg$decode("%3\u011C\"\"5\"7\u011D/,#;6/#$+\")(\"'#&'#"),
11299
+        peg$decode(";\xAD.# &;6"),
11300
+        peg$decode("%;6/5#;</,$;\xB1/#$+#)(#'#(\"'#&'#"),
11301
+        peg$decode(";6.# &;H"),
11302
+        peg$decode("%;\xB3/5#;./,$;\x90/#$+#)(#'#(\"'#&'#"),
11303
+        peg$decode("%$;!/&#0#*;!&&&#/' 8!:\u011E!! )"),
11304
+        peg$decode("%;\x9E/' 8!:\u011F!! )"),
11305
+        peg$decode("%;\xB6/^#$%;B/,#;\xA0/#$+\")(\"'#&'#06*%;B/,#;\xA0/#$+\")(\"'#&'#&/($8\":\u0120\"!!)(\"'#&'#"),
11306
+        peg$decode("%%;7/e#$%2J\"\"6J7K/,#;7/#$+\")(\"'#&'#0<*%2J\"\"6J7K/,#;7/#$+\")(\"'#&'#&/#$+\")(\"'#&'#/\"!&,)"),
11307
+        peg$decode("%;L.# &;\x99/]#$%;B/,#;\xB8/#$+\")(\"'#&'#06*%;B/,#;\xB8/#$+\")(\"'#&'#&/'$8\":\u0121\" )(\"'#&'#"),
11308
+        peg$decode(";\xB9.# &;\xA0"),
11309
+        peg$decode("%3\u0122\"\"5#7\u0123/:#;</1$;6/($8#:\u0124#! )(#'#(\"'#&'#"),
11310
+        peg$decode("%$;!/&#0#*;!&&&#/' 8!:\u0125!! )"),
11311
+        peg$decode("%;\x9E/' 8!:\u0126!! )"),
11312
+        peg$decode("%$;\x9A0#*;\x9A&/x#;@/o$;M/f$;?/]$$%;B/,#;\xA0/#$+\")(\"'#&'#06*%;B/,#;\xA0/#$+\")(\"'#&'#&/'$8%:\u0127% )(%'#($'#(#'#(\"'#&'#"),
11313
+        peg$decode(";\xBE"),
11314
+        peg$decode("%3\u0128\"\"5&7\u0129/k#;./b$;\xC1/Y$$%;A/,#;\xC1/#$+\")(\"'#&'#06*%;A/,#;\xC1/#$+\")(\"'#&'#&/#$+$)($'#(#'#(\"'#&'#.# &;\xBF"),
11315
+        peg$decode("%;6/k#;./b$;\xC0/Y$$%;A/,#;\xC0/#$+\")(\"'#&'#06*%;A/,#;\xC0/#$+\")(\"'#&'#&/#$+$)($'#(#'#(\"'#&'#"),
11316
+        peg$decode("%;6/;#;</2$;6.# &;H/#$+#)(#'#(\"'#&'#"),
11317
+        peg$decode(";\xC2.G &;\xC4.A &;\xC6.; &;\xC8.5 &;\xC9./ &;\xCA.) &;\xCB.# &;\xC0"),
11318
+        peg$decode("%3\u012A\"\"5%7\u012B/5#;</,$;\xC3/#$+#)(#'#(\"'#&'#"),
11319
+        peg$decode("%;I/' 8!:\u012C!! )"),
11320
+        peg$decode("%3\u012D\"\"5&7\u012E/\x97#;</\x8E$;D/\x85$;\xC5/|$$%$;'/&#0#*;'&&&#/,#;\xC5/#$+\")(\"'#&'#0C*%$;'/&#0#*;'&&&#/,#;\xC5/#$+\")(\"'#&'#&/,$;E/#$+&)(&'#(%'#($'#(#'#(\"'#&'#"),
11321
+        peg$decode(";t.# &;w"),
11322
+        peg$decode("%3\u012F\"\"5%7\u0130/5#;</,$;\xC7/#$+#)(#'#(\"'#&'#"),
11323
+        peg$decode("%;I/' 8!:\u0131!! )"),
11324
+        peg$decode("%3\u0132\"\"5&7\u0133/:#;</1$;I/($8#:\u0134#! )(#'#(\"'#&'#"),
11325
+        peg$decode("%3\u0135\"\"5%7\u0136/]#;</T$%3\u0137\"\"5$7\u0138/& 8!:\u0139! ).4 &%3\u013A\"\"5%7\u013B/& 8!:\u013C! )/#$+#)(#'#(\"'#&'#"),
11326
+        peg$decode("%3\u013D\"\"5)7\u013E/R#;</I$3\u013F\"\"5#7\u0140./ &3\u0141\"\"5(7\u0142.# &;6/($8#:\u0143#! )(#'#(\"'#&'#"),
11327
+        peg$decode("%3\u0144\"\"5#7\u0145/\x93#;</\x8A$;D/\x81$%;\xCC/e#$%2D\"\"6D7E/,#;\xCC/#$+\")(\"'#&'#0<*%2D\"\"6D7E/,#;\xCC/#$+\")(\"'#&'#&/#$+\")(\"'#&'#/,$;E/#$+%)(%'#($'#(#'#(\"'#&'#"),
11328
+        peg$decode("%3\u0146\"\"5(7\u0147./ &3\u0148\"\"5$7\u0149.# &;6/' 8!:\u014A!! )"),
11329
+        peg$decode("%;6/Y#$%;A/,#;6/#$+\")(\"'#&'#06*%;A/,#;6/#$+\")(\"'#&'#&/#$+\")(\"'#&'#"),
11330
+        peg$decode("%;\xCF/G#;./>$;\xCF/5$;./,$;\x90/#$+%)(%'#($'#(#'#(\"'#&'#"),
11331
+        peg$decode("%$;!/&#0#*;!&&&#/' 8!:\u014B!! )"),
11332
+        peg$decode("%;\xD1/]#$%;A/,#;\xD1/#$+\")(\"'#&'#06*%;A/,#;\xD1/#$+\")(\"'#&'#&/'$8\":\u014C\" )(\"'#&'#"),
11333
+        peg$decode("%;\x99/]#$%;B/,#;\xA0/#$+\")(\"'#&'#06*%;B/,#;\xA0/#$+\")(\"'#&'#&/'$8\":\u014D\" )(\"'#&'#"),
11334
+        peg$decode("%;L.O &;\x99.I &%;@.\" &\"/:#;t/1$;?.\" &\"/#$+#)(#'#(\"'#&'#/]#$%;B/,#;\xA0/#$+\")(\"'#&'#06*%;B/,#;\xA0/#$+\")(\"'#&'#&/'$8\":\u014E\" )(\"'#&'#"),
11335
+        peg$decode("%;\xD4/]#$%;B/,#;\xD5/#$+\")(\"'#&'#06*%;B/,#;\xD5/#$+\")(\"'#&'#&/'$8\":\u014F\" )(\"'#&'#"),
11336
+        peg$decode("%;\x96/& 8!:\u0150! )"),
11337
+        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"),
11338
+        peg$decode("%%;6/k#$%;A/2#;6/)$8\":\u015A\"\"$ )(\"'#&'#0<*%;A/2#;6/)$8\":\u015A\"\"$ )(\"'#&'#&/)$8\":\u015B\"\"! )(\"'#&'#.\" &\"/' 8!:\u015C!! )"),
11339
+        peg$decode("%;\xD8/Y#$%;A/,#;\xD8/#$+\")(\"'#&'#06*%;A/,#;\xD8/#$+\")(\"'#&'#&/#$+\")(\"'#&'#"),
11340
+        peg$decode("%;\x99/Y#$%;B/,#;\xA0/#$+\")(\"'#&'#06*%;B/,#;\xA0/#$+\")(\"'#&'#&/#$+\")(\"'#&'#"),
11341
+        peg$decode("%$;!/&#0#*;!&&&#/' 8!:\u015D!! )"),
11342
+        peg$decode("%;\xDB/Y#$%;B/,#;\xDC/#$+\")(\"'#&'#06*%;B/,#;\xDC/#$+\")(\"'#&'#&/#$+\")(\"'#&'#"),
11343
+        peg$decode("%3\u015E\"\"5&7\u015F.; &3\u0160\"\"5'7\u0161./ &3\u0162\"\"5*7\u0163.# &;6/& 8!:\u0164! )"),
11344
+        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"),
11345
+        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"),
11346
+        peg$decode(";1.\" &\""),
11347
+        peg$decode("%%;6/k#$%;A/2#;6/)$8\":\u015A\"\"$ )(\"'#&'#0<*%;A/2#;6/)$8\":\u015A\"\"$ )(\"'#&'#&/)$8\":\u015B\"\"! )(\"'#&'#.\" &\"/' 8!:\u017A!! )"),
11348
+        peg$decode("%;L.# &;\x99/]#$%;B/,#;\xE1/#$+\")(\"'#&'#06*%;B/,#;\xE1/#$+\")(\"'#&'#&/'$8\":\u017B\" )(\"'#&'#"),
11349
+        peg$decode(";\xB9.# &;\xA0"),
11350
+        peg$decode("%;\xE3/Y#$%;A/,#;\xE3/#$+\")(\"'#&'#06*%;A/,#;\xE3/#$+\")(\"'#&'#&/#$+\")(\"'#&'#"),
11351
+        peg$decode("%;\xEA/k#;./b$;\xED/Y$$%;B/,#;\xE4/#$+\")(\"'#&'#06*%;B/,#;\xE4/#$+\")(\"'#&'#&/#$+$)($'#(#'#(\"'#&'#"),
11352
+        peg$decode(";\xE5.; &;\xE6.5 &;\xE7./ &;\xE8.) &;\xE9.# &;\xA0"),
11353
+        peg$decode("%3\u017C\"\"5#7\u017D/:#;</1$;\xF0/($8#:\u017E#! )(#'#(\"'#&'#"),
11354
+        peg$decode("%3\u017F\"\"5%7\u0180/:#;</1$;T/($8#:\u0181#! )(#'#(\"'#&'#"),
11355
+        peg$decode("%3\u0182\"\"5(7\u0183/F#;</=$;\\.) &;Y.# &;X/($8#:\u0184#! )(#'#(\"'#&'#"),
11356
+        peg$decode("%3\u0185\"\"5&7\u0186/:#;</1$;6/($8#:\u0187#! )(#'#(\"'#&'#"),
11357
+        peg$decode("%3\u0188\"\"5%7\u0189/O#%;</3#$;!0#*;!&/#$+\")(\"'#&'#.\" &\"/'$8\":\u018A\" )(\"'#&'#"),
11358
+        peg$decode("%;\xEB/G#;;/>$;6/5$;;/,$;\xEC/#$+%)(%'#($'#(#'#(\"'#&'#"),
11359
+        peg$decode("%3\x92\"\"5#7\xD3.# &;6/' 8!:\u018B!! )"),
11360
+        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!! )"),
11361
+        peg$decode("%;\xEE/D#%;C/,#;\xEF/#$+\")(\"'#&'#.\" &\"/#$+\")(\"'#&'#"),
11362
+        peg$decode("%;U.) &;\\.# &;X/& 8!:\u0191! )"),
11363
+        peg$decode("%%;!.\" &\"/[#;!.\" &\"/M$;!.\" &\"/?$;!.\" &\"/1$;!.\" &\"/#$+%)(%'#($'#(#'#(\"'#&'#/' 8!:\u0192!! )"),
11364
+        peg$decode("%%;!/?#;!.\" &\"/1$;!.\" &\"/#$+#)(#'#(\"'#&'#/' 8!:\u0193!! )"),
11365
+        peg$decode(";\xBE"),
11366
+        peg$decode("%;\x9E/^#$%;B/,#;\xF3/#$+\")(\"'#&'#06*%;B/,#;\xF3/#$+\")(\"'#&'#&/($8\":\u0194\"!!)(\"'#&'#"),
11367
+        peg$decode(";\xF4.# &;\xA0"),
11368
+        peg$decode("%2\u0195\"\"6\u01957\u0196/L#;</C$2\u0197\"\"6\u01977\u0198.) &2\u0199\"\"6\u01997\u019A/($8#:\u019B#! )(#'#(\"'#&'#"),
11369
+        peg$decode("%;\x9E/^#$%;B/,#;\xA0/#$+\")(\"'#&'#06*%;B/,#;\xA0/#$+\")(\"'#&'#&/($8\":\u019C\"!!)(\"'#&'#"),
11370
+        peg$decode("%;6/5#;0/,$;\xF7/#$+#)(#'#(\"'#&'#"),
11371
+        peg$decode("$;2.) &;4.# &;.0/*;2.) &;4.# &;.&"),
11372
+        peg$decode("$;%0#*;%&"),
11373
+        peg$decode("%;\xFA/;#28\"\"6879/,$;\xFB/#$+#)(#'#(\"'#&'#"),
11374
+        peg$decode("%3\u019D\"\"5%7\u019E.) &3\u019F\"\"5$7\u01A0/' 8!:\u01A1!! )"),
11375
+        peg$decode("%;\xFC/J#%28\"\"6879/,#;^/#$+\")(\"'#&'#.\" &\"/#$+\")(\"'#&'#"),
11376
+        peg$decode("%;\\.) &;X.# &;\x82/' 8!:\u01A2!! )"),
11377
+        peg$decode(";\".S &;!.M &2F\"\"6F7G.A &2J\"\"6J7K.5 &2H\"\"6H7I.) &2N\"\"6N7O"),
11378
+        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?"),
11379
+        peg$decode("%;\u0100/b#28\"\"6879/S$;\xFB/J$%2\u01A3\"\"6\u01A37\u01A4/,#;\xEC/#$+\")(\"'#&'#.\" &\"/#$+$)($'#(#'#(\"'#&'#"),
11380
+        peg$decode("%3\u01A5\"\"5%7\u01A6.) &3\u01A7\"\"5$7\u01A8/' 8!:\u01A1!! )"),
11381
+        peg$decode("%;\xEC/O#3\xB1\"\"5#7\xB2.6 &3\xB3\"\"5#7\xB4.* &$;+0#*;+&/'$8\":\u01A9\" )(\"'#&'#"),
11382
+        peg$decode("%;\u0104/\x87#2F\"\"6F7G/x$;\u0103/o$2F\"\"6F7G/`$;\u0103/W$2F\"\"6F7G/H$;\u0103/?$2F\"\"6F7G/0$;\u0105/'$8):\u01AA) )()'#(('#(''#(&'#(%'#($'#(#'#(\"'#&'#"),
11383
+        peg$decode("%;#/>#;#/5$;#/,$;#/#$+$)($'#(#'#(\"'#&'#"),
11384
+        peg$decode("%;\u0103/,#;\u0103/#$+\")(\"'#&'#"),
11385
+        peg$decode("%;\u0103/5#;\u0103/,$;\u0103/#$+#)(#'#(\"'#&'#"),
11386
+        peg$decode("%;\x84/U#;'/L$;\x92/C$;'/:$;\x90/1$; .\" &\"/#$+&)(&'#(%'#($'#(#'#(\"'#&'#"),
11387
+        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/#$+\")(\"'#&'#&/#$+$)($'#(#'#(\"'#&'#"),
11388
+        peg$decode(";\x99.# &;L"),
11389
+        peg$decode("%2\u01AF\"\"6\u01AF7\u01B0/5#;</,$;\u010A/#$+#)(#'#(\"'#&'#"),
11390
+        peg$decode("%;D/S#;,/J$2:\"\"6:7;/;$;,.# &;T/,$;E/#$+%)(%'#($'#(#'#(\"'#&'#")
11391
+      ],
11392
+
11393
+      peg$currPos          = 0,
11394
+      peg$savedPos         = 0,
11395
+      peg$posDetailsCache  = [{ line: 1, column: 1 }],
11396
+      peg$maxFailPos       = 0,
11397
+      peg$maxFailExpected  = [],
11398
+      peg$silentFails      = 0,
11399
+
11400
+      peg$result;
11401
+
11402
+  if ("startRule" in options) {
11403
+    if (!(options.startRule in peg$startRuleIndices)) {
11404
+      throw new Error("Can't start parsing from rule \"" + options.startRule + "\".");
11405
+    }
11406
+
11407
+    peg$startRuleIndex = peg$startRuleIndices[options.startRule];
11408
+  }
11409
+
11410
+  function text() {
11411
+    return input.substring(peg$savedPos, peg$currPos);
11412
+  }
11413
+
11414
+  function location() {
11415
+    return peg$computeLocation(peg$savedPos, peg$currPos);
11416
+  }
11417
+
11418
+  function expected(description, location) {
11419
+    location = location !== void 0 ? location : peg$computeLocation(peg$savedPos, peg$currPos)
11420
+
11421
+    throw peg$buildStructuredError(
11422
+      [peg$otherExpectation(description)],
11423
+      input.substring(peg$savedPos, peg$currPos),
11424
+      location
11425
+    );
11426
+  }
11427
+
11428
+  function error(message, location) {
11429
+    location = location !== void 0 ? location : peg$computeLocation(peg$savedPos, peg$currPos)
11430
+
11431
+    throw peg$buildSimpleError(message, location);
11432
+  }
11433
+
11434
+  function peg$literalExpectation(text, ignoreCase) {
11435
+    return { type: "literal", text: text, ignoreCase: ignoreCase };
11436
+  }
11437
+
11438
+  function peg$classExpectation(parts, inverted, ignoreCase) {
11439
+    return { type: "class", parts: parts, inverted: inverted, ignoreCase: ignoreCase };
11440
+  }
11441
+
11442
+  function peg$anyExpectation() {
11443
+    return { type: "any" };
11444
+  }
11445
+
11446
+  function peg$endExpectation() {
11447
+    return { type: "end" };
11448
+  }
11449
+
11450
+  function peg$otherExpectation(description) {
11451
+    return { type: "other", description: description };
11452
+  }
11453
+
11454
+  function peg$computePosDetails(pos) {
11455
+    var details = peg$posDetailsCache[pos], p;
11456
+
11457
+    if (details) {
11458
+      return details;
11459
+    } else {
11460
+      p = pos - 1;
11461
+      while (!peg$posDetailsCache[p]) {
11462
+        p--;
11463
+      }
11464
+
11465
+      details = peg$posDetailsCache[p];
11466
+      details = {
11467
+        line:   details.line,
11468
+        column: details.column
11469
+      };
11470
+
11471
+      while (p < pos) {
11472
+        if (input.charCodeAt(p) === 10) {
11473
+          details.line++;
11474
+          details.column = 1;
11475
+        } else {
11476
+          details.column++;
11477
+        }
11478
+
11479
+        p++;
11480
+      }
11481
+
11482
+      peg$posDetailsCache[pos] = details;
11483
+      return details;
11484
+    }
11485
+  }
11486
+
11487
+  function peg$computeLocation(startPos, endPos) {
11488
+    var startPosDetails = peg$computePosDetails(startPos),
11489
+        endPosDetails   = peg$computePosDetails(endPos);
11490
+
11491
+    return {
11492
+      start: {
11493
+        offset: startPos,
11494
+        line:   startPosDetails.line,
11495
+        column: startPosDetails.column
11496
+      },
11497
+      end: {
11498
+        offset: endPos,
11499
+        line:   endPosDetails.line,
11500
+        column: endPosDetails.column
11501
+      }
11502
+    };
11503
+  }
11504
+
11505
+  function peg$fail(expected) {
11506
+    if (peg$currPos < peg$maxFailPos) { return; }
11507
+
11508
+    if (peg$currPos > peg$maxFailPos) {
11509
+      peg$maxFailPos = peg$currPos;
11510
+      peg$maxFailExpected = [];
11511
+    }
11512
+
11513
+    peg$maxFailExpected.push(expected);
11514
+  }
11515
+
11516
+  function peg$buildSimpleError(message, location) {
11517
+    return new peg$SyntaxError(message, null, null, location);
11518
+  }
11519
+
11520
+  function peg$buildStructuredError(expected, found, location) {
11521
+    return new peg$SyntaxError(
11522
+      peg$SyntaxError.buildMessage(expected, found),
11523
+      expected,
11524
+      found,
11525
+      location
11526
+    );
11527
+  }
11528
+
11529
+  function peg$decode(s) {
11530
+    var bc = new Array(s.length), i;
11531
+
11532
+    for (i = 0; i < s.length; i++) {
11533
+      bc[i] = s.charCodeAt(i) - 32;
11534
+    }
11535
+
11536
+    return bc;
11537
+  }
11538
+
11539
+  function peg$parseRule(index) {
11540
+    var bc    = peg$bytecode[index],
11541
+        ip    = 0,
11542
+        ips   = [],
11543
+        end   = bc.length,
11544
+        ends  = [],
11545
+        stack = [],
11546
+        params, i;
11547
+
11548
+    while (true) {
11549
+      while (ip < end) {
11550
+        switch (bc[ip]) {
11551
+          case 0:
11552
+            stack.push(peg$consts[bc[ip + 1]]);
11553
+            ip += 2;
11554
+            break;
11555
+
11556
+          case 1:
11557
+            stack.push(void 0);
11558
+            ip++;
11559
+            break;
11560
+
11561
+          case 2:
11562
+            stack.push(null);
11563
+            ip++;
11564
+            break;
11565
+
11566
+          case 3:
11567
+            stack.push(peg$FAILED);
11568
+            ip++;
11569
+            break;
11570
+
11571
+          case 4:
11572
+            stack.push([]);
11573
+            ip++;
11574
+            break;
11575
+
11576
+          case 5:
11577
+            stack.push(peg$currPos);
11578
+            ip++;
11579
+            break;
11580
+
11581
+          case 6:
11582
+            stack.pop();
11583
+            ip++;
11584
+            break;
11585
+
11586
+          case 7:
11587
+            peg$currPos = stack.pop();
11588
+            ip++;
11589
+            break;
11590
+
11591
+          case 8:
11592
+            stack.length -= bc[ip + 1];
11593
+            ip += 2;
11594
+            break;
11595
+
11596
+          case 9:
11597
+            stack.splice(-2, 1);
11598
+            ip++;
11599
+            break;
11600
+
11601
+          case 10:
11602
+            stack[stack.length - 2].push(stack.pop());
11603
+            ip++;
11604
+            break;
11605
+
11606
+          case 11:
11607
+            stack.push(stack.splice(stack.length - bc[ip + 1], bc[ip + 1]));
11608
+            ip += 2;
11609
+            break;
11610
+
11611
+          case 12:
11612
+            stack.push(input.substring(stack.pop(), peg$currPos));
11613
+            ip++;
11614
+            break;
11615
+
11616
+          case 13:
11617
+            ends.push(end);
11618
+            ips.push(ip + 3 + bc[ip + 1] + bc[ip + 2]);
11619
+
11620
+            if (stack[stack.length - 1]) {
11621
+              end = ip + 3 + bc[ip + 1];
11622
+              ip += 3;
11623
+            } else {
11624
+              end = ip + 3 + bc[ip + 1] + bc[ip + 2];
11625
+              ip += 3 + bc[ip + 1];
11626
+            }
11627
+
11628
+            break;
11629
+
11630
+          case 14:
11631
+            ends.push(end);
11632
+            ips.push(ip + 3 + bc[ip + 1] + bc[ip + 2]);
11633
+
11634
+            if (stack[stack.length - 1] === peg$FAILED) {
11635
+              end = ip + 3 + bc[ip + 1];
11636
+              ip += 3;
11637
+            } else {
11638
+              end = ip + 3 + bc[ip + 1] + bc[ip + 2];
11639
+              ip += 3 + bc[ip + 1];
11640
+            }
11641
+
11642
+            break;
11643
+
11644
+          case 15:
11645
+            ends.push(end);
11646
+            ips.push(ip + 3 + bc[ip + 1] + bc[ip + 2]);
11647
+
11648
+            if (stack[stack.length - 1] !== peg$FAILED) {
11649
+              end = ip + 3 + bc[ip + 1];
11650
+              ip += 3;
11651
+            } else {
11652
+              end = ip + 3 + bc[ip + 1] + bc[ip + 2];
11653
+              ip += 3 + bc[ip + 1];
11654
+            }
11655
+
11656
+            break;
11657
+
11658
+          case 16:
11659
+            if (stack[stack.length - 1] !== peg$FAILED) {
11660
+              ends.push(end);
11661
+              ips.push(ip);
11662
+
11663
+              end = ip + 2 + bc[ip + 1];
11664
+              ip += 2;
11665
+            } else {
11666
+              ip += 2 + bc[ip + 1];
11667
+            }
11668
+
11669
+            break;
11670
+
11671
+          case 17:
11672
+            ends.push(end);
11673
+            ips.push(ip + 3 + bc[ip + 1] + bc[ip + 2]);
11674
+
11675
+            if (input.length > peg$currPos) {
11676
+              end = ip + 3 + bc[ip + 1];
11677
+              ip += 3;
11678
+            } else {
11679
+              end = ip + 3 + bc[ip + 1] + bc[ip + 2];
11680
+              ip += 3 + bc[ip + 1];
11681
+            }
11682
+
11683
+            break;
11684
+
11685
+          case 18:
11686
+            ends.push(end);
11687
+            ips.push(ip + 4 + bc[ip + 2] + bc[ip + 3]);
11688
+
11689
+            if (input.substr(peg$currPos, peg$consts[bc[ip + 1]].length) === peg$consts[bc[ip + 1]]) {
11690
+              end = ip + 4 + bc[ip + 2];
11691
+              ip += 4;
11692
+            } else {
11693
+              end = ip + 4 + bc[ip + 2] + bc[ip + 3];
11694
+              ip += 4 + bc[ip + 2];
11695
+            }
11696
+
11697
+            break;
11698
+
11699
+          case 19:
11700
+            ends.push(end);
11701
+            ips.push(ip + 4 + bc[ip + 2] + bc[ip + 3]);
11702
+
11703
+            if (input.substr(peg$currPos, peg$consts[bc[ip + 1]].length).toLowerCase() === peg$consts[bc[ip + 1]]) {
11704
+              end = ip + 4 + bc[ip + 2];
11705
+              ip += 4;
11706
+            } else {
11707
+              end = ip + 4 + bc[ip + 2] + bc[ip + 3];
11708
+              ip += 4 + bc[ip + 2];
11709
+            }
11710
+
11711
+            break;
11712
+
11713
+          case 20:
11714
+            ends.push(end);
11715
+            ips.push(ip + 4 + bc[ip + 2] + bc[ip + 3]);
11716
+
11717
+            if (peg$consts[bc[ip + 1]].test(input.charAt(peg$currPos))) {
11718
+              end = ip + 4 + bc[ip + 2];
11719
+              ip += 4;
11720
+            } else {
11721
+              end = ip + 4 + bc[ip + 2] + bc[ip + 3];
11722
+              ip += 4 + bc[ip + 2];
11723
+            }
11724
+
11725
+            break;
11726
+
11727
+          case 21:
11728
+            stack.push(input.substr(peg$currPos, bc[ip + 1]));
11729
+            peg$currPos += bc[ip + 1];
11730
+            ip += 2;
11731
+            break;
11732
+
11733
+          case 22:
11734
+            stack.push(peg$consts[bc[ip + 1]]);
11735
+            peg$currPos += peg$consts[bc[ip + 1]].length;
11736
+            ip += 2;
11737
+            break;
11738
+
11739
+          case 23:
11740
+            stack.push(peg$FAILED);
11741
+            if (peg$silentFails === 0) {
11742
+              peg$fail(peg$consts[bc[ip + 1]]);
11743
+            }
11744
+            ip += 2;
11745
+            break;
11746
+
11747
+          case 24:
11748
+            peg$savedPos = stack[stack.length - 1 - bc[ip + 1]];
11749
+            ip += 2;
11750
+            break;
11751
+
11752
+          case 25:
11753
+            peg$savedPos = peg$currPos;
11754
+            ip++;
11755
+            break;
11756
+
11757
+          case 26:
11758
+            params = bc.slice(ip + 4, ip + 4 + bc[ip + 3]);
11759
+            for (i = 0; i < bc[ip + 3]; i++) {
11760
+              params[i] = stack[stack.length - 1 - params[i]];
11761
+            }
11762
+
11763
+            stack.splice(
11764
+              stack.length - bc[ip + 2],
11765
+              bc[ip + 2],
11766
+              peg$consts[bc[ip + 1]].apply(null, params)
11767
+            );
11768
+
11769
+            ip += 4 + bc[ip + 3];
11770
+            break;
11771
+
11772
+          case 27:
11773
+            stack.push(peg$parseRule(bc[ip + 1]));
11774
+            ip += 2;
11775
+            break;
11776
+
11777
+          case 28:
11778
+            peg$silentFails++;
11779
+            ip++;
11780
+            break;
11781
+
11782
+          case 29:
11783
+            peg$silentFails--;
11784
+            ip++;
11785
+            break;
11786
+
11787
+          default:
11788
+            throw new Error("Invalid opcode: " + bc[ip] + ".");
11789
+        }
11790
+      }
11791
+
11792
+      if (ends.length > 0) {
11793
+        end = ends.pop();
11794
+        ip = ips.pop();
11795
+      } else {
11796
+        break;
11797
+      }
11798
+    }
11799
+
11800
+    return stack[0];
11801
+  }
11802
+
11803
+
11804
+    options.data = {}; // Object to which header attributes will be assigned during parsing
11805
+
11806
+    function list (head, tail) {
11807
+      return [head].concat(tail);
11808
+    }
11809
+
11810
+
11811
+  peg$result = peg$parseRule(peg$startRuleIndex);
11812
+
11813
+  if (peg$result !== peg$FAILED && peg$currPos === input.length) {
11814
+    return peg$result;
11815
+  } else {
11816
+    if (peg$result !== peg$FAILED && peg$currPos < input.length) {
11817
+      peg$fail(peg$endExpectation());
11818
+    }
11819
+
11820
+    throw peg$buildStructuredError(
11821
+      peg$maxFailExpected,
11822
+      peg$maxFailPos < input.length ? input.charAt(peg$maxFailPos) : null,
11823
+      peg$maxFailPos < input.length
11824
+        ? peg$computeLocation(peg$maxFailPos, peg$maxFailPos + 1)
11825
+        : peg$computeLocation(peg$maxFailPos, peg$maxFailPos)
11826
+    );
11827
+  }
11828
+}
11829
+
11830
+module.exports = {
11831
+  SyntaxError: peg$SyntaxError,
11832
+  parse:       peg$parse
11833
+};
11834
+
11835
+
11836
+/***/ }),
11837
+/* 38 */
11838
+/***/ (function(module, exports, __webpack_require__) {
11839
+
11840
+"use strict";
11841
+/**
11842
+ * @name SIP
11843
+ * @namespace
11844
+ */
11845
+
11846
+module.exports = function (SIP) {
11847
+    var Modifiers;
11848
+    function stripPayload(sdp, payload) {
11849
+        var i;
11850
+        var media_descs = [];
11851
+        var current_media_desc;
11852
+        var lines = sdp.split(/\r\n/);
11853
+        for (i = 0; i < lines.length;) {
11854
+            var line = lines[i];
11855
+            if (/^m=(?:audio|video)/.test(line)) {
11856
+                current_media_desc = {
11857
+                    index: i,
11858
+                    stripped: []
11859
+                };
11860
+                media_descs.push(current_media_desc);
11861
+            }
11862
+            else if (current_media_desc) {
11863
+                var rtpmap = /^a=rtpmap:(\d+) ([^/]+)\//.exec(line);
11864
+                if (rtpmap && payload === rtpmap[2]) {
11865
+                    lines.splice(i, 1);
11866
+                    current_media_desc.stripped.push(rtpmap[1]);
11867
+                    continue; // Don't increment 'i'
11868
+                }
11869
+            }
11870
+            i++;
11871
+        }
11872
+        for (i = 0; i < media_descs.length; i++) {
11873
+            var mline = lines[media_descs[i].index].split(' ');
11874
+            // Ignore the first 3 parameters of the mline. The codec information is after that
11875
+            for (var j = 3; j < mline.length;) {
11876
+                if (media_descs[i].stripped.indexOf(mline[j]) !== -1) {
11877
+                    mline.splice(j, 1);
11878
+                    continue;
11879
+                }
11880
+                j++;
11881
+            }
11882
+            lines[media_descs[i].index] = mline.join(' ');
11883
+        }
11884
+        return lines.join('\r\n');
11885
+    }
11886
+    function stripMediaDescription(sdp, description) {
11887
+        var descriptionRegExp = new RegExp("m=" + description + ".*$", "gm");
11888
+        var groupRegExp = new RegExp("^a=group:.*$", "gm");
11889
+        if (descriptionRegExp.test(sdp)) {
11890
+            var midLineToRemove_1;
11891
+            sdp = sdp.split(/^m=/gm).filter(function (section) {
11892
+                if (section.substr(0, description.length) === description) {
11893
+                    midLineToRemove_1 = section.match(/^a=mid:.*$/gm);
11894
+                    if (midLineToRemove_1) {
11895
+                        midLineToRemove_1 = midLineToRemove_1[0].match(/:.+$/g)[0].substr(1);
11896
+                    }
11897
+                    return false;
11898
+                }
11899
+                return true;
11900
+            }).join('m=');
11901
+            var groupLine = sdp.match(groupRegExp);
11902
+            if (groupLine && groupLine.length === 1) {
11903
+                groupLine = groupLine[0];
11904
+                var groupRegExpReplace = new RegExp("\ *" + midLineToRemove_1 + "[^\ ]*", "g");
11905
+                groupLine = groupLine.replace(groupRegExpReplace, "");
11906
+                sdp = sdp.split(groupRegExp).join(groupLine);
11907
+            }
11908
+        }
11909
+        return sdp;
11910
+    }
11911
+    Modifiers = {
11912
+        stripTcpCandidates: function (description) {
11913
+            description.sdp = description.sdp.replace(/^a=candidate:\d+ \d+ tcp .*?\r\n/img, "");
11914
+            return SIP.Utils.Promise.resolve(description);
11915
+        },
11916
+        stripTelephoneEvent: function (description) {
11917
+            description.sdp = stripPayload(description.sdp, 'telephone-event');
11918
+            return SIP.Utils.Promise.resolve(description);
11919
+        },
11920
+        cleanJitsiSdpImageattr: function (description) {
11921
+            description.sdp = description.sdp.replace(/^(a=imageattr:.*?)(x|y)=\[0-/gm, "$1$2=[1:");
11922
+            return SIP.Utils.Promise.resolve(description);
11923
+        },
11924
+        stripG722: function (description) {
11925
+            description.sdp = stripPayload(description.sdp, 'G722');
11926
+            return SIP.Utils.Promise.resolve(description);
11927
+        },
11928
+        stripRtpPayload: function (payload) {
11929
+            return function (description) {
11930
+                description.sdp = stripPayload(description.sdp, payload);
11931
+                return SIP.Utils.Promise.resolve(description);
11932
+            };
11933
+        },
11934
+        stripVideo: function (description) {
11935
+            description.sdp = stripMediaDescription(description.sdp, "video");
11936
+            return SIP.Utils.Promise.resolve(description);
11937
+        },
11938
+        addMidLines: function (description) {
11939
+            var sdp = description.sdp;
11940
+            if (sdp.search(/^a=mid.*$/gm) === -1) {
11941
+                var mlines_1 = sdp.match(/^m=.*$/gm);
11942
+                sdp = sdp.split(/^m=.*$/gm);
11943
+                mlines_1.forEach(function (elem, idx) {
11944
+                    mlines_1[idx] = elem + '\na=mid:' + idx;
11945
+                });
11946
+                sdp.forEach(function (elem, idx) {
11947
+                    if (mlines_1[idx]) {
11948
+                        sdp[idx] = elem + mlines_1[idx];
11949
+                    }
11950
+                });
11951
+                sdp = sdp.join('');
11952
+                description.sdp = sdp;
11953
+            }
11954
+            return SIP.Utils.Promise.resolve(description);
11955
+        }
11956
+    };
11957
+    return Modifiers;
11958
+};
11959
+
11960
+
11961
+/***/ }),
11962
+/* 39 */
11963
+/***/ (function(module, exports, __webpack_require__) {
11964
+
11965
+"use strict";
11966
+/* WEBPACK VAR INJECTION */(function(global) {
11967
+/**
11968
+ * @fileoverview Simple
11969
+ */
11970
+/* Simple
11971
+ * @class Simple
11972
+ */
11973
+module.exports = function (SIP) {
11974
+    var C = {
11975
+        STATUS_NULL: 0,
11976
+        STATUS_NEW: 1,
11977
+        STATUS_CONNECTING: 2,
11978
+        STATUS_CONNECTED: 3,
11979
+        STATUS_COMPLETED: 4
11980
+    };
11981
+    /*
11982
+     * @param {Object} options
11983
+     */
11984
+    var Simple = function (options) {
11985
+        /*
11986
+         *  {
11987
+         *    media: {
11988
+         *      remote: {
11989
+         *        audio: <DOM element>,
11990
+         *        video: <DOM element>
11991
+         *      },
11992
+         *      local: {
11993
+         *        video: <DOM element>
11994
+         *      }
11995
+         *    },
11996
+         *    ua: {
11997
+         *       <UA Configuration Options>
11998
+         *    }
11999
+         *  }
12000
+         */
12001
+        if (options.media.remote.video) {
12002
+            this.video = true;
12003
+        }
12004
+        else {
12005
+            this.video = false;
12006
+        }
12007
+        if (options.media.remote.audio) {
12008
+            this.audio = true;
12009
+        }
12010
+        else {
12011
+            this.audio = false;
12012
+        }
12013
+        if (!this.audio && !this.video) {
12014
+            // Need to do at least audio or video
12015
+            // Error
12016
+            throw new Error('At least one remote audio or video element is required for Simple.');
12017
+        }
12018
+        this.options = options;
12019
+        // https://stackoverflow.com/questions/7944460/detect-safari-browser
12020
+        var browserUa = global.navigator.userAgent.toLowerCase();
12021
+        var isSafari = false;
12022
+        var isFirefox = false;
12023
+        if (browserUa.indexOf('safari') > -1 && browserUa.indexOf('chrome') < 0) {
12024
+            isSafari = true;
12025
+        }
12026
+        else if (browserUa.indexOf('firefox') > -1 && browserUa.indexOf('chrome') < 0) {
12027
+            isFirefox = true;
12028
+        }
12029
+        var sessionDescriptionHandlerFactoryOptions = {};
12030
+        if (isSafari) {
12031
+            sessionDescriptionHandlerFactoryOptions.modifiers = [SIP.Web.Modifiers.stripG722];
12032
+        }
12033
+        if (isFirefox) {
12034
+            sessionDescriptionHandlerFactoryOptions.alwaysAcquireMediaFirst = true;
12035
+        }
12036
+        if (!this.options.ua.uri) {
12037
+            this.anonymous = true;
12038
+        }
12039
+        this.ua = new SIP.UA({
12040
+            // User Configurable Options
12041
+            uri: this.options.ua.uri,
12042
+            authorizationUser: this.options.ua.authorizationUser,
12043
+            password: this.options.ua.password,
12044
+            displayName: this.options.ua.displayName,
12045
+            // Undocumented "Advanced" Options
12046
+            userAgentString: this.options.ua.userAgentString,
12047
+            // Fixed Options
12048
+            register: true,
12049
+            sessionDescriptionHandlerFactoryOptions: sessionDescriptionHandlerFactoryOptions,
12050
+            transportOptions: {
12051
+                traceSip: this.options.ua.traceSip,
12052
+                wsServers: this.options.ua.wsServers
12053
+            }
12054
+        });
12055
+        this.state = C.STATUS_NULL;
12056
+        this.logger = this.ua.getLogger('sip.simple');
12057
+        this.ua.on('registered', function () {
12058
+            this.emit('registered', this.ua);
12059
+        }.bind(this));
12060
+        this.ua.on('unregistered', function () {
12061
+            this.emit('unregistered', this.ua);
12062
+        }.bind(this));
12063
+        this.ua.on('failed', function () {
12064
+            this.emit('unregistered', this.ua);
12065
+        }.bind(this));
12066
+        this.ua.on('invite', function (session) {
12067
+            // If there is already an active session reject the incoming session
12068
+            if (this.state !== C.STATUS_NULL && this.state !== C.STATUS_COMPLETED) {
12069
+                this.logger.warn('Rejecting incoming call. Simple only supports 1 call at a time');
12070
+                session.reject();
12071
+                return;
12072
+            }
12073
+            this.session = session;
12074
+            this.setupSession();
12075
+            this.emit('ringing', this.session);
12076
+        }.bind(this));
12077
+        this.ua.on('message', function (message) {
12078
+            this.emit('message', message);
12079
+        }.bind(this));
12080
+        return this;
12081
+    };
12082
+    Simple.prototype = Object.create(SIP.EventEmitter.prototype);
12083
+    Simple.C = C;
12084
+    // Public
12085
+    Simple.prototype.call = function (destination) {
12086
+        if (!this.ua || !this.checkRegistration()) {
12087
+            this.logger.warn('A registered UA is required for calling');
12088
+            return;
12089
+        }
12090
+        if (this.state !== C.STATUS_NULL && this.state !== C.STATUS_COMPLETED) {
12091
+            this.logger.warn('Cannot make more than a single call with Simple');
12092
+            return;
12093
+        }
12094
+        // Safari hack, because you cannot call .play() from a non user action
12095
+        if (this.options.media.remote.audio) {
12096
+            this.options.media.remote.audio.autoplay = true;
12097
+        }
12098
+        if (this.options.media.remote.video) {
12099
+            this.options.media.remote.video.autoplay = true;
12100
+        }
12101
+        if (this.options.media.local && this.options.media.local.video) {
12102
+            this.options.media.local.video.autoplay = true;
12103
+            this.options.media.local.video.volume = 0;
12104
+        }
12105
+        this.session = this.ua.invite(destination, {
12106
+            sessionDescriptionHandlerOptions: {
12107
+                constraints: {
12108
+                    audio: this.audio,
12109
+                    video: this.video
12110
+                }
12111
+            }
12112
+        });
12113
+        this.setupSession();
12114
+        return this.session;
12115
+    };
12116
+    Simple.prototype.answer = function () {
12117
+        if (this.state !== C.STATUS_NEW && this.state !== C.STATUS_CONNECTING) {
12118
+            this.logger.warn('No call to answer');
12119
+            return;
12120
+        }
12121
+        // Safari hack, because you cannot call .play() from a non user action
12122
+        if (this.options.media.remote.audio) {
12123
+            this.options.media.remote.audio.autoplay = true;
12124
+        }
12125
+        if (this.options.media.remote.video) {
12126
+            this.options.media.remote.video.autoplay = true;
12127
+        }
12128
+        return this.session.accept({
12129
+            sessionDescriptionHandlerOptions: {
12130
+                constraints: {
12131
+                    audio: this.audio,
12132
+                    video: this.video
12133
+                }
12134
+            }
12135
+        });
12136
+        // emit call is active
12137
+    };
12138
+    Simple.prototype.reject = function () {
12139
+        if (this.state !== C.STATUS_NEW && this.state !== C.STATUS_CONNECTING) {
12140
+            this.logger.warn('Call is already answered');
12141
+            return;
12142
+        }
12143
+        return this.session.reject();
12144
+    };
12145
+    Simple.prototype.hangup = function () {
12146
+        if (this.state !== C.STATUS_CONNECTED && this.state !== C.STATUS_CONNECTING && this.state !== C.STATUS_NEW) {
12147
+            this.logger.warn('No active call to hang up on');
12148
+            return;
12149
+        }
12150
+        if (this.state !== C.STATUS_CONNECTED) {
12151
+            return this.session.cancel();
12152
+        }
12153
+        else {
12154
+            return this.session.bye();
12155
+        }
12156
+    };
12157
+    Simple.prototype.hold = function () {
12158
+        if (this.state !== C.STATUS_CONNECTED || this.session.local_hold) {
12159
+            this.logger.warn('Cannot put call on hold');
12160
+            return;
12161
+        }
12162
+        this.mute();
12163
+        this.logger.log('Placing session on hold');
12164
+        return this.session.hold();
12165
+    };
12166
+    Simple.prototype.unhold = function () {
12167
+        if (this.state !== C.STATUS_CONNECTED || !this.session.local_hold) {
12168
+            this.logger.warn('Cannot unhold a call that is not on hold');
12169
+            return;
12170
+        }
12171
+        this.unmute();
12172
+        this.logger.log('Placing call off hold');
12173
+        return this.session.unhold();
12174
+    };
12175
+    Simple.prototype.mute = function () {
12176
+        if (this.state !== C.STATUS_CONNECTED) {
12177
+            this.logger.warn('An acitve call is required to mute audio');
12178
+            return;
12179
+        }
12180
+        this.logger.log('Muting Audio');
12181
+        this.toggleMute(true);
12182
+        this.emit('mute', this);
12183
+    };
12184
+    Simple.prototype.unmute = function () {
12185
+        if (this.state !== C.STATUS_CONNECTED) {
12186
+            this.logger.warn('An active call is required to unmute audio');
12187
+            return;
12188
+        }
12189
+        this.logger.log('Unmuting Audio');
12190
+        this.toggleMute(false);
12191
+        this.emit('unmute', this);
12192
+    };
12193
+    Simple.prototype.sendDTMF = function (tone) {
12194
+        if (this.state !== C.STATUS_CONNECTED) {
12195
+            this.logger.warn('An active call is required to send a DTMF tone');
12196
+            return;
12197
+        }
12198
+        this.logger.log('Sending DTMF tone: ' + tone);
12199
+        this.session.dtmf(tone);
12200
+    };
12201
+    Simple.prototype.message = function (destination, message) {
12202
+        if (!this.ua || !this.checkRegistration()) {
12203
+            this.logger.warn('A registered UA is required to send a message');
12204
+            return;
12205
+        }
12206
+        if (!destination || !message) {
12207
+            this.logger.warn('A destination and message are required to send a message');
12208
+            return;
12209
+        }
12210
+        this.ua.message(destination, message);
12211
+    };
12212
+    // Private Helpers
12213
+    Simple.prototype.checkRegistration = function () {
12214
+        return (this.anonymous || (this.ua && this.ua.isRegistered()));
12215
+    };
12216
+    Simple.prototype.setupRemoteMedia = function () {
12217
+        // If there is a video track, it will attach the video and audio to the same element
12218
+        var pc = this.session.sessionDescriptionHandler.peerConnection;
12219
+        var remoteStream;
12220
+        if (pc.getReceivers) {
12221
+            remoteStream = new global.window.MediaStream();
12222
+            pc.getReceivers().forEach(function (receiver) {
12223
+                var track = receiver.track;
12224
+                if (track) {
12225
+                    remoteStream.addTrack(track);
12226
+                }
12227
+            });
12228
+        }
12229
+        else {
12230
+            remoteStream = pc.getRemoteStreams()[0];
12231
+        }
12232
+        if (this.video) {
12233
+            this.options.media.remote.video.srcObject = remoteStream;
12234
+            this.options.media.remote.video.play().catch(function () {
12235
+                this.logger.log('play was rejected');
12236
+            }.bind(this));
12237
+        }
12238
+        else if (this.audio) {
12239
+            this.options.media.remote.audio.srcObject = remoteStream;
12240
+            this.options.media.remote.audio.play().catch(function () {
12241
+                this.logger.log('play was rejected');
12242
+            }.bind(this));
12243
+        }
12244
+    };
12245
+    Simple.prototype.setupLocalMedia = function () {
12246
+        if (this.video && this.options.media.local && this.options.media.local.video) {
12247
+            var pc = this.session.sessionDescriptionHandler.peerConnection;
12248
+            var localStream;
12249
+            if (pc.getSenders) {
12250
+                localStream = new global.window.MediaStream();
12251
+                pc.getSenders().forEach(function (sender) {
12252
+                    var track = sender.track;
12253
+                    if (track && track.kind === 'video') {
12254
+                        localStream.addTrack(track);
12255
+                    }
12256
+                });
12257
+            }
12258
+            else {
12259
+                localStream = pc.getLocalStreams()[0];
12260
+            }
12261
+            this.options.media.local.video.srcObject = localStream;
12262
+            this.options.media.local.video.volume = 0;
12263
+            this.options.media.local.video.play();
12264
+        }
12265
+    };
12266
+    Simple.prototype.cleanupMedia = function () {
12267
+        if (this.video) {
12268
+            this.options.media.remote.video.srcObject = null;
12269
+            this.options.media.remote.video.pause();
12270
+            if (this.options.media.local && this.options.media.local.video) {
12271
+                this.options.media.local.video.srcObject = null;
12272
+                this.options.media.local.video.pause();
12273
+            }
12274
+        }
12275
+        if (this.audio) {
12276
+            this.options.media.remote.audio.srcObject = null;
12277
+            this.options.media.remote.audio.pause();
12278
+        }
12279
+    };
12280
+    Simple.prototype.setupSession = function () {
12281
+        this.state = C.STATUS_NEW;
12282
+        this.emit('new', this.session);
12283
+        this.session.on('progress', this.onProgress.bind(this));
12284
+        this.session.on('accepted', this.onAccepted.bind(this));
12285
+        this.session.on('rejected', this.onEnded.bind(this));
12286
+        this.session.on('failed', this.onFailed.bind(this));
12287
+        this.session.on('terminated', this.onEnded.bind(this));
12288
+    };
12289
+    Simple.prototype.destroyMedia = function () {
12290
+        this.session.sessionDescriptionHandler.close();
12291
+    };
12292
+    Simple.prototype.toggleMute = function (mute) {
12293
+        var pc = this.session.sessionDescriptionHandler.peerConnection;
12294
+        if (pc.getSenders) {
12295
+            pc.getSenders().forEach(function (sender) {
12296
+                if (sender.track) {
12297
+                    sender.track.enabled = !mute;
12298
+                }
12299
+            });
12300
+        }
12301
+        else {
12302
+            pc.getLocalStreams().forEach(function (stream) {
12303
+                stream.getAudioTracks().forEach(function (track) {
12304
+                    track.enabled = !mute;
12305
+                });
12306
+                stream.getVideoTracks().forEach(function (track) {
12307
+                    track.enabled = !mute;
12308
+                });
12309
+            });
12310
+        }
12311
+    };
12312
+    Simple.prototype.onAccepted = function () {
12313
+        this.state = C.STATUS_CONNECTED;
12314
+        this.emit('connected', this.session);
12315
+        this.setupLocalMedia();
12316
+        this.setupRemoteMedia();
12317
+        this.session.sessionDescriptionHandler.on('addTrack', function () {
12318
+            this.logger.log('A track has been added, triggering new remoteMedia setup');
12319
+            this.setupRemoteMedia();
12320
+        }.bind(this));
12321
+        this.session.sessionDescriptionHandler.on('addStream', function () {
12322
+            this.logger.log('A stream has been added, trigger new remoteMedia setup');
12323
+            this.setupRemoteMedia();
12324
+        }.bind(this));
12325
+        this.session.on('hold', function () {
12326
+            this.emit('hold', this.session);
12327
+        }.bind(this));
12328
+        this.session.on('unhold', function () {
12329
+            this.emit('unhold', this.session);
12330
+        }.bind(this));
12331
+        this.session.on('dtmf', function (tone) {
12332
+            this.emit('dtmf', tone);
12333
+        }.bind(this));
12334
+        this.session.on('bye', this.onEnded.bind(this));
12335
+    };
12336
+    Simple.prototype.onProgress = function () {
12337
+        this.state = C.STATUS_CONNECTING;
12338
+        this.emit('connecting', this.session);
12339
+    };
12340
+    Simple.prototype.onFailed = function () {
12341
+        this.onEnded();
12342
+    };
12343
+    Simple.prototype.onEnded = function () {
12344
+        this.state = C.STATUS_COMPLETED;
12345
+        this.emit('ended', this.session);
12346
+        this.cleanupMedia();
12347
+    };
12348
+    return Simple;
12349
+};
12350
+
12351
+/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(28)))
12352
+
12353
+/***/ }),
12354
+/* 40 */
12355
+/***/ (function(module, exports, __webpack_require__) {
12356
+
12357
+"use strict";
12358
+/* WEBPACK VAR INJECTION */(function(global) {
12359
+var toplevel = global.window || global;
12360
+function getPrefixedProperty(object, name) {
12361
+    if (object == null) {
12362
+        return;
12363
+    }
12364
+    var capitalizedName = name.charAt(0).toUpperCase() + name.slice(1);
12365
+    var prefixedNames = [name, 'webkit' + capitalizedName, 'moz' + capitalizedName];
12366
+    for (var i in prefixedNames) {
12367
+        var property = object[prefixedNames[i]];
12368
+        if (property) {
12369
+            return property.bind(object);
12370
+        }
12371
+    }
12372
+}
12373
+module.exports = {
12374
+    WebSocket: toplevel.WebSocket,
12375
+    Transport: __webpack_require__(10),
12376
+    open: toplevel.open,
12377
+    Promise: toplevel.Promise,
12378
+    timers: toplevel,
12379
+    // Console is not defined in ECMAScript, so just in case...
12380
+    console: toplevel.console || {
12381
+        debug: function () { },
12382
+        log: function () { },
12383
+        warn: function () { },
12384
+        error: function () { }
12385
+    },
12386
+    addEventListener: getPrefixedProperty(toplevel, 'addEventListener'),
12387
+    removeEventListener: getPrefixedProperty(toplevel, 'removeEventListener')
12388
+};
12389
+
12390
+/* WEBPACK VAR INJECTION */}.call(this, __webpack_require__(28)))
12391
+
12392
+/***/ })
12393
+/******/ ]);
12394
+});
0 12395
\ No newline at end of file